add_permastruct()WP 3.0.0

Adds a new permalink structure for pretty URLs.

Creates not one rule, but several based on one specified permalink structure, what rules to create is determined by the $args parameter and the tags of the structure itself...

Explanation

The permalink structure is an abstract concept and means setting (defining) the rules for how a pretty URL (human-readable URL) should look.

This function allows you to quickly create a group of rules (with regular expressions) that will rewrite the URL into internal query parameters. The new rules will be added to the WP_Rewrite::$extra_permastructs property (array).

When rewrite rules are created by the function WP_Rewrite::rewrite_rules(), all these new permalinks are passed to the function WP_Rewrite::generate_rewrite_rules(), which in turn converts them into regular expressions and determines what URL should result if the regex matches the current request URL.

The $args parameter allows you to control how WP_Rewrite::generate_rewrite_rules() will create the new permalink structure.

Explanation again, in other words.

The added structure, for example, book/%book% is parsed and based on it, the necessary pretty URL rewrite rules are added to the pretty URL settings (see the global variable $wp_query).

The tags specified in the structure, for example %book%, are replaced with the corresponding part of the regular expression that is specified when registering the rewrite tag in add_rewrite_tag().

If unknown tags are specified in the structure, they will not be replaced with groups of regular expressions and will remain in the rewrite rules as is. For example, the pretty URL will look like this if an unregistered tag %order_id% is specified:

[order/%order_id%/?$] => index.php?%order_id%$matches[1]

The tag (placeholder) needs to be registered separately using the function add_rewrite_tag().

This function is usually used in conjunction with the functions: add_rewrite_tag() and add_rewrite_rule()

No Hooks.

Returns

null. Nothing.

Usage

add_permastruct( $name, $struct, $args );
$name(string) (required)
Name of the structure. The name of the post type for which the pretty URL structure is created.
$struct(string) (required)
The pretty URL structure itself.
$args(array)

Parameters for building the link from the specified structure.

For more details, see:

The following parameters are set by default:

$defaults = [
	'with_front'  => true,
	'ep_mask'     => EP_NONE,
	'paged'       => true,
	'feed'        => true,
	'forcomments' => false,
	'walk_dirs'   => true,
	'endpoints'   => true,
];

By default: [] (defaults)

Possible elements of the array:

  • with_front(boolean)
    Whether to prepend the structure with the parameter WP_Rewrite::$front.
    By default true.

  • paged(boolean)
    Whether to add rules for post pagination - /post_name/page/xx? If set to true, then the post can use the shortcode <!--nextpage-->. See wp_link_pages().
    By default true.

  • feed(boolean)
    Whether to add rules for feed pages - /feed/?
    By default true.

  • forcomments(boolean)
    Make the feed link a request for the comment feed. A parameter &withcomments=1 will be added.
    By default false.

  • walk_dirs(boolean)
    If set to true, a rewrite rule will be created for each directory specified in the structure. For example, if the structure is specified as /%year%/%month%/%day/, then rules will be created for the directories: /%year%/, /%year%/%month%/ and /%year%/%month%/%day%/.
    By default true.

  • ep_mask(integer)
    Indicates which additional (to the base pretty URL) entry points WordPress should create for the rewrite rules. EP - endpoints.

    Parameters should be combined using bitwise OR:

    'rewrite' => [
    	'ep_mask' => EP_PERMALINK | EP_ROOT
    ],

    Possible values:

    EP_NONE         // disables all endpoint rules (attachment, comments, ...).
    EP_PERMALINK    // single post
    EP_ATTACHMENT   // attachment page
    EP_DATE         // any date archives
    EP_YEAR         // year archive
    EP_MONTH        // month archive
    EP_DAY          // day archive
    EP_ROOT         // main blog page
    EP_COMMENTS     // comment pages
    EP_SEARCH       // search page
    EP_CATEGORIES   // category archive
    EP_TAGS         // tag archive
    EP_AUTHORS      // author archive
    EP_PAGES        // pages (post_type=page)
    EP_ALL_ARCHIVES // EP_DATE | EP_YEAR | EP_MONTH | EP_DAY | EP_CATEGORIES | EP_TAGS | EP_AUTHORS
    EP_ALL          // EP_PERMALINK | EP_ATTACHMENT | EP_ROOT | EP_COMMENTS | EP_SEARCH | EP_PAGES | EP_ALL_ARCHIVES

    The code for building the pretty URL with these flags can be found in WP_Rewrite::generate_rewrite_rules()

    How it works step by step:

    1. At the beginning of the function, the value of the mask is passed as is and does not change anymore.

    2. For each directory of the structure, a helper mask $ep_mask_specific is calculated:

      • %year% → EP_YEAR
      • %monthnum% → EP_MONTH
      • %day% → EP_DAY
      • otherwise EP_NONE
    3. Comment rules

      • If the mask contains EP_PAGES or EP_PERMALINK/comment-page-N/ is added.
      • Otherwise, if it contains EP_ROOT and the main page is set → /comment-page-N/ is added for the root.
    4. Endpoint rules ($this->endpoints)
      For each registered endpoint:

      • If (endpoint_mask & $ep_mask) or (endpoint_mask & $ep_mask_specific) is true → the rule .../<endpoint>/... is added to the current URL template.
    5. Nested endpoints of attachments

      • For attachments, only EP_ATTACHMENT is checked for the endpoints themselves, $ep_mask is not involved here.
    6. If $ep_mask = EP_NONE (by default)

      • Comments are not added.
      • Endpoints will still be added for dates (EP_YEAR|EP_MONTH|EP_DAY) because ep_mask_specific is triggered.
    7. If $ep_mask contains multiple flags (for example EP_PERMALINK|EP_PAGES)

      • All branches are triggered, the condition uses bitwise &.
    8. Summary
      $ep_mask affects only:

      • the generation of pagination comment rules;
      • the selection of endpoints that are attached to the URL template.

    By default EP_NONE

  • endpoints(boolean)
    Whether to add endpoints at the end of the pretty URL rewrite rules? Which endpoints to add is specified in ep_mask.

    By default true.

Examples

0

#1 Friendly URL structure for book custom post type

Let's say when registering a post type with register_post_type() we specified parameter rewrite=false. And now we want to manually set Friendly URL for this post type, then we may use this code.

add_action( 'init', 'book_post_type_permastruct' );

function book_post_type_permastruct(){
	$post_type = 'book';

	$permastruct = "$post_type/%book%"; // Friendly URL structure

	$args = [
		'with_front'  => true,
		'paged'       => true,
		'ep_mask'     => EP_NONE,
		'feed'        => false,
		'forcomments' => false,
		'walk_dirs'   => false,
		'endpoints'   => false,
	];

	add_permastruct( $post_type, $permastruct, $args );

	// Add a rewrite tag so that add_permastruct() understands it.
	// It will then be replaced by the part of the regular 
	// expression string specified in the second parameter.
	add_rewrite_tag( "%book%", '([^/]+)', "post_type=$post_type&name=" );
}

The third parameter in add_permastruct() can be omitted, then the arguments will be default.

After installing the code, you need to reset the Friendly URL rules, for this you just need to go to Settings > Permalinks in the admin panel. Or run function flush_rewrite_rules():

// flush rewrite rules, if your permalink changed (e.g. on plugin activation):
flush_rewrite_rules();

Notes

Changelog

Since 3.0.0 Introduced.

add_permastruct() code WP 6.9.1

function add_permastruct( $name, $struct, $args = array() ) {
	global $wp_rewrite;

	// Back-compat for the old parameters: $with_front and $ep_mask.
	if ( ! is_array( $args ) ) {
		$args = array( 'with_front' => $args );
	}

	if ( func_num_args() === 4 ) {
		$args['ep_mask'] = func_get_arg( 3 );
	}

	$wp_rewrite->add_permastruct( $name, $struct, $args );
}