Take the 2-minute tour ×
WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. It's 100% free, no registration required.

There is earlier post with similar title, but it does not look in to the WordPress 3.3, and that is important as 3.3 advertises interestingly: "Use the postname permalink structure without a performance penalty"

Problem with Wordpress 3.2 and earlier was that first it looked page names, and then 404. It didn't check the arbitrary post types first. 3.3 on the other hand must look post types, then pages, and finally 404 (as it advertises this feature). This implies that custom post types without slug should be simple, if they didn't hard code post_type=post somewhere.

I can't find a 3.3 specific solution yet though.

Question: How can I define permalink struct "/%postname%/" for any given custom post type "xyz"?

Thanks.

share|improve this question
    
I don't see a question - what are you actually asking? –  tnorthcutt Jan 5 '12 at 14:37
    
For clarity, you want to define a new custom post type that uses the permalink structure of /%postname%/? Are you planning on having posts also use this same permastructure, or will they have a prefix? –  prettyboymp Jan 6 '12 at 19:34
    
Following this to see if anyone comes up with an answer. I've tried the above approaches too along with simply setting the rewrite slug to '/' which also breaks page permalinks. Le sigh... –  user16458 May 25 '12 at 3:19
add comment

5 Answers

I created a solution and i couldnt find a problem with it. Please try and tell me if you find a problem

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

Change 'yemek' with your post type name.

share|improve this answer
add comment

prettyboymp answer is almost the same I got yesterday, but I'm not happy with it. prettyboymp's answer has a one flaw, it does not work when /%postname%/ is being used simultaenously on multiple post types.

Here is my answer, which also looks in to current structure, and creates array of post types to fallback on. There is one flaw in this too though, if two post types have same slug and both are /%postname%/ then it shows both.

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"));
share|improve this answer
    
Is it possible that certain post-types get hierarchical. I tried it myself, but nothing seems to work... It thinks the post is an attachment with parent/child/... And if I do parent/child/grandchild/ it gets a 404. –  Rob Vermeer Jan 12 '12 at 16:26
add comment

This isn't easily done in WP 3.3 unless you trick the rewrite rules to be in the correct spot and make wp_rewrite think verbose rules are being used in the front end. The class below works.

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' ) );
share|improve this answer
    
Copy pasted this code in me theme, flushed rewrite rules. Added a new post, viewed the post (url is correct), got a 404... On WP 3.3.1. Any idea why this won't work for me? (Thanks for the code btw!) –  Rob Vermeer Jan 6 '12 at 22:52
    
EP_NONE -> EP_PERMALINK to get comment pages working, and then to get multiple post types working with /%postname%/ you must also use parse_query filter. See my answer above. –  Ciantic Jan 7 '12 at 12:44
    
Rob, did you add a new post or add a new 'test' post? This wasn't clear in the original question of whether posts needed to also have the permastructure of /%post_name%/. If that is the case why even create a new post type? Also, you'll have potential issues with name conflicts if more than one post type has the same permastructure. –  prettyboymp Jan 9 '12 at 13:24
add comment

Holy car keys!

I think this works. It almost works, it's super simple, only one line:

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. If you try this at home, after adding this one line Go to "Settings" -> "Permalinks" and Save Changes, it refreshes the permalinks.

I was reading the WP register_post_type() source code and found a line:

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

Needless to say but without slug I concluded it should work, and it did. Even the permalink editing underneath the title in editor works correctly!

Update: This breaks page permalinks, back to drawing board...

share|improve this answer
    
I also tried this one, with similar outcome. Would be very cool if this will work. Maybe someone else with an idea? –  Rob Vermeer Jan 6 '12 at 11:51
    
@RobVermeer Noticed that without the line (with just default slug), the WordPress is already capable of redirecting to the url. E.g. "some-post" redirects to "anything/some-post". In codespeak, somewhere in the code there is a support for CPT's without slug it just defaults to redirect. face palm –  Ciantic Jan 6 '12 at 12:26
add comment

This link should answer your question:

http://ottopress.com/2011/how-the-postname-permalinks-in-wordpress-3-3-work/

share|improve this answer
    
No it does not, it only explains how it works in terms of SQL. But no mention of custom post types, which is the problem. –  Ciantic Jan 6 '12 at 9:24
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.