Want to learn object-oriented programmming? Get my free course

Using inheritance with WordPress

As a WordPress developer, you’re always looking for ways to better reuse your code between projects. Your time is valuable and you don’t want to reinvent the wheel each time you start a new project.

Object-oriented programming can help you with that. In a previous post, I covered why you should learn it. Now it’s time to take things further by going over the main feature for code reuse. You’ve probably heard about it before. It’s called “inheritance“.

Inheritance, what’s that?

Inheritance is about maximizing the code reuse between your classes. It allows you to create a hierarchy between your classes. That hierarchy creates a “is-a” relationship between your classes.

That’s why a lot of examples follow the formula:

  • class Car extends Vehicle (Car is a Vehicle)
  • class Dog extends Animal (Dog is an Animal)

They aren’t practical examples, but they highlight that relationship.

The take away from those examples is that you need to learn to see the relationship between your classes. Once that happens, you’ll be able to leverage inheritance to create reusable code for your projects.

Visibility revisited

When I covered encapsulation, I mentioned three possible access levels for properties and methods.

  • Public
  • Private
  • Protected

“Public” meant that anyone could access the property or method. Meanwhile, “Private” meant the opposite. You could only access it internally. It’s time to flesh out those definitions a bit more.

When using inheritance, defining a property or method as private restricts it to the class that defined it. Its children can’t access it. Meanwhile, protected grants access to the entire class hierarchy. This means that child classes can access it.

The inheritance toolkit

Before going ahead with a practical example, let’s go over some of the tools that you can use with inheritance. A good understanding of that toolkit will allow you to leverage inheritance to its full potential.

Interfaces

Interfaces are the most basic tool in your inventory. You should see an interface as a contract. By implementing an interface, your class agrees to implement specific methods. You can only define public methods in an interface.

By only offering a contract, you let others worry about the implementation. All that you care about is that the methods in your contract exist. Let’s look at a small example.

interface Post_Interface
{
    /**
     * Get the CSS class.
     *
     * @return string
     */
    public function get_class();

    /**
     * Get the post type.
     *
     * @return string
     */
    public function get_type();
}

The Post_Interface represents a small contract for WordPress posts. It has two methods: get_class and get_type. Any class that implements Post_Interface will need to have these methods.

Built-in PHP interfaces

PHP is full of useful interfaces that you can use to make your life easier. For example, Countable allows you to pass your object to the built-in count function.

class Posts implements Countable
{
    /**
     * @var Post_Interface[]
     */
    protected $posts;

    // ...

    public function count()
    {
        return count($this->posts);
    }
}

$posts = new Posts();

$num_posts = count($posts);

The Posts class above contains multiple instances of Post_Interface objects. Because Posts implements the Countable interface, we can pass Posts to the count function. This gives us an easy way to get the total number of  Post_Interface objects in Posts.

Interface inheritance

Interfaces can also inherit from other interfaces. That’s the case with the built-in interface Traversable. Traversable allows you to use your object in a foreach loop, but you can’t use it directly. You need to implement either Iterator or IteratorAggregate which are its child interfaces.

class Posts implements IteratorAggregate
{
    /**
     * @var array
     */
    protected $posts;

    // ...

    public function getIterator()
    {
        return new ArrayIterator($this->posts);
    }
}

$posts = new Posts();

foreach ($posts as $post) {
    // Do stuff
}

This example shows our Posts  class implementing the IteratorAggregate.  There’s just a small problem. We can’t have our getIterator return our posts array as is.

That’s because of the IteratorAggregate contract. It says that getIterator needs to return an object implementing a Traversable interface. Lucky for us, there’s a PHP class designed to turn an array into a Traversable object.

That’s why getIterator returns an instance of ArrayIterator. It’s a class that turns an array into Traversable object. Now, we can loop through the posts in our Posts class.

Implementing multiple interfaces

While a class can only have one parent class, it can implement as many interfaces as it wants. This is a powerful feature of interfaces. You can have a single class fulfill as many contracts as it wants.

class Posts implements Countable, IteratorAggregate
{
    /**
     * @var array
     */
    protected $posts;

    // ...

    public function count()
    {
        return count($this->posts);
    }

    public function getIterator()
    {
        return new ArrayIterator($this->posts);
    }
}

For example, our Posts class now implements both Countable and IteratorAggregate. This lets you pass a Posts object inside the count function and in a foreach loop. Both will work.

Abstract classes

Let’s say you want to reuse your code in your classes, but each class has just a tiny difference between how they behave. You could implement it partially, but the other classes would need to do the rest of the work. That’s what abstract classes do.

They partially implement the logic in a class, but leave some details for the child classes. Abstract methods are the methods that a child class needs to implement. They function the same way as a method defined in an interface. The one difference is that you can define an abstract method as protected.

You can view an abstract class as an interface where you already coded some of the logic. You should know that, because they are incomplete, you can’t instantiate abstract classes.

abstract class Abstract_Post implements Post_Interface
{
    /**
     * @var int
     */
    protected $id;

    /**
     * Get the CSS class.
     *
     * @return type
     */
    public function get_class()
    {
        return $this->get_type() . '-' . $this->id;
    }

    abstract public function get_type();
}

In the case of the Abstract_Post class shown above, we know some common details for all classes. Every post will have a post ID. It will also output its CSS class the same way.  get_class concatenates the post type and its ID together.

But we don’t know its post type yet. That’s why get_type uses the abstract keyword. It lets us use get_type in get_class without the need to code it. We’ll leave that to the concrete classes.

Concrete classes

Concrete classes are the classes that your code will end up using. They might implement one or more interfaces and/or extend an abstract class. The important thing is that you can instantiate these classes.

class Attachment extends Abstract_Post
{
    /**
     * Get the post type.
     *
     * @return string
     */
    public function get_type()
    {
        return 'attachment';
    }
}

$attachment = new Attachment();

$attachment->get_class();

Now, it’s time to code the get_type method. For our Attachment class, we make it return attachment. It’s the same value as the existing WordPress post type. Because we’ve completed our class, we can instantiate it and use it.

Overriding methods

Here is a scenario: You defined a method in your parent class. It works for 90% of the use cases, but not in that one child class. What can you do? Well, you can override the method!

You override a method by defining that method again in a child class. Doing so replaces the old one and allows you to add that custom logic you wanted.

class Video extends Attachment
{
    /**
     * Get the post type.
     *
     * @return string
     */
    public function get_type()
    {
        return 'video';
    }
}

In our Video class, we overrode our get_type method. Instead of returning attachment, it’ll return video.

The parent method is still available if you want to use it. All you need to do is use the parent keyword. This is useful when you only want to alter the output of the parent method.

class Picture extends Attachment
{
    /**
     * Get the post type.
     *
     * @return string
     */
    public function get_type()
    {
        return 'picture-' . parent::get_type();
    }
}

In this final example, the get_type method for the Picture class won’t return attachment. Instead, it’ll return picture-attachment. attachment comes from our call to parent::get_type().

Final keyword

There might be some cases where you don’t want others to extend your class or override your method. That’s where the final keyword comes in. It prevents someone from extending a class or overriding a method.

There’s rarely a case for a class to be final, but you might see final methods in some cases. You generally use a final method when the method is crucial to the functioning of a class. In that case, overriding the method might have dire consequences.

Making sure you get the right type of object

How can you make sure that you are receiving the correct type of object in your code? You don’t want errors because someone didn’t give you the correct object. Let’s look at two options available to you so you don’t get errors in your code.

Type hinting

Type hinting is a useful tool when using inheritance. It allows you to force a function or method to accept only a specific type as a parameter. This saves you the need to do the validation in your code. That said, receiving an invalid parameter will cause a fatal error in PHP.

/**
 * Save post to the database.
 *
 * @param WP_Post_Interface $post
 */
function save_post(WP_Post_Interface $post)
{
    // You are sure $post implements WP_Post_Interface
}

Validating in your code

You can also check the object type in your code as well. PHP has two ways for you to do it. You can use either the is_a function or the instanceof operator. This is how WordPress likes to do it since it allows for defensive coding. Using this form of validation prevents PHP fatal errors.

/**
 * Save post to the database.
 *
 * @param mixed $post
 */
function save_post($post)
{
    // You are not sure $post implements WP_Post_Interface
    
    if (!$post instanceof WP_Post_Interface) {
        return;
    }
    
    // You are sure $post implements WP_Post_Interface
}

The point of the above example is to show the before and after state within our save_post method. Before our instanceof check, our post variable could be anything. But after it, we’re sure that post implements WP_Post_Interface.

What should you check?

That’s the better question to ask. Is it the correct class or just an interface? While it’s up to you, using interfaces for validation allows for the most flexibility.

When you’re validating a class, you’re telling them how to interact with your code. You’re asserting more control over it as a result. They have to use your class or they can’t do anything.

Validating using an interface allows others to build what they want. You’re not forcing them to use your classes. You just want them to use the contract that you created.

A practical example with WP_Widget

WordPress widgets are an excellent showcase on how to use inheritance. There is a clear relationship between the WP_Widget class and all its children. That distinct relationship allows for a large amount of code reuse. You can see the impact of it by the small size of the child classes.

How it currently works

To develop your own custom widget, you need to extend the WP_Widget class and add your own logic. WordPress expects you to override the widget method. Otherwise, it will throw a fatal error.

class WP_Test_Widget extends WP_Widget
{
    public function widget($args, $instance)
    {
        echo 'test';
    }
}

You can find more information about making widgets in the codex.

Leveraging inheritance

As an exercise, let’s rewrite parts of the code to use inheritance. This should give you a good idea of how to use the tools described earlier.

Defining an interface

Let’s start by defining the interface WP_Widget_Interface. You want to create a baseline contract for all widgets in WordPress. By doing so, we establish which methods WordPress deems necessary for a widget class.

interface WP_Widget_Interface
{
    /**
     * Register the widget.
     */
    public function register();

    /**
     * Echo the widget content.
     *
     * @param array $args
     * @param array $instance
     */
    public function widget($args, $instance);
}

You’ll notice that the interface has only two methods. This isn’t a mistake. You want to limit the interface to required methods only. The only public methods that WordPress uses are register and widget. All other methods are internal.

It is worth noting that some methods need to be public due to the nature of the callback system. That said, they should not be part of the interface. WordPress does not need to be aware of them for you to fulfill your contract.

Taking a look at WP_Widget

Now that we have defined an interface for widgets, let’s take a better look at the WP_Widget class. Let’s rework it while maintaining the behaviour expected by WordPress.

Managing property and method visibility

WP_Widget uses only public methods and properties. The documentation defines private methods as methods meant for internal use. We’re going to rework the visibility of the methods and properties. That’s because we want them to follow encapsulation principles.

This means that only a few functions are public. There’s the register and widget methods. We defined those in the interface. Also, you have the three callback methods which should also be public.

All other methods are for internal use only. This means that you should define those methods as “protected”. This goes for the properties as well.

Using an abstract class

The WP_Widget class is an ideal candidate for an abstract class. WordPress expects each child object to implement its own widget method. By using an abstract class, we’re deferring the need to implement the method to the child class. No need to use a “die”!

Using the final keyword

WP_Widget documentation highlights methods that shouldn’t be overridden but leaves it at that. We’re going to use the final keyword to lock down those methods. We are, again, formalizing a behaviour that WordPress expects.

The result

You can see the result below. This isn’t an exact copy of all the methods. It highlights the changes discussed earlier.

abstract class Abstract_WP_Widget implements WP_Widget_Interface
{
    /**
     * @var array 
     */
    protected $widget_options;
    /**
     * @var string 
     */
    protected $id_base;
    /**
     * @var string 
     */
    protected $name;
    /**
     * @var array 
     */
    protected $control_options;
    /**
     * @var bool 
     */
    protected $number = false;
    /**
     * @var bool
     */
    protected $id = false;
    /**
     * @var bool 
     */
    protected $updated = false;

    /**
     * Constructor
     *
     * @param type $id_base
     * @param type $name
     * @param type $widget_options
     * @param type $control_options
     */
    public function __construct( $id_base, $name, $widget_options = array(), $control_options = array() )
    {
    }

    /**
     * {@inheritdoc}
     */
    final public function register()
    {
    }

    /**
     * Generate the actual widget content.
     */
    final public function display_callback($args, $widget_args = 1)
    {
    }

    /**
     * Generate the control form.
     */
    final public function form_callback($widget_args = 1)
    {
    }

    /**
     * Deal with changed settings.
     *
     * @param mixed $deprecated Not used.
     */
    final public function update_callback($deprecated = 1)
    {
    }

    /**
     * Echo the settings update form.
     *
     * @param array $instance Current settings
     */
    protected function form($instance)
    {
    }

    /**
     * Constructs name attributes for use in form() fields.
     *
     * @param string $field_name
     * 
     * @return string
     */
    protected function get_field_name($field_name) {
    }

    /**
     * Constructs id attributes for use in form() fields.
     *
     * @param string $field_name
     * 
     * @return string
     */
    protected function get_field_id($field_name) {
    }

    /**
     * Update a widget instance.
     *
     * @param array $new_instance
     * @param array $old_instance
     *
     * @return array
     */
    protected function update($new_instance, $old_instance)
    {
    }
}

Changing the validation in WordPress

We have a proper interface for widgets. We can make changes to the_widget function. Instead of validating based on the WP_Widget class, we will use the interface.

function the_widget($widget, $instance = array(), $args = array()) {
    global $wp_widget_factory;

    $widget_obj = $wp_widget_factory->widgets[$widget];
    if ( !is_a($widget_obj, 'WP_Widget_Interface') )
        return;
    
    // ...
    
    $widget_obj->widget($args, $instance);
}

Meanwhile, WP_Widget_Factory should also validate an object to see if it’s a WP_Widget. It doesn’t. That’s a bug I submitted to Trac. Here is a possible way we could handle it.

class WP_Widget_Factory {
    var $widgets = array();

    function register($widget_class) {
        $widget_obj = new $widget_class();

        if ( !is_a($widget_obj, 'WP_Widget_Interface') )
            return;

        $this->widgets[$widget_class] = $widget_obj;
    }

    // ...
}

It comes down to practice

Inheritance is one of the most powerful features of object-oriented programming. The amount of time you save with the code reuse is incredible.

That said, it can also be the hardest thing to grasp for newcomers. Being able to see the relationship between your classes takes time and practice. So keep at it!

Creative Commons License