Support » Developing with WordPress » Rewrite URL with add_rewrite_rule only for frontend

  • Resolved Michael

    (@migaweb)


    I want to add a rewrite rule to render a custom post type (/custom-post/child1) to a special page:

    function rewrite_rules() {
     $postName = "custom-post";
     $postId = 123;
     
     add_rewrite_rule(
       $postName.'/?([^/]*)/',
       'index.php?page_id=' . $postId.'&pid=$matches[1]&ptype='.$postName,
       'top'
     );
    }
    add_action('init', 'rewrite_rules');

    This works fine BUT it breaks editing the post with Elementor in the backend.

    Can I change the rule so that it will only work for the frontend? I’ve tried it with !is_admin() around it but then it won’t work in the frontend anymore.

    The rewrite rule should only apply for “/custom-post/child1” to “fixed page” while viewing the post in the frontend not while I’m editing pages in the backend.

Viewing 10 replies - 1 through 10 (of 10 total)
  • Moderator bcworkz

    (@bcworkz)

    There’s no opportunity to apply conditionals to rewrite rules. The regex either matches or it doesn’t. Maybe you could apply conditional logic farther down the line? For example, in “pre_get_posts”, if the query vars indicate this rule was applied, but the request is related to the editor, alter the query vars back to what they would have been without the rule.

    I’m not sure what Elementor is doing where the rewrite rule comes into play. is_admin() might not work in that context. It’s worth trying it anyway. If it fails to work as expected, I recommend asking through Elementor’s dedicated support forum how you might separate an Elementor request from actual front end requests.

    Thread Starter Michael

    (@migaweb)

    Thanks, I’ll have a look at pre_get_posts!

    Elementor is calling /custom-post/demo/?elementor-preview=1786&ver=1658091006 to open the editor and so it will apply the rewrite rule. My hope was that I can ignore those URLs somehow. But I’ll check if that perhaps is possible with pre_get_posts or if I can specify my add_rewrite_rule not to match those.

    Elementors support is on Facebook now….so not an option 🙂

    You could also check if Elementor is currently running. There is an article on this here: https://ralphjsmit.com/elementor-check-active

    I am currently testing with e.g.

    if( !did_action( 'elementor/loaded' ) ) {
    }

    whether Elementor is generally available.

    There is another Elementor support forum here: https://wordpress.org/support/plugin/elementor/

    Thread Starter Michael

    (@migaweb)

    Thanks @threadi, you are right! Didn’t think about the plug-in support forum. Will check that.

    if( !did_action( 'elementor/loaded' ) ) {} won’t help since the rewrite rule is set already in the init event. I use that check to make sure Elementor is used in my plugin init so activating the plugin won’t cause errors when Elementor is not there.

    • This reply was modified 3 weeks, 3 days ago by Michael.
    Thread Starter Michael

    (@migaweb)

    I’ve tried to alter my rewrite rule with (?!.*elementor) in front and it works when testing it in https://regexr.com/ with
    (?!.*elementor)custom-post\/?([^/]*)\/?
    and

    
    http://localhost/~test/custom-post/demo/
    http://localhost/~test/custom-post/demo/?elementor-preview=1786&ver=1658094603
    

    it will only match the first URL. But when I open http://localhost/~test/custom-post/demo/?elementor-preview=1786&ver=1658094603 in my browser it still follows the redirect 🤔

    Moderator bcworkz

    (@bcworkz)

    I’m not sure what’s happening there. I’ve another thought on a different approach. Could you implement the functionality of this special page entirely through template code? You can still pull in editable content from the CPT or where ever. You could then leave rewrite rules alone and let WP do what it does. To get to this special page template, instead of rewrite rules or pre_get_posts, use “template_redirect” or “template_include” hooks to direct execution to this special page template.

    By the time those hooks fire, all the is_*() functions should work as expected. As should did_action( 'elementor/loaded' ) perhaps. I’m not sure where else you’d see elementor-preview query string, but it has to be somewhere. If not as a query var, then somewhere in $_SERVER.

    I don’t know the inner workings of Elementor, but I suspect it hooks into that URL using the same or similar mechanism. The choice to redirect to the template has to be made before Elementor does its thing, so this may not be a viable approach. Just spit-balling ideas.

    Thread Starter Michael

    (@migaweb)

    That is an interesting approach! Definitely going to try that, thanks! The global goal is that all CPT posts will be rendered in the one page that I’ve defined with the $postId in the rewrite rule. That page has special fields where it will render the content of the CPT post. Using the add_rewrite_rule made it quick to setup and everything was working fine until someone wanted to use the Elementor Editor in those CPT posts 🙂

    Thanks again for the input, going to check those functions and see if they’ll do what I’ll need!

    Thread Starter Michael

    (@migaweb)

    @bcworkz thanks again for your hints! I have it working now.
    template_include worked fine BUT I had to use wp_redirect to forward to my page (its not a template file) which worked too but it changed the URL. So I searched a bit around and found that I can change the request in add_filter('request').

    Downside: the page Elementor is calling custom-post/demo/?elementor-preview=1786&ver=1658094603 is a normal request and I Elementors is_preview_mode or is_admin() is both false. So I had to use $_SERVER["REQUEST_URI"] and check for elementor-preview to identify that request. With that I can check everything in my request filter!

    Still have to do some more tests and see if I can identify it without the $_SERVER var but for the moment it works like this.

    👍

    Thread Starter Michael

    (@migaweb)

    one last question @bcworkz:
    everything works fine in one WP instance. I have a different on the same server and when I change the query_vars it results in a 301:

    
    add_filter('request', function ($query_vars) {
        if (is_admin() ) {
            return $query_vars;
        }
    
       $query_vars["page"] = "";
       $query_vars["post_type"] = "";
       $query_vars["custompost"] = "";
       $query_vars["name"] = "";
       $query_vars["pid"] = 123;
       $query_vars["ptype"] = "custompost";
       $query_vars["pagename"] = get_post_field('post_name', 321);
       return $query_vars;
    });
    

    and it will redirect to the page instead of just showing the result like the other WP instance does. Same CPT, same htacces, same post list 🤔
    Even if I copy the theme and plugin in a third instance it works fine. Just the one folder is doing a 301 and I don’t know why.

    Moderator bcworkz

    (@bcworkz)

    Well, that’s quite strange. Once WP gets control of the request, it shouldn’t redirect unless an explicit Location: header is sent. Usually by calling wp_redirect() or similar. If there was such code somewhere, I’d expect it to be the same behavior in every identical installation.

    I’m inclined to think it’s due to an external factor and not WP itself. Such as something in .htaccess or virtual server files.

    If the installations are not identical (other than different folder), it could be due to a theme or plugin that’s not common to the other installations.

    Oh, do make sure all requests have a terminal / in the URL. Without it, WP will 301 redirect to an URL that has it.

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