如何拥有像Domain.com/Term/Postname这样的永久链接?

时间:2014-02-24 作者:Daniel

我试图创建一个URL结构,如domain.com/term/postname, 但我只得到404对于所有非CPT页面。

function add_video_post_type() {

    $labels = array(
        \'name\'                => _x( \'Videos\', \'Post Type General Name\', \'kibble\' ),
        \'singular_name\'       => _x( \'Video\', \'Post Type Singular Name\', \'kibble\' ),
        \'menu_name\'           => __( \'Videos\', \'kibble\' ),
        \'parent_item_colon\'   => __( \'Parent Item:\', \'kibble\' ),
        \'all_items\'           => __( \'All Items\', \'kibble\' ),
        \'view_item\'           => __( \'View Item\', \'kibble\' ),
        \'add_new_item\'        => __( \'Add New Item\', \'kibble\' ),
        \'add_new\'             => __( \'Add New\', \'kibble\' ),
        \'edit_item\'           => __( \'Edit Item\', \'kibble\' ),
        \'update_item\'         => __( \'Update Item\', \'kibble\' ),
        \'search_items\'        => __( \'Search Item\', \'kibble\' ),
        \'not_found\'           => __( \'Not found\', \'kibble\' ),
        \'not_found_in_trash\'  => __( \'Not found in Trash\', \'kibble\' ),
    );
    $rewrite = array(
        \'slug\'                => \'%video_genre%\',
        \'with_front\'          => true,
        \'pages\'               => true,
        \'feeds\'               => true,
    );
    $args = array(
        \'label\'               => __( \'video_type\', \'kibble\' ),
        \'description\'         => __( \'Video Posts\', \'kibble\' ),
        \'labels\'              => $labels,
        \'supports\'            => array( \'title\', \'editor\', \'thumbnail\', ),
        \'taxonomies\'          => array( \'video_genre\' ),
        \'hierarchical\'        => false,
        \'public\'              => true,
        \'show_ui\'             => true,
        \'show_in_menu\'        => true,
        \'show_in_nav_menus\'   => true,
        \'show_in_admin_bar\'   => true,
        \'menu_position\'       => 5,
        \'menu_icon\'           => \'dashicons-format-video\',
        \'can_export\'          => true,
        \'has_archive\'         => true,
        \'exclude_from_search\' => false,
        \'publicly_queryable\'  => true,
        \'rewrite\'             => $rewrite,
        \'capability_type\'     => \'page\',
    );
    register_post_type( \'video_type\', $args );

}

add_action( \'init\', \'add_video_post_type\', 0 );

function custom_video_genre() {

    $labels = array(
        \'name\'                       => _x( \'Video Categories\', \'Taxonomy General Name\', \'kibble\' ),
        \'singular_name\'              => _x( \'Video Category\', \'Taxonomy Singular Name\', \'kibble\' ),
        \'menu_name\'                  => __( \'Categories\', \'kibble\' ),
        \'all_items\'                  => __( \'All Items\', \'kibble\' ),
        \'parent_item\'                => __( \'Parent Item\', \'kibble\' ),
        \'parent_item_colon\'          => __( \'Parent Item:\', \'kibble\' ),
        \'new_item_name\'              => __( \'New Item Name\', \'kibble\' ),
        \'add_new_item\'               => __( \'Add New Item\', \'kibble\' ),
        \'edit_item\'                  => __( \'Edit Item\', \'kibble\' ),
        \'update_item\'                => __( \'Update Item\', \'kibble\' ),
        \'separate_items_with_commas\' => __( \'Separate items with commas\', \'kibble\' ),
        \'search_items\'               => __( \'Search Items\', \'kibble\' ),
        \'add_or_remove_items\'        => __( \'Add or remove items\', \'kibble\' ),
        \'choose_from_most_used\'      => __( \'Choose from the most used items\', \'kibble\' ),
        \'not_found\'                  => __( \'Not Found\', \'kibble\' ),
    );
    $args = array(
        \'labels\'                     => $labels,
        \'hierarchical\'               => true,
        \'public\'                     => true,
        \'show_ui\'                    => true,
        \'show_admin_column\'          => true,
        \'show_in_nav_menus\'          => true,
        \'show_tagcloud\'              => true,
    );
    register_taxonomy( \'video_genre\', \'video_type\', $args );

    }

    add_action( \'init\', \'custom_video_genre\', 0 );

    add_filter(\'post_type_link\', \'filter_post_type_link\', 10, 2);

    function filter_post_type_link( $link, $post ) {

    if ( strpos( $link, \'%video_genre%\' ) === false )
        return $link;

    $terms = wp_get_object_terms( $post->ID, \'video_genre\' );

    if ( current( $terms ) ) :

        $new_parent = current( $terms );

        foreach ( $terms as $term ) {
            if ( $term->parent == 0 ) {
                $new_parent = $term;
                break;
            }
        }

        $new_parent = $new_parent ? $new_parent : $terms[0];

        $category_string = $new_parent->slug;

        $category_string = trim( $category_string, \'/\' );

    endif;

    // set a default
    $category_string = ( isset( $category_string ) && $category_string ) ? $category_string : \'uncategorized\';

    $link = str_replace( \'%video_genre%\', $category_string, $link );
    return $link;
}

3 个回复
最合适的回答,由SO网友:Matthew Boynes 整理而成

简短回答将此添加到functions.php 文件或您拥有此代码其余部分的任何地方,假设这都在您的主题中。如果这是一个插件,那么前两行需要在setup_theme, 所以你需要加入到这个行动中。

而且,如果是我,我会把所有的东西都放在一节课上。如果这样做了,请使用类属性而不是全局属性$video_type_rewrite_rules 变量

$GLOBALS[\'wp_rewrite\']->use_verbose_page_rules = true;

function wpse_135707_video_type_rewrite_rules( $rules ) {
    $GLOBALS[\'video_type_rewrite_rules\'] = $rules;
    return array();
}
add_filter( \'video_type_rewrite_rules\', \'wpse_135707_video_type_rewrite_rules\' );

function wpse_135707_add_video_type_to_rewrite_rules_array( $rules ) {
    return array_merge( $rules, $GLOBALS[\'video_type_rewrite_rules\'] );
}
add_filter( \'rewrite_rules_array\', \'wpse_135707_add_video_type_to_rewrite_rules_array\' );
很长的答案是你的重写规则太笼统了。WordPress重写规则的工作方式是,规则是特定顺序数组中的正则表达式。当请求传入时,数组将循环通过以尝试匹配路径。一旦找到匹配项(只有一个例外,我很快就会看到),代码将退出循环,其余规则将被忽略。通常,分类法或帖子类型将为规则提供一个静态“锚”,因此两个帖子类型不会冲突。也就是说,如果您的post类型的permastruct是\'video/%video_genre%\' 这不会是个问题。换句话说,%video_genre% 替换为正则表达式,该正则表达式为extremely generic. 如果正则表达式中没有固定的文本字符串,它将匹配该url深度处的任何路径(url中的斜杠数相同)。

综上所述,您可以将permalink结构设置为/%category%/%postname%/, 那为什么这不会导致页面断裂呢?一些permalink结构有一个例外,上面的解决方案利用了这一点。这就是$use_verbose_page_rules 进来了;如果url结构以postname、category、tag或author开头,WordPress将设置$use_verbose_page_rulestrue, 这导致了两个变化。首先,重写规则的顺序改变了,在帖子之前设置页面,这没什么大不了的。其次,当该规则与请求匹配时,WordPress会在提交重写规则之前检查页面是否确实存在。如果它不存在,它将继续在规则上循环。这是发生这种情况的唯一例外。这里的主要缺点是,每个不是页面的请求都会导致额外的数据库查询,并在文本字段上进行搜索。如果你有一个庞大的数据库(成千上万的帖子),这个操作会对你的页面负载产生明显的影响。无论如何,我们在这里做的另一件事是将帖子类型的重写规则移动到页面重写规则之后,这样页面将首先匹配,检查它是否存在,如果不存在,则匹配视频规则。

其他选项到目前为止,最好的选择是避免重写这种通用规则。为此,请在帖子类型的重写规则中提供静态文本,如上所述(例如。\'video/%video_genre%\'.in this question. 此选项允许您拥有所需的任何永久链接结构,并具有其他具有通用重写规则(如此规则)的帖子类型

最后,确保在进行任何这些更改后刷新您的重写。

SO网友:Sudeep K Rana

我尝试了你的代码,重置permalink的行为异常。但我在给permalink设置一个新的register_taxanomy() 学期

我尝试了一个插件来重置自定义帖子类型的永久链接,只做了一点更改就成功了。

插件是:WP Permastructure

What I did is this:1) 在函数中注册post类型。php没有定义重写参数,因为我要用插件(上面的链接)来管理它。

2) 删除了所有不必要的代码,只保留可以注册帖子类型和分类的代码。

3) 已安装插件。参观Settings>Permalinks.

4) 设置Video post类型的永久链接。

Now the Weird Behaviour

a) 如果我将video post type的永久链接设置为/%video_genre%/%postname%/ 事情不正常,你的行为也不一样。404非CPT岗位。

b) 如果我将永久链接设置为/%video_genre%/%postname%/%post_id%. 也包括post\\u id。它正在工作并在url中显示video\\u流派。所有其他岗位也都运转良好。

奇怪吧!!

c) 然后我决定想出一个类似于这种行为的方法,并将永久链接设置为/%video_genre%/%postname%/1. 正在添加/1 在它的结尾。猜猜它是怎么工作的。找不到此行为的任何解释。

只要它能满足你的需要。这很好。试试看。

SO网友:Bendoh

我的结果就是您所经历的:启用此代码后,普通帖子返回404。如果我禁用了代码,但没有重置永久链接,我就会得到错误的帖子。

上面的答案并不能真正解释发生了什么,所以我释放了我的调试器。

我看到的是,对于普通帖子,它试图设置video_genrevideo_type 解析普通帖子的permalink后查询vars,这是不正确的。

我觉得在重写slug中使用替换变量看起来很奇怪,结果证明我是对的,这就是问题所在。使用这些替换变量可以提供如下永久匹配模式:

%video_genre%/feed/(feed|rdf|rss|rss2|atom)/ => $post_type=video_type&feed=$matches[1]

([^/]+)/([^/]+)(/[0-9]+)?/?$ => index.php?video_genre=$matches[1]&video_type=$matches[2]&page=$matches[3]

这是与我对常规帖子的请求相匹配的规则,因此设置video\\u流派和video\\u类型查询变量,而不是实际生成帖子的正确变量。

因此,虽然substitution变量在创建链接时很有用,但在filter_post_type_link, 它打破了permalink匹配系统。

解决方案

您尝试执行的操作会在永久链接结构中产生继承冲突,因为WordPress不知道您是尝试访问video\\u类型的CPT还是常规帖子。

相反,我要做的是设置rewrite 参数到false 您可以在其中调用register\\u post\\u type。然后在你的post_type_link 筛选,根据要筛选的帖子类型显式返回链接video_type 而不是依赖于您使用的替换变量。

function filter_post_type_link( $link, $post ) {
    if( $post->post_type != \'video_type\' )
        return $link;

    $terms = wp_get_object_terms( $post->ID, \'video_genre\' );

    if ( current( $terms ) ) :

        $new_parent = current( $terms );

        foreach ( $terms as $term ) {
            if ( $term->parent == 0 ) {
                $new_parent = $term;
                break;
            }
        }

        $new_parent = $new_parent ? $new_parent : $terms[0];

        $category_string = $new_parent->slug;

        $category_string = trim( $category_string, \'/\' );

    endif;

    // set a default
    $category_string = ( isset( $category_string ) && $category_string ) ? $category_string : \'uncategorized\';

    $link = home_url( path_join( $category_string, $post->post_name ) );
    return $link;
}
然后手动解析请求并设置所需的变量:

function wpse135707_parse_request( $wp ) {
    $terms = get_terms( \'video_genre\', array( \'hide_empty\' => false, \'fields\' => \'id=>slug\' ) );

    if( preg_match( \'#^(\' . join( \'|\', $terms ) . \')/([^/]+)#\', $wp->request, $matches ) ) {
        $wp->query_vars = array(
            \'post_type\' => \'video_type\',
            \'name\' => $matches[2]
        );
    }
}
add_action( \'parse_request\', \'wpse135707_parse_request\' );
然而,这种方法有一个缺点,即可能与其他permalinks发生冲突。这将解析任何以任何video\\u流派slug开头的URL,并假设它是video\\u类型的帖子,这可能适合您的目的。

结束

相关推荐

从图像路径中删除‘wp-Content/Themes/Themename/’

我目前正在将一个基于其他CMS的旧网站移动到一个新服务器上,使用WordPress。然而,这个网站在Google上排名很好,我必须保留所有的链接结构,包括来自图片的链接结构。因此,在旧CMS中,图像链接如下:http://www.domain-name.de/images/image1.jpg 现在,他们是这样的:http://www.domain-name.de/wp-content/themes/theme-name/images/image1.jpg 但它们必须与第一个示例中的一