woocommerce过期产品定制post_status

时间:2015-07-16 09:21:25

标签: php wordpress woocommerce http-status-code-404

我将woocommerce的商品信息类型扩展为名为“已过期”的自定义post_status

所需的行为是将产品发布到商店并在一段时间后将其设置为过期。

只有在商店中才能看到已发布的产品,但在post_status设置为过期后,产品的固定链接仍然有效,但显示的是不同的模板。

Woocommerce本身只显示产品(在商店和单一产品视图中)默认情况下使用“发布”post_status,所以我最初的想法是简单地挂钩pre_get_posts并添加'过期'到post_status查询变种。

稍微补充的是对帖子,产品和页面使用相同的slug。

http://example.com/page-name

http://example.com/post-name

http://example.com/product-name

为了实现这一切,我提出了以下代码:

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


    }

}

只需手动检查是否存在具有给定名称的帖子以及它具有的post_status。之后,相应地设置查询变量。

并为过期产品添加自定义模板:

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只是我主题目录中woocmmerce/single-product.php的简单副本。

上面的代码有效...但是这样做似乎有点hacky,因为自定义模板显示但是wordpress发送404标题并且标题设置为'找不到页面'所以我基本上覆盖404模板。

副作用是不会加载woocommerce样式和脚本。我真的试图深入研究woocommerce的文档,但我无法隔离错误。

有关实现理想行为的正确方法的任何建议吗?

更新

通过添加

验证生成的SQL查询
add_action('the_posts','test_sql_request');

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

过期的产品有SQL请求:

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

但它返回一个空数组。在phpmyadmin中运行确切的查询返回了正确的帖子。发布产品的查询看起来完全相同,除了post_status和name(selfexplainatory)...但返回数组中的正确帖子。

1 个答案:

答案 0 :(得分:3)

好的,所以失败不在上面发布的代码中,而是在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' );

问题部分是

 'public' => false

并且必须更改为

'public' => true

即使您查询ID,我也不知道public属性会影响查询。已过期的产品ID为103,而$post = new WP_Query('p=103');不会返回单个帖子,其中$post = get_post(103);会返回正确的帖子。

对于类似情况的人来说,这可能会阻止一些未来的头痛。