问题描述

看起来所有的网页资源都基于删除自定义帖子类型 slug 的主题

yourdomain.com/CPT-SLUG/post-name

现在非常陈旧的解决方案通常引用了预装 WP 3.5 安装。一个常见的是:

'rewrite'   => array( 'slug' => false, 'with_front' => false ),

在您的 register_post_type 功能。这不再奏效,误导了。所以我要求社区在 2017 年第一季度在 WordPress 4.7.X 的边…

从重写参数或其他任何地方,从自定义帖子类型帖子的 URL 中删除 Post Type Slug 的现代和高效方法是什么?

脚注:请通过观看/推广来支持这张 trac 票:https://core.trac.wordpress.org/ticket/34136#ticket

最佳解决方案

以下代码将会起作用,但您只需要牢记,如果您的自定义帖子类型的插件与页面或帖子的插槽相同,则冲突可能会轻松发生

首先,我们将从永久链接中删除 s::

function na_remove_slug( $post_link, $post, $leavename ) {

    if ( 'events' != $post->post_type || 'publish' != $post->post_status ) {
        return $post_link;
    }

    $post_link = str_replace( '/' . $post->post_type . '/', '/', $post_link );

    return $post_link;
}
add_filter( 'post_type_link', 'na_remove_slug', 10, 3 );

只是去除 s 子是不够的。现在,您将获得一个 404 页面,因为 WordPress 只期望帖子和页面的行为。您还需要添加以下内容:

function na_parse_request( $query ) {

    if ( ! $query->is_main_query() || 2 != count( $query->query ) || ! isset( $query->query['page'] ) ) {
        return;
    }

    if ( ! empty( $query->query['name'] ) ) {
        $query->set( 'post_type', array( 'post', 'events', 'page' ) );
    }
}
add_action( 'pre_get_posts', 'na_parse_request' );

只需将”events” 更改为您的自定义帖子类型即可。您可能需要刷新您的固定链接。

次佳解决方案

不久之前,我试图弄清楚这一点,而我所知道的简短的答案是否定的。至少不能从重写参数内。

如果您在 wp-includes/post.php line 1454 中查看 register_post_type 的实际代码,那么长的解释变得很明显:

add_permastruct( $post_type, "{$args->rewrite['slug']}/%$post_type%", $permastruct_args );

您可以看到前缀 $ args-> 将 [‘slug’] 重写为%$ post_type%重写标记。人们可以认为 「让我们把 s just to to then then then then」「」「」「」「」「」「」until until until until until until until:::::

if ( empty( $args->rewrite['slug'] ) )
    $args->rewrite['slug'] = $post_type;

您可以看到该函数总是期望一个不为空的段值,否则使用该 post 类型。

第三种解决方案

响应 my previous answer:您可以自定义 rewrite 参数到 false 注册一个新的 post 类型,并自己处理这样的重写规则

<?php
function wpsx203951_custom_init() {

    $post_type = 'event';
    $args = (object) array(
        'public'      => true,
        'label'       => 'Events',
        'rewrite'     => false, // always set this to false
        'has_archive' => true
    );
    register_post_type( $post_type, $args );

    // these are your actual rewrite arguments
    $args->rewrite = array(
        'slug' => 'calendar'
    );

    // everything what follows is from the register_post_type function
    if ( is_admin() || '' != get_option( 'permalink_structure' ) ) {

        if ( ! is_array( $args->rewrite ) )
            $args->rewrite = array();
        if ( empty( $args->rewrite['slug'] ) )
            $args->rewrite['slug'] = $post_type;
        if ( ! isset( $args->rewrite['with_front'] ) )
            $args->rewrite['with_front'] = true;
        if ( ! isset( $args->rewrite['pages'] ) )
            $args->rewrite['pages'] = true;
        if ( ! isset( $args->rewrite['feeds'] ) || ! $args->has_archive )
            $args->rewrite['feeds'] = (bool) $args->has_archive;
        if ( ! isset( $args->rewrite['ep_mask'] ) ) {
            if ( isset( $args->permalink_epmask ) )
                $args->rewrite['ep_mask'] = $args->permalink_epmask;
            else
                $args->rewrite['ep_mask'] = EP_PERMALINK;
        }

        if ( $args->hierarchical )
            add_rewrite_tag( "%$post_type%", '(.+?)', $args->query_var ? "{$args->query_var}=" : "post_type=$post_type&pagename=" );
        else
            add_rewrite_tag( "%$post_type%", '([^/]+)', $args->query_var ? "{$args->query_var}=" : "post_type=$post_type&name=" );

        if ( $args->has_archive ) {
            $archive_slug = $args->has_archive === true ? $args->rewrite['slug'] : $args->has_archive;
            if ( $args->rewrite['with_front'] )
                $archive_slug = substr( $wp_rewrite->front, 1 ) . $archive_slug;
            else
                $archive_slug = $wp_rewrite->root . $archive_slug;

            add_rewrite_rule( "{$archive_slug}/?$", "index.php?post_type=$post_type", 'top' );
            if ( $args->rewrite['feeds'] && $wp_rewrite->feeds ) {
                $feeds = '(' . trim( implode( '|', $wp_rewrite->feeds ) ) . ')';
                add_rewrite_rule( "{$archive_slug}/feed/$feeds/?$", "index.php?post_type=$post_type" . '&feed=$matches[1]', 'top' );
                add_rewrite_rule( "{$archive_slug}/$feeds/?$", "index.php?post_type=$post_type" . '&feed=$matches[1]', 'top' );
            }
            if ( $args->rewrite['pages'] )
                add_rewrite_rule( "{$archive_slug}/{$wp_rewrite->pagination_base}/([0-9]{1,})/?$", "index.php?post_type=$post_type" . '&paged=$matches[1]', 'top' );
        }

        $permastruct_args = $args->rewrite;
        $permastruct_args['feed'] = $permastruct_args['feeds'];
        add_permastruct( $post_type, "%$post_type%", $permastruct_args );
    }
}
add_action( 'init', 'wpsx203951_custom_init' );

您现在可以看到 add_permastruct 电话现在不包括 slug 了。我测试了两个场景:

  1. 当我创建了一个页面,其中的”calendar” 页面被覆盖的帖子类型存档,也使用”calendar” slug 。

  1. 当我创建了一个带有 s 子”my-event” 的页面和一个事件 (CPT) 与 s lug “my-event”,显示自定义的帖子类型。

  1. 任何其他页面也不工作。如果你看看上面的图片,那就很明白为什么:自定义帖子类型规则总是与一个页面插槽匹配。因为 WordPress 无法识别是否是一个页面或不存在的自定义帖子类型,它将返回 404. 这就是为什么您需要一个小块来识别页面或 CPT 。一个可能的解决方案是拦截错误并寻找可能存在 similar to this answer 的页面。

参考文献

注:本文内容整合自 Google/Baidu/Bing 辅助翻译的英文资料结果。如果您对结果不满意,可以加入我们改善翻译效果:薇晓朵技术论坛。