SOLID: Dependency Inversion with ACF

How to apply dependency inversion principle when using ACF plugin in your WordPress projects??

The Dependency inversion principle: "Depend upon abstractions, not concretions."

One of the biggest advantages of such approach is reducing impact of external providers to the core of your application which helps especially medium and large sizes WordPress websites. Why it might be important? Getting know with this article might get you more context.

Once we disable ACF plugin, the page (depends on your conctrete implementation) will still work fine. If you decide to switch ACF to another plugin, you jest need to write a new implementation. You won't need to touch any other files in your application.

#1 Contract

The first thing that we need to do is create a contract (abstration) that ensures that the application implements correct settings module. The contracts are one of the most important parts of business rules.

namespace App\Contracts;

interface Settings
{
    public function getField(string $name, int $id);
}

#2 Implementation

Implement controllers that will handle settings management in your application (concrete implementation).

namespace App\Integrations\WP;

use App\Contracts\Settings as ISettings;

class Settings implements ISettings
{
    public function getField(string $name, int $id)
    {
        return get_post_meta($id, $name, true);
    }
}
namespace App\Integrations\ACF;

use App\Contracts\Settings as ISettings;

class Settings implements ISettings
{
    public function getField(string $name, int $id)
    {
        return get_field($name, $id);
    }
}

If you have concerns that results for get_field and get_post_meta might return different results for the same field - you're right! ACF provides much more features as fields filtering what might cause different results, but it depends on you how it will behave. If you design data architecture focused on business rules, you'll be able to solve this problem.

#3 Initialize

Initialize the concrete implementations based on active plugins.

namespace App;

use App\Contracts\Settings;

class Facade
{
    private Settings $settings;

    public function __construct()
    {
        $plugins = apply_filters('active_plugins', get_option('active_plugins'));

        if (in_array('advanced-custom-fields-pro/acf.php', $plugins)) {
            $this->settings = new \App\Integrations\ACF\Settings();
        } else {
            $this->settings = new \App\Integrations\WP\Settings();
        }
    }

    public function settings(): Settings
    {
        return $this->settings;
    }
}

#4 Usage

Just use the settings facade.

printf(__('Post: %s', 'app'), app()->settings()->getField('title', 1));

Feedback

How satisfied you are after reading this article?