woocommerce 过期产品自定义 post_status

woocommerce expired products custom post_status

我扩展了 woocommerce 的产品 post 类型,使其具有名为 'expired' 的自定义 post_status

期望的行为是将产品发布到商店并将其设置为在特定时间跨度后过期。

只有已发布的产品应该在商店中可见,但是在 post_status 设置为过期后产品的永久链接应该仍然有效,但显示不同的模板。

Woocommerce 本身默认只显示带有 "publish" post_status 的产品(在商店和单个产品视图中)所以我最初的想法是简单地连接到 pre_get_posts 并添加 'expired' 到 post_status 查询变量。

一点补充是 posts、产品和页面使用相同的 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 是否存在以及它有什么 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 的普通副本。

上面的代码有效...但是这样做似乎有点老套,因为自定义模板得到显示但 wordpress 发送 404 header 并且标题设置为 'page not found'所以我基本上覆盖了 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

但它 returns 是一个空数组。 运行 phpmyadmin 中的确切查询返回了正确的 post。发布产品的查询看起来相同,除了 post_status 和名称(不言自明)...但是 returns 数组中的右侧 post。

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

我不知道 public 属性影响查询,即使您查询 ID。过期产品的 ID 为 103,$post = new WP_Query('p=103'); 没有 return 一个 post,其中 $post = get_post(103); return 是正确的 post。

也许这可以防止将来遇到类似情况的人头疼。