Adding WHERE clause to redirection query overwrites existing query

#580272
  • Resolved Anonymous
    Rank Math free

    Hey team,

    I am working on adding cursor-based pagination support when querying for redirections in WPGraphQL for Rank Math SEO.

    I believe the correct way to do this is with the rank_math/redirection/get_redirections_query action, however calling $table->where() overrides the existing sql rules, instead of appending it.

    Is this a bug in the Query_Builder implementation, or am I doing something wrong (and if so, do you have a better approach)?

    (PS: my assumption is that we will face the same issue when trying to expose 404 Monitor logs to WPGraphQL, so solving this is essential to Rank Math feature parity with headless).

    Here’s a simplified code example to illustrate the issue:


    add_action(
    'rank_math/redirection/get_redirections_query',
    function( $table, $args ) {
    // 'after' is the redirection ID that we're paginating from.
    if ( empty( $args['after'] ) ) {
    return;
    }

    // Confirm $table->sql_clauses has the correct where, limit, `orderby, etc.
    error_log( print_r( $table, true ) );

    // Get the operator from the args.
    $operator = 'DESC' === $args['order'] ? '<' : '>';

    // Get the value from the redirection.
    $cursor = \RankMath\Redirections\DB::get_redirection_by_id( absint( $args['after'] ) );
    $value = $cursor[ $args['orderby'] ];

    // I want to *add* the where clause to the existing ones.
    $table->where( $args['orderby'], $operator, $value ); // e.g. 'id', '<', 5

    // $table->sql_clauses has been OVERRIDDEN, so only 'WHERE id < '5' exists.
    error_log( print_r($table, true );
    },
    10,
    2
    );

    Pastebin of the logged table before/after: https://pastebin.com/VTcXQ9Wm

Viewing 11 replies - 1 through 11 (of 11 total)
  • Anonymous
    Rank Math free

    Apologies, it seems your <code> tab breaks on backticks, and there’s no way to edit the post, so here’s the example snippet in a Pastebin

    Hello,

    Thank you for contacting Rank Math and sorry for not following up quickly and any inconvenience that might have been caused due to that. The $table->where() doesn’t overwrite the existing where clause in the query it will append it.

    Please check here the 4th parameter passed to the where function: https://github.com/rankmath/seo-by-rank-math/blob/master/vendor/mythemeshop/wordpress-helpers/src/database/class-where.php#L34

    Can you please share some more details of what exactly you want to do so we can reproduce and test it on our setup?

    Looking forward to helping you.

    Anonymous
    Rank Math free

    (Sorry Pratik, didnt see it autocorrected until after I posted)

    Anonymous
    Rank Math free

    Thanks for the response, Pratic, but I’m not sure I follow.

    As you noted, the $table->where() call should append the where clause, however in this case it is not.

    The Pastebin I provided should be independently replicable (tested against WP v6.2 + RM v1.0.116) – just add it to your test env’s functions.php. You can see the where() call on line 22 (the fourth parameter is unset in this example, since it defaults to ‘AND’ which is the behavior we want here. In the IRL code linked below, ‘AND’ is explicitly set.).

    The real-world code can be found in this PR. This method hooks onto the rank_math/redirection/get_redirections_query action to append the necessary where clause (i.e only the results after a provided post ). However, instead of appending the clause, it replaces it, as evidenced by this test (because the preexisitng order/orderby clauses are overwritten, only 1 redirection is returned). But again, the Pastebin replicates the issue without all that extraneous logic.

    If there’s any additional context/debugging information you need, please let me know.

    Hello,

    Thank you for sharing the details. I was able to reproduce the issue on my setup.

    The issue is you are using \RankMath\Redirections\DB::get_redirection_by_id( absint( $args[‘after’] ) ); function where the $table instance is getting reset. If you comment this code, you’ll see the where clause contains 2 items:
    `
    [0] => WHERE status != ‘trashed’
    [1] => AND id < 5 `

    Instead of using the get_redirection_by_id function, please try using a custom query. Here is a modified PasteBin

    I hope that helps.

    Anonymous
    Rank Math free

    Thanks Pratik, the pastebin you provided is working in isolation, and I am working to apply it to the actual code. Leaving this open for now and will post back if I run into any issues.

    (PS just to bring it to the attention of the dev team: the overuse of shared static properties and modifying references instead of instances really makes it a PITA for developers to integrate, test, and build with RankMath. The lack of encapsulation around DB::get_redirection_by_id() is just one example.)

    Hello,

    Thank you so much for your input. Sure, we will keep this ticket open for you.

    In the meantime, please do not hesitate to let us know if you need our assistance with anything else.

    Anonymous
    Rank Math free

    Looks like I am running into the same issue calling DB::get_redirections( $args ); multiple times in the same process. The where and order_by args in the new query get appended on the previous $table (since its a static singleton), instead of the $table getting reset between calls.

    For example, calling that method three times, leaves me with
    SELECT SQL_CALC_FOUND_ROWS * FROM wp_rank_math_redirections WHERE status = 'active' AND status = 'active' AND status = 'active' AND created < '2023-06-11 11:12:46' ORDER BY created, created, created LIMIT 0, 3.

    I’m not seeing any publicly accessible reset methods, and unlike your workaround for querying a single ID, manually building a SQL query that mimics DB::get_redirections() isn’t really tenable if we want our extension to be future-compatible with Rank Math.

    Hello,

    Can you please tell us why you are calling the DB::get_redirections( $args ); multiple times in the same process? This function can return multiple Redirections rules based on the $args.

    Looking forward to helping you.

    Anonymous
    Rank Math free

    It’s a fairly standard use case when using WPGraphQL APIs (e.g. in the same request you might get the list of active redirections, the redirection for a given id, and any redirections that match a provided uri).

    It’s also a performance necessity when querying for _lots_ of items. This is less critical for redirects but it looks like 404 logs use the same static patterns.

    And sadly, there’s no real way to ‘workaround’ this in the frontend. Static site generation (Gatsby, NextJS + Apollo, etc) will combine and dedupe queries to minimize the number of requests, and paginate through results to avoid killing the database.

    (PS, we had the same issue with RankMath:Paper, which was resolved by adding a public static reset() method. It’s not ideal – there or here – but works in a pinch a lot easier to implement than refactoring Rank Math to be DRY and use dependency injection)

    Hello,

    Thank you for your suggestion. I have added it to our feature list, and we will try to incorporate it in future updates.

    In the meantime, please let us know if you need our help with anything else.

    Hello,

    Since we did not hear back from you for 15 days, we are assuming that you found the solution. We are closing this support ticket.

    If you still need assistance or any other help, please feel free to open a new support ticket, and we will be more than happy to assist.

    Thank you.

Viewing 11 replies - 1 through 11 (of 11 total)

The ticket ‘Adding WHERE clause to redirection query overwrites existing query’ is closed to new replies.