如何根据语言重写自定义帖子类型 slug?

Posted

技术标签:

【中文标题】如何根据语言重写自定义帖子类型 slug?【英文标题】:How can I rewrite custom post types slugs based on language? 【发布时间】:2012-10-18 11:56:44 【问题描述】:

我正在使用 WordPress 构建一个网站,它更像是一个 CMS,而不是一个博客平台。我大量使用了自定义帖子类型和自定义分类法。最后但并非最不重要的一点是,我使用 WPML 插件使它成为多语言。

在 CPT 声明期间,我将字符串和 slug 包装在 gettext 中,以便在 WPML 中准备好翻译。

CPT声明示例如下:

register_post_type('rooms',
    array(
        'label' => __('Rooms','valletta'),
        'description' => __('','valletta'),
        'public' => true,
        'show_ui' => true,
        'show_in_menu' => true,
        'capability_type' => 'post',
        'hierarchical' => true,
        'rewrite' => array('slug' => __('rooms','valletta')),
        'query_var' => true,
        'exclude_from_search' => false,
        'menu_position' => 25,
        'supports' => array('title','editor','excerpt','custom-fields','comments',),
        'taxonomies' => array('features','typology',),
        'labels' => array (
            'name' => __('Rooms','valletta'),
            'singular_name' => __('room','valletta'),
            'menu_name' => __('Rooms','valletta'),
            'add_new' => __('Add room','valletta'),
            'add_new_item' => __('Add New room','valletta'),
            'edit' => __('Edit','valletta'),
            'edit_item' => __('Edit room','valletta'),
            'new_item' => __('New room','valletta'),
            'view' => __('View room','valletta'),
            'view_item' => __('View room','valletta'),
            'search_items' => __('Search Rooms','valletta'),
            'not_found' => __('No Rooms Found','valletta'),
            'not_found_in_trash' => __('No Rooms Found in Trash','valletta'),
            'parent' => __('Parent room','valletta'),
        )
    )
);

如您所见,我也包含了 slug 术语,这(对我而言)非常有意义。我想要实现的是,当用户访问意大利语的“标准”网站时,将通过 /camere/nome-camera/ 到达房间 CPT 页面,而英语用户将通过 /rooms/room-name/ 获得它。这适用于意大利语,并且 WPML 也可以正确翻译英语版本的 slug,所以如果我在意大利语网站上查看房间 CPT 并切换到英语版本,WordPress 会被带到 /rooms/,唯一的问题是它显示 404。

我查看了 WPML 网站,他们承认 slugs 翻译仍在进行中,并且可能会在插件的下一个版本中发布。好的,没关系。

我想要实现的是在 WPML 更新是插件时使用的 hack。我的想法是在我的 .htaccess 中有一些自定义重写规则,并对这些 CPT 页面进行 URL 重写。我认为我可以删除 slug 翻译,以便为两种语言提供一个 slug,然后有一个重写规则,当有人键入翻译的 slug 时,会得到“标准”,但至少内容是正确的,并且:a)用户不会注意到任何事情,因为浏览器不会重定向页面而只是重写 URL 并且 b) WP 没有任何变化(或者它不会??)。

所以问题是:我该怎么做?删除 slug 翻译很好,只是在 WPML 后端删除,但我对重写规则等不太满意,所以我正在寻找帮助我实现目标的人,并最终展示更好的方法来实现什么我需要(如果我的想法是否合理,自然会有反馈)。

对不起,如果我错过了什么。如果您需要更多信息,我会在这里提供。

【问题讨论】:

【参考方案1】:

基本上,我认为在每次页面加载时运行 flush_rewrite_rules() 可以让您以您想要的方式本地化页面 slug,但是这是一个非常糟糕的解决方案,因为它还会在每个页面加载时写入 .htaccess 文件一旦有多个用户访问该站点,这会极大地减慢速度,并且可能会产生非常奇怪的结果。查看documentation,您似乎可以提供false 作为第一个参数,这会禁用.htaccess 的写入,但这仍然不是一个好的解决方案,因为文档还指出以下内容:

重要提示:刷新重写规则是一项昂贵的操作,有 是建议在“init”上执行它的教程和示例 钩。这是不好的做法。相反,您应该刷新重写规则 插件的激活钩子,或者当你知道重写时 需要更改规则(例如添加新的分类法或帖子 输入你的代码)。

每次我自己遇到这个问题时,我最终都会使用适用于两种语言的永久链接结构,但这也不是一个很好的解决方案。

一个好的起点可能是检查/wp-includes/rewrite.php,看看是否有可能通过过滤器覆盖给定帖子类型的永久链接,并根据用户的语言设置返回一个slug。另一种选择可能是尝试为每种语言添加第二个永久链接,以便自定义帖子类型中的每个帖子都可以通过register_post_type 中指定的永久链接以及您在其他地方指定的永久链接获得。您可以使用WP_Rewrite 或通过向您的.htaccess 添加一些mod_rewrite 指令来执行此操作。在后一种情况下,这样的事情可能会起作用:

$data = 'Rewrit­eRule ^/localized-type-name/(.*)$ /type-name/$1 [R,NC,L]';
// You might want to do a little more work on the actual rewrite rule, it's very much from the top of my head so it might not even work
insert_with_markers( ABSPATH . '/.htaccess', 'NAME OF YOUR MARKER', $data );
$wp_rewrite->flush_rules();

更新:您可能想查看this thread。

【讨论】:

其实我还没能解决这个问题。我尝试了各种方法......使用 .htaccess sems 不适用于 WP(或者我做错了)。我想唯一的解决方案是等待 WPML 在他们插件的下一次更新中发布此功能。【参考方案2】:

有可能。

由于您使用 WPML 插件,因此 php 常量 I ICL_LANGUAGE_CODE 给出当前语言。然后,在注册帖子类型的帖子时使用以下代码:

 $args = array (

    'labels'            => array (
        'name'              => _x( 'Destination','post type general name',TT_CPT_DOMAIN ),
        'singular_name'     => _x( 'Destination','post type singular name',TT_CPT_DOMAIN ),
        'add_new'           => _x( 'Add Destination','post type general name',TT_CPT_DOMAIN ),

        'edit_item'         => __( 'Edit Destination',TT_CPT_DOMAIN ),
        'not_found_in_trash' => __( 'No Destination found in Trash',TT_CPT_DOMAIN ),
        'taxonomies'        => __('post_tag','category'),
        'parent_item_colon' => '',
        'menu_name'         => __( 'Destination',TT_CPT_DOMAIN ) 
    ),

    'has_archive'       => true,
    'hierarchical'      => true,
    'menu_position'     => 3,
    'supports'          => array ('title'),
    'menu_icon'         => TT_CPT_PLUGIN_URL. 'images/News.png',  
    'rewrite'           => array('slug' => ( (ICL_LANGUAGE_CODE=='sv')? 'resor':'reiser' ) ),
    'menu_icon'              => TT_CPT_PLUGIN_URL . '/cpts/images/icon_news.png'        

);

注意这条线

rewrite'           => array('slug' => ( (ICL_LANGUAGE_CODE=='sv')? 'resor':'reiser' ) ),

如果您自己处理语言或使用任何其他插件,您可以使用类似的逻辑。 祝你好运!

【讨论】:

如果您使用的是 WPML,这会破坏单一语言的 CPT 单页

以上是关于如何根据语言重写自定义帖子类型 slug?的主要内容,如果未能解决你的问题,请参考以下文章

自定义帖子类型 Slug 重写问题

自定义帖子类型和分类法使用相同的 slug 和重写

如何在自定义帖子类型的重写规则中放置元值?

无法重命名自定义帖子类型的 slug

Wordpress - 如何通过 slug 获取自定义帖子类型?

在函数文件中更改自定义帖子类型 slug