Wordpress - What is the correct method for determining 'is_front_page' when using filters such as 'pre_get_posts' and 'posts_where'?

Regarding the posts_orderby, posts_where, posts_join and posts_clauses hooks, the current \WP_Query object is available through the second input argument.

These are the relevant parts from the \WP_Query class:

$orderby = apply_filters_ref_array( 'posts_orderby', array( $orderby, &$this ) );
$where   = apply_filters_ref_array( 'posts_where', array( $where, &$this ) );
$join    = apply_filters_ref_array( 'posts_join', array( $join, &$this ) );
$clauses = (array) apply_filters_ref_array( 'posts_clauses', array( compact( $pieces ), &$this ) );

all using the apply_filters_ref_array function and &$this is the current \WP_Query instance. The Codex says the following about this function:

This function is identical to apply_filters, but the arguments passed to the functions hooked to $tag are supplied using an array.

You can access the second argument with for example:

add_filter( 'posts_where', function( $where, \WP_Query $q )
{
    if( $q->is_front_page() ) <-- This method won't work here with a static front-page!!!
    {
        // ...
    }
}, 10, 2 );

so you don't have to rely on the global $wp_query object.

After tracing this inside WP_Query, we've found the reason why calling the is_front_page() method doesn't work inside these filter callbacks. There problem lies within the is_page() method that tries to use the get_queried_object() method that still hasn't got an object to return.

The is_home() method works on the other hand, and it isn't calling the is_page() method.

Update:

There seems to be at least two Trac tickets, #27015 and #21790, that related to this problem.

In #27015 there's a suggested patch by @mattonomics, that modifies the queried_object object within the parse_query() method.

So why not try these modifications in our case, but through the parse_query hook instead:

/**
 * A workaround for the is_front_page() check inside pre_get_posts and later hooks.
 *
 * Based on the patch from @mattonomics in #27015
 *
 * @see http://wordpress.stackexchange.com/a/188320/26350
 */

add_action( 'parse_query', function( $q )
{
    if( is_null( $q->queried_object ) && $q->get( 'page_id' ) )
    {
        $q->queried_object    = get_post( $q->get( 'page_id' ) );
        $q->queried_object_id = (int) $q->get( 'page_id' );
    }
} );

We should be able to add further changes this way, from that patch.


instead of

$query->is_front_page()

try using

$query->get('page_id') == get_option('page_on_front')

(in context:)

function custom_pre_get_posts( $query ) {
    if ( $query->get('page_id') == get_option('page_on_front') ) {
        // do stuff
    }
}
add_action('pre_get_posts', 'custom_pre_get_posts');

This solution is from here: https://core.trac.wordpress.org/ticket/21790#comment:11