When I started out as a WordPress developer, I was working with object-oriented PHP before I even really knew what it was, thanks to WordPress post API class, WP_Query.
In that article, I said that PHP has two data types that are considered “compound,” meaning we can store more than one piece of data in them. In PHP, objects and arrays are the only two data types that are actually considered compound.
Objects are similar to arrays in that they provide structure for storing data, however, unlike arrays, objects are created with blueprints called classes, which can contain functions.
In this article, we’re going to look at WP_Query as a way of understanding how classes and objects work.
A Little Background
Before we dive in, let’s talk about syntax and terminology. It’s important to make sure you have a good understanding of the terms “class,” “object” and “instance.” In any program, you can only have a class of a given name once. If I were to create a class in a WordPress plugin called “WP_Query” I would get a fatal error, since that class is already defined.
Classes are not actually objects but rather they are rules for creating an object. We can create as many objects of the WP_Query class as we want, however, each time we do, we are instantiating a new instance of the WP_Query class.
As I noted at the beginning of this article, arrays and objects are similar in that they can both contain other data types. With arrays, we use bracket notation to define and access index or keys of an array. With objects, we don’t have keys or indexes, instead, we have properties. Properties act just like variables, except they are inside of an object.
For example look at this class:
class say_hi { public $hello = 'Hi Roy'; }
In this class, we have a property called “hello.” It looks like a variable and acts like a variable but can only be accessed in the context of the class.
If we instantiate an object of this class by adding the keyword “new,” then we can access the property like this:
$hi = new say_hi(); echo $hi->hello;
Classes are more than just containers for data stored in properties. They also encapsulate functionality. Inside of a class, a function is called a method. Methods are like functions, but they can only be used in the context of the object they are a part of. This allows us to make use of property or method visibility, as well as processing the data stored in the properties of the object.
Let’s add a method to this class that will work with the property we defined:
class say_hi { public $hello = 'Hi Roy'; public function hi_roy(){ echo $this->hello; } }
Inside of a class, the current instance is held in a special variable called $this. That’s why we had to use $this to access the property. Just like functions outside of classes, methods define their own scope. That is why we can have a variable, with the same name as a class property:
class say_hi { public $hello = 'Hi Roy'; public function hi_roy(){ return $this->hello; } public function hi_shawn(){ $hello = 'Hi Shawn'; return $hello; } }
Methods are also accessed using the special property $this. One thing to keep in mind is that you should never have a method with the same name as a class. In PHP4 and PHP5 this acted as a static constructor.
WP_Query
Now that we have the right terminology in place, we can move on to WP_Query.
WP_Query is WordPress’ posts API, we use it to get collections of posts, which we store in the $posts property of WP_Query, determine information about the post collection and loop through those collections.
If you’ve ever done any WordPress development, you’ve seen a standard WordPress posts loop like this:
if ( have_posts() ) { while ( have_posts() ) { the_post(); the_content(); } }
If you look inside of all of those functions — seriously you should, reading the source is important for mastering WordPress — you will see they are all using an object stored in the global variable $wp_query. Most of the standard “template tags” we use in WordPress are written this way.
The shortest explanation of what WordPress does, in the front-end, is it creates a WP_Query object, based on the current URL, and places it in the global variable $wp_query.
As a result, we could rewrite that loop like this:
global $wp_query; if ( $wp_query->have_posts() ) { while ( $wp_query->have_posts() ) { $wp_query->the_post(); echo apply_filters( 'the_content', $wp_query->post->post_content ); } }
While this is unnecessarily complicated versus the normal way of making a loop, this way makes it clear that what we are doing in the loop, is iterating through the posts — to be more specific the objects of the WP_Post class — stored in the posts property of the WP_Query instance stored in the global variable $wp_query.
This “main instance” of WP_Query, doesn’t have to be the only one. A recent posts or popular posts widget can exist on the same page, and will use a different instance of the WP_Query class to get and display those collections of posts.
Making Your Own
I said earlier that instances of classes are created using the new keyword. I also said that class instance can contain different data in their properties. That means that even though they have the same methods, those methods will behave differently since they are acting on different data.
Property values get set in one of two ways: internally by the object or by modifying the property externally. Most of the properties of WP_Query are public, so we could technically change them from outside of the object, but that’s not a great idea.
Normally with WP_Query, we pass it an array of arguments that define what posts it should query for, and that sets its properties internally. I’m not going to walk you through every parameter of WP_Query.
We can pass our array of arguments into the object when we instantiate. For example, to tell WP_Query to get 5 posts of the “my-product” post type, we could do this:
$args = [ 'post_type' => 'my-product', 'posts_per_page' => 5 ]; $query = new WP_Query( $args );
When we create an instance this way — passing arguments inside of two parentheses, we are passing those arguments to the class’ __construct() method. Constructors are a type of magic method, that is called when the class instantiated. These methods can accept any number of arguments, WP_Query’s constructor method takes one argument, but other classes take more.
WordPress As A Gateway To Object-Oriented Programming
WordPress may not be a totally object-oriented application, but we have classes for all of our content types that we use for finding and iterating through collections of posts, using WP_Query; users, via WP_User_query; taxonomy terms, using WP_Tax_Query and comments thanks to WP_Comment_Query.
I would encourage you to read through each of these classes — not the docs — the source code and make yourself more familiar with how they work, what properties they have and what methods you can use from them.
Understanding these basic query APIs will make your life as a WordPress developer easier. It will also help you learn how classes are designed.
No Comments