1

I have an open / closed script that I'd like to be placed in 3 separate areas of my page: The header, the footer and on a mobile menu panel when responsive.

I can get it to work fine in the header, but the minute I try to call it again (normally or via a shortcode) it wreaks havoc - causing strange layout changes or blank mobile panels.

I can't figure out what is causing this to happen, despite trying everything in the book (returning variables and calling those etc.)

This is setup as a function within Wordpress child theme's Functions.php file:

function open_closed_message() {

    date_default_timezone_set('America/Toronto');
    $date = new DateTime;
    echo date("D m/d/y  h:i:s ",time());

    $times = array(
        'mon' => '9:00 AM - 9:00 PM',
        'tue' => '9:00 AM - 9:00 PM',
        'wed' => '9:00 AM - 9:00 PM',
        'thu' => '9:00 AM - 9:00 PM',
        'fri' => '9:00 AM - 9:00 PM',
        'sat' => '11:00 AM - 6:00 PM',
        'sun' => 'closed'
    );

    function compileHours($times, $timestamp) {
        $times = $times[strtolower(date('D',$timestamp))];
        if(!strpos($times, '-')) return array();
        $hours = explode(",", $times);
        $hours = array_map('explode', array_pad(array(),count($hours),'-'), $hours);
        $hours = array_map('array_map', array_pad(array(),count($hours),'strtotime'),         $hours, array_pad(array(),count($hours),array_pad(array(),2,$timestamp)));
        end($hours);
        if ($hours[key($hours)][0] > $hours[key($hours)][1]) $hours[key($hours)][1] =         strtotime('+1 day', $hours[key($hours)][1]);
        return $hours;
    }

    function isOpen($now, $times) {
        $open = 0; // time until closing in seconds or 0 if closed
        // merge opening hours of today and the day before
        $hours = array_merge(compileHours($times,         strtotime('yesterday',$now)),compileHours($times, $now)); 

        foreach ($hours as $h) {
            if ($now >= $h[0] and $now < $h[1]) {
                $open = $h[1] - $now;
                return $open;
            } 
        }
        return $open;
    }

    $now = time();
    $open = isOpen($now, $times);

    if ($open == 0) {
        echo "Closed - Sorry, we are not making deliveries.";
    } 
    elseif ($open <= 1800) {
        $tomorrow = strtotime('tomorrow', $now);
        if (date('N', $tomorrow) == 7) {
            $tomorrow = strtotime('next monday', $now);
        }
        $day = strtolower(date('D', $tomorrow));
        $tomorrow = date('l', $tomorrow);
        $opentime = preg_replace('/^(\d+:\d+ [AP]M).*/', '$1', $times[$day]);
        echo "Finishing up current orders. We re-open $tomorrow at $opentime";
    }
    else {
        echo "Open - Yes, we are making deliveries.";
    }
}

All help is extremely appreciated as I have been trying to wrap my brain around this for hours.

  • so there is actually no error (500 error). just breaks the layout, then there's nothing to debug on the code above, its how to apply it in the layout. just make sure the text is in its proper place so that it doesn't break your html structure / markup – Kevin Mar 18 '20 at 04:02
  • Check this https://stackoverflow.com/questions/39818420/php-function-cannot-be-run-more-than-once – Full Stop Mar 18 '20 at 04:12

1 Answers1

2

Ok, so to make it short. Nesting functions is a dirty business. Your error goes as follows: You trigger the parent function. When this runs, it registers the nested functions. Which is why the first time you have no problem. However, when you run the parent for a second time, php will error saying that the nested functions already exists because its trying to register them again.

If you must preserve your code you can check if the function has already been registered.

function open_closed_message() {

    date_default_timezone_set('America/Toronto');
    $date = new DateTime;
    echo date("D m/d/y  h:i:s ",time());

    $times = array(
        'mon' => '9:00 AM - 9:00 PM',
        'tue' => '9:00 AM - 9:00 PM',
        'wed' => '9:00 AM - 9:00 PM',
        'thu' => '9:00 AM - 9:00 PM',
        'fri' => '9:00 AM - 9:00 PM',
        'sat' => '11:00 AM - 6:00 PM',
        'sun' => 'closed'
    );
// Check if function exists
if (!function_exists('compileHours')) {
    function compileHours($times, $timestamp) {
        $times = $times[strtolower(date('D',$timestamp))];
        if(!strpos($times, '-')) return array();
        $hours = explode(",", $times);
        $hours = array_map('explode', array_pad(array(),count($hours),'-'), $hours);
        $hours = array_map('array_map', array_pad(array(),count($hours),'strtotime'),         $hours, array_pad(array(),count($hours),array_pad(array(),2,$timestamp)));
        end($hours);
        if ($hours[key($hours)][0] > $hours[key($hours)][1]) $hours[key($hours)][1] =         strtotime('+1 day', $hours[key($hours)][1]);
        return $hours;
    }
}

// Check if function exists
if (!function_exists('isOpen')) {
    function isOpen($now, $times) {
        $open = 0; // time until closing in seconds or 0 if closed
        // merge opening hours of today and the day before
        $hours = array_merge(compileHours($times,         strtotime('yesterday',$now)),compileHours($times, $now)); 

        foreach ($hours as $h) {
            if ($now >= $h[0] and $now < $h[1]) {
                $open = $h[1] - $now;
                return $open;
            } 
        }
        return $open;
    }
}

    $now = time();
    $open = isOpen($now, $times);

    if ($open == 0) {
        echo "Closed - Sorry, we are not making deliveries.";
    } 
    elseif ($open <= 1800) {
        $tomorrow = strtotime('tomorrow', $now);
        if (date('N', $tomorrow) == 7) {
            $tomorrow = strtotime('next monday', $now);
        }
        $day = strtolower(date('D', $tomorrow));
        $tomorrow = date('l', $tomorrow);
        $opentime = preg_replace('/^(\d+:\d+ [AP]M).*/', '$1', $times[$day]);
        echo "Finishing up current orders. We re-open $tomorrow at $opentime";
    }
    else {
        echo "Open - Yes, we are making deliveries.";
    }
}

or you can make a class. which would be wayyyyyyyy better

class open_closed_message{

    public $date;

    public $times;

    public function __construct(){
        date_default_timezone_set('America/Toronto');
        $this->date = new DateTime;

        $this->times = [
            'mon' => '9:00 AM - 9:00 PM',
            'tue' => '9:00 AM - 9:00 PM',
            'wed' => '9:00 AM - 9:00 PM',
            'thu' => '9:00 AM - 9:00 PM',
            'fri' => '9:00 AM - 9:00 PM',
            'sat' => '11:00 AM - 6:00 PM',
            'sun' => 'closed'
        ];
    }

    public function message(){
        echo date("D m/d/y  h:i:s ",time());

        $now = time();
        $open = $this->isOpen($now, $this->times);

        if ($open == 0) {
            echo "Closed - Sorry, we are not making deliveries.";
        } elseif ($open <= 1800) {
            $tomorrow = strtotime('tomorrow', $now);
            if (date('N', $tomorrow) == 7) {
                $tomorrow = strtotime('next monday', $now);
            }
            $day = strtolower(date('D', $tomorrow));
            $tomorrow = date('l', $tomorrow);
            $opentime = preg_replace('/^(\d+:\d+ [AP]M).*/', '$1', $this->times[$day]);
            echo "Finishing up current orders. We re-open $tomorrow at $opentime";
        }
        else {
            echo "Open - Yes, we are making deliveries.";
        }
    }

    private function compileHours($times, $timestamp){
        $times = $times[strtolower(date('D',$timestamp))];
        if(!strpos($times, '-')) return array();
        $hours = explode(",", $times);
        $hours = array_map('explode', array_pad(array(),count($hours),'-'), $hours);
        $hours = array_map('array_map', array_pad(array(),count($hours),'strtotime'),         $hours, array_pad(array(),count($hours),array_pad(array(),2,$timestamp)));
        end($hours);
        if ($hours[key($hours)][0] > $hours[key($hours)][1]) $hours[key($hours)][1] =         strtotime('+1 day', $hours[key($hours)][1]);
        return $hours;
    }

    private function isOpen($now, $times) {
        $open = 0; // time until closing in seconds or 0 if closed
        // merge opening hours of today and the day before
        $hours = array_merge(compileHours($times,         strtotime('yesterday',$now)),compileHours($times, $now));

        foreach ($hours as $h) {
            if ($now >= $h[0] and $now < $h[1]) {
                $open = $h[1] - $now;
                return $open;
            }
        }
        return $open;
    }
}

run Class

$openClose = new open_closed_message();

run method

$openClose->message();
Jpv
  • 93
  • 3
  • 17
  • This worked perfectly, thank you so much! I didn't end up using the class because I wasn't sure how to properly call the functions within it (forgive me, I'm not a guru with this stuff). Could you quickly explain how, once the class is built, I can call it to execute the same way I would a function? – user3628937 Mar 18 '20 at 17:35