I have three different Custom Post Types:

  1. Company
  2. Employee
  3. Project

They are connected with ACF relationship fields so as the Company can have multiple Employees and each Employee can have a project attached. The get_field() function retrieves attached post objects to create some sort of relationship.

What I need to do is create three permalink structures for these CPT:

  1. For Companies: www.somepage.com/%company_name%
  2. For Employees: www.somepage.com/%company_name%/%employee_name%
  3. For Projects: www.somepage.com/%company_name%/%employee_name%/%project_name%

What I have already managed to do is to set permalink structure to them with this piece of code:

function dd_custom_permalinks($permalink, $post, $leavename) {
    $post_id = $post->ID;
    if(($post->post_type != 'project' && $post->post_type != 'employee' && $post->post_type != 'company') || empty($permalink) || in_array($post->post_status, array('draft', 'pending', 'auto-draft')))
        return $permalink;

    if (get_field("employees", $post->ID)) {
        $permalink = str_replace('%company%', $post->post_name, $permalink);
    } elseif (get_field("company", $post->ID)) {
        $permalink = str_replace('%company%', get_field("company", $post->ID)[0]->post_name, $permalink);
        $permalink = str_replace('%employee%', $post->post_name, $permalink);
    } elseif (get_field("employee", $post->ID)) {
        $employee= get_field("employee", $post->ID)[0];
        $company= get_field("company", $employee->ID)[0];
        $permalink = str_replace('%company%', $company->post_name, $permalink);
        $permalink = str_replace('%employee%', $employee->post_name, $permalink);
        $permalink = str_replace('%project%', $post->post_name, $permalink);

    return $permalink;
add_filter('post_type_link', 'dd_custom_permalinks', 10, 3);

The problem is I cannot find a way to make them valid, as the structure always leads to Company (first part of the custom url structure). Probably I have to bind the further with the CPT query somehow?

I have also tried using custom rewrite rules, but I can't understand how should this be done to be fair. Here's what I got so far (not working):

function dd_custom_rewrite_rules() {
    add_rewrite_tag('%company%', '([^/]+)', 'company=');
    add_permastruct('company', '/%company%', false);

    add_rewrite_tag('%employee%', '([^/]+)', 'employee=');
    add_permastruct('employee', '/%company%/%employee%', false);
    add_rewrite_tag('%project%', '([^/]+)', 'project=');
    add_permastruct('project', '/%company%/%employee%/%project%', false);

add_action( 'init', 'dd_custom_rewrite_rules' );

Any ideas how (or maybe IF) can I get this to work properly?

  • 1
    One way to prevent the issue is by using the actual "company" slug in the rewrite rule's RegEx pattern, e.g. ^company/(foo|bar-baz)/([^/]+)/? which would match example.com/company/foo/.. and example.com/company/bar-baz/... But you'll need to ensure the slug is in sync with the current one in the posts table, so if foo was later on changed to foo-inc, then the same needs to be done on the rewrite rule.
    – Sally CJ
    Jul 13, 2021 at 14:13

1 Answer 1


Sally CJ commented an important detail that helped me reach what I needed.

Apart from that I struggled with what seemed to be regex error - one of my rules was overriding another because there was no $ character in regex to end the string.

Working solution for custom rewrites:

function dd_custom_rewrite_rules() {
    add_rewrite_tag('%company%', '([a-z0-9-]+)', 'company=');
    add_rewrite_tag('%employee%', '([a-z0-9-]+)', 'employee=');
    add_rewrite_tag('%project%', '([a-z0-9-]+)', 'project=');

    add_permastruct('project', '/company/%company%/%employee%/%project%', false);
    add_permastruct('employee', '/company/%company%/%employee%', false);
    add_permastruct('company', '/company/%company%', false);



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.