WordPress 3.3带有/%postname%/permastruct的自定义POST类型?

时间:2012-01-01 作者:Ciantic

早期也有类似标题的帖子,但它没有查看WordPress 3.3,这一点很重要,因为3.3有趣地宣传:“使用postname permalink结构,不会造成性能损失”

Wordpress 3.2及更早版本的问题是,它首先查看页面名称,然后查看404。它没有首先检查任意的帖子类型。3.3另一方面,必须查看帖子类型,然后是页面,最后是404(因为它宣传此功能)。这意味着,如果没有硬编码,没有slug的自定义post类型应该是简单的post_type=post 在某处

但我还没有找到3.3的具体解决方案。

Question: 如何为任何给定的自定义帖子类型“xyz”定义permalink结构“/%postname%/”?

谢谢

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

这在WP 3.3中很难做到,除非您欺骗重写规则,使其位于正确的位置,并使WP\\U rewrite认为在前端使用了详细的规则。下面的课程有效。

class Test_Post_Type {
    const POST_TYPE = \'test\';

    public static function init() {
        global $wp_rewrite;

        $post_type_obj = register_post_type( self::POST_TYPE, array(
            \'labels\' => array(
                \'name\' => __( \'Tests\' ),
                \'singular_name\' => __( \'Test\' ),
                \'add_new\' => __( \'Add New\' ),
                \'add_new_item\' => __( \'Add New Test\' ),
                \'edit_item\' => __( \'Edit Test\' ),
                \'new_item\' => __( \'New Test\' ),
                \'all_items\' => __( \'All Tests\' ),
                \'view_item\' => __( \'View Test\' ),
                \'search_items\' => __( \'Search Tests\' ),
                \'not_found\' => __( \'No Tests found\' ),
                \'not_found_in_trash\' => __( \'No Tests found in Trash\' ),
                \'menu_name\' => __( \'Tests\' )
            ),
            \'publicly_queryable\' => true,
            \'exclude_from_search\' => true,
            \'hierarchical\' => false,
            \'public\' => true,
            \'rewrite\' => false,
            \'has_archive\' => true,
            \'supports\' => array( \'title\', \'editor\', \'thumbnail\', \'test_source\' ),
            \'taxonomies\' => array( \'category\', \'post_tag\' ),
        ) );

        $post_type_obj = get_post_type_object(self::POST_TYPE);

        //register the rewrite tag for permalink building
        $wp_rewrite->add_rewrite_tag( \'%\' . $post_type_obj->query_var . \'%\', \'([^/]+)\', $post_type_obj->query_var . \'=\' );

        //we have to add the permastruct here in order to build the permalink, otherwise we\'ll need to filter the post_type link
        add_permastruct(self::POST_TYPE, \'%\' . $post_type_obj->query_var . \'%/\', false );

        //add a filter to remove the permastructs generated above
        add_filter(self::POST_TYPE . \'_rewrite_rules\', array(__CLASS__, \'_remove_default_rules\')); 

        //now we add a filter to put the generated rewrite rules in the correct spot
        add_action(\'generate_rewrite_rules\', array(__CLASS__, \'_filter_rewrite_rules\'));

        if(!is_admin()) {
            //we need verbose_page_rules to be on on the front end in order for pages to be process properly
            $wp_rewrite->use_verbose_page_rules = true;
        }
    }

    /**
     * Filter to remove the rules for this post type when they\'re automatically generated due to the permastruct registration
     * @param type $rules
     * @return type 
     */
    public static function _remove_default_rules($rules) {
        return array();
    }

    /**
     * Filters the rules at the end to add back the ones for this post type at the bottom
     * @param WP_Rewrite $wp_rewrite 
     */
    public static function _filter_rewrite_rules($wp_rewrite) {
        $post_type_obj = get_post_type_object(self::POST_TYPE);
        $my_rules = $wp_rewrite->generate_rewrite_rules(\'%\' . $post_type_obj->query_var . \'%\', EP_NONE);
        $wp_rewrite->rules += $my_rules;
    }

}

add_action( \'init\', array( \'Test_Post_Type\', \'init\' ) );

SO网友:Ciantic

神圣的车钥匙!

我认为这是可行的。它几乎可以工作,非常简单,只有一行:

global $wp_rewrite;
$args = array(
    \'public\' => true,
    \'publicly_queryable\' => true,
    \'show_ui\' => true,
    \'show_in_menu\' => true,
    \'query_var\' => true,
    \'rewrite\' => array(\'slug\' => \'anything\'),
    \'capability_type\' => \'post\',
    \'has_archive\' => true,
    \'hierarchical\' => false,
    \'menu_position\' => null,
    \'supports\' => array(\'title\',\'editor\',\'thumbnail\')
);
register_post_type(\'my_custom_post_type\', $args);

$wp_rewrite->add_permastruct(\'my_custom_post_type\', "%my_custom_post_type%");
P.S. 如果您在家尝试此操作,添加这一行后,请转到“设置”->“永久链接”并保存更改,它会刷新永久链接。

我在看WPregister_post_type() 源代码并找到一行:

$wp_rewrite->add_permastruct($post_type, "{$args->rewrite[\'slug\']}/%$post_type%", $args->rewrite[\'with_front\'], $args->permalink_epmask);
不用说,但没有slug,我断定它应该会起作用,它确实起作用了。即使在编辑器中标题下的permalink编辑也能正常工作!

Update: 这将打破页面永久链接,返回绘图板。。。

SO网友:Ciantic

prettyboymp的答案和我昨天得到的几乎一样,但我不满意。prettyboymp的答案有一个缺陷,即当/%postname%/同时用于多个帖子类型时,它不起作用。

这是我的答案,它也查看了当前的结构,并创建了一系列可以回退的帖子类型。不过,这也有一个缺陷,如果两个帖子类型具有相同的slug,并且都是/%postname%/那么它会同时显示这两个。

class MyCustomPostType {
    /**
     * Register post type
     **/
    public static function register_post_type() {
        global $wp_rewrite;

        $args = array(
            \'public\' => true,
            \'publicly_queryable\' => true,
            \'show_ui\' => true,
            \'show_in_menu\' => true,
            \'query_var\' => true,
            \'rewrite\' => false,
            \'capability_type\' => \'post\',
            \'has_archive\' => true,
            \'hierarchical\' => false,
            \'menu_position\' => null,
            \'supports\' => array(\'title\',\'editor\',\'thumbnail\')
        );

        register_post_type(\'my_custom_post_type\', $args);

        // Enables the pages to work simultaneously
        $wp_rewrite->use_verbose_page_rules = true;
        add_filter("rewrite_rules_array", array(__CLASS__, \'rewrite_rules_array\'));
        add_action("parse_query", array(__CLASS__, \'parse_query\'));
        add_filter("post_type_link", array(__CLASS__, \'post_type_link\'), 1, 4);
    }

    public static function post_type_link($link, $post, $leavename=false, $sample=false) {
        if ($sample && ($begin = strpos($link, "?my_custom_post_type=")) !== false) {
            return substr($link, 0, $begin-1) . "/%my_custom_post_type%/";
        }
        return str_replace("?my_custom_post_type=", "", $link) . "/";
    }

    public static function parse_query($query) {
        global $wp, $wp_rewrite;

        // Is this query for /%post_name%/? Is it main request query?
        if (isset($query->query[\'name\'])
            && substr($wp->matched_rule, 0, 7) == "([^/]+)"
            && isset($query->query)
            && isset($wp->query_vars)
            && $query->query == $wp->query_vars)
        {
            //echo \'<p><h1>hit!</h1></p>\';
            if (!($post_types = get_query_var("post_type"))) {
                if ($wp_rewrite->permalink_structure == "/%postname%/")
                    $post_types = array("post");
                else
                    $post_types = array();
            }

            if (is_array($post_types))
                $post_types[] = "my_custom_post_type";

            set_query_var("post_type", $post_types);
            //set_query_var("posts_per_page", 1);
        }
    }

    public static function rewrite_rules_array($array) {
        global $wp_rewrite;
        // Same rules as in /%post_name%/
        return array_merge($array, $wp_rewrite->generate_rewrite_rules("/%postname%/", EP_PERMALINK));
    }
}


add_action(\'init\', array("MyCustomPostType", "register_post_type"));

SO网友:Ünsal Korkmaz

我创建了一个解决方案,但找不到问题。如果发现问题,请告诉我

add_action(\'init\', \'firmasite_resimlitarif_cpt\', 0);
function firmasite_resimlitarif_cpt() 
{

// Yemek Tarifi

  $args = array(
    \'public\' => true,
    \'show_in_menu\' => true, 
    \'permalink_epmask\' => EP_NONE,
    \'rewrite\' => array(\'slug\'=>\'/\',\'with_front\'=>false),
    \'has_archive\' => false,
    \'supports\' => array(\'title\',\'editor\',\'thumbnail\')
  ); 
  register_post_type(\'yemek\',$args);

}


// http://wordpress.stackexchange.com/questions/37650/wordpress-3-3-custom-post-type-with-postname-permastruct
add_action("parse_query", \'firmasite_resimlitarif_parse_query\');
function firmasite_resimlitarif_parse_query($query) {
    global $wp, $wp_rewrite;


    // Is this query for /%post_name%/? Is it main request query?
    if (isset($query->query[\'name\'])
        && substr($wp->matched_rule, 0, 7) == "([^/]+)"
        && isset($query->query)
        && isset($wp->query_vars)
        && $query->query == $wp->query_vars)
    {
        if (!($post_types = get_query_var("post_type"))) {
            if ($wp_rewrite->permalink_structure == "/%postname%/")
                $post_types = array("post");
            else
                $post_types = array();
        }

        if (is_array($post_types)){ 
            $post_types[] = \'yemek\';
            $post_types[] = \'page\';
        }


        set_query_var("post_type", $post_types);
    } 
}
用您的帖子类型名称更改“yemek”。

SO网友:weston deboer
SO网友:Privateer

对于这一点,我能想到的最简洁的答案是(我正在构建一个插件,它确实需要一个没有任何前导slug的自定义post类型)使用a custom page template 而不是使用自定义帖子类型。

通过这样做,您的“自定义帖子类型”可以拥有诸如/之类的URL,而无需担心跨入页面或帖子永久链接。

为此,我最终做了以下几点:

在我的插件中添加一个自定义页面模板,设置页面模板,以便在页面编辑器中选择它,创建只显示我的页面模板的自定义元框,这允许我:

使用WP_Query

通过挂钩添加特殊处理add_meta_boxes 存储自定义数据

将我的自定义模板添加到通过筛选page\\u attributes\\u dropdown\\u pages\\u args、theme\\u page\\u templates、wp\\u insert\\u post\\u data和template\\u include显示的模板中see this post on adding page templates to a plugin

当然,虽然这不会影响页面或帖子链接,但它确实有几个明显的缺点。

No archive您将没有存档(如果需要的话),但可以通过创建另一个页面模板来解决这一问题,以使用自定义模板绘制所有页面的存档。

Managed under Pages在管理中,您无法获得将所有帖子类型分组在一起的良好左侧导航。

通过在页面列表中添加一个过滤器(让您根据正在使用的页面模板进行过滤)、显示新列中使用的任何页面模板等,可以部分解决此问题。

话虽如此,我想要的东西不会让用户奇怪,为什么他们创建了一个新的自定义页面,却发现他们无法再访问正常页面,或者新的自定义页面导致他们网站上的现有页面消失。

我知道这不是real 解决方案,但这是一个非常适合我需要的替代方案。

结束

相关推荐

Custom permalinks

我们有一个自定义类型music./music/ /music/post-name/ 此外,我们还有一个类似标签的分类法genres. 其URL为:/music-genres/genre-name/ 我尝试创建如下URL:/music/ /music/post-name/ /music/genres/ /music/genres/genre-name/ /music-genres/ 应替换为/music/genres/.最后,我们应该得到如下url