Woocommerce expired products custom post_status

I expanded the post type of the product woocommerce

so that the custom one is post_status

called "expired".

The desired behavior is to publish the product in the store and expire after a certain amount of time.

Only published products should be visible in the store, but the product permalink should still work after the post_status expires, but a different template is displayed.

Woocommerce only displays products (only in store and in one view) with "publish" post_status

by default, so my initial thought was to just connect to pre_get_posts

and add "expired" to the post_status

vara request .

A small addition is to use the same pool for posts, products and pages.

http://example.com/page-name

http://example.com/post-name

http://example.com/product-name

To accomplish all of this, I came up with the following code:

add_action(
    'pre_get_posts',
    'custom_pre_get_posts'
);

function custom_pre_get_posts($query) {
    global $wpdb;

    if( !is_admin() && $query->is_main_query() && $post_name = $query->get('name')) {

        $result = $wpdb->get_row(
            $wpdb->prepare(
                'SELECT post_type, ID, post_status FROM '.$wpdb->posts.' WHERE post_name = %s LIMIT 1',
                $post_name
            )
        );



        if(!empty($result) && $result->post_type == 'product'){
            $query->set('name', $post_name);
            $query->set('product', $post_name);
            $query->set('post_type', $result->post_type);
            $query->set('post_status', $result->post_status);               
        }


    }

}

      

Just manually check if a mail with the given name exists and what post_status it has. After that, the corresponding queries are set.

And include a custom template for expired products:

add_filter( 
    'template_include', 
    'custom_expired_templates', 
    99 
);

function custom_expired_templates($template){

    global $wp_query;
    $status = $wp_query->get('post_status');
    $type = $wp_query->get('post_type');

    if($status === 'expired' && $type ==='product'){
        $template = locate_template( array( 'woocommerce/expired-single-product.php' ) );
    }

    return $template;
}

      

woocommerce/expired-single-product.php

is just a copy woocmmerce/single-product.php

in my theme directory.

The above code works ... but it seems like it's a hack to do it this way, since the custom template gets rendered, but wordpress sends the 404 header and the header gets page not found, so I'm basically rewriting the 404 template ...

A side effect is that woocommerce styles and scripts won't load. I actually tried to dig into the woocommerce documentation, but I was unable to isolate the error.

Any advice on the proper way to achieve the desired behavior?

Update

Checked the received SQL query by adding

add_action('the_posts','test_sql_request');

function test_sql_request($posts){
    echo $GLOBALS['wp_query']->request;
    var_dump($posts);
    return $posts;
}

      

The expired product has a SQL query:

SELECT wp_posts.* FROM wp_posts WHERE 1=1 AND wp_posts.post_name = 'expired-product' AND wp_posts.post_type = 'product' AND ((wp_posts.post_status = 'expired')) ORDER BY wp_posts.post_date DESC

      

but it returns an empty array. Running an exact query in phpmyadmin returned the correct post. The query for the post product looks identical, except for post_status and the name (selfexplainatory) ... but it returns the right entry in the array.

+3


source to share


1 answer


So, the failure was not in the code above, but in the registration itself post_status

:

function my_custom_post_status(){

    register_post_status( 'expired', array(
        'label'                     => _x( 'expired', 'product' ),
        'public'                    => false,
        'exclude_from_search'       => true,
        'show_in_admin_all_list'    => true,
        'show_in_admin_status_list' => true,
        'label_count'               => _n_noop( 'Expired <span class="count">(%s)</span>', 'Expired <span class="count">(%s)</span>' ),
    ) );
}

add_action( 'init', 'my_custom_post_status' );

      

The problematic part

 'public' => false

      



and it needs to be replaced with

'public' => true

      

I didn't know that the public attribute affects requests even when asking for an id. The expired product has an ID of 103 and $post = new WP_Query('p=103');

does not return a single message that $post = get_post(103);

returns the correct entry.

Perhaps this will prevent some future headaches for someone in a similar situation.

+3


source







All Articles