skip to Main Content

I am new here! I have created multiple CPT but I need them to have the same parent slug because of the redirections, I am creating a new website but I need the URL-s of the old one.

Example of what I have:

    www.domain.com/villas/single-villa
    www.domain.com/yachts/single-yacht
    www.domain.com/cars/single-car

I need this:

www.domain.com/listing/single-villa
www.domain.com/listing/single-yacht
www.domain.com/listing/single-car

I have been searching for solution for days but didn’t manage to solve it. I know that this is not a good practice to do but I have no other option. If someone has the solution please help.

This is my code for one CPT, the others have the same structure:

function wtp_yachts() {

    $labels = array(
        'name'                  => _x( 'Yachts', 'Post Type General Name', 'text_domain' ),
        'singular_name'         => _x( 'Yachts', 'Post Type Singular Name', 'text_domain' ),
        'menu_name'             => __( 'Yachts', 'text_domain' ),
        'name_admin_bar'        => __( 'Edit Yachts', 'text_domain' ),
        'archives'              => __( 'Аrchive', 'text_domain' ),
        'parent_item_colon'     => __( 'Parent Yacht:', 'text_domain' ),
        'all_items'             => __( 'All Yachts', 'text_domain' ),
        'add_new_item'          => __( 'Add New Yacht', 'text_domain' ),
        'add_new'               => __( 'Add New Yacht', 'text_domain' ),
        'new_item'              => __( 'New Yacht', 'text_domain' ),
        'edit_item'             => __( 'Edit Yacht', 'text_domain' ),
        'update_item'           => __( 'Update Yacht', 'text_domain' ),
        'view_item'             => __( 'View Yacht', 'text_domain' ),
        'search_items'          => __( 'Search', 'text_domain' ),
        'not_found'             => __( 'Not Found', 'text_domain' ),
        'not_found_in_trash'    => __( 'Not Found', 'text_domain' ),
        'featured_image'        => __( 'Featured Image', 'text_domain' ),
        'set_featured_image'    => __( 'Set featured image', 'text_domain' ),
        'remove_featured_image' => __( 'Remove featured image', 'text_domain' ),
        'use_featured_image'    => __( 'Use as featured image', 'text_domain' ),
        'insert_into_item'      => __( 'Insert into item', 'text_domain' ),
        'uploaded_to_this_item' => __( 'Uploaded to this item', 'text_domain' ),
        'items_list'            => __( 'List of Cards', 'text_domain' ),
        'items_list_navigation' => __( 'Items list navigation', 'text_domain' ),
        'filter_items_list'     => __( 'Filter items list', 'text_domain' ),
    );
    $args = array(
        'label'                 => __( 'Yachts', 'text_domain' ),
        'description'           => __( 'Yachts', 'text_domain' ),
        'labels'                => $labels,
        'supports'              => array( 'title', 'thumbnail', 'editor'),
        'hierarchical'          => false,
        'public'                => true,
        'show_ui'               => true,
        'show_in_menu'          => true,
        'menu_position'         => 5,
        'menu_icon'             => 'dashicons-palmtree',
        'show_in_admin_bar'     => true,
        'show_in_nav_menus'     => true,
        'can_export'            => true,
        'has_archive'           => true,
        'exclude_from_search'   => false,
        'publicly_queryable'    => true,
        'capability_type'       => 'page',
        'show_in_rest' => true,
        'rewrite'      => array(
            'slug'       => '', 
            'with_front' => false, 
        ),
    );
    register_post_type( 'yachts', $args );

}
add_action( 'init', 'wtp_yachts', 0 );

I have tried to change the slug in $args but it only works for the last one CPT in the code, for the others I get 404. I’ve tried some hooks and filters but nothing.

2

Answers


  1. Chosen as BEST ANSWER

    Found the solution with a little help from a friend. And all the CPT must be set to have the same slug "listing".

    function customPostType() {
        register_post_type(
            'villas_post',
            [
                'labels' => [
                    'name' => 'Villas',
                    'singular_name' => 'Villa',
                ],
                'public' => true,
                'has_archive' => true,
                'rewrite' => ['slug' => 'listing'],
            ]
        );
    
        register_post_type(
            'yachts_post',
            [
                'labels' => [
                    'name' => 'Yachts',
                    'singular_name' => 'Yacht',
                ],
                'public' => true,
                'has_archive' => true,
                'rewrite' => ['slug' => 'listing'],
            ]
        );
    }
    
    add_action('init', 'customPostType');
    
    function modifyRequest($query) {
        if (!preg_match('//listing/.+/', $_SERVER['REQUEST_URI'])) {
            return $query;
        }
    
        global $wpdb;
    
        $postName = $query['name'];
    
        $sql = "
            SELECT post_type
            FROM {$wpdb->prefix}posts
            WHERE post_name = %s
            LIMIT 1
        ";
        $sql = $wpdb->prepare($sql, $postName);
    
        $result = $wpdb->get_results($sql)[0] ?? null;
    
        if (null === $result) {
            // TODO: Return 404 actually, dunno how
            return $query;
        }
    
        $postType = $result->post_type;
    
        $query = [
            'page' => $query['page'],
            'post_type' => $postType,
            'name' => $postName,
        ];
        $query[$postType] = $postName;
    
        return $query;
    }
    
    add_filter( 'request', 'modifyRequest' );
    

  2. To achieve your desired URL-structure for your custom post types with the same parent slug, you can change the rewrite rules for each CPT and set a common base slug. Here`s how you do it:

    1. Define a common base slug:

    Define the base slug that you want to use for every CPT. In your case, you want to use "listing" as the base slug.

    2. Change the rewrite-rules for each CPT:

    You need to set the rewrite rules for each CPT to include the common base slug. You can change the "rewrite" parameter in your CPT registration code.

      function wtp_yachts() {
                $base_slug = 'listing'; // Common base slug
            
                $labels = array(
                    // ... (your labels)
                );
            
                $args = array(
                    'label'                 => __( 'Yachts', 'text_domain' ),
                    'description'           => __( 'Yachts', 'text_domain' ),
                    'labels'                => $labels,
                    'supports'              => array( 'title', 'thumbnail', 'editor'),
                    'hierarchical'          => false,
                    'public'                => true,
                    'show_ui'               => true,
                    'show_in_menu'          => true,
                    'menu_position'         => 5,
                    'menu_icon'             => 'dashicons-palmtree',
                    'show_in_admin_bar'     => true,
                    'show_in_nav_menus'     => true,
                    'can_export'            => true,
                    'has_archive'           => true,
                    'exclude_from_search'   => false,
                    'publicly_queryable'    => true,
                    'capability_type'       => 'page',
                    'show_in_rest' => true,
                    'rewrite' => array(
                        'slug'       => $base_slug . '/yachts', // Common base slug + CPT name
                        'with_front' => false, 
                    ),
                );
                register_post_type( 'yachts', $args );
            }
            add_action( 'init', 'wtp_yachts', 0 );
    

    Repeat this process for every other CPT, e.g. "Villas" and "Cars", by changing the CPT name and the base slug in the "rewrite" parameter accordingly.

    This will ensure that all your CPTs have URLs like:

    www.domain.com/listing/single-villa
    www.domain.com/listing/single-yacht
    www.domain.com/listing/single-car
    

    Make sure you flush the rewrite rules after making these changes by going to the "Settings > Permalinks" page in your WordPress dashboard. This will ensure that the new rewrite rules take effect.

    By using a common base slug, you can get the URL structure you want while keeping your CPTs organized.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search