I simply want two custom post type meta propertys to be the identifiers for the URL. I implements a solution but it just 404's

registering post type:

final private static function register_post_types ()
    $labels = array(
        'name'               => _x( 'Properties', 'post type general name', ' propertystreambootstrap' ),
        'singular_name'      => _x( 'Property', 'post type singular name', ' propertystreambootstrap' ),
        'menu_name'          => _x( 'Properties', 'admin menu', ' propertystreambootstrap' ),
        'name_admin_bar'     => _x( 'Property', 'add new on admin bar', ' propertystreambootstrap' ),
        'add_new'            => _x( 'Add New', 'property', ' propertystreambootstrap' ),
        'add_new_item'       => __( 'Add New Property', ' propertystreambootstrap' ),
        'new_item'           => __( 'New Property', ' propertystreambootstrap' ),
        'edit_item'          => __( 'Edit Property', ' propertystreambootstrap' ),
        'view_item'          => __( 'View Property', ' propertystreambootstrap' ),
        'all_items'          => __( 'All Properties', ' propertystreambootstrap' ),
        'search_items'       => __( 'Search Properties', ' propertystreambootstrap' ),
        'parent_item_colon'  => __( 'Parent Properties:', ' propertystreambootstrap' ),
        'not_found'          => __( 'No properties found.', ' propertystreambootstrap' ),
        'not_found_in_trash' => __( 'No properties found in Trash.', ' propertystreambootstrap' )

    $args = array(
        'labels'             => $labels,
        'description'        => __( 'Properties for your website.', ' propertystreambootstrap' ),
        'public'             => true,
        'publicly_queryable' => true,
        'show_ui'            => true,
        'show_in_menu'       => true,
        'menu_icon'          => 'dashicons-building',
        'query_var'          => true,
        //'rewrite'            => array( 'slug' => 'malta-property/%department%/%location%/%reference%' ),
    'rewrite'            => array( 'slug' => 'malta-property/%location%/%reference%'),
    'has_archive' => 'about-cool-post-types',
        'capability_type'    => 'post',
        'has_archive'        => false,
        'hierarchical'       => false,
        'menu_position'      => null,
        'supports'           => array('title', 'editor', 'excerpt', 'post-thumbnails', 'thumbnail')
    register_post_type( 'property', $args );


Url rewrites:

final public static function url_rewrite()
  global $wp_rewrite;
  $wp_rewrite->add_rewrite_tag('%reference%', '([^&]+)', 'reference=');
  $wp_rewrite->add_rewrite_tag('%location%', '([^&]+)', 'location=');
  return null;

filter function:

final public static function permalink_structure ($permalink, $post, $leavename)
  if (false !== strpos($permalink, '%reference%')) {
    $reference = get_post_meta($post->ID, 'propertystream_agent_ref', true);
    $location = wp_get_post_terms($post->ID, 'location');
    $location = str_replace('-cat', '', $location[0]->slug);
  //  die($location);
  //  $department = wp_get_post_terms($post->ID, 'department');
    $rewritecode = array(
    //  '%department%',

    $rewritereplace = array(
    //  $department,
      $leavename? $post->post_name : '',

    $permalink = str_replace($rewritecode, $rewritereplace, $permalink);
  return $permalink;

This all generates the code I want but it just 404's - to get it to work I have to add $leavename = true in the filter function but that adds the postname to the URL and I do not want that.

  • It's 404 most likely because WordPress doesn't know what the post is since the post slug is not present in the permalink. There's a possible workaround, but only if the meta propertystream_agent_ref is unique for each post. Also, if location is a custom taxonomy, you shouldn't need to add_rewrite_tag() for the %location% tag. – Sally CJ Jul 20 at 7:42
  • @SallyCJ What is the workaround? yes the properystream_agent_ref is unique for each post. I imagined wordpress would know what the post is as the filter function is plugged into the filter that gets the link so i imagined there would be some reference to that post on the backend (like it being the current post object) so theoretically it would just register that URL as a valid URL for that object, I was maybe wrong in assuming wordpress is that intuitive – seanyt123 Jul 21 at 0:49
  • No, WordPress won't automatically know the meta key by simply parsing the URL of the current request/page. You need to "help" WordPress knows about it (i.e. that %reference% part). But I wonder if you still need help with this question? (perhaps already answered somewhere else?) – Sally CJ Jul 21 at 18:37
  • No I do still need help please! It's making me head scrach, all I need is for there to be no post title and for it to use the reference as the unique identifier in the URL instead, please! – seanyt123 Jul 21 at 18:45

Fixing the 404 error

So it's because of the ([^&]+) in your add_rewrite_tag() calls:

$wp_rewrite->add_rewrite_tag('%reference%', '([^&]+)', 'reference=');
//$wp_rewrite->add_rewrite_tag('%location%', '([^&]+)', 'location=');

To fix the error, you should use ([^/]+) and not ([^&]+).

I also intentionally commented out the second line because if the taxonomy's slug is location, then WordPress should have already added the %location% rewrite tag.

Removing the post slug from the permalink

You shouldn't remove it from within your permalink_structure() method, which I assumed is hooked to the post_type_link filter.

Instead, you can quite easily remove the slug like so: (WordPress by default appends /%<post type slug>% to the $permastruct['struct'], so the code below removes that post slug identifier)

// Add this after the post type has been registered (after the register_post_type() call).

global $wp_rewrite;

$permastruct = $wp_rewrite->extra_permastructs['property'];
$permastruct['struct'] = str_replace( '/%property%', '', $permastruct['struct'] );
$wp_rewrite->extra_permastructs['property'] = $permastruct;

And in the permalink_structure() method, the $rewritecode should not include the post slug:

$rewritecode = array(

$rewritereplace = array(

Locating the correct "property"/post based on the "reference" part in the request/page path

The code below is pretty self-explanatory, but if you've got any questions, let me know:

add_action( 'parse_request', function( $wp ){
    // Check if the request/page path begins with /malta-property/<location>/<reference>
    if ( preg_match( '#^malta-property/([^/]+)/([^/]+)#', $wp->request, $matches ) ) {
        $posts = get_posts( [
            'post_type'      => 'property',
            'meta_key'       => 'propertystream_agent_ref',
            'meta_value'     => $matches[2],
            'posts_per_page' => 1,
        ] );

        if ( ! empty( $posts ) ) {
            $wp->query_vars['name'] = $posts[0]->post_name;
            $wp->query_vars['post_type'] = 'property'; // must set post type
} );

And remember to flush the rewrite rules — just visit the "Permalink Settings" page.

Also, as mentioned in my comment, I'm assuming each "property" post always has a metadata named propertystream_agent_ref and that the value is unique.

  • So It's still adding the post name to the end of the url :/ I did this.. $wp_rewrite->add_permastruct('property', '/malta-property/%location%/%reference%'); $permastruct = $wp_rewrite->extra_permastructs['property']; var_dump($permastruct['struct']); $permastruct['struct'] = str_replace( '/%property%', '', $permastruct['struct'] ); die(var_dump($permastruct['struct'])); to see what would happen and the value of permastruct is identical before and after the replacement. so there's never a %property% tag inside the struct – seanyt123 Jul 22 at 9:15
  • oops! don't worry, i fixed it by remove my own add_permastruct line – seanyt123 Jul 22 at 9:23
  • Yes, there's no need for the $wp_rewrite->add_permastruct() - WordPress already did that and we're just removing the /%property% from the default structure. – Sally CJ Jul 22 at 9:24
  • So basically, use the same code as in the question and just change those necessary as mentioned in the answer. – Sally CJ Jul 22 at 9:29
  • 1
    works a charm! thanks :) – seanyt123 Jul 22 at 13:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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