让分层定制帖子类型固定链接像页面一样工作

时间:2012-12-28 作者:somatic

我在这里仔细研究了关于自定义post类型permalinks的所有问题,但大多数问题似乎要么是自定义分类法重写的问题,要么是flush\\u rewrite\\u rules()的明显缺失。但在我的例子中,我只使用了一个自定义的post类型(没有分类法),设置为层次结构(这样我就可以分配父子关系),并对属性metabox等进行了适当的“支持”。我用了一千种不同的方式刷新了重写规则。我尝试过不同的permalink结构。但子URL总是导致404!

我最初为“parent”和“child”元素提供了独立的自定义post类型(使用p2p),并且我可能在为“parent”分组使用分类法时不会遇到任何问题-我知道这些分类法在语义上更准确。但对于客户端来说,当“帖子”像页面一样显示在管理中时,他们最容易看到层次结构:一个简单的树,其中子级显示在父级下方,前缀为“-”,并按正确的顺序排列。此外,还可以使用各种通过拖放指定顺序的方法。通过分类法(或p2p)分组会在管理列表中形成一个简单的“帖子”列表,这在视觉上并不明显。

因此,我追求的是与核心“页面”完全相同的行为,但我的自定义帖子类型。我已经按预期注册了帖子类型,在管理中效果很好-我可以为每个新闻稿“post”指定一个父级和一个menu\\u顺序,它们会正确显示在编辑列表中:

Spring 2012
— First Article
— Second Article
它们的永久线似乎构造得很好。事实上,如果我更改了结构的任何内容,甚至在注册post类型时更改了重写slug,它们会自动正确更新,因此我知道有什么在起作用:

http://mysite.com/parent-page/child-page/                  /* works for pages! */
http://mysite.com/post-type/parent-post/child-post/        /* should work? */
http://mysite.com/newsletter/spring-2012/                  /* works! */
http://mysite.com/newsletter/spring-2012/first-article/    /* 404 */
http://mysite.com/newsletter/spring-2012/second-article/   /* 404 */
我还创建了具有层次关系的标准核心“页面”,它们在管理中看起来完全相同,但实际上在前端也可以工作(父URL和子URL都可以正常工作)。

我的永久链接结构设置为:

http://mysite.com/%postname%/
我也尝试过这一点(只是因为许多其他答案似乎表明这是必要的,尽管在我的案例中没有意义):

http://mysite.com/%category%/%postname%/
我的注册CPT参数包括:

$args = array(
    \'public\'                => true,
    \'publicly_queryable\'    => true,
    \'show_ui\'               => true,
    \'has_archive\'           => \'newsletter\',
    \'hierarchical\'          => true,
    \'query_var\'             => true,
    \'supports\'              => array( \'title\', \'editor\', \'thumbnail\', \'page-attributes\' ),
    \'rewrite\'               => array( \'slug\' => \'newsletter\', \'with_front\' => false ),
我的自定义贴子类型与正常页面子类型之间唯一明显的区别是,我的CPT在永久链接结构的开头有slug,然后是父/子slug(其中页面仅以父/子slug开头,没有“前缀”)。我不知道为什么这会把事情搞砸。大量的文章似乎表明,这正是这种层次化CPT永久链接应该如何表现的——但我的,虽然结构良好,但不起作用。

同样让我困惑的是,当我检查404页面的query\\u vars时,它们似乎包含了WP“查找”我的子页面的正确值,但有些东西不起作用。

$wp_query object WP_Query {46}
public query_vars -> array (58)
\'page\' => integer 0
\'newsletter\' => string(25) "spring-2012/first-article"
\'post_type\' => string(10) "newsletter"
\'name\' => string(13) "first-article"
\'error\' => string(0) ""
\'m\' => integer 0
\'p\' => integer 0
\'post_parent\' => string(0) ""
\'subpost\' => string(0) ""
\'subpost_id\' => string(0) ""
\'attachment\' => string(0) ""
\'attachment_id\' => integer 0
\'static\' => string(0) ""
\'pagename\' => string(13) "first-article"
\'page_id\' => integer 0
[...]
我尝试过各种主题,包括《二十一世纪》,只是为了确保我没有丢失模板。

使用重写规则检查器,url将显示以下内容:http://mysite.com/newsletter/spring-2012/first-article/

newsletter/(.+?)(/[0-9]+)?/?$   
       newsletter: spring-2012/first-article
           page: 
(.?.+?)(/[0-9]+)?/?$    
       pagename: newsletter/spring-2012/first-article
           page: 
在其他检查器页面上的显示方式:

RULE:
newsletter/(.+?)(/[0-9]+)?/?$
REWRITE:
index.php?newsletter=$matches[1]&page=$matches[2]
SOURCE:
newsletter
这个重写输出会让我相信以下“不漂亮”的permalink会起作用:

http://mysite.com/?newsletter=spring-2012&page=first-article

它不是404,但它显示的是父CPT项目“新闻稿”,而不是子CPT项目。请求如下所示:

Array
(
    [page] => first-article
    [newsletter] => spring-2012
    [post_type] => newsletter
    [name] => spring-2012
)

5 个回复
最合适的回答,由SO网友:somatic 整理而成

因此,在确认我可以通过一个完全干净的安装和一个CPT声明获得预期的分层页面行为之后,我知道错误在我自己的插件中的某个地方,我使用该插件来处理CPT创建(非常复杂,处理自定义元盒、分类法等)。问题是,尽管所有的建议都是检查重写或查询问题,但我看不到任何明显的错误。我检查了每个过滤器和挂钩,查看了每个点的查询,没有发现任何会导致404的原因。

因此,我的任务是手动禁用/启用9个大型类中的每一个,然后找到其中至少2个是导致404的原因,逐个检查每个函数并禁用/启用它们,然后在这些函数中逐行跟踪-即使我不知道原因,暴力也试图准确地查看导致404的原因。

那时候我发现使用$query->get_queried_object(). 似乎使用这个包装器函数实际上修改了$query本身,我认为在函数结束时返回的是不变的。涉及两个类的三个过滤器,它们修改了查询:parse_query, posts_orderby, posts_join - 所有回调函数都在调用$query->get_queried_object() 在通过时$query 然后运行一些条件测试,有时修改查询变量(如特殊排序顺序情况)。奇怪的是,尽管我使用了这个函数,但这些函数实际上在其设计目的上工作得很好。我以前从未注意到返回的$查询有任何错误!

不知何故,在数十个现场制作网站上开发和使用了一年多之后,我从未经历过这个错误带来的任何负面影响。只有当我冒险进入分级CPT时,这一点小小的差异才突然打破了局面。这正是让我如此难以接受的部分原因——我尽可能地说,我的查询过滤器是值得信赖的!

我承认,我仍然不知道为什么调用这个函数只会破坏CPT子页面的这一个小方面,而从未出现任何其他问题!但很明显,在过滤器回调中使用它会损坏返回的$query 以某种方式通过删除此呼叫,我的404错误消失了。

感谢所有的提示-希望我能分得一份赏金,因为我从每个答案中获得了洞察力,即使最终的解决方案有些不相关。这是一堂教育课程,告诉你不要盲目相信你的代码,即使它已经可靠地为你工作了很长时间,或者它没有产生任何明显的错误。

有时,正如凯撒图表如此巧妙地体现的那样,你只需开始拨动开关,直到灯重新亮起。在我的例子中,我必须采取相同的故障排除策略,一直到函数中的各个行,然后才能看到问题。

SO网友:Brady Vercher

这是我第一次参加Stack Exchange,但我会尝试一下,看看是否可以帮助您找到正确的方向。

默认情况下,层次化CPT的行为与您描述的方式完全相同。在本例中,唯一的slug前缀“newsletter”是让重写引擎知道如何区分不同帖子类型的请求。

这些CPT注册参数看起来不错,但当请求CPT时pagename 查询变量不应具有值,并且name 查询变量应与相同newsletter 在这里,您的设置中似乎存在冲突。

要帮助调试,请安装并激活Rewrite Rules Inspector Plugin, 然后访问屏幕“Tools -> Rewrite Rules.“”

查看列表时,您的所有新闻稿CPT规则都应列在任何页面重写规则之前。通过扫描“Source列。

  • 如果符合,请在中输入“第一篇文章”CPT的URLMatch URL”字段,然后单击“筛选”按钮查看匹配的规则。它应该匹配新闻稿规则和页面规则,但新闻稿规则应该是第一个规则。
  • 如果这没有显示任何问题,请搜索post_name 中的列wp_posts 找到其他带有“first article”slug的帖子,看看是否有冲突。也可以搜索“时事通讯”,只是为了确定。

    添加以下代码段以在请求的早期检查查询变量,以检查并查看哪些变量是由重写规则匹配设置的(请访问前端的子CPT)。如果pagename 此处未显示var,则由请求后面的内容设置:

    add_filter( \'request\', \'se77513_display_query_vars\', 1 );
    
    function se77513_display_query_vars( $query_vars ) {
        echo \'<pre>\' . print_r( $query_vars, true ) . \'</pre>\';
    
        return $query_vars;
    }
    
    任何修改查询变量的插件/函数都可能导致冲突,因此,如果仍然看到问题,请禁用它们。还要在每个步骤后刷新重写规则,特别是如果请求与上面第二步中的错误规则匹配(在单独的选项卡中打开“永久链接”屏幕,然后刷新)。

    SO网友:Bainternet

    这个parent/Child 只要您设置

    \'hierarchical\'=> true,
    \'supports\' => array(\'page-attributes\' ....
    

    Update:

    我刚刚再次测试了它,它按照预期工作,使用以下测试用例:

    add_action(\'init\',\'test_post_type_wpa77513\');
    function test_post_type_wpa77513(){
        $args = array(
            \'public\' => true,
            \'publicly_queryable\' => true,
            \'show_ui\' => true, 
            \'show_in_menu\' => true, 
            \'query_var\' => true,
            \'rewrite\' => true,
            \'capability_type\' => \'post\',
            \'has_archive\' => true, 
            \'hierarchical\' => true,
            \'supports\' => array( \'title\', \'editor\', \'thumbnail\', \'page-attributes\' )
        ); 
    
        register_post_type( \'newsletter\', $args );
    }
    
    将permalink设置为/%postname%/ 我的时事通讯/家长/孩子工作得很好。

    SO网友:kaiser

    除了问»Have you tried turning it off and on again?«, 我还必须问“你是否有任何插件处于活动状态,你的主题是否对永久链接有任何影响(例如:注册分类法、帖子类型、添加重写规则等)?

    如果是这样的话:在您禁用所有插件并切换到TwentyEleven之后,这种情况还会发生吗?enter image description here

    要进一步调试,请转到GitHub并抓取Toschos "Rewrite" Plugin. 然后切换到官方插件repoon wp.org and grap the MonkeyManRewriteAnalyzer Plugin. 我甚至写了一个小小的扩展来将两者粘合在一起。这将为您提供有关设置的许多详细信息。

    SO网友:Melanie Sumner

    您是否运行最新版本的WP?我想这是第一个问题(比如当你打电话给技术支持,他们问你电脑是否插好电源!),因为我已经读到这个问题在最新的版本更新中得到了解决。

    digwp上有一篇帖子。解决此问题的com(http://digwp.com/2011/06/dont-use-postname/)显然,WP不能轻易区分帖子和页面之间的区别,如果您使用基于文本的选项启动URL,WP会触发一个标志,为您拥有的每个页面/帖子创建一个规则。如果你的网站上有很多内容,这可能会导致大量的请求,并且你的服务器可能会超时,这将导致大量的404,即使页面存在。

    所以如果您先使用基于数字的结构,然后使用基于文本的结构,我敢打赌您的404问题将得到解决。现在,考虑到SEO问题,我不会使用日期结构,但做出这个决定对你来说已经足够合乎逻辑了。

    结束

    相关推荐

    widgetlogic and permalinks

    我试图使用widgetlogic在某些页面上有条件地显示菜单。每个菜单都使用如下标记is_page(array(\"Page Name\", \"Page Name 2\" ...)), 在我尝试更改permalinks之前,它一直工作得很好(因此所有菜单都会从各自的页面中消失)。我做错什么了吗?是否有解决方法?