Save product first publishing date as “First publish date” and set custom product badges



Currently I always always display a “new” product badge, when a product is created and published in the store. For that we use the standard WooCommerce function $product->get_date_modified().

However, we also want to display a “back in stock” product badge when a product is back in stock. For that we use the code from that answer: Display custom product badge when a product is back in stock WooCommerce

So in this case, we do not want to display the “new” and the “back in stock” badge at the same time. That’s why we try to code a check which helps to decide which badge must be displayed.

For that I try to store the first publishing date of a product in order to show or not show the custom badges.

The goal would be:

  • Publishing product process: If a product has not set a “first published date”, then store the current date ad the “first published date”
  • IF the “first published date” is older than 10 days set custom value to TRUE
  • IF the “first published date” is today or in the last 10 days => do nothing

Current Code

// Save date in custom field when product is first published
// If a product has no "first published date" store the current date (when product is saved) as first publishing date

function woo_first_product_published_date( $product_id ) {

if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
        
    if ( ! empty ( $first_publish_date) ) {

    // Store current date

    } 
 }


// Check if stock is 0 or not
function woo_updated_product_stock( $product_id ) {

   $product  = wc_get_product( $product_id );

   $stock_qty  = $product->get_stock_quantity();

// If stock is >=1 AND publishing date is older than 10 days set custom value to true
   if ($stock_qty >=1 && get_post_meta( $product->get_id(), '_first_publish_date', true) > 10 )
}

// IF a product published date is today or in the last 10 days => do nothing
   else{
      update_post_meta( $product_id, '_earlier_update',  false);
   }
}

add_action( 'woocommerce_updated_product_stock', 'woo_updated_product_stock', 10, 3);
add_action( 'woocommerce_update_product', 'woo_updated_product_stock',10, 3 );
add_action('save_post_product', 'woo_updated_product_stock', 10, 3);


// Add "back in stock" badge
add_action( 'woocommerce_before_shop_loop_item_title', function() {      
    global $product;
    $newness_days  = 10;
    $product_id    = $product->get_id();
    $date_modified = $product->get_date_modified()->date('Y-m-d');
    
    // Add 10 day on product modify date  becase fresh back in stock will show 10 days from current modify dates
    $back_in_stock = strtotime($date_modified. " + $newness_days day");
    $today         = strtotime(date('Y-m-d'));

    $earlier_update = get_post_meta( $product_id, '_earlier_update', true );
        
    if (($earlier_update && $today < $back_in_stock) && !$product->is_on_sale() && $product->is_in_stock() ) {
    echo '<div class="badge_loop_wrapper"><img src="https://staging01.ch/wp-content/uploads/2021/09/back_in_stock_badge.png"/></div>';
    
    }
});


// Add "new" badge for new products in store
add_action( 'woocommerce_before_shop_loop_item_title', function() {      
   global $product;
   $newness_days = 10;
   $created = strtotime( $product->get_date_modified() );
    
    // Check if product is new
    if ( ( time() - ( 60 * 60 * 24 * $newness_days ) ) < $created && !$product->is_on_sale() && $product->is_in_stock() && get_post_meta( $product->get_id(), '_earlier_update', true) !== '1' ) {
      echo '<div class="badge_loop_wrapper"><img src="https://staging01.ch/wp-content/uploads/2021/01/new_badge.png"/></div>';
   }

});

Answer

According to what I can gather from your question you are looking for the solution way too far, and using $product->get_date_created() and $product->get_date_modified() will suffice without adding extra data yourself when (re)saving the product.

  • If the product is created, and not older than 10 days, the ‘new’ badge will be displayed
  • If the product is modified in the first 10 days, after it was created. The ‘new’ badge will still be displayed
  • If the product is edited afterwards (update stock), then the ‘back in stock’ badge will be shown, provided this adjustment is not older than 10 days
  • Of course you can extend the ‘modified’ check with additional checks, whether there is actually a stock and such, but the basic principle of the code remains the same

So the following should suffice:

function action_woocommerce_before_shop_loop_item_title() {
    global $product;
    
    // Is a WC product
    if ( is_a( $product, 'WC_Product' ) ) {
        // 10 days in seconds
        $ten_days = 10 * 24 * 60 * 60;
        
        // Get now datetime (from Woocommerce datetime object) + Get now timestamp
        $datetime_now = new WC_DateTime();
        $timestamp_now = $datetime_now->getTimestamp();
        
        // Get product created datetime + product created timestamp
        $datetime_created  = $product->get_date_created();
        $timestamp_created = $datetime_created->getTimestamp();
        
        // Difference in seconds between now and date created
        $time_delta_created = $timestamp_now - $timestamp_created;
        
        // If the difference is less than 10, apply "New" label
        if ( $time_delta_created < $ten_days ) {
            echo '<span>' . __( 'New', 'woocommerce' ) . '</span>';
        } else {
            // Get product modified datetime + product modified timestamp
            $datetime_modified  = $product->get_date_modified();
            $timestamp_modified = $datetime_modified->getTimestamp();
            
            // Difference in seconds between now and date created
            $time_delta_modified = $timestamp_now - $timestamp_modified;
            
            // If the difference is less than 10, apply "Back in stock" label
            if ( $time_delta_modified < $ten_days ) {
                echo '<span>' . __( 'Back in stock', 'woocommerce' ) . '</span>';
            }
        }
    }
}
add_action( 'woocommerce_before_shop_loop_item_title', 'action_woocommerce_before_shop_loop_item_title', 10 );

If the product is not published immediately but only after +10 days, then $product->get_date_created() cannot be used.

To get around this you can add the following, this will adjust the created date to the date the product is published, not the date the product was created. An extra check is also provided for when the publish status of the product should change afterwards.

/**
 * Fire a callback only when my-custom-post-type posts are transitioned to 'publish'.
 *
 * @param string  $new_status New post status.
 * @param string  $old_status Old post status.
 * @param WP_Post $post       Post object.
 */
function action_transition_post_status( $new_status, $old_status, $post ) {
    if ( $old_status != 'publish' && $new_status == 'publish' && ! empty( $post->ID ) && in_array( $post->post_type, array( 'product' ) ) ) {
        // Get product
        $product = wc_get_product( $post->ID );
        
        // Is a WC product
        if ( is_a( $product, 'WC_Product' ) ) {         
            // Get meta value
            $published_first_time = $product->get_meta( '_published_first_time' );
            
            // When empty OR false
            if ( empty ( $published_first_time ) || $published_first_time == false ) {
                // Update meta data
                $product->update_meta_data( '_published_first_time', true );
                
                // Get an instance of the current WC_DateTime object
                $date_time = new WC_DateTime();
                
                // Set product created date
                $product->set_date_created( $date_time );
                
                // Save the data (in database)
                $product->save();
            }
        }
    }
}
add_action( 'transition_post_status', 'action_transition_post_status', 10, 3 );


Source: stackoverflow