i extended product post type of woocommerce have custom post_status called 'expired'.
the desired behavior publish product shop , set expired after time span.
only published products should visible in shop permalink product should still working after post_status set expired display different template.
woocommerce displays products(in shop , single product view) "publish" post_status default initial thought hook pre_get_posts , add 'expired' post_status query vars.
a little addition use same slug posts, products , pages.
http://example.com/product-name
to accomplish came 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 '.$wpdb->posts.' 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 checking if post given name exists , post_status has. after query vars set accordingly.
and include custom template 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 plain copy of woocmmerce/single-product.php in theme directory.
the above code works... seems kind of hacky way since custom template gets display wordpress sends 404 header , title gets set 'page not found' i'm overwriting 404-template.
a side effect woocommerce styles , scripts won't load. tried dig documentation of woocommerce not able isolate error.
any recommendations on proper way accomplish desired behavior?
update
verified resulting sql query 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 sql request:
select wp_posts.* wp_posts 1=1 , wp_posts.post_name = 'expired-product' , wp_posts.post_type = 'product' , ((wp_posts.post_status = 'expired')) order wp_posts.post_date desc but returns empty array. running exact query in phpmyadmin returned right post. query publish product looks identical except post_status , name (selfexplainatory) ... returns right post in array.
ok, failure not in code posted above in registration of post_status itself:
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 is
'public' => false and has changed to
'public' => true i didn't know public attribute affects querying when query id. expired product has id 103 , $post = new wp_query('p=103'); doesn't return single post $post = get_post(103); return correct post.
maybe prevents future headaches in similar situation.
Comments
Post a Comment