使分层自定义帖子类型永久链接像页面一样工作


16

我在这里搜索了有关自定义帖子类型永久链接的每个问题,但大多数似乎是自定义分类法重写的问题,或者是flush_rewrite_rules()的明显缺失。但就我而言,我仅使用自定义帖子类型(无分类法),设置为分层(以便我可以分配父子关系),并为属性metabox提供适当的“支持”,等等。已经以一千种不同的方式刷新了重写规则。我尝试了不同的永久链接结构。但是子URL始终会显示404!

我最初为“父母”和“孩子”元素使用了独立的自定义帖子类型(使用p2p),使用“父母”分组的分类法可能不会遇到麻烦-我知道这些在语义上会更加准确。但是对于客户端而言,当管理员在页面中显示“帖子”时,就像页面一样,它们最容易可视化层次结构:一棵简单的树,其中子代出现在父代下方,前缀为“-”,正确的顺序。另外,可以使用通过拖放来分配顺序的各种方法。通过分类法(或p2p)进行分组会在管理员列表中生成“帖子”的平坦列表,这在视觉上根本不那么明显。

因此,我所追求的实际上是与核心“页面”完全相同的行为,但是具有我的自定义帖子类型。我已经按预期注册了帖子类型,并且在管理员中它可以正常运行-我可以为每个新闻稿“ post”分配一个父项和一个menu_order,它们会正确显示在编辑列表中:

Spring 2012
 First Article
 Second Article

而且它们的永久链接似乎已正确构建。实际上,如果我更改了结构的任何内容,或者甚至在注册帖子类型时更改了重写代码,它们都会自动正确更新,因此我知道某些工作正常:

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在永久链接结构的开头有一个子弹,然后是父子子弹(其中页面仅以父子子弹开始,没有“前缀”)。我不知道为什么这会使事情搞砸了。大量文章似乎表明,这正是这种层次结构的CPT永久链接应具有的行为-但是我的尽管格式很好,但是却不起作用。

当我检查该404页的query_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

此重写输出将使我相信以下“非漂亮”永久链接将起作用:

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

它不是404,但显示的是父CPT项目“新闻通讯”,而不是子项。该请求看起来像这样:

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

Answers:


15

这是我第一次参加Stack Exchange,但我会尝试一下,看看是否能为您指明正确的方向。

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

这些CPT注册参数看起来不错,但是当请求CPT时,pagename查询var应该没有值,并且name查询var应该与newsletter此处相同,因此看来您的设置中存在冲突。

为了帮助调试,安装并激活“ 重写规则”检查器插件,然后访问“ 工具->重写规则 ” 屏幕。

  1. 在查看列表时,应该在所有页面重写规则之前列出您的新闻简讯CPT的所有规则。通过扫描“ ”列来验证是否是这种情况。
  2. 如果可以,请在“ 匹配URL ”字段中输入“第一条” CPT的URL,然后单击“过滤器”按钮以查看匹配的规则。它应与新闻通讯规则和页面规则匹配,但新闻通讯规则应位于第一位。

如果那没有发现任何问题,请在该post_name列中搜索wp_posts以找到其他带有“第一条”标语的帖子,以查看是否可能发生碰撞。还要确保搜索“新闻通讯”。

添加以下代码段以在请求的早期检查您的查询变量,以检查并确定重写规则匹配设置了哪些变量(请在前端访问子CPT)。如果pagenamevar没有出现在这里,则是稍后在请求中设置了它:

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;
}

任何修改查询变量的插件/功能都可能引起冲突,因此,如果仍然看到问题,请禁用它们。还要在每个步骤之后刷新您的重写规则,尤其是如果请求在上述第二步中匹配了错误规则时(请在单独的标签中打开“永久链接”屏幕,然后刷新它)。


我已经编辑了问题,以显示重写规则检查器的输出,因为这些注释不允许足够的格式。CPT的规则确实显示在列表的顶部,而不是其他任何内容-但不确定下面的哪些规则是“页面”规则(不清楚)。另外,post_name列中没有冲突。
体细胞的2013年

您对适当的永久链接结构有任何想法吗?我回过头来,/%postname%/因为/%category%/只包括似乎在重写检查器中进一步混淆了事情。我什至已经看到人们声称,/%category%/对于CPT而言,它神奇地映射为“父母”,尽管我认为这不是真的。
体细胞的2013年

该输出似乎来自另一个插件,这就是为什么您看不到规则的“源”的原因。无论哪种方式,看来您的规则都很好。我已经编辑了答案,以包含一个片段来检查请求中较早的查询变量,以确保正确设置了变量。
Brady Vercher 2013年

至于永久链接结构,我不喜欢包含该类别。这只是另一个动静的部分,无济于事,帖子可以属于多个类别。如果您将来很有可能会更改永久链接结构,或者希望另一个CPT加载时没有任何多余的前缀,那么我建议您使用固定且唯一的名称对结构进行“命名” /blog/%postname%/
Brady Vercher 2013年

它是正确的插件,但是有两个页面:“重写分析器”和“重写规则”,均提供测试URL。我尝试了另一页,它确实将源显示为第一个缩进组的“程序”,第二个显示为“页”。
体细胞的

5

parent/Child只要您进行设置,永久链接即开即用

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

更新:

我只是再次测试了一下,并且可以通过以下测试用例按预期工作:

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 );
}

并且永久链接设置为/%postname%/我可以让时事通讯/父母/孩子正常工作。


我上面的代码没有显示它,但是我确实有page-attributes支持(实际上仅是显示用于分配亲子关系的metabox,不应该影响永久链接)-但是得到了404。需要设置什么永久链接结构?还是有关系吗?
体细胞

@somatic我只是再次测试了它,并且它工作正常,至于我不确定该是否固定,但以任何方式更新了我的答案。
Bainternet

我可以确认,为“标签”添加了一个参数数组(没有CPT将不会出现在admin中),这个基本示例确实适用于twentlytwelve的WP3.5原始安装。但我注意到您的register_post_type$ args 有一些关键区别:我用过'rewrite' => array( 'slug' => 'newsletter', 'with_front' => false ),而您只用了true。您也简单地通过truehas_archive,在这里我通过了塞。但是,当我匹配您的参数时,我仍然得到404 ...仍在尝试查找我要去哪里。
体细胞的2013年

3

除了询问“您是否尝试过将其关闭然后再次打开?”之外,我还必须询问“您是否有任何活动的插件,并且您的主题对永久链接有任何作用(例如:注册分类法,帖子类型,添加重写规则)等)?

如果是这样:在禁用所有插件并切换到TwentyEleven之后,这种情况还会发生吗? 在此处输入图片说明

要进一步调试,请转到GitHub并获取Toschos“重写”插件。然后切换到wp.​​org上的官方插件仓库,并获取MonkeyManRewriteAnalyzer插件。我什至写了一些扩展,将两者粘合在一起。这将为您提供有关设置的许多详细信息。


好吧,如果我禁用了所有功能,那么我将不会有自定义帖子类型,这就是这个问题的重点...但是,是的,即使是二十二十个主题,我也尝试过。我仍在挖掘一些必要的插件,以查看造成查询混乱的原因,因为据我所知,永久链接本身结构良好。
体细胞的

@somatic 当然不会禁用您的 :)
kaiser

@somatic请参阅更新。
kaiser

1

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

因此,我剩下的任务是手动禁用/启用9个大类中的每个大类,然后找到至少2个大类导致404,逐一遍历每个函数,然后禁用/启用它们,然后跟踪行在这些函数中逐行显示-即使我不知道为什么,也要通过蛮力尝试确切地找出导致404错误的原因。

那就是我发现使用的后果$query->get_queried_object()。似乎使用此包装函数实际上会修改$ query本身,我以为我在函数末尾返回的值保持不变。在2个班三个滤参与修改该查询:parse_queryposts_orderbyposts_join-和所有的回调函数被调用$query->get_queried_object()上传递的$queryARG来然后再运行一些条件测试,有时修改查询瓦尔(如特殊排列顺序的情况下)。奇怪的是,尽管我使用了这些功能,这些功能实际上在设计时可以正常工作。我以前从未发现返回的$ query有什么问题!

不知何故,在数十个现场制作站点上进行了超过一年的开发和使用之后,我从未经历过此错误带来的任何不利影响。只有当我冒险进入分级CPT时,这一小小的差异突然打破了一切。这就是让我如此努力的部分原因-据我所知,我的查询过滤器值得信赖!

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

感谢所有提示-希望我能分配赏金,因为从每个答案中获得的见识都可以,即使最终解决方案之间没有关系。这是一个教育课程,不要盲目地信任您的代码,即使它已经为您可靠地工作了很长时间,也没有产生任何明显的错误。

有时,正如凯撒(Kaiser)的图表如此巧妙地体现出来,您只需要开始抛出开关,直到灯重新亮起即可。就我而言,我必须采取相同的故障排除策略,一直到功能的各个行,然后才能看到问题。


您也可以使用包装函数,get_queried_object()而无需拦截$wpdb对象。
kaiser

但是那$query要抢哪个呢?我在过滤器中使用parse_query,并且需要专门获取$query从过滤器传递的特定对象的查询对象...
体细胞

我只是尝试在过滤器中使用包装器parse_query。它再次导致了相同的404错误。我必须找到某种方法来复制所做的get_queried_object()操作,而又不会弄污这些过滤器……
体细胞学2013年

-2

您是否正在运行最新版本的WP?我想这是第一个问题(例如,当您致电技术支持人员时,他们会询问您是否插入了计算机!),因为我已阅读到此问题已在最新版本的更新中解决。

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

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


2
我在3.5。从WP3.3.1开始,digiwp上的此问题已修复。
体细胞2013年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.