0

So...here is part of my code for a plugin. I'm a newb of sorts so be kind. I've read up on global variables but I can't seem to get it to work and I've read you shouldn't use them anyway. So what would be the best way to write the code below without having to re-declare the variables for each function? Here is the full code if necessary.

// Display the product badge on the shop page

add_action( 'woocommerce_after_shop_loop_item_title', 'wc_simple_product_badge_display_shop', 30 );
function wc_simple_product_badge_display_shop() {
    $title = get_post_meta( get_the_ID(), '_wc_simple_product_badge_title', true ); // badge title
    $class = get_post_meta( get_the_ID(), '_wc_simple_product_badge_class', true ); // badge class
    $duration = get_post_meta( get_the_ID(), '_wc_simple_product_badge_duration', true ); // badge duration
    $postdate = get_the_time( 'Y-m-d' ); // post date
    $postdatestamp = strtotime( $postdate ); // post date in unix timestamp
    $difference = round ((time() - $postdatestamp) / (24*60*60));  // difference in days between now and product's post date

    if ( !empty( $title ) && empty( $duration ) || !empty( $title ) && $difference <= $duration ){ // Check to see if there is a title and the product is still within the duration timeframe if specified
        $class = !empty( $class ) ? $class : '';
        echo '<span class="wc_simple_product_badge ' . $class . '">' . $title . '</span>';
    }
}

// Display the product badge on the single page

add_filter( 'woocommerce_single_product_image_html', 'wc_simple_product_badge_display_single' );    
function wc_simple_product_badge_display_single( $img_html ) {
    $title = get_post_meta( get_the_ID(), '_wc_simple_product_badge_title', true ); // badge title
    $class = get_post_meta( get_the_ID(), '_wc_simple_product_badge_class', true ); // badge class
    $duration = get_post_meta( get_the_ID(), '_wc_simple_product_badge_duration', true ); // badge duration
    $single_opt = get_post_meta( get_the_ID(), '_wc_simple_product_badge_single_page_option', true ); // badge on single page
    $postdate = get_the_time( 'Y-m-d' ); // post date
    $postdatestamp = strtotime( $postdate ); // post date in unix timestamp
    $difference = round ((time() - $postdatestamp) / (24*60*60));  // difference in days between now and product's post date

    if ( !empty( $title ) && empty( $duration ) && $single_opt === 'yes' || !empty( $title ) && $difference <= $duration && $single_opt === 'yes' ){ // Check to see if there is a title and the product is still within the duration timeframe ()if specified) and the checkbox is checked to show on single page view
        $class = !empty( $class ) ? $class : '';
        echo '<span class="wc_simple_product_badge ' . $class . '">' . $title . '</span>';
        return $img_html;
}

    elseif ( $single_opt === 'no' ) { // Check to see if the checkbox is unchecked to show on single page view
        return $img_html;
    }

}

2 Answers 2

2

Create a class to store the variables as private, internal members. Set up the variables when the post object is set up, that's the action the_post.

Then assign class methods as callbacks instead of separate functions.

Here is your code slightly reformatted:

The class

class WPSE_WC_Badge
{
    private $title = '';    
    private $class = '';    
    private $duration = '';    
    private $postdate = '';    
    private $postdatestamp = '';    
    private $difference = 0;

    public function __construct( \WP_Post $post )
    {
        $this->title         = get_post_meta( $post->ID, '_wc_simple_product_badge_title', TRUE ); // badge title
        $this->class         = get_post_meta( $post->ID, '_wc_simple_product_badge_class', TRUE ); // badge class
        $this->duration      = get_post_meta( $post->ID, '_wc_simple_product_badge_duration', TRUE ); // badge duration
        $this->postdate      = get_the_time( 'Y-m-d', $post ); // post date
        $this->postdatestamp = strtotime( $this->postdate ); // post date in unix timestamp
        // difference in days between now and product's post date
        $this->difference = round( ( time() - $this->postdatestamp ) / DAY_IN_SECONDS );
    }

    function loop()
    {
        if ( ! empty( $this->title ) && empty( $this->duration )
             || ! empty( $this->title ) && $this->difference <= $this->duration
        )
        { // Check to see if there is a title and the product is still within the duration timeframe if specified
            echo '<span class="wc_simple_product_badge ' . $this->class . '">' . $this->title . '</span>';
        }
    }

    function single( $img_html )
    {
        $single_opt = get_post_meta( get_the_ID(), '_wc_simple_product_badge_single_page_option', TRUE ); // badge on single page

        if ( ! empty ( $this->title ) && empty( $this->duration ) && $single_opt === 'yes'
             || ! empty( $this->title ) && $this->difference <= $this->duration && $single_opt === 'yes'
        )
        {
            echo '<span class="wc_simple_product_badge ' . $this->class . '">' . $this->title . '</span>';

            return $img_html;
        }

        return $img_html;
    }
}

And the registration

add_action( 'the_post', function( \WP_Post $post ) {

    $badge = new WPSE_WC_Badge( $post );

    // Display the product badge on the shop page
    add_action( 'woocommerce_after_shop_loop_item_title', [ $badge, 'loop' ], 30 );
    // Display the product badge on the single page
    add_filter( 'woocommerce_single_product_image_html', [ $badge, 'single' ] );
});

I haven't tested this, please take it just as starting point.

3
  • Sweet...I'll give it a test tomorrow. I'll have to read up to try to understand the way that you used 'class' Commented May 31, 2016 at 2:43
  • @toscho, what does \WP_Post mean? can that be changed, like \WP_MyPost, or does it have to say \WP_Post because we are passing in $post into the class?
    – klewis
    Commented Nov 4, 2016 at 15:52
  • 1
    @blackhawk \WP_Post is the type of the object that is passed by WordPress to that hook. You cannot change that.
    – fuxia
    Commented Nov 4, 2016 at 21:51
2

While Toscho's answer isn't wrong, using a class would circumvent the issue, the OP's original question is regarding the usage of globals and as such answers should be directly geared to that.

--- Using Globals ---

Any variable defined in the global scope (not inside a function or similar) is inherently a global. To access a global with in a function you must use the global keyword e.g. global $myglobal

Here is your code refactored to demonstrate:

<?php

$product_data = array();

// populating the global on a hook before the other two
add_action('woocommerce_before_single_product','populate_product_data');
function populate_product_data() {
    global $product_data;

    $postdate = get_the_time( 'Y-m-d' ); // post date
    $postdatestamp = strtotime($postdate);

    $product_data = array(
        'title'         => get_post_meta( get_the_ID(), '_wc_simple_product_badge_title', true ), // badge title
        'class'         => get_post_meta( get_the_ID(), '_wc_simple_product_badge_class', true ), // badge class
        'duration'      => get_post_meta( get_the_ID(), '_wc_simple_product_badge_duration', true ), // badge duration
        'single_opt'    => get_post_meta( get_the_ID(), '_wc_simple_product_badge_single_page_option', true ), // badge on single page
        'postdate'      => $postdate,
        'postdatestamp' => $postdatestamp, // post date in unix timestamp
        'difference'    => round ((time() - $postdatestamp) / (24*60*60)),  // difference in days between now and 
    );
}

add_action( 'woocommerce_after_shop_loop_item_title', 'wc_simple_product_badge_display_shop', 30 );
function wc_simple_product_badge_display_shop() {
    global $product_data;

    if ( !empty( $product_data['title'] ) && empty( $product_data['duration'] ) || !empty( $product_data['title'] ) && $product_data['difference'] <= $product_data['duration'] ){ // Check to see if there is a title and the product is still within the duration timeframe if specified
        $class = !empty( $class ) ? $class : '';
        echo '<span class="wc_simple_product_badge ' . $product_data['class'] . '">' . $product_data['title'] . '</span>';
    }
}

// Display the product badge on the single page

add_filter( 'woocommerce_single_product_image_html', 'wc_simple_product_badge_display_single' );    
function wc_simple_product_badge_display_single( $img_html ) {
    global $product_data;

    if ( !empty( $product_data['title'] ) && empty( $product_data['duration'] ) && $product_data['single_opt'] === 'yes' || !empty( $product_data['title'] ) && $product_data['difference'] <= $product_data['duration'] && $product_data['single_opt'] === 'yes' ){ // Check to see if there is a title and the product is still within the duration timeframe ()if specified) and the checkbox is checked to show on single page view
        $class = !empty( $product_data['title'] ) ? $product_data['title'] : '';
        echo '<span class="wc_simple_product_badge ' . $product_data['class'] . '">' . $product_data['title'] . '</span>';
        return $img_html;
}

    elseif ( $product_data['single_opt'] === 'no' ) { // Check to see if the checkbox is unchecked to show on single page view
        return $img_html;
    }

}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.