Support

Account

Home Forums General Issues Change permalink of CPT to be child of another CPT Reply To: Change permalink of CPT to be child of another CPT

  • To change the permalink of a Custom Post Type (CPT) in WordPress to act as a child of another CPT, you’ll need to customize the rewrite rules and manage the hierarchy through hooks in your theme’s functions.php file or a custom plugin. Here’s a step-by-step guide:

    Example Setup
    – **Parent CPT**: parent_cpt
    – **Child CPT**: child_cpt
    – Desired permalink structure: /parent_cpt/child_cpt/

    1. Register Custom Post Types
    First, make sure both your parent and child CPTs are registered. The key is to set up the rewrite rule correctly for the child CPT.

    Parent CPT Registration
    `php
    function register_parent_cpt() {
    $labels = array(
    ‘name’ => ‘Parent CPT’,
    ‘singular_name’ => ‘Parent CPT’,
    );
    $args = array(
    ‘labels’ => $labels,
    ‘public’ => true,
    ‘rewrite’ => array( ‘slug’ => ‘parent_cpt’ ),
    );
    register_post_type( ‘parent_cpt’, $args );
    }
    add_action( ‘init’, ‘register_parent_cpt’ );
    `

    Child CPT Registration (with rewrite)
    `php
    function register_child_cpt() {
    $labels = array(
    ‘name’ => ‘Child CPT’,
    ‘singular_name’ => ‘Child CPT’,
    );
    $args = array(
    ‘labels’ => $labels,
    ‘public’ => true,
    ‘rewrite’ => array( ‘slug’ => ‘parent_cpt/%parent_cpt%/child_cpt’, ‘with_front’ => false ),
    ‘has_archive’ => true,
    );
    register_post_type( ‘child_cpt’, $args );
    }
    add_action( ‘init’, ‘register_child_cpt’ );
    `

    2. Add Rewrite Logic to Handle Permalinks
    We need to intercept and replace %parent_cpt% with the actual parent_cpt slug. Here’s how to do that.

    Handle Permalink Replacement
    `php
    function child_cpt_permalink($permalink, $post) {
    if ($post->post_type !== ‘child_cpt’) {
    return $permalink;
    }

    // Get the parent CPT ID
    $parent_id = get_post_meta($post->ID, ‘parent_cpt_id’, true);

    if ($parent_id) {
    $parent_post = get_post($parent_id);
    $parent_slug = $parent_post->post_name;
    return str_replace(‘%parent_cpt%’, $parent_slug, $permalink);
    }

    return $permalink;
    }
    add_filter(‘post_type_link’, ‘child_cpt_permalink’, 10, 2);
    `

    3. Add Rewrite Rules
    This rule tells WordPress how to parse URLs in the desired format.

    `php
    function add_custom_rewrite_rules() {
    add_rewrite_rule(
    ‘^parent_cpt/([^/]+)/child_cpt/([^/]+)/?$’,
    ‘index.php?child_cpt=$matches[2]’,
    ‘top’
    );
    }
    add_action(‘init’, ‘add_custom_rewrite_rules’);
    `

    4. Save Parent CPT as Post Meta
    You need a way to associate the child post with its parent. You can do this via a meta box in the admin area or using a custom relationship field.

    Here’s an example of saving a parent_cpt_id as a post meta field:

    `php
    function save_child_cpt_meta($post_id, $post, $update) {
    if ($post->post_type != ‘child_cpt’) {
    return;
    }

    if (isset($_POST[‘parent_cpt_id’])) {
    update_post_meta($post_id, ‘parent_cpt_id’, $_POST[‘parent_cpt_id’]);
    }
    }
    add_action(‘save_post’, ‘save_child_cpt_meta’, 10, 3);
    `

    5. Flush Rewrite Rules
    Whenever you add new rewrite rules, you need to flush them. You can do this temporarily by visiting the **Settings > Permalinks** page, or by adding this line temporarily to your code:

    `php
    flush_rewrite_rules();
    `

    Final Notes
    – The parent-child relationship is stored using post meta (parent_cpt_id), but you can adjust this based on how you’re managing relationships.
    – If you’re using a plugin like Advanced Custom Fields (ACF) for relationships, the code can be modified accordingly.

    This setup allows the child CPT to inherit the parent CPT’s slug in the URL structure.