Support » Developing with WordPress » Unable to re-introduce base slug for custom post type

  • Resolved HeyBlondie

    (@heyblondie)



    Hi

    I have been searching and searching the interwebs for days and I simply can’t find where to start to solve, or fault-find, this issue. I’m hoping someone might be able to point me in the right direction?

    Brief Overview:
    I have taken over admin for a website which is a custom build, and functions almost entirely on Custom Post Types(CPT). I think it’s a fantastic piece of work by the original developer.

    There are 4 CPTs in use with one of them providing the main navigation from the front page. (I’ll call this one the MainCPT).

    Permalinks are set to %postname%

    All CPTs display a permalink with the CPT name as part of the link, except for the one that provides the main navigation.

    3 of the CPTs display like this:
    siterurl/custom-post-type-name/postname

    The MainCPT used for main pages/navigation displays without the slug:
    siteurl/postname

    The site is working perfectly fine, except for the issue mentioned below…

    The Issue:
    I am introducing pagination on various pages and while they work for 3 of the CPTs, it isn’t working for the MainCPT. I am assuming that it has something to do with the fact that the base slug has been removed from permalink.

    I simply have no idea how the base slug has been removed from the MainCPT and I am unable to “re-introduce” it??

    Creation of CPT is as follows:

    function add_sport_content_type(){
    $labels = array(
    		'name' => 'Sport Types',
    		'name_admin_bar' => 'Sport Types',
    		'singular_name' => 'Sport Type',
    		'add_new' => 'Add New',
    		'add_new_item' => 'Add New Sport Type',
    		'edit_item' => 'Edit Sport Type',
    		'new_item' => 'New Sport Type',
    		'view_item' => 'View Sport Type',
    		'search_items' => 'Search The Sport Types',
    		'not_found' => 'No Sport Types were found',
    		'not_found_in_trash' => 'No Sport Types were found in the trash'
    	);
    
    	$args = array(
    		'labels' => $labels,
    		'public' => true,
    		'publicly_queryable' => true,
    		'show_ui' => true,
    		'show_in_menu' => true,
    		'query_var' => true,
    		'rewrite' => array('slug' => 'sport-type'),
    		'capability_type' => 'post',
    		'has_archive' => true,
    		'hierarchical' => true,
    		'menu_position'	 => 91,
    		'menu_icon' => 'dashicons-networking',
    		'supports' => array('title','thumbnail','editor','excerpt','order','page-attributes','comments')
    	);
    
    	register_post_type('sport-type',$args);
    }
    add_action('init','add_sport_content_type');

    NOTE:
    I have tried changing ‘rewrite’ to:
    'rewrite' => array('slug' => 'sport-type', 'with_front' = true),

    …but it makes no difference.

    There are also no ‘rewrite’ type modifications to the .htaccess file (that I can see anyway), but on that level, I’m not exactly sure what I would need to look for?

    For sake of information:

    As there often appears to be issues of pagination not working with CPTs, I have, on this site, had to include the following function to enable pagination to work:

    function fix_request_redirect( $request ) {
      $post_types = array(
        'post',
    		'cpt1',
    		'cpt2',
    		'cpt3',
    		'sport-type'
        );
    
      if ( isset( $request->query_vars['post_type'] )
        && in_array( $request->query_vars['post_type'], $post_types )
        && true === $request->is_singular
        && - 1 == $request->current_post
        && true === $request->is_paged
        )
      {
        add_filter( 'redirect_canonical', '__return_false' );
      }
    
      return $request;
    }
    add_action( 'parse_query', 'fix_request_redirect' );

    I have also needed this function on another site I developed using CPTs. For more info on this, maybe this is more informative than what I could provide:
    https://core.trac.wordpress.org/ticket/15551

    Hopefully I have provided enough information for someone to make informed suggestions and I will of course provide what other information might be needed.

    Thanks 🙂

    The page I need help with: [log in to see the link]

Viewing 8 replies - 1 through 8 (of 8 total)
  • HeyBlondie

    (@heyblondie)

    …to add to the OP …

    Firstly what I’m wanting to do is to enable the base slug for the MainCPT to see if that solves the pagination issue.

    Other than that, if there are suggestions as to why the pagination wouldn’t be working, and how to fix it, that would also be very helpful.

    Moderator bcworkz

    (@bcworkz)

    Hi heyblondie,

    There is no standard way to get a CPT to not require a base slug and there are at least a couple ways to accomplish this that immediately come to mind. More likely exist. As you surely know, permalinks lacking a base normally indicate a default post or page post type. There could be a WP rewrite rule added that somehow regexp matches URLs lacking a base and rewrites the request to specify a particular CPT. We would normally find a call to add_rewrite_rule() somewhere if this is done, but it’s possible to directly manipulate the global rewrite rules array without calling the function.

    What I would do myself if I wanted to do such a thing, is to hook into the “pre_get_posts” action and check each query for its ‘post_type’ query var. Any query where post type is post or page would indicate a request with no base parameter, so in such cases we can change the query var to use our CPT instead of or in addition to post or page post types.

    HeyBlondie

    (@heyblondie)

    Hi bcworkz

    Thanks for the response.

    I must admit that I don’t fully understand these aspects related to rewriting of URLs, but I have found reference previously to the things you mention for how to ‘remove’ the base from a CPT permalinks, but I can find no existence of any such functions in any of the existing files on the site.

    (the site uses a custom theme and is based on TwentyThirteen)

    I can find no call to add_rewrite_rule() anywhere and no pre_get_posts. That’s why I’m at a bit of a loss as to how the base has been removed in the first place. …and subsequently how to remedy, or reverse, it.

    Or maybe there’s something else that I’m really not grasping correctly?

    Moderator bcworkz

    (@bcworkz)

    The only other way I can think of to manipulate permastructs is to directly manipulate the global $wp_rewrite object, an instance of WP_Rewrite class. You could try var_dumping this object and examine the various properties. But unless you are able to easily grasp what regular expressions do, you could easily miss what you are looking for.

    Or maybe see if you can find custom code that makes use of global $wp_rewrite. The *nix command grep or similar file search command is very useful in finding specific text strings in the dozens of PHP files.

    I suppose you could simply add another rewrite rule that picks up on a base parameter even though it’s not required. WP should “see” this base and respond appropriately. You can filter permalink output to include the base even though it’s not required. The problem will be if you need another CPT to be queried when no base occurs. I think something added to “pre_get_posts” may be able to work around that issue. So basically add your own functionality over the top of what exists. It doesn’t really matter what else is done in this regard as long as your code has the final say in what happens.

    Thank you again for these suggestions.

    I’ll work through them in the coming days and see what I can find.

    Hi @bcworkz

    I had a look at the various suggestions you made and after var_dumping the $wp_rewrite object, I saw some differences with regard to the CPT in question. I kept looking through the various function files that exist (there are quite a few on this custom site) and low and behold, I found the following:

    /**
     * Remove the slug from published post permalinks.
     * Only affect our CPT though.
     */
    function vipx_remove_cpt_slug( $post_link, $post, $leavename ) {
    
        if ( ! in_array( $post->post_type, array( 'sport-type' ) )
            || 'publish' != $post->post_status )
            return $post_link;
    
        $post_link = str_replace(
            '/' . $post->post_type . '/', '/', $post_link
        );
    
        return $post_link;
    }
    add_filter( 'post_type_link', 'vipx_remove_cpt_slug', 10, 3 );
    
    function vipx_parse_request_tricksy( $query ) {
    
        // Only noop the main query
        if ( ! $query->is_main_query() )
            return;
    
        // Only noop our very specific rewrite rule match
        if ( 2 != count( $query->query )
            || ! isset( $query->query[ 'page' ] ) )
            return;
    
        // 'name' will be set if post permalinks are just post_name,
        // otherwise the page rule will match
        if ( ! empty( $query->query[ 'name' ] ) )
            $query->set( 'post_type', array( 'post', 'sport-type', 'page' ) );
    }
    add_action( 'pre_get_posts', 'vipx_parse_request_tricksy' );

    Commenting these two functions out, does restore the base slug for the CPT and the pagination then works also.

    It appears part of the problem is that I didn’t effectively search ALL files for relevant strings (such as ‘pre_get_posts’) which is something I’ve only just realised can be done [in Atom].

    Question:
    So I guess, before I remove these functions on the live site and change URLs for existing pages (potentially affecting other sites linking to those pages**), is there any chance you could point me in the direction of information to keeping the URL/permalink structure (without the base CPT slug) and have pagination work? I have been searching for solutions but haven’t found anything I can use as yet.

    …or is it better to start a new post for that question?

    ** I realise I could organise some redirects if I change the URL, but I’m just seeing if I can avoid having to do that.

    Thank you again for your replies.

    Moderator bcworkz

    (@bcworkz)

    Nice sleuthing! Finding specific code in an unfamiliar site can sometimes be close to impossible. Just knowing the correct search terms can be difficult.

    We generally like to see new topics when the gist of the dialog becomes totally different than the original topic. For the future, it helps those experiencing similar issues find what they are looking for more easily during searches. However, there are many dozens of resolved pagination topics already in existence. I leave it up to you how to handle your particular topics.

    Without knowing how the initial page is queried, it’s hard to say why pagination fails. The usual reason is because the initial page content is queried through a new custom query on the template. The WP default pagination functions all rely on the main request’s query to determine what the next/previous page queries should be. When custom queries are used on a template, the WP pagination functions have no idea this is done, so pagination fails to work correctly.

    Many people try to steal pagination parameters from the main query and use them in their custom query. This can appear to work, but the logic is flawed because the pagination functions still think the main query is being used, which generally matches a different number of posts, so the ultimate page count does not match and improper links are generated.

    In the case of custom queries, the only true solution is to create custom pagination functions to match. The custom query can then take the page number request and calculate the proper 'offset' query arg. This isn’t as difficult as it may sound, but there is usually a better solution.

    Most custom queries can also be accomplished by altering the main query in the “pre_get_posts” action. By altering the main query instead of creating a custom query, the default pagination functions should work correctly.

    When it comes to deciding whether to create a new permastuct along with redirects from old URLs, or to stick with the original URLs, I would consider which permastruct results in the best URLs from a user/SEO standpoint. If a new one is better, it’s better to get the redirects over with now than to stubbornly cling to the old way just to avoid redirects. Of course, there are exceptions, such as when redirects cannot be formulated with a few rules and dozens of custom redirects would required.

    Thank you again for such a helpful and detailed response.

    Yes I do in fact have a custom query, and loop, inside the main loop. I’m not really in a position to work on a custom solution to the pagination so my best solution is to enable a suitably worded slug to add into the URL. …and then organise redirects.

Viewing 8 replies - 1 through 8 (of 8 total)
  • You must be logged in to reply to this topic.