PHP function works… but causes errors in WordPress when called more than once?-ThrowExceptions

Exception or error:

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.

How to solve:

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();

Leave a Reply

Your email address will not be published. Required fields are marked *