如何在自定义帖子类型固定链接中添加自定义分类?

时间:2019-09-03 作者:sadmansh

我有一个自定义分类法叫做campaign 和一个名为asset. 对于资产,我希望具有以下permalink结构:mysite.com/<campaign_name>/<asset_name>. 我已经通过以下代码实现了这一点,但是现在如果我转到任何具有url结构的正常页面mysite.com/<pagename> 它给出了404。当我注释掉函数中用于注册自定义post类型的重写slug部分,或者添加此部分时ams/%campaign%, 它可以工作,但这不是我想要的自定义帖子类型的URL结构。

用于注册自定义分类的代码:

...
\'rewrite\' => array(
    \'slug\' => \'\',
    \'with_front\' => true,
),
...
注册自定义帖子类型的代码:

...
rewrite\' => array(
    \'slug\' => \'%campaign%\',
    \'with_front\' => true,
),
...
重写规则的函数:

function ams_asset_add_rewrite_rules( $rules ) {
    global $post;
    if ($post->post_type == \'asset\' ) {
        $new = array();
        $new[\'([^/]+)/(.+)/?$\'] = \'index.php?asset=$matches[2]\';
        $new[\'(.+)/?$\'] = \'index.php?campaign=$matches[1]\';
        return array_merge( $new, $rules );
    }
    return $rules;
}
add_filter( \'rewrite_rules_array\', \'ams_asset_add_rewrite_rules\' );

// Handle the \'%campaign%\' URL placeholder
function ams_asset_filter_post_type_link( $link, $post = 0 ) {
    if ( $post->post_type == \'asset\' ) {
        $cats = wp_get_object_terms( $post->ID, \'campaign\' );
        if ( $cats ) {
            $link = str_replace( \'%campaign%\', $cats[0]->slug, $link );
        }
    }
    return $link;
}
add_filter( \'post_type_link\', \'ams_asset_filter_post_type_link\', 10, 2 );
编辑:它不是重复的。我解释了为什么这个可能重复的问题不能解决我的问题。

2 个回复
最合适的回答,由SO网友:Sohan Zaman 整理而成

解决方案可能有点棘手,但您走的是正确的道路。

您需要使用动态重写注册分类法和post类型:

function wpse346452_cpt() {

    register_taxonomy( \'campaign\', \'asset\', array( \'label\' => \'Campaing\' ) );

    register_post_type( \'asset\', array(
        \'public\' => true,
        \'label\' => \'Asset\',
        \'rewrite\' => array(
            \'slug\' => \'%campaign_name%\',
        ),
    ) );

}
add_action( \'init\', \'wpse346452_cpt\' );
您需要替换该动态重写,以便它表示所附的术语:
function wpse346452_permalink( $post_link, $post ) {
    if( is_object( $post ) && $post->post_type == \'asset\' ) {
        $terms = wp_get_object_terms( $post->ID, \'campaign\' );
        if( $terms ) {
            return str_replace( \'%campaign_name%\' , $terms[0]->slug , $post_link );
        }
    }
    return $post_link;
}
add_filter( \'post_type_link\', \'wpse346452_permalink\', 10, 2 );
因为重写规则尚未定义,所以现在得到404。每次你在竞选活动中有一个新的任期,你都需要一个新的规则。因此,让我们为每个可用术语动态添加重写规则:
function wpse346452_dynamic_rw_rules() {

    $terms = get_terms( array(
        \'taxonomy\' => \'campaign\',
        \'hide_empty\' => false,
    ) );

    if( !empty( $terms ) ) {
        foreach( $terms as $term ) {
            add_rewrite_rule(
                \'^\' . $term->slug . \'/(.*)/?$\',
                \'index.php?post_type=asset&name=$matches[1]\',
                \'top\'
            );
        }
    }

}
add_action( \'init\', \'wpse346452_dynamic_rw_rules\' );
现在它将根据您的需要工作。但缺点是,无论何时添加新活动,都需要转到永久链接设置并保存,从而刷新重写规则。因此,让我们也将其自动化:

function wpse346452_flush_rewrite( $term_id, $tt_id, $taxonomy = \'campaign\' ) {
    if( $taxonomy === \'campaign\' ) {
        $term = get_term_by( \'term_taxonomy_id\', $tt_id );
        add_rewrite_rule(
            \'^\' . $term->slug . \'/(.*)/?$\',
            \'index.php?post_type=asset&name=$matches[1]\',
            \'top\'
        );
        if( !function_exists( \'flush_rewrite_rules\' ) ) {
            require_once WPINC . \'/rewrite.php\';
        }
        flush_rewrite_rules();
    }
}
add_action( \'edit_term\', \'wpse346452_flush_rewrite\', 10, 3 );
add_action( \'create_campaign\', \'wpse346452_flush_rewrite\', 10, 3 );
在这里,我们将连接到创建和编辑术语,如果分类法是活动,那么我们将启动flush_rewrite_rules() 刷新永久链接。

据我所知,这是做这件事的唯一完美方法。但这样做是有限制的。由于添加术语没有限制,因此它可能与其他插件的重写规则冲突。所以需要小心使用。

SO网友:Antti Koskinen

我的回答并不直接适用于您的案例,因为我的经验是使用CPT permalinks做一些有趣的事情,但没有分类法。但最终的结果或多或少是相同的,因为在开始使用自定义permalink结构后,该网站的一半内容最终显示为404。

我花了很长时间才弄清楚到底发生了什么并解决了问题。问题是WordPress开始认为一些内容是附件,而不是页面/帖子/CPT。为了再次显示内容,我将一个自定义函数连接到parse_request 基本上是蛮力逼迫$wp->query_vars 是正确的。

这可能不是最优雅或最有效的解决方案,但它做到了。我确实尝试过添加自定义重写规则,但由于我无法理解重写概念,因此我一事无成。

这是我用来解决404问题的代码的简化版本。基本的想法是我只是用了query_vars 我做过,做过海关$wpdb 查询以获取正确的数据,然后将该数据推送到query_vars 并从中删除不必要的数据。

add_action( \'parse_request\',  \'modify_parse_request\' );
function modify_parse_request( $wp ) {
    if ( is_admin() || ! is_main_query() )  {
        return;
    }
    global $wpdb;

    // var_dump($wp->query_vars); // see whats really happening with your query

    if ( ! empty( $wp->query_vars[\'attachment\'] ) ) {

        // $path = explode( \'/\', $wp->request ); // you might need to get the page name from request

        $sql = "
            SELECT ID, post_name, post_type
            FROM $wpdb->posts
            WHERE post_name=%s
        ";
        $post = $wpdb->get_results( $wpdb->prepare( $sql, $wp->query_vars[\'attachment\'] ) ); // modify this

        // "brute force" the query variables to be correct
        if ( $post ) { // modify this
            $wp->query_vars[\'p\'] = $post->ID;
            $wp->query_vars[\'post_type\'] = $post->post_type;
            $wp->query_vars[\'name\'] = $wp->query_vars[\'attachment\'];
            unset( $wp->query_vars[\'attachment\'] );
        }

    }

}
这肯定不是一个复制粘贴的例子,只是一些食物或想法。如果使用自定义分类法+cpt\\U post\\U name permalink结构,也许可以以此为起点,让页面重新工作。

相关推荐