On my site several filters should be applied if the user is viewing the static home page. My understanding is that is_front_page()
should determine if that is indeed the case.
However, whenever I use the function I find that sometimes it returns true
(e.g. posts_orderby
) but mostly it returns false
(e.g. pre_get_posts
, posts_fields
, posts_join
and posts_where
). Regardless of the result though, I always recieve the following notice -
Trying to get property of non-object in {my_path}\wp-includes\query.php on line 4373
The method containing the offending line is WP_Query::is_front_page()
-
public function is_front_page() {
// most likely case
if ( 'posts' == get_option( 'show_on_front') && $this->is_home() )
return true;
/** The offending line */ elseif ( 'page' == get_option( 'show_on_front') && get_option( 'page_on_front' ) && $this->is_page( get_option( 'page_on_front' ) ) )
return true;
else
return false;
}
To combat this issue I have created my own function, as below, but it seems "dirty" to have had to do so. So my question is thus - is there a better way to do this?
function fgw_is_front_page($q){
if(!is_a($q, 'WP_Query'))
return false;
return (get_option('show_on_front') == 'page' && get_option('page_on_front') && $q->get('page_id') == get_option('page_on_front'));
}
Afer further investigation it seems that the offending line is actually 4369 (wp-includes/querey.php) - $page_obj = $this->get_queried_object();
$page_obj
is being returned as null
, meaning that check for $q->is_front_page()
fails. This seems wrong, and unless anyone is able to explain how this could in any way be expected behaviour I'll look at opening a ticket on Trac.
I have now amended the above function. Making use of the second argument passed to all of the filters that I am using (the WP_Query instance), as mentioned by @birgire, has allowed me to do away with the global.
However, taking the below example, I am still receiving the aformentioned notice (and result of false
) when checking $q->is_front_page()
-
add_filter('posts_fields','fgw_index_posts_fields', 10, 2);
function fgw_index_posts_fields($fields, $q){
global $wpdb;
if(!is_admin() && is_main_query() && (is_home() || $q->is_front_page($q)))
$fields.= $wpdb->prepare(', %1$s.name as category_name', $wpdb->terms);
return $fields;
}
Replacing $q->is_front_page()
with fgw_is_front_page($q)
works, but again it feels dirty to have to use a custom solution when seemingly there is one that already exists.
On my site several filters should be applied if the user is viewing the static home page. My understanding is that is_front_page()
should determine if that is indeed the case.
However, whenever I use the function I find that sometimes it returns true
(e.g. posts_orderby
) but mostly it returns false
(e.g. pre_get_posts
, posts_fields
, posts_join
and posts_where
). Regardless of the result though, I always recieve the following notice -
Trying to get property of non-object in {my_path}\wp-includes\query.php on line 4373
The method containing the offending line is WP_Query::is_front_page()
-
public function is_front_page() {
// most likely case
if ( 'posts' == get_option( 'show_on_front') && $this->is_home() )
return true;
/** The offending line */ elseif ( 'page' == get_option( 'show_on_front') && get_option( 'page_on_front' ) && $this->is_page( get_option( 'page_on_front' ) ) )
return true;
else
return false;
}
To combat this issue I have created my own function, as below, but it seems "dirty" to have had to do so. So my question is thus - is there a better way to do this?
function fgw_is_front_page($q){
if(!is_a($q, 'WP_Query'))
return false;
return (get_option('show_on_front') == 'page' && get_option('page_on_front') && $q->get('page_id') == get_option('page_on_front'));
}
Afer further investigation it seems that the offending line is actually 4369 (wp-includes/querey.php) - $page_obj = $this->get_queried_object();
$page_obj
is being returned as null
, meaning that check for $q->is_front_page()
fails. This seems wrong, and unless anyone is able to explain how this could in any way be expected behaviour I'll look at opening a ticket on Trac.
I have now amended the above function. Making use of the second argument passed to all of the filters that I am using (the WP_Query instance), as mentioned by @birgire, has allowed me to do away with the global.
However, taking the below example, I am still receiving the aformentioned notice (and result of false
) when checking $q->is_front_page()
-
add_filter('posts_fields','fgw_index_posts_fields', 10, 2);
function fgw_index_posts_fields($fields, $q){
global $wpdb;
if(!is_admin() && is_main_query() && (is_home() || $q->is_front_page($q)))
$fields.= $wpdb->prepare(', %1$s.name as category_name', $wpdb->terms);
return $fields;
}
Replacing $q->is_front_page()
with fgw_is_front_page($q)
works, but again it feels dirty to have to use a custom solution when seemingly there is one that already exists.
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.
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/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/ticket/21790#comment:11