Indeed - in the get_pages()
documentation we can see that it accepts either a string or an array as an argument. It does seem a little bit weird to call a function with the arguments concatenated into a string, doesn't it?
Under the hood, the get_pages()
function uses the WP_Query
class in order to query for Page-type posts, and the root of the ambiguity boils down to WP_Query
's implementation. The class was built such that it can accept a string of query arguments which will be converted into a more appropriate data structure - an associative array of arguments - before creating the actual SQL query to retrieve data from the database. The reason WP_Query
was built this way is to accommodate queries which are specified via the "querystring" or "search string" in the URL (the list of key/value pairs which begins after a ?
and is delineated with an &
thereafter).
In my opinion, I would agree with your skepticism - it doesn't make sense to me to use a query in string format when writing an internal function such as the one described by the book, more specifically for two reasons:
- String concatenation is inelegant and harder to interpret for humans and code analysis tools alike. The only reason
WP_Query
is capable of interpreting string arguments to begin with is out of necessity for parsing URLs.
- Query arguments as a string require
WP_Query
to perform a tiny amount of additional work to convert them back into usable data.
In my subjective opinion, without describing why it might implement the function in the manner which it has, the book's example should be implemented with an associative array instead:
function page_is_parent(){
global $post;
$pages = get_pages(
[
'child_of' => $post->ID,
]
);
return count( $pages );
}
Additional Critique
I would go further to critique a few other points of that function.
- I feel it is named inappropriately - the name the author has given to the function does not describe what it does. The function returns the number of pages which the current Page is a parent to. It can be used for the purpose implied by the author's chosen name in that it will return a "truthy" value if the current page is a parent to one or more pages and a "falsey"
0
if it is not. But the name does not actually describe what the function actually does which can lead to misuse. if( page_is_parent() > 1 )
hardly makes sense to anyone but the person who wrote the function.
- Whenever possible, it is best to avoid directly accessing WordPress's global values in order to avoid circumventing filtration and sanitization logic which might otherwise be provided by accessor APIs. Instead of
global $post
, we have a convenient substitute in the form of get_post()
which will access the same global if necessary.
The above in mind, I personally would implement the proposed function as follows:
function get_child_page_count() {
$post = get_post();
$child_pages = get_pages(
[
'child_of' => $post->ID,
]
);
return count( $child_pages );
}
You can read if( get_child_page_count() > 1 )
and know exactly what's going on a whole lot better than if( page_is_parent() > 1)
- that's super-nice, isn't it?
An Advanced Form
The book may well get into this at some point, but for the purposes of counting the number of child pages, the provided query is inefficient. get_pages()
retrieves the full data for every child page when all the function cares about is how many there are.
WP_Query
provides a mechanism which get_pages()
does not - the ability to only ask for certain columns instead of full rows via the fields
parameter. Further, the WP_Query
object provides a found_posts
property detailing how many posts matched the query in total even if they were not returned "on the current page." So ultimately, we can ask for a single matching page's ID but still retrieve the total number of matching pages. This should speed things up a wee bit - not enough to matter when you're only dealing with a moderate number of child pages, but it can definitely make a difference when you're working with a lot of pages.
As a final point of critique, we can expand the function such that not only will it consider the current post when utilized within The Loop, but we can also pass an argument to have it calculate the number of child Pages for a specific Page/Page ID.
All together, I would implement the function as follows:
function get_child_page_count( $page = null ) {
// Retrieve the post object specified by the $page argument, or from
// the global $post if the argument is omitted.
$post = get_post( $page );
$query = new WP_Query(
[
'post_type' => 'page', // Query for pages...
'post_parent' => $post->ID, // ...which have a parent of the page passed as an argument (or the current page if omitted)...
'fields' => 'ids', // ...and only retrieve their IDs...
'posts_per_page' => 1, // ...but only retrieve 1 from the database.
]
);
return $query->found_posts; // Return the total number of matching posts.
}
Of course, you could also write that query as
$query = new WP_Query( 'post_type=page&post_parent=' . $post->ID . '&fields=ids&posts_per_page=1' );
...but that's utter nonsense, in my book ;)