1

I'm trying to catch the params sent by the rewrite rules and then display a selected post.

But for now, even if I can retrieve those param, the page redirect to the archive of my custom post type. Where I need to display the post that match a custom query build from the query string given by the rewrite rule.

add_action('init', function () {
    $terms_slug = getCustomTermsSlug();
    // @note Catch /{foo}
    add_rewrite_rule('^(' . implode('|', $terms_slug) . ')/?', 'index.php?post_type=custom&foo=$matches[1]', 'top');
});

add_action('init', function () {
    add_rewrite_tag('%foo%', '([^&]+)');
}, 10, 0);

add_action('pre_get_posts', function ($query) {
    if (is_admin() || !$query->is_main_query()) {
        return;
    }

    if (get_query_var('foo')) {
        $tax_query = [[
            'taxonomy' => 'custom',
            'field' => 'slug',
            // @note "foo" is a custom taxonomy term
            'terms' => get_query_var('foo'),
        ]];

        $query->set('tax_query', $tax_query);
    }

    return $query;
});

First, I don't understand why it redirect to the archive page?

Second, maybe the "pre_get_posts" is not the right place to make the customized query but where I can do it then?

Third, how to display the selected post in response of the clean URL given?

Thank's for your help! ;-)

@EDIT I've tried using actions like "template_redirect" or "parse_request" but it feel really *hacky. Is anyone know how to force the redirect (eg. rewrite matching) to the first post of the custom query?

7
  • 1
    You've used term_sulg in one place
    – birgire
    Commented Aug 16, 2017 at 10:51
  • hello @birgire, the "term_slug" string is only an example... but what did you mean exactly? Commented Aug 16, 2017 at 12:37
  • You use $args but don't set it anywhere.
    – Milo
    Commented Aug 16, 2017 at 13:05
  • Oh ! That's a mistake when writing the question... I fix that right now! ;-) Commented Aug 16, 2017 at 13:38
  • 1
    It's difficult and sometimes impossible to convert one type of request to another in pre_get_posts. You need to hook before query parsing if you are doing anything major, or you need to set the correct query vars in your rule to let wp know you intend this to be a single post view rather than archive.
    – Milo
    Commented Aug 16, 2017 at 15:44

1 Answer 1

1

It appear, like @milo also said, that the correct way to doing this is by using the "parse_request" action that stand before the "pre_get_posts" action (see https://codex.wordpress.org/Plugin_API/Action_Reference).

The complete solution I came with :

add_action('init', function () {
    $refs_slug = getCustomRefTermsSlug(); // this will return an array of all the terms slug existing in the custom "ref" taxonomy

    // @note Catch /{foo|bar|baz} and redirect to index.php?catch_me=true?ref={foo|bar|baz}
    add_rewrite_rule('^(' . implode('|', $refs_slug) . ')/?', 'index.php?post_type=custom&catch_me=true&ref=$matches[1]', 'top');
});

add_action('init', function () {
    add_rewrite_tag('%ref%', '([^&]+)');
    add_rewrite_tag('%catch_me%', '([^&]+)');
}, 10, 0);

add_action('parse_request', function ($query) {
    if (array_key_exists('catch_me', $query->query_vars) && $query->query_vars['catch_me']) {
        $args = [
            'post_type' => 'custom',
            'posts_per_page' => 1,
            'fields' => 'ids',
            'tax_query' => [],
        ];

        if (array_key_exists('ref', $query->query_vars)) {
            $args['tax_query'][] = [
                'taxonomy' => 'ref',
                'field' => 'slug',
                'terms' => $query->query_vars['ref'],
            ];
        }

        // get the right post
        $tmp_query = new \WP_Query($args);
        $post_id = $tmp_query->posts[0];

        // tell wordpress what post to display
        $query->query_vars = [
            'post_type' => 'custom',
            'p' => $post_id,
        ];
    }

    return $query;
});

add_filter('post_type_link', function ($url, $post) {
    if (get_post_type($post) == 'custom') {
        $refs_slug = getCustomRefTermsSlug($post->ID); // this will return an array of all the terms slug of the custom "ref" taxonomy assigned to the post

        // @note Return "/{foo|bar|bar}" as the permalink of the post
        return '/' . implode('/', $refs_slug);
    }

    return $url;
}, 10, 2);

Feel free to give me comments! ;-)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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