Shiba

Adventures in WordPress

  • — Home —
  • Dog
  • Art
  • Contact
  • WordPress Articles
    • WP Plugins
    • WP Programming
    • WP Admin Panels
    • WP Theme Design
    • WP How-To
    • WP Theme Images
You are here: Home / WordPress Admin / Custom Post Type / Custom Post Type Permalinks – Part 2

Custom Post Type Permalinks – Part 2

Tweet

by ShibaShake 133 Comments

In Custom Post Type Permalinks – Part 1 we considered how to set different permalink options from the register_post_type function call. Here, we focus on how to create our own permalink structures.

With the register_post_type function, we can easily set our custom post type permalink structure to look like this (assuming custom post type = gallery).

http://shibashake.com/wordpress-theme/gallery/test-1

However, we may want to fully customize our custom object permalink structure, similar to how we can fully customize our post permalink structure. Suppose we want to set our permalink structures as follows –

Post permalink structure

/articles/%postname%

Gallery custom post type permalink structure

/galleries/%year%/%monthnum%/%gallery%

1. Turn Off Default Rewrite Rules

First, we set the rewrite argument to false in our register_post_type function call.

	$args = array(
		'publicly_queryable' => true,
		'query_var' => true,
		'rewrite' => false,
                ...
	); 
	register_post_type('gallery',$args);

After we set the argument to false, our gallery custom post type will no longer use pretty permalinks. Instead, our links will look like this –

http://shibashake.com/wordpress-theme?gallery=test-1

Note – It is also necessary to set query_var to true to enable proper custom post type queries.

2. Add New Custom Post Type Rewrite Rules

To get back our pretty permalinks, we need to add our own %gallery% rewrite tag, and our own gallery perma-structure.

// add to our plugin init function
global $wp_rewrite;
$gallery_structure = '/galleries/%year%/%monthnum%/%gallery%';
$wp_rewrite->add_rewrite_tag("%gallery%", '([^/]+)', "gallery=");
$wp_rewrite->add_permastruct('gallery', $gallery_structure, false);

The add_rewrite_tag function accepts 3 arguments.

  1. tag name – Our custom post type tag name. E.g. %gallery%.
  2. regex – A regular expression that defines how to match our custom post type name.
  3. query -The query variable name to use for our custom post type plus an = at the end. The result of our regular expression above gets appended to the end of our query.

For example, suppose our pretty permalink is –

http://shibashake.com/wordpress-theme/galleries/2010/06/test-1

The result of the regular expression match from %gallery% is test-1. This value gets passed on as a public query to our main blog –

http://shibashake.com/wordpress-theme?gallery=test-1

Later, the query link gets translated back into our original pretty permalink so that our end-users are shielded from this whole process.

The add_permastruct function takes in 4 arguments.

  1. name – Name of our custom post type. E.g. gallery.
  2. struct – Our custom post type permalink structure. E.g.
    /galleries/%year%/%monthnum%/%gallery%
    
  3. with_front – Whether to prepend our blog permalink structure in front of our custom post type permalinks. If we set with_front to true here, our gallery permalinks would look like this –
  4. http://shibashake.com/wordpress-theme/articles/galleries/2010/06/test-1
    

    This is not what we want, so we set it to false.

  5. ep_mask – Sets the ep_mask for our custom post type.

Adding the add_permastruct function changes our gallery object permalinks from

http://shibashake.com/wordpress-theme?gallery=test-1

to

http://shibashake.com/wordpress-theme/galleries/%year%/%monthnum%/test-1

which results in a 404 or file not found page error. This is because the permalink tags %year% and %monthnum% were not properly translated.

3. Translate Custom Post Type Permalink Tags

Finally we need to translate the additional tags in our custom post type permalink. To do this, we hook into the post_type_link filter. The code used in our tag translation function was adapted from the regular WordPress post get_permalink function.

// Add filter to plugin init function
add_filter('post_type_link', 'gallery_permalink', 10, 3);	
// Adapted from get_permalink function in wp-includes/link-template.php
function gallery_permalink($permalink, $post_id, $leavename) {
	$post = get_post($post_id);
	$rewritecode = array(
		'%year%',
		'%monthnum%',
		'%day%',
		'%hour%',
		'%minute%',
		'%second%',
		$leavename? '' : '%postname%',
		'%post_id%',
		'%category%',
		'%author%',
		$leavename? '' : '%pagename%',
	);

	if ( '' != $permalink && !in_array($post->post_status, array('draft', 'pending', 'auto-draft')) ) {
		$unixtime = strtotime($post->post_date);
	
		$category = '';
		if ( strpos($permalink, '%category%') !== false ) {
			$cats = get_the_category($post->ID);
			if ( $cats ) {
				usort($cats, '_usort_terms_by_ID'); // order by ID
				$category = $cats[0]->slug;
				if ( $parent = $cats[0]->parent )
					$category = get_category_parents($parent, false, '/', true) . $category;
			}
			// show default category in permalinks, without
			// having to assign it explicitly
			if ( empty($category) ) {
				$default_category = get_category( get_option( 'default_category' ) );
				$category = is_wp_error( $default_category ) ? '' : $default_category->slug;
			}
		}
	
		$author = '';
		if ( strpos($permalink, '%author%') !== false ) {
			$authordata = get_userdata($post->post_author);
			$author = $authordata->user_nicename;
		}
	
		$date = explode(" ",date('Y m d H i s', $unixtime));
		$rewritereplace =
		array(
			$date[0],
			$date[1],
			$date[2],
			$date[3],
			$date[4],
			$date[5],
			$post->post_name,
			$post->ID,
			$category,
			$author,
			$post->post_name,
		);
		$permalink = str_replace($rewritecode, $rewritereplace, $permalink);
	} else { // if they're not using the fancy permalink option
	}
	return $permalink;
}

We Are Done

Once we translate the additional permalink tags, our gallery permalinks will look like this –

http://shibashake.com/wordpress-theme/galleries/2010/06/test-1

And just like that – we are done!

Permalink Conflicts

A common issue that arises when you create your own permalinks are permalink conflicts.

Permalink conflicts occur when two permalinks share the same regular expression structure.

Note – it is regular expression structure and NOT tag structure.

You can use tags with different and unique sounding names but it will not remove your conflict issue as long as your regular expression structure remains the same.

When permalink conflicts happen, you will usually get a 404 Page Not Found error. This happens because when the WordPress system goes to look for the proper permalink rule to fire, there are multiple ones that match. As a result, the system will only fire the first rule that it sees. Those objects that are tied to all subsequent but duplicate patterns will necessarily return a Page Not Found error because the system is using the wrong permalink rule.

The easiest way to avoid permalink conflict issues is to insert a unique slug into your structure. For example, instead of doing –

/%author%/%gallery%/

Do –

/gallery/%author%/%gallery%/

Adding the unique slug/keyword gallery into your permalink structure ensures that there are no regular expression pattern conflicts.


Is it possible to have multiple objects share the same permalink rule?

Yes, but this can get very messy. One way to do this is to only create a single permalink structure for all of your target objects. Then you must manually resolve which object you want by hooking into the request filter hook.

Related Articles

Custom Post Type Permalinks

How to set permalink attributes while creating custom post type objects.

Add Custom Taxonomy Tags to Your WordPress Permalinks

How to include taxonomy tags into our custom post type permalinks.

Add Custom Post Type Columns

How to expand custom post type administration menus with new columns.

Comments

« Previous 1 2
  1. Mike iLL says

    May 3, 2016 at 7:42 am

    Still super-helpful. Thanks so much for taking the time.

    Reply
  2. Maksim says

    September 30, 2015 at 4:48 am

    Hi, I need help.
    I need url structure: http:/stgnlion.com/rajatieto/horoskoopit/kuukausihoroskooppi/syyskuu/2015/test

    horoskoopit- just word
    kuukausihoroskooppi – post type name
    syyskuu – september on finish
    2015 – year

    so I create rewrite like this: $kuukausihoroskooppi_structure = ‘/horoskoopit/kuukausihoroskooppi/%monthnum%/%year%/%kuukausihoroskooppi%’;

    And I don`t need post_slug in url, but when I remove %kuukausihoroskooppi% from revrite, then this page open like archive.php

    And I need that month be not a number, it should be word so in $date I change code on: $date = explode(” “,date_i18n(‘Y F d H i s’, $unixtime));

    but then this page open like 404 page.

    What`s wrong and can I do url structure like:
    http:/stgnlion.com/rajatieto/horoskoopit/kuukausihoroskooppi/syyskuu/2015
    without slug of post and month with word?

    Reply
  3. Andhi Irawan says

    May 25, 2015 at 1:03 am

    Hi,
    Nice tutorial
    I have question, example I have a blog http://blog123.com
    and product web http://productABC.com
    In blog123 has post same name with productABC, like Gadget and Travel
    I want to create a link automatically in blog123.
    In blog123, for post Travel (http://blog123.com/travel), I create Show Product button link that link to http://productABC.com/travel.
    I want that button link automatically via code something like http://[productABC base url]/[title from blog123 post title or attribute or post permalink]

    Reply
  4. Rolo says

    April 25, 2015 at 4:10 pm

    I spent HOURS trying to figure this out and your post saved me. I love wp and I hate wp. Thank you!!!!!!

    Reply
  5. Gerard says

    January 20, 2015 at 6:26 pm

    Is it possible to remove the slug of a custom post type? I would like to use them a lot but with the following URL structure: first the domain, then the postname, without the custom post type slug between the domain and the postname slug.

    Thanks in advance!

    Reply
  6. Marc Steel says

    April 28, 2014 at 7:38 pm

    Thank you so much. This was just a giant timesaver, much obliged.

    Reply
  7. Jos Faber says

    April 8, 2014 at 3:00 pm

    Thanks to this awesome post I’ve managed to create a complex rewrite structure with three different custom post types ( ~/brands/brand/model/type ).

    Thanks a gazillion!!

    Reply
  8. David Beastall says

    February 12, 2014 at 6:00 pm

    Hi,

    I’ve just used your code to add in the month and year into the permalink structure used for a custom post type that displays Events on my clients website. I’m a novice with functions and PHP, however this was really helpful and worked first time, I’m very happy.

    WordPress version: 3.8.1

    Thank you

    David

    Reply
  9. John says

    December 18, 2013 at 7:23 am

    Works fine! Is there a way to have a post title (with periods inside, not hyphens) in place of post name? thanks!

    Reply
  10. cfxd says

    November 23, 2013 at 11:31 am

    Thank you for posting this series, it’s very thorough and the material is great!

    Can you post more information on multiple objects sharing the same rewrite rule? I need my permalink structure to be like the example you used without the unique prefix, like:

    /%author%/%gallery%/

    The problem is that when I remove the unique prefix from your example code then all of my CPTs result in 404 errors. I would really appreciate more details on how to avoid this.

    Thank you again!

    Reply
  11. Aryan says

    November 22, 2013 at 4:57 pm

    You are great. I was making a plugin for WP and I stucked in rewrite rule, I was searching for this tutorial since past 5 days. Thankyou for writing such amazing post.

    Reply
  12. Ross says

    August 16, 2013 at 3:10 pm

    Your articles are some of the only good ones out there on this subject, thank you. Do you know how to create a custom permalink structure that will assign a random string of letters/numbers to each post? (For example, like bit.ly/38ejsi6) — Maybe creating a structure that allows /%random% where %random% is an 8 character random string? You may be the only one who can help me on this!

    Reply
    • Ken Reidy says

      September 30, 2013 at 3:59 am

      I think you can utilize wp_generate_password to create random character.

      Reply
  13. Marco Panichi says

    July 8, 2013 at 12:09 am

    What if I’ve created a hierarchical custom type?

    The code suggested doesn’t work unfortunally!

    I can access posts only from /my-post and not from /my-parent-post/my-post

    Reply
  14. Sajid says

    May 18, 2013 at 1:20 pm

    So many comments I also tried but 404 error appear but thanks for the script. Then I found the solution here http://wordpress.org/extend/plugins/wp-permastructure/ I tried & satisfied it is very cool ๐Ÿ™‚

    Reply
  15. Raquel Patro says

    April 20, 2013 at 1:26 pm

    How can I create rules to display the custom post like my “standart posts, but add “.html” at the end of permalinks? I need a for only one CPT, so that others stay with the default setting.

    Reply
  16. Manny Fleurmond says

    March 30, 2013 at 8:10 am

    I’m not sure when but the arguments for add_permastruct got changed: http://core.trac.wordpress.org/browser/tags/3.5.1/wp-includes/rewrite.php#L0

    The tutorial mighe need an update

    Reply
  17. Looic says

    January 8, 2013 at 8:54 am

    Hi,
    Very interesting tutoriel, and very happy if you could have a look at this post in the WordPress support forums. I just tried to put your code and it doesn’t work. Perhaps you could help me.

    http://wordpress.org/support/topic/custom-post-type-permalink-broken-3-match-for-a-single-custom-post

    Thank you,
    Looic.

    Reply
  18. Peter says

    December 22, 2012 at 11:07 am

    Hi, i’m trying to remove the custom post type slug entirely. I’ve used this array but the slug keeps generating ‘rewrite’ => array(‘slug’=>”,’with_front’=>false), is this valid? I found it in the WP forums some said it worked others said it didn’t. How can I create custom posts so that no slug is generated? Thanks

    Reply
    • ShibaShake says

      December 26, 2012 at 10:22 am

      Try setting rewrite to false. If you do not want the post to be searchable, then set publicly_queryable to false.

      Reply
  19. Espen says

    October 17, 2012 at 8:19 pm

    Hello, I’m trying to make a custom_post_type “review” and I want to add those to pages. I want to use pages as parents. I have managed to link up regular pages to the custom type. But the permalinks will not work. I only get 404.

    What I want is for the custom type to integrate with pages like regular posts:

    http://mysite.com/page/review-name
    alternatively:
    http://mysite.com/page/reviews/review-name

    Default the permalinks are: http://mysite.com/reviews/page/review-name but that gives me a 404 – and I don’t want that structure

    Only way to access the review is to type in this URL:
    http:/mysite.com/reivews/review-name

    That works, but I don’t want that either.

    Any tips? I’m close to pulling my hair out ๐Ÿ™‚

    Reply
  20. Maor Barazany says

    July 25, 2012 at 6:39 am

    Thank you Shibashake for this in-depth article.
    I managed to create working custom permalinks to CPT. The issue is that when rewrite set to false in the register_post_type function, than the archive page of the CPT is not being assigned a pretty url.
    i.e. I have cpt event and permalink for a single event may be /event/%year%/%monthnum%/%event% but the archive of all events valid only via example.com/?post_type=event and not with example.com/events.

    If setting the rewrite slug, then each single event post is losign the custom structure.
    How can these 2 can work together?

    Thanks

    Reply
    • ShibaShake says

      August 1, 2012 at 2:20 pm

      Hmmm, one possibility is to hook into the WordPress loop “request” filter and enable it manually.
      http://shibashake.com/wordpress-theme/mastering-the-wordpress-loop

      This is not something I have really looked into though, so there are probably better ways to do it.

      Reply
    • Dennis O'Neil says

      April 7, 2013 at 9:46 pm

      Maor,

      I expect you’ve already found your solution, but I wanted to share how I handled the exact issue you’ve described. The code in this post was exactly what I needed to customize my site URL structure (thank you ShibaShake). However, I too, had 404’s on all of my previously working sitename.com/custom-post-slug/ URL’s.

      To correct this, I added an additional permalink structure and made it unique enough to avoid conflicts. Using the example in this post, it would look something like this:

      $gallery_archive_structure = ‘/anything-unique/%post_type%/’;
      $wp_rewrite->add_rewrite_tag(“%post_type%”, ‘([^/]+)’, “post_type=”);
      $wp_rewrite->add_permastruct(‘post’, $gallery_archive_structure, false);

      In my instance, the links to the archive page(s) are hard-coded in the theme so there was no need to edit the WP generated archive link, but I suppose that’d be possible, too.

      Hope this helps the next person.

      Reply
  21. Erik Landvall says

    July 13, 2012 at 3:19 pm

    I had some problems with a code snippet I created from you example. At last I figured out that the date parameter was the cause of the problem. In your example it states date( ‘Y m d’ … ). I fixed my problem with date( ‘Y n j’ … )

    Hope that can help if someone else runs in to the same issue

    Reply
« Previous 1 2

Leave a Reply Cancel reply

Your email address will not be published.

Recent Posts

  • Screen-shot of mobile responsive Poll Daddy object, where text floats properly to the right of radio buttons.How to Make Poll Daddy Objects Mobile Responsive
  • Screen-shot of blog post with no page border (flowing design).Genesis Skins 1.5
  • Screen-shot of the media manager Create-Gallery screen, while doing a post search.Shiba Media Library 3.7
  • Screenshot of the Edit Gallery screen after we hit the Create Gallery button.How to Expand the WordPress Media Manager Interface
  • Blonde girl looking through and holding a circular picture frame.Shiba Gallery 4.3
  • Close-up of beautiful blonde holding a square picture frame.Google Authorship - Good or Bad for Search Traffic?
  • Shiba Widgets 2.0
  • Media Temple screenshot of editing my sub-domain DNS entry.Using CDN Cnames with w3tc and MultiSite
  • Shiba Skins WordPress ThemeShiba Skins WordPress Theme
  • How to add the Media Manager Menu to the Theme Preview InterfaceHow to Add the Media Manager Menu to the Theme Preview Interface

Recent Comments

  • WordPress Search Widget – How to Style It (56)
    • Nelson
      - Tanks master - Fine
    • TelFiRE
      - How do you style the "X" that shows up when you start typing?
  • Update custom inputs with the proper data using Javascript.Expand the WordPress Quick Edit Menu (58)
    • Mike G
      - This is exactly what is happening to me. It is updating the value in the database and in the column, but I have to refresh ...
    • PhoenixJP
      - Thanks for this tutorial. Does someone knows if this still work with wordpress 5.03 and 5.1.
    • Francine Carrel
      - This is a very long time away from your original comment, but did you ever work it out? I am stuck on the exact same thing ...
  • Custom meta-box with a set of radio-buttons.Add a Metabox to Your Custom Post Type Screen (27)
    • mike
      - Hi Shiba am a newbie to wordpress, I just installed a plugin with a custom post type, but has no option for discussion and ...
  • Write a Plugin for WordPress Multi-Site (45)
    • Andrew
      - Hi,action 'wpmu_new_blog' has been deprecated. Use โ€˜wp_insert_siteโ€™ instead.
  • Populate our Edit Gallery menu using a gallery shortcode.How to Add the WordPress 3.5 Media Manager Interface – Part 2 (29)
    • Janine
      - Still relevant in 2019.
  • WordPress Excerpt – How to Style It (36)
    • James
      - Great post. I really need some help. I have set border lines around my excerpts on my blog page/post page. The problem is ...
  • Add Custom Taxonomy Tags to Your WordPress Permalinks (123)
    • Darshan Saroya
      - Update permalinks. Go to settings > permalink and just save it.

Copyright © 2021 · Genesis Skins by ShibaShake · Terms of Service · Privacy Policy ·