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