# Welcome

The Deep Web Solutions WordPress Framework, from now on referred to as the DWS WP Framework, is a web development PHP framework for building [WordPress plugins](https://developer.wordpress.org/plugins/intro/what-is-a-plugin/). It powers all the official [DWS Plugins](https://www.deep-web-solutions.com/plugins/).

This documentation was written primarily for developers. It is advisable to be at least somewhat familiar with the [concepts and tools](/key-concepts-and-dev-tools) mentioned in the document, but if you're not, reading through the articles here should give you a basic introduction and links to further reading material. If you're looking for the user documentation of our plugins, go [here](https://docs.deep-web-solutions.com/).

While the code tries to be as self-documenting as possible and the test plugins bundled with each module provide some usage examples too, this document should help provide a more human-friendly introduction into working with the framework effectively. It is written both for internal training use and for external developers, hence why some information might be slightly extraneous or opinionated.

To learn more about the motivation and history behind building this framework, please refer to this [knowledge base article](https://docs.deep-web-solutions.com/knowledge-base/short-history-of-our-framework/).


# Primary goals

The development of our framework started in April 2020 (read more about [its history](https://docs.deep-web-solutions.com/knowledge-base/short-history-of-our-framework/)) and had primarily 3 goals:

1. [Central yet modular design](/primary-goals/modular-design) -- the whole point of the framework is to have one central codebase for abstractions and functionalities that are reusable across multiple plugins; however, different plugins have different overlapping needs and we didn't want to force you to load code that will be unused.
2. [Modern development standards](/key-concepts-and-dev-tools) -- this framework was meant to fully embrace all the best practices of modern web development; the key concepts and dev tools section provides an introduction into each of them.
3. [Dependencies-free](/primary-goals/no-3rd-party-dependencies) -- the framework should enable anyone to build WordPress plugins using modern tools, but it shouldn't force you to use any 3rd-party libraries you don't want to in production; wherever possible, the framework doesn't assume anything more than whatever [the PSR standards](https://www.php-fig.org/psr/) foresee.

Obviously, programming is a very opinionated field. We might believe that we've achieved these goals, but you might disagree completely. And that's fine!&#x20;

If you like our framework and want to use it yourself, [you may do so](https://packagist.org/packages/deep-web-solutions/) (keeping in mind the GPLv3+ license). If you don't like it, that's awesome too -- but we would really appreciate any feedback you may have just in case there's something that didn't cross our minds yet.


# Modular design

The DWS WP Framework has a modular design and thus consists of multiple so-called modules. Currently, there's 7 different modules that more-or-less build on top of each other. In relative order, they are:

1. [Bootstrapper Module](https://packagist.org/packages/deep-web-solutions/wp-framework-bootstrapper) -- validates that appropriate versions of PHP and WordPress are running or displays a user-friendly error if not.
2. [Helpers Module](https://packagist.org/packages/deep-web-solutions/wp-framework-helpers) -- a collection of small, helpful, static snippets that can be reused across various projects.
3. [Foundations Module](https://packagist.org/packages/deep-web-solutions/wp-framework-foundations) -- a collection of abstractions useful for building semantically-rich plugins; technically, simple plugins can already be built at this level.
4. [Utilities Module](https://packagist.org/packages/deep-web-solutions/wp-framework-utilities) -- a collection of services for working with template files, value validation, admin notices, dependencies, hooks etc.
5. [Core Module](https://packagist.org/packages/deep-web-solutions/wp-framework-core) -- an opinionated collection of abstractions for building plugins; relies on the abstractions defined by the Foundations Module and some services from the Utilities Module but its usage is optional.
6. [Settings Module](https://packagist.org/packages/deep-web-solutions/wp-framework-settings) -- provides a unified way for interacting with various settings APIs like [ACF](https://www.advancedcustomfields.com/), [MetaBox](https://metabox.io/), and [WordPress](https://codex.wordpress.org/Settings_API) itself.
7. [WooCommerce Module](https://packagist.org/packages/deep-web-solutions/wp-framework-woocommerce) -- a bridge between the DWS Framework and the WooCommerce API.

The reasoning is simple. If you're building a plugin that's meant to be an extension for [WooCommerce](https://woocommerce.com/), then you probably want to include the WooCommerce module. If not, why would you want that code in your plugin? Similarly, you might want a very simple plugin that doesn't require any settings, so no settings module either. And so on...


# No 3rd-party dependencies

The framework itself doesn't have any 3rd-party dependencies. Our [plugins](https://www.deep-web-solutions.com/plugins/) do -- but we don't force you to use the same libraries we do.

For example, we are strong advocates for [Dependency Injection](/key-concepts-and-dev-tools/dependency-injection-php-di) and we really like [PHP-DI](https://php-di.org/), but you are free to build your plugins using either no dependency injection at all or using a different container. Whenever the framework references dependency injection, it simply assumes that it's been passed on a [PSR-11](https://www.php-fig.org/psr/psr-11/)-compatible container (which should be most, if not all, popular containers) **and it always provides a fallback** in case no container is used at all.

That being said, the framework does have internal dependencies. It is possible to build a plugin using only the [Bootstrapper Module](https://packagist.org/packages/deep-web-solutions/wp-framework-bootstrapper). If you need the [Helpers Module](https://packagist.org/packages/deep-web-solutions/wp-framework-helpers), it will auto-install the Bootstrapper Module as well when using [Composer](/key-concepts-and-dev-tools/dependency-management-composer) since that is listed as a dependency. Similarly, the [Foundations Module](https://packagist.org/packages/deep-web-solutions/wp-framework-foundations) depends on both the Bootstrapper and the Helpers modules, and so on.

There is an exception though. The [Settings Module](https://packagist.org/packages/deep-web-solutions/wp-framework-settings) does **NOT** depend on the [Core Module](https://packagist.org/packages/deep-web-solutions/wp-framework-core) as it is technically an extension to the [Utilities Module](https://packagist.org/packages/deep-web-solutions/wp-framework-utilities). As the [WooCommerce Module](https://packagist.org/packages/deep-web-solutions/wp-framework-woocommerce) depends on the Settings one, it doesn't require the Core module either.


# Key concepts and dev tools

Modern development standards was one of the primary goals of the DWS WP Framework. It is meant to fully embrace all the best practices and tools of modern web development.

In this section, we try to offer an introduction into a few key concepts and development tools that you'll need in order to work effectively with the framework. A basic understanding of PHP and WordPress is assumed.


# PHP and WP requirements

The DWS WP Framework won't run unless the minimum PHP and WP requirements are met. Those were set pretty step, we admit, but there were good reasons that we argue for below.

{% tabs %}
{% tab title="PHP7.4+" %}
This was a bit of a controversial choice as we started. PHP7.4 was still relatively new, and we didn’t know it would take over a year to release the first stable version. Even as of the writing of this article (April 2021), PHP7.4 powers “only” 26.5% of all WordPress installations according to the official [WordPress statistics](https://wordpress.org/about/stats/).

As a rule of thumb, one usually wants to support over 50% of PHP and WordPress versions actively used out there. That would mean that we should currently also support PHP7.3, or even better, PHP7.2 in order to support over 70% of all installations.

However, we decided against it. Right now, PHP7.3 is in [EOL](https://www.php.net/supported-versions.php) and support for PHP7.2 has been discontinued. As time passes, more-and-more installations will migrate to PHP7.4, and 25%+ is also not a bad share!

Moreover, PHP7.4 comes with a few [new features](https://stitcher.io/blog/new-in-php-74) that are just awesome for writing high-quality code, like typed class properties. It also introduced some deprecations and changed the concatenation precedence, so writing code that’s PHP7.4-conform will make it easier to upgrade in the future.

Last but not least, as the last version of PHP7 (since PHP8 got released in November 2020), it’s the version that most people are likely to stick with in the coming years similarly to how many people are somehow still “stuck” on PHP5.6 (last version before PHP7.0).

In short, it proves to be a slight disadvantage right now, but within 6-12 months (Q1-Q2 2022), that will disappear. And the advantages it brings are considerable, in our opinion.
{% endtab %}

{% tab title="WP5.5+" %}
Similarly to the PHP version, choosing the minimum WP version to support is again tricky. One the one hand, we do want to support as many users as possible, but it’s simply not wise to support very old WP versions.

We used again the [WP statistics ](https://wordpress.org/about/stats/)page and decided to support a minimum of WP5.5. As of April 2021, that means over 57% of all active WordPress installations which easily follows our rule of thumb, i.e. more than 50%. As time moves on, that share will again only increase.

Picking WP5.5 also has some practical implications. WordPress 5.5 deprecated jQuery 1.12 and shipped the first really mature version of the Gutenberg builder, in our opinion. Also, it introduced a native way of passing on arguments to templates which was a very nice feature.
{% endtab %}
{% endtabs %}


# Object-Oriented Programming

The DWS WP Framework is fully OOP. Support for OOP hasn’t been historically great in PHP, but it’s remarkably good in PHP7 in general and PHP7.4 in particular. And it only gets better in PHP8!

That means that most logic is encapsulated in ([namespaced](https://www.php.net/manual/en/language.namespaces.php)) classes. There is a long debate to be had about OOP vs non-OOP, but we believe that WordPress plugins are great candidates for an OOP design.

To make things predictable (and standardized), the namespace-structure follows the PSR-4 standard. You can read more about that [here](https://www.php-fig.org/psr/psr-4/) but it’s basically a convention that enforces the following things:

* One class -- one PHP file.
* The namespace structure follows the folder structure of the filesystem.
* Each namespace is of the form:

```
\<ProjectNamespace>(\<SubNamespaceNames>)*\<ClassName>
```

For example, let’s assume that:

* your project namespace is *SomeCompany\Plugins\SomePlugin*
* all your PHP files are in the *includes* folder

Then the class *SomeCompany\Plugins\SomePlugin\Admin\Settings* will be in the file *includes/Admin/Settings.php*.


# Semantic Versioning

The concept of [semantic versioning](https://semver.org/), or SemVer for short, is simple — developers should be able to tell at a glance whether an update is likely to cause problems or not. We promise to make releases in a manner that is compatible with SemVer. In a nutshell:

* All releases of the form A.\*.\* will be compatible with each other. Version B.\*.\* is guaranteed to break everything.
* All releases of the form A.B.\* are simple bug-fixes. It should be a no-brainer to update from A.B.C to A.B.D, no matter what C and D are, and we guarantee as much as humanely possible that everything will keep working.
* All updates from A.B.\* to A.C.\* contain new features, but as much as humanely possible, won’t break any existing functionality.

As a rule of thumb, updates are by definition risky and you should always test them in a staging environment first. But using SemVer, we try our best to offer you bite-sized updates that explain the differences between them at a glance.


# Version Control (git / GitHub)

Version control is an absolute must for any software project, especially if more than one developer is involved or the project is more complex than an afternoon of work.

The DWS WP Framework is using the popular [git source control system](https://git-scm.com/) and all the source code (and its history) is open [on GitHub](https://github.com/deep-web-solutions).


# Dependency Management (Composer)

In short, [Composer ](https://getcomposer.org/)is a dependency manager for PHP. If you’ve worked with npm for NodeJS, Maven for Java or NuGet for C#, the principle should be familiar. Basically, Composer lets us define a *composer.json* file in our project root which contains a list of dependencies for the project. Using commands such as *composer install* we can then automagically add those dependencies to our project.

By default, Composer pulls the dependencies from [Packagist ](https://packagist.org/)which is also where you can find the [open-source modules](https://packagist.org/packages/deep-web-solutions/) of our framework. You can also define your own package sources, such as GitHub or a private packages repository. You can read more about how that works and how a composer.json file looks like by reading [this article](https://getcomposer.org/doc/02-libraries.md) of the official documentation.

Composer also has another ground-breaking advantage — it generates an autoloader for your project. You probably know this already, but in PHP you need to call *include* or *require* before using the contents of a file. It can become tedious (and it’s definitely error-prone) to do that for all the files in your project, especially as your plugin grows. Moreover, if you want to only load classes conditionally, that becomes a nightmare!

An [autoloader ](https://www.php.net/manual/en/language.oop5.autoload.php)lets you define a function that loads PHP files containing classes only when the class is used. That basically guarantees the conditional loading. Moreover, the Composer autoloader also supports loading simple files containing plain PHP functions (albeit non-conditionally).

{% hint style="info" %}
By using the PSR-4 autoloading standard for our project structure and Composer for loading dependencies and generating an autoloader, it’s **virtually impossible** to cause a “function/class does not exist” runtime error in production!
{% endhint %}

&#x20;[Here is an example](https://github.com/deep-web-solutions/wordpress-framework-bootstrapper/blob/master/composer.json) of a *composer.json* file that is actually used by the first module of the framework, the Bootstrapper. The relevant entries are “autoload” and “autoload-dev”. The autoloader is then the only file that we need to *require* as one of the first things the module does in [*bootstrap.php*](https://github.com/deep-web-solutions/wordpress-framework-bootstrapper/blob/master/bootstrap.php).


# Automated Testing (Codeception + Github Actions)

Testing is the only way to find bugs. And bugs are bad. It’s pretty much guaranteed there will always be bugs in any project, but there are ways to make sure that the number of bugs are minimized. One of those ways is automated testing like [unit](https://en.wikipedia.org/wiki/Unit_testing), [integration](https://en.wikipedia.org/wiki/Integration_testing), [functional](https://en.wikipedia.org/wiki/Functional_testing), and [acceptance ](https://en.wikipedia.org/wiki/Acceptance_testing)testing.

All DWS WordPress Framework modules use [Codeception ](https://codeception.com/)for writing and running automated tests. Codeception is a framework for writing PHP tests, not WordPress tests specifically. For that reason, it natively doesn’t support integration tests (which in the context of WordPress Plugins are tests for running the code within WordPress). To use Codeception effectively, we’re using the [WP-Browser](https://wpbrowser.wptestkit.dev/) package (all of this should be obvious by looking at the *dev-dependencies* specified in the *composer.json* files).

There are basically 4 levels of tests (mentioned in the paragraph above). A good breakdown of what each test stands for is [offered by WP-Browser](https://wpbrowser.wptestkit.dev/levels-of-testing).

{% hint style="info" %}
Not all levels of testing make sense for all modules. For example, acceptance tests make sense for the [Bootstrapper Module](https://packagist.org/packages/deep-web-solutions/wp-framework-bootstrapper), while acceptance tests alone make no sense for the [Helpers Module](https://packagist.org/packages/deep-web-solutions/wp-framework-helpers).
{% endhint %}

Writing good automated tests ensures that our code works as intended and that we don’t accidentally break anything while releasing a new version. It is obviously a rinse-and-repeat process and the tests themselves can be flawed since we are also humans ergo intrinsically flawed, but at the very least, it should let us avoid silly mistakes and most regression bugs.

### Test across different environments

If automated tests pass during development, that simply means that everything is good on the PHP version and WP version that the developer is using to run the tests against. That’s great, but it still doesn’t mean it will work everywhere else (for example, you might be running PHP8 and all tests pass but you still aren’t sure that they pass on PHP7.4 which is our minimum guarantee).

For that we use [Github Actions](https://github.com/features/actions). Theye allows us to run all of our tests across different versions of PHP and WordPress by setting up virtual machines to our specifications and … running the tests again in each one.

{% hint style="info" %}
A new version is never released unless ***all*** automated tests pass in all relevant environments!
{% endhint %}


# Dependency Injection (PHP-DI)

Automated testing is great, but whether it’s easy to write or not depends on your code design. As a rule of thumb, the more loosely coupled your classes are, the easier they are to test. And one can’t talk about loosely coupled classes and not mention [dependency injection](https://en.wikipedia.org/wiki/Dependency_injection).

One simple example should clarify how it works. Imagine a class that encountered an error and wants to log it. Let’s also assume you’re using [Monolog ](https://packagist.org/packages/monolog/monolog)to create loggers that handle these events. Without dependency injection, whenever the class encounters an error it must now instantiate a logger and use it. If you have 50 classes that use loggers, you would write the code for instantiating a logger 50 times in 50 places (well, you’d probably write a function somewhere to simply retrieve an instantiated logger and that too would be a sort of dependency injection, in a nutshell).

With dependency injection, you would create a logger at some point in time and then simply pass it along to each class that can log errors (traditionally, in the constructor or through a method like `set_logger`). That way your classes don’t actually know what a logger is or how it works or how to get one — they simply get one passed along.

Normally you wouldn’t even bind yourself to any specific logger but you would use an interface. Luckily, for loggers, there already exists the [PSR-3](https://www.php-fig.org/psr/psr-3/) standard (which Monolog also implements). So your classes simply expect a PSR-3 `LoggerInterface` object passed on in the constructor.

When you write automatic tests for your classes, you don’t need to actually load Monolog too! You can just pass on any PSR-3 implementing class, or just use [Mockery ](https://github.com/mockery/mockery)to create one on the fly.

Dependency injection containers usually provide an array of features that are much more powerful than just that (e.g., auto-wiring or on-the-fly instantiation). For our projects, we use [PHP-DI](https://php-di.org/) but this is not actually a requirement for using our framework. The framework accepts any [PSR-11](https://www.php-fig.org/psr/psr-11/)-compatible container and only assumes the features that PSR-11 foresees.


# Coding Standards (PHPCS and PHPMD)

Automated testing doesn’t mean just functionality — code quality and looks are important too! WordPress coding standards are enforced using the popular [PHP CodeSniffer](https://github.com/squizlabs/PHP_CodeSniffer) tool and code quality is being continuously checked using the [PHP Mess Detector](https://phpmd.org/) rules. The custom rules used by DWS are present in the *phpcs.xml.dist* and *phpmd.xml.dist* files in each public project on [GitHub](https://github.com/deep-web-solutions/).

Basically, this ensures that a few WordPress-specific errors can never occur as long as the tests pass. Here are some examples:

* All output is ran through an escaping function.
* All user input is ran through a sanitization function.
* All translatable strings use the same language domain.
* All global functions/variables/classes are prefixed properly.


# Dependencies Scoping (PHP-Scoper)

Some more advanced PHP developers have probably already thought about the issue of class collision. In every programming language that we are aware of, you can only declare classes and global functions with unique names. The name of the class prefixed by its namespace (or, more accurately, the namespace is the prefix of the class name).

So, for example, if two plugins that use our framework are installed on the same WordPress site, the site should theoretically crash because now you have our framework being loaded twice and that causes name conflict runtime errors. And that’s bad … very, very bad!

Another cool thing about [Composer ](/key-concepts-and-dev-tools/dependency-management-composer)is that the autoloader only loads a file once, even if present in multiple autoloaders. So technically, as long as both plugins are using Composer to autoload the DWS Framework, that particular error can’t happen.

But there still is the issue of running different versions of the framework. Plugin A might rely on version 1.1 of a module, whereas Plugin B might rely on version 1.2 of the same module. In our example, only the files of Plugin A will be autoloaded (since it comes alphabetically before Plugin B and that’s how WordPress loads its plugins by default) and thus Plugin B will probably throw an error at some point. Again, that’s bad.

One popular strategy to solve this issue is to use a so-called *Loader* that waits for all the plugins that use a given framework and then decided to only load the newest version. Well, that’s nice, but what if Plugin A needs version 1 and Plugin B needs version 2? By the logic of [Semantic Versioning](/key-concepts-and-dev-tools/semantic-versioning), Plugin A is now pretty much guaranteed to throw an error. Not good enough.

Another popular strategy is to include the framework version in the namespace of the classes. That way, both the DWS Framework of Plugin A and the DWS Framework of Plugin B will be autoloaded. This solves both issues actually! But it’s a bit of a drain to have to update all the references to the framework classes after every update … there probably is a way to automate that, but we’re still not fans of the namespacing structure.

So we decided to use [PHP-Scoper](https://github.com/humbug/php-scoper) to prefix all of our dependencies with a plugin-specific prefix. That means the following:

* Each of our plugins is bundled with the exact DWS Framework modules that it has been tested with. It will never break because another plugin was installed.
* The namespaces (and thus class names) stay stable after every update. Less error potential from our side!
* We can use the same strategy to prefix 3rd-party dependencies too to avoid issues like [WP-Rocket encountered in August 2020](https://github.com/wp-media/wp-rocket/issues/3003) when WooCommerce started using a newer version of the same [dependency injection](/key-concepts-and-dev-tools/dependency-injection-php-di) container.


# TypeScript and Sass

Web development without JavaScript and CSS can hardly be called web development. As for modern web development, the tools of choice are [TypeScript ](https://www.typescriptlang.org/)and [Sass](https://sass-lang.com/).

Both are more-or-less syntactic sugar around JavaScript and CSS, respectively, but they go a long way in ensuring that the code is easier to read and maintain.

While not strictly part of the DWS WP Framework, the example plugin used on [the respective tutorial page](/your-first-plugin) comes with a pre-configured setup for compiling TS and SCSS files into JS and CSS files, respectively, using [Grunt tasks](/key-concepts-and-dev-tools/task-runners-grunt) (together with a few other post-optimizations).

Using TypeScript and Sass is **not** part of this documentation, but they are mentioned since we strongly recommend using them in any modern project to minimize bugs and increase developer satisfaction.


# Task Runners (Grunt)

Similarly to how [Composer](/key-concepts-and-dev-tools/dependency-management-composer) supports [scripts](https://getcomposer.org/doc/articles/scripts.md) to create shortcuts or outright automations for different tasks, something similar can be done within the [npm ecosystem](https://www.npmjs.com/). Specifically, we are talking about task runners like [Grunt ](https://gruntjs.com/)and [Gulp](https://gulpjs.com/).

The DWS WP Framework uses Grunt to automate certain tasks. For example, some modules [use Grunt tasks](https://github.com/deep-web-solutions/wordpress-framework-bootstrapper/blob/master/Gruntfile.js) to automatically generate the POT file by scanning the code for translatable strings.

The example plugin [has Grunt tasks](https://github.com/deep-web-solutions/wordpress-plugins-utility/blob/master/Gruntfile.js) pre-written for compiling [TypeScript and Sass](/key-concepts-and-dev-tools/typescript-and-sass) assets and performing other post-optimizations to the compiled files. All of this is powered by [npm packages](https://www.npmjs.com/) listed in [the `packages.json` file](https://github.com/deep-web-solutions/wordpress-plugins-utility/blob/master/package.json) together with the configuration written in the project's [Gruntfile](https://github.com/deep-web-solutions/wordpress-plugins-utility/blob/master/Gruntfile.js).

Most of these tasks can also be handled by Composer scripts, but npm provides some easy-to-use packages that were built out for these tasks. It just makes more sense to use JavaScript instead of PHP.

The purpose of this documentation is **not** to teach you how to use task runners, but we strongly encourage you learn how to use them. It's pretty simple really and they can automate some pretty difficult tasks.


# Setting up your dev environment

If you haven't used these development tools before, it can be a little bit of a hassle to set them up for the first time. The articles in this section should help you get started with setting up all the used dev tools on your machine!

We have articles prepared for the following operating systems:

* [Windows](/setting-up-your-dev-environment/windows)


# Windows

This article will try to help you set up a development environment on your Windows machine. The assumption will be that you are trying to either contribute to the framework or build a plugin using it (and thus following all the standards laid out by the framework).

There is no guarantee that this will work. We can't account for software conflicts or misconfigurations present on your machine, but this should point you at least in the right direction.

### Development folder

You're obviously free to organize your project files however you want, but we have a few suggestions that have worked well for us (since you're on Windows, especially). Namely, in your [home directory](https://askubuntu.com/a/1180130), create a new folder called *Source*. We also [change its icon](https://www.makeuseof.com/tag/customize-icon-windows/) to this for easy recognition (place the icon file inside the folder):

{% file src="/files/-MXl5a9jjw3yrGhC5CaG" %}
Source folder icon
{% endfile %}

Inside the *Source* folder, we usually create 3 new ones: *Tools, Framework,* and *Plugins*. Of course, your choice may vary based on what you want to do.

### Linux Subsystem for Windows

Although we're running on Windows, the Linux Subsystem for Windows (WSL for short) is what we'll be using to install most software. If you are already familiar with the Linux command line, this should all feel pretty familiar.

Microsoft has a great article already explaining how to enable WSL and how to install your distribution of choice. In the spirit of not reinventing the wheel, just follow the steps [from here](https://docs.microsoft.com/en-us/windows/wsl/install-win10). We recommend using WSL 2 and installing the [Ubuntu 20.04 LTS](https://www.microsoft.com/store/apps/9n6svws3rx71) distribution once you reach that step, but any distribution should do.

The article also mentions that you can optionally install [Windows Terminal](https://docs.microsoft.com/en-us/windows/terminal/get-started) to run PowerShell and WSL side-by-side. You don't have to, but we find it handy especially when using VVV for testing.

### Install DevKinsta

For [automated testing](/key-concepts-and-dev-tools/automated-testing-codeception-+-travis-ci), you will need a running web server. For this task, we highly recommend [DevKinsta](https://kinsta.com/devkinsta/) although any tool like [Local by Flywheel](https://localwp.com/), [VVV](https://varyingvagrantvagrants.org/) or even plain old [WAMP](https://www.wampserver.com/en/) will do. If you move forward with VVV and followed our dev folder structure from above, VVV would belong into the *Tools* folder.

DevKinsta has a great guide on how to install it [right here](https://kinsta.com/knowledgebase/devkinsta/installation/). Due to the virtualization nature of WSL2, your local environment is likely to be rather slow. Currently there is no known workaround and while it is annoying, it's usually fast enough for most purposes.

Each module's `tests` folder contains an extra `README.md` file explaining how to set it all up to run tests on your local machine. WP-Browser also has some useful tutorials (albeit you need to selectively pick what applies) [for VVV](https://wpbrowser.wptestkit.dev/tutorials/vvv-setup), [for WAMP](https://wpbrowser.wptestkit.dev/tutorials/wamp-setup), and [for Local by Flywheel](https://wpbrowser.wptestkit.dev/tutorials/local-flywheel-setup).

{% hint style="info" %}
Unless explicitly mentioned otherwise, all the steps outlined below should be performed in your WSL terminal.
{% endhint %}

### Install PHP7.4

While not strictly required to use 7.4, it is best to use a still supported version. If you followed our recommendation and installed Ubuntu, [here](https://computingforgeeks.com/how-to-install-php-on-ubuntu/) is an article explaining how to install PHP. If you installed a different distribution, at the bottom of the article you will find links to instructions for other systems.

Since we will **not** be using WSL as a server, you don't need to follow the instructions about setting up nginx or PHP-FPM. Vanilla PHP7.4 will do.

### Install Composer and Node.js

As **the** PHP dependency manager, you will need to install Composer on your WSL. [Here is an article](https://www.digitalocean.com/community/tutorials/how-to-install-and-use-composer-on-ubuntu-20-04) explaining how to install Composer on Ubuntu 20.04 together with links to other versions and distributions. The article show the installation of Composer 1.10, but you'll likely end up with Composer 2. That is fine and even recommended. If not, run `composer self-update` after the installation.

Optionally, you can go ahead and install Node.js and its companion dependency manager, npm. An article describing this procedure for Ubuntu 20.04 is [here](https://www.digitalocean.com/community/tutorials/how-to-install-node-js-on-ubuntu-20-04). Node.js and npm are not *strictly* necessary for using the framework, but they do enable the use of [task runners](/key-concepts-and-dev-tools/task-runners-grunt) and thus easy compilation of [TypeScript and Sass](/key-concepts-and-dev-tools/typescript-and-sass) code and other automatable tasks. If you're doing that some other way already (or don't need/want that at all), feel free to skip this step.

### Install Git

For [version control](/key-concepts-and-dev-tools/version-control-git-github), we use git. Hence it is a good idea to install it on your WSL distribution. [Here is an article](https://www.digitalocean.com/community/tutorials/how-to-install-git-on-ubuntu-20-04) describing to how to that on Ubuntu 20.04.

However, the git command line is notoriously complicated. We strongly recommend you use a GUI instead, like [GitKraken ](https://www.gitkraken.com/)(which is available for Windows, MacOS, and Linux -- in this case, you should download the Windows version for your main OS). It's a good idea to install git on WSL regardless though, just in case you'll need it at some point.

### Convenience stuff

You can choose to edit your [.bashrc](https://www.journaldev.com/41479/bashrc-file-in-linux) file to include the following commands:

```bash
# go to the Source folder on startup
cd /mnt/c/Users/<YOUR WINDOWS USER NAME>/Source

# store the Windows host IP
export WINDOWS_HOST_IP=`cat /etc/resolv.conf | grep nameserver | cut -d ' ' -f 2`
```

### You're done!

Congratulations! Your dev environment is set up. It's time to open up your favorite IDE (we recommend [PhpStorm](https://www.jetbrains.com/phpstorm/)) and try out all your fancy new tools by setting up [your first plugin](/your-first-plugin) project!


# Your first plugin

As mentioned on the [modular design page](/primary-goals/modular-design), using our framework usually makes sense when you use at least the first 3 modules (Bootstrapper, Helpers, and Foundations). Those are as general as we can humanly think of and they try to set literally no expectations on your project while simultaneously offering you all the abstractions you need (in the form of Interfaces, Traits, and Abstract Classes) to build your plugin the way you see fit.

&#x20;If you only use only these 3 modules, there is a good chance there will be some unused files, but that shouldn't have any performance impact if you use the [Composer autoloader](/key-concepts-and-dev-tools/dependency-management-composer) (which for the rest of this documentation, we will definitely assume that you are).

{% hint style="info" %}
If you haven't already, check out our dedicated section for [setting up a development environment](/setting-up-your-dev-environment) on your machine.
{% endhint %}

There is an [example plugin](https://github.com/deep-web-solutions/wordpress-plugins-utility) on GitHub that only uses the first 5 modules. It's meant as a sort-of starter project for adding custom code to client websites (basically a replacement for the classical `functions.php`), but it can be easily used as a starter plugin as well.

We recommend that you download this plugin and use it as your starting base. This is a checklist of things you probably want to do after downloading the example plugin:

1. Rename the folder from `wordpress-plugins-utility` to the slug of your plugin.
2. Do a search for `DWS WordPress Utility Plugin` and replace it with your plugin's name.
3. Similarly, make sure to update the plugin header in `bootstrap.php` and `README.md` and optionally change the minimum PHP and WP versions.
4. Change the Deep Web Solutions references in `composer.json` and `package.json`.
5. Update the `composer.json` file to reflect the modules you really want to use. By default, the example plugin also installs `php-di/php-di` for [dependency injection](/key-concepts-and-dev-tools/dependency-injection-php-di) and `monolog/monolog` for logging but you are free to use your preferred packages.
6. Do a search for `DWS_Deps` and replace it with a unique name for your plugin. For example, we're using `DWS_LPM_Deps` for our [Locked Payment Methods plugin](https://www.deep-web-solutions.com/plugins/locked-payment-methods-for-woocommerce/).
7. Run `composer update --ignore-platform-reqs` and `npm update` in the plugin directory.

Congratulations! You are now ready to use start building a WordPress plugin using the DWS Framework. Continue reading the documentation of each module in order to understand how to use the framework effectively.


# Multiple plugins using the framework on the same site

The keen observer might have noticed already that the `composer.json` file of the example plugin is somewhat different from that of the framework modules.

An advanced user might've already looked over the framework files and thought about issues like namespace collisions across different versions of the framework when multiple plugins are using it on the same WordPress site.

We explained this problem (and our solution) in our [dependency scoping introduction](/key-concepts-and-dev-tools/dependencies-scoping-php-scoper). In a nutshell, this is how what you need to do for this to *not* be a problem:

* The plugin dependencies go in the `require-dev` block instead of the `require` block.
* The package `deep-web-solutions/wordpress-configs` is required too.
* The `autoload` block must also contain the autoload configuration of all dependencies **but** prefixed with your plugin's unique scoping prefix. In the example plugin, that's `DWS_Deps`. The autoload configuration of a package can be found in its own `composer.json` file.
* Include a `prefix-dependencies` entry in your *scripts* block. This entry should contain calls to the [PHP-Scoper](https://github.com/humbug/php-scoper) binary file. The example plugin [contains examples](https://github.com/deep-web-solutions/wordpress-plugins-utility/blob/master/composer.json) for the DWS Framework, PHP-DI, and Monolog.
* Include `DeepWebSolutions\\Config\\Composer\\PrefixDependencies::postAutoloadDump` in the `post-autoload-dump` scripts command event. You can read more about Composer Scripts [here](https://getcomposer.org/doc/articles/scripts.md).

Basically, this will automagically do the following stuff every time you regenerate the Composer autoloader (usually on *install* and *update* commands):

* The static `PrefixDependencies::postAutoloadDump` method will be called from the `deep-web-solutions/wordpress-configs` package.
* That method will first make sure that Composer is running in dev mode, and if so, tries to ensure that things will run smoothly and calls the `prefix-dependencies` script.
* Using the pre-built configurations files for PHP-Scoper found in the `deep-web-solutions/wordpress-configs` package (or your custom config files), it will regenerate prefixed versions of your dependency files. Currently there are config files readily available for the [DWS Framework](https://packagist.org/packages/deep-web-solutions/), for [PHP-DI](https://packagist.org/packages/php-di/php-di), and for [Monolog](https://packagist.org/packages/monolog/monolog).

There is a bit more to it (specifically for compatibility with scoping a *WordPress* framework), but that's the gist of it. If you're interested in the whole nitty-gritty, check the files in the [wordpress-configs](https://github.com/deep-web-solutions/wordpress-configs) package.

{% hint style="info" %}
Run `composer install --no-dev` to remove all the development dependencies from the `vendor` folder and your plugin is basically ready to be installed on a WordPress site.
{% endhint %}

{% hint style="info" %}
If you're using some server upload deployment strategy (like automatic upload on save, provided by PhpStorm), simply exclude the `vendor` folder from upload and run the aforementioned Composer command on your server to generate the autoloader.
{% endhint %}


# Frequently Asked Questions

### Why do all the modules put their bootstrapping functions in a separate file?

If you've looked [over the code](https://github.com/deep-web-solutions/) of the DWS WP Framework modules, you probably noticed that all of them have a `bootstrap.php` file that's autoloaded by [Composer](/key-concepts-and-dev-tools/dependency-management-composer) and a separate `bootstrap-functions.php` file that's included among the very first things. The functions defined in that file are usually just getters for constants defined in the `bootstrap.php` file, so why not define the getters in the same file?

That was the original design actually, but it didn't work out too well for [automated testing](/key-concepts-and-dev-tools/automated-testing-codeception-+-travis-ci). Since the `bootstrap.php` file is autoloaded, it is also loaded every time when a development tool (like [Codeception](/key-concepts-and-dev-tools/automated-testing-codeception-+-travis-ci) or [PHPMD or PHP Code Sniffer](/key-concepts-and-dev-tools/coding-standards-phpcs-and-phpmd)) is run.&#x20;

Absolutely nothing in the autoloaded `bootstrap.php` file is executed because the very first command is to return if the WordPress-specific constant `ABSPATH` is not set. However, before the file is executed, PHP parses it and "learns" about the functions defined in said file. That's why it's possible to call a function defined at line 500 while executing line 25.

Therefore, if the `bootstrap.php` file is included a second time during the same PHP request, there will be a runtime error about the functions being defined already. Coincidentally, the automated tests do exactly that! By putting the functions in a separate, non-autoloaded file, and only including them *after* the `ABSPATH` constant has been set, those errors can be easily avoided.

Another solution is to wrap the functions inside `function_exists` conditional statements, like WordPress that, but in our case it makes the code unnecessarily clunky.

### Is development done forever on the DWS Framework?

With regret, we're happy to announce that is not the case. While we find that the current version of the framework fulfills its purpose splendidly, there will always be performance improvements, new features, PHP and WordPress upgrades etc.

### Are you actively developing the next version of the framework?

Not actively, no. As mentioned in the question above, the current version is already pretty great (in our opinion). But inadvertently, through using it and learning of new use-cases, the next version is probably evolving somewhere in our subconscious.

For the time being, however, rest-assured that there won't be any ground-breaking changes any time soon!

### I still have questions about using the framework

It's probably best if you [open a discussion](https://docs.github.com/en/discussions) on GitHub. All our framework modules are available [here](https://github.com/deep-web-solutions/) -- just pick the one that fits your questions the best and ask away!


# Motivation

When building a website, you (usually) know exactly what server it will run on. Or, at the very least, you will set up the server(s) afterwards to the exact requirements of your code.

For example, if you write an API using PHP8, you will assume that the server running the code will have ... well, PHP8, and probably a good caching infrastructure. In the world of CMS plugins, you can assume exactly none of that.

The only assumptions you can make are the requirements of the CMS itself. In the case of WordPress we can safely assume that we'll have the following things:

* WordPress
* PHP
* A database

The list of assumptions is **not** PHP7. It's not even PHP5! It's simply PHP. Maybe the plugin is running on WP5+, maybe it's running on WP2.7 or lower. Maybe it's MySQL, maybe MariaDB, maybe something else.

{% hint style="info" %}
That doesn't mean that our plugin needs to support every version under the sun, but it does mean that it must be prepared to handle less-than-ideal environments gracefully.
{% endhint %}

In 99% of the cases, we don't actually care about the underlying database system. However, we care about the WordPress and PHP versions in 100% of the cases!

Of course, WordPress has supported forever the `Requires at least` plugin header line that only lets you to install or update a plugin from the public repository if your WP version is higher than the minimum specified. [Since August 2017](https://make.wordpress.org/plugins/2017/08/29/minimum-php-version-requirement/), there also exists a `Requires PHP` line that does the same thing for the PHP version.

All of this doesn't apply to premium plugins however. Also, it doesn't stop people from manually uploading a plugin's files either through FTP/SFTP or via the admin GUI. One can also argue that with the release of the [PHP fatal error protection](https://wptavern.com/wordpress-5-2-jaco-released-includes-fatal-php-error-protection-and-a-recovery-mode) feature in WP5.2, such checks don't matter because the plugin will simply fail to activate so the website will keep working.

While these are valid points, they don't fulfill all the requirements:

* Degrade gracefully, i.e. do not throw any errors and let the user know about the problem
* What if someone actually tries to install your plugin on WP5.1?

Getting this right is not complicated, but it definitely counts as a boring, repetitive task when starting a new plugin project. The purpose of this module, therefore, is to run on as many PHP+WP combinations as possible and *graciously* stop the whole plugin from running if the minimum requirements are not fulfilled.

{% hint style="warning" %}
In an ideal world, the Bootstrapper module would run on all PHP versions back to the early releases of 1995. In the real world, however, we need to draw a line somewhere. In our case, that line was PHP5.3, the first one to support namespaces. According to the [official WP stats](https://wordpress.org/about/stats/), that forsakes about 0.6% of users as of April 2021.
{% endhint %}


# How it works

The main PHP lines of the module explained in plain English.

This module is **by far** the simplest among all of them. But it only works if a couple of things that are fulfilled:

1. It must be the very first thing that the plugin loads.
2. The other modules (and the plugin itself) must refuse to continue running if this module fails to initialize.

Luckily, the first condition is pretty simple to fulfill. The module's entry point is the `bootstrap.php` file (just like all the other modules, actually) and it is defined in [the `composer.json` file](https://github.com/deep-web-solutions/wordpress-framework-bootstrapper/blob/master/composer.json) as an autoload target. Since every single other module also depends on the Bootstrapper module, Composer's autoloader will ensure this file is the first one to load across the entire framework.

As far as the second condition is concerned, you can rest assured that our other modules to follow it. As for your own plugin, well, that depends on you so we're probably covered again!

On a functional level, the file `bootstrap-functions.php` contains the checker function. The main logic is handled by the **very** simple `dws_wp_framework_check_php_wp_requirements_met` function.

If the minimum requirements are met, the namespaced constant `DWS_WP_FRAMEWORK_BOOTSTRAPPER_INIT` is set to true, otherwise it is set to false [in `bootstrap.php`](https://github.com/deep-web-solutions/wordpress-framework-bootstrapper/blob/master/bootstrap.php). It is best to **not** access the constant directly, but through use of the helper function `dws_wp_framework_get_bootstrapper_init_status` defined [in `bootstrap-functions.php`](https://github.com/deep-web-solutions/wordpress-framework-bootstrapper/blob/master/bootstrap-functions.php).

Should the constant be set to false, the module also outputs [the `requirements-error.php` template](https://github.com/deep-web-solutions/wordpress-framework-bootstrapper/blob/master/src/templates/requirements-error.php) as an admin notice. This notice will contain the name of the module that failed to initialize and provide some more information about what went wrong.

{% hint style="warning" %}
If the Bootstrapper module fails, all subsequent framework modules will fail too. However, the admin notice will only be outputted **only once** and will contain the name of the **first module** that failed only.
{% endhint %}

Here is an example of what the notice looks like:

![Default requirements error admin notice](/files/-MXlkX2chcY0I-5Kftbv)


# How to use

The module is available for free installation through [Composer](/key-concepts-and-dev-tools/dependency-management-composer) [on Packagist](https://packagist.org/packages/deep-web-solutions/wp-framework-bootstrapper). Assuming you've added the Bootstrapper module to your project using [Composer](/key-concepts-and-dev-tools/dependency-management-composer), your plugin's main file should look something like this:

```php
<?php
/**
 * Plugin Name:       My Test Plugin
 * Version:           1.0.0
 * Requires at least: 5.7
 * Requires PHP:      8.0
 */
 
 // Load the Composer autoloader.
 \is_file( __DIR__ . '/vendor/autoload.php' ) && require_once __DIR__ . '/vendor/autoload.php';
 

 // Bootstrap the plugin (maybe)!
 if ( dws_wp_framework_check_php_wp_requirements_met( '8.0', '5.7' ) ) {
   // move ahead with plugin initialization
 } else {
   dws_wp_framework_output_requirements_error( 'My Test Plugin', '1.0.0', '8.0', '5.7', array( 'optional_argument' ) );
 }
```

The example above is very rudimentary. You can check [our example plugin's bootstrap file](https://github.com/deep-web-solutions/wordpress-plugins-utility/blob/master/bootstrap.php) for a more complete example.

{% hint style="danger" %}
There is no point for the Bootstrapper module to run on all PHP versions back to 5.3 if your own bootstrap file doesn't. For example, import of functions from another namespace is only supported since PHP5.6! **For brevity**, that has not been included in the code example above, but it is shown in the example plugin's bootstrap file.
{% endhint %}

{% hint style="warning" %}
All the bootstrap files of the DWS Framework are backwards compatible with PHP5.3. However, we obviously can't guarantee the same thing for any 3rd-party libraries you might bundle with your plugin. We have had success ensuring this using [Rector's PHP Downgrade rules](https://github.com/rectorphp/rector/blob/main/docs/rector_rules_overview.md#downgradephp70) bundled as a Composer script in [our wordpress-configs package](https://packagist.org/packages/deep-web-solutions/wordpress-configs).
{% endhint %}

### Actions

The outputted admin notice can be customized using the following actions:

* `dws_wp_framework_requirements_error_before` -- called before any HTML output of the notice
* `dws_wp_framework_requirements_error_start` -- called right after the opening `<div>`
* `dws_wp_framework_requirements_error_list_before` -- called right after the opening `<ul>`
* `dws_wp_framework_requirements_error_list_after` -- called right before the closing `</ul>`&#x20;
* `dws_wp_framework_requirements_error_end` -- called right before the closing `</div>`
* `dws_wp_framework_requirements_error_after` -- called after the entire HTML output of the notice

All actions receive the same arguments as the `dws_wp_framework_output_requirements_error` function. In order, those are:

* The name of the component triggering the requirements error output.
* The version of the said component.
* The minimum PHP version required by said component.
* The minimum WP version required by said component.
* Any optional arguments passed on (array).


# White Labeling

The module was built to be used foremost internally by the Deep Web Solutions development team, but we tried to include white-labeling functionality for all potential customer-facing strings.

Basically, in order to replace our name with yours, all you have to do is define the constants you want to overwrite **before** loading the [Composer ](/key-concepts-and-dev-tools/dependency-management-composer)autoload file. For example:

```php
<?php
/**
 * Plugin Name:       My Test Plugin
 * Version:           1.0.0
 * Requires at least: 5.7
 * Requires PHP:      8.0
 */
 
 // Define white-labeling constants.
 \define( 'DeepWebSolutions\Framework\DWS_WP_FRAMEWORK_WHITELABEL_NAME', 'My Awesome Company Name' );
 
 // Load the Composer autoloader.
 \is_file( __DIR__ . '/vendor/autoload.php' ) && require_once __DIR__ . '/vendor/autoload.php';
 
```

The supported white-label strings are located [in the `bootstrap-whitelabel.php` file](https://github.com/deep-web-solutions/wordpress-framework-bootstrapper/blob/master/bootstrap-whitelabel.php).

{% hint style="warning" %}
You have to define the constant together with the appropriate namespace. If you're using [dependency scoping](/key-concepts-and-dev-tools/dependencies-scoping-php-scoper) (like you should), your namespace will be different than the one showed in the example above.
{% endhint %}


# Motivation

This entire module is designed as a collection of small, static, reusable code snippets organized in final classes. Some of the methods are polyfills (like the `Strings::starts_with` and `Strings::ends_with` methods which are native to PHP8). Some are WordPress-specific (like the `Users::has_roles`) but the most are really PHP-specific. Sometimes they just improve upon existing PHP or WP functions (like `Misc::wp_parse_args_recursive` which extends the native wp\_parse\_args).

Basically a snippet belongs in this module if its logic is universal. It doesn't belong logically to whichever class or trait needs the functionality and its likely to be needed somewhere else as well. It's something we wish existed already either as a PHP or WordPress function.


# How to use

The module is available for free installation through [Composer](/key-concepts-and-dev-tools/dependency-management-composer) [on Packagist](https://packagist.org/packages/deep-web-solutions/wp-framework-helpers).

There is no special way of using the helpers. They're simple static methods. The best documentation is simply to [browse the code on GitHub](https://github.com/deep-web-solutions/wordpress-framework-helpers/tree/master/src/includes) and, if you need more examples, to [browse the tests on GitHub](https://github.com/deep-web-solutions/wordpress-framework-helpers/tree/master/tests).

{% hint style="info" %}
It might be worthwhile to look over all the snippets at least once. There's not that many of them and even a lingering thought of certain functionalities being pre-implemented can help if you need them later on during your projects.
{% endhint %}


# Motivation and How to use

The Foundations Module is the proverbial meat of the entire DWS WP Framework. It provides very little actual functionality and it consists mostly of interfaces, traits, and abstract classes. Understanding this module is absolutely crucial for understanding the whole framework. Arguably, understanding this module is the single thing required to start working with the framework.

{% hint style="info" %}
Building WordPress plugins is already possible once you understand this module. The rest of the modules build on top of the foundations by providing pre-built functionalities. If you need none of that, you're almost ready to start!
{% endhint %}

The module is available for free installation through [Composer](/key-concepts-and-dev-tools/dependency-management-composer) [on Packagist](https://packagist.org/packages/deep-web-solutions/wp-framework-foundations). The rest of the pages in this section will offer an introduction into the abstractions provided by this module.


# Actions

The actions namespace contains interfaces that describe objects which can perform certain actions. It's basically semantic sugar for human convenience. The following interfaces are declared:

* [`InitializableInterface`](https://github.com/deep-web-solutions/wordpress-framework-foundations/blob/master/src/includes/Actions/InitializableInterface.php) -- describes an object that implements an `initialize` method
* [`SetupableInterface`](https://github.com/deep-web-solutions/wordpress-framework-foundations/blob/master/src/includes/Actions/SetupableInterface.php) -- describes an object that implements a `setup` method
* [`OutputtableInterface`](https://github.com/deep-web-solutions/wordpress-framework-foundations/blob/master/src/includes/Actions/OutputtableInterface.php) -- describes an object that implements an `output` method
* [`RunnableInterface`](https://github.com/deep-web-solutions/wordpress-framework-foundations/blob/master/src/includes/Actions/RunnableInterface.php) -- describes an object that implements a `run` method
* [`ResettableInterface`](https://github.com/deep-web-solutions/wordpress-framework-foundations/blob/master/src/includes/Actions/ResettableInterface.php) -- describes an object that implements a `reset` method

The result of the aforementioned methods is either `null` on success, or a specific `Exception` object describing the issue on failure.

{% hint style="info" %}
Semantically, an initializable object should be initialized before calling any other methods on it. If it's also setupable, then the setup should only be run on successful initialization.
{% endhint %}

There is nothing more to the action interfaces. You are obviously free to misuse them in your own plugins, but the framework will adhere to all the hints and conventions laid out in this document.


# Local action traits

There are a few traits offered for your convenience. Every single action interface comes with a basic trait that provides the following implementation:

* Stores the action result as a nullable exception property.
* Stores the action state as a nullable boolean property with the following interpretation:
  * `null` means that the action has not been attempted yet and accessing the action result will throw a PHP runtime error.
  * `true` means that the action was performed successfully and accessing the action result will return `null`.
  * `false` means that the action failed and accessing the action result will return the `Exception` which caused the failure.
* Provides getters for both the action result and state.
* Implements the respective action method. The action method set the action state and result, and will return an exception is called more than once (but will maintain the original state and result).

The most confusing part must be the last point. If the action method is already implemented, then where do you put your class' action logic? Short answer: in a protected action method that ends with `_local`. Long answer: either there, or in a protected method defined by an [action extension trait](/foundations-module/actions/extension-action-traits). But we'll look into that on the next page.

It might be best to look at an example. Open the default trait for the `OutputtableInterface` by clicking [here](https://github.com/deep-web-solutions/wordpress-framework-foundations/blob/master/src/includes/Actions/Outputtable/OutputtableTrait.php) and then look at the method `output`. The first `if` statement basically checks for the existence of the trait `OutputLocalTrait` (see [here](https://github.com/deep-web-solutions/wordpress-framework-foundations/blob/master/src/includes/Actions/Outputtable/OutputLocalTrait.php)) on the current object and, if present, calls the method `output_local` which has the same return type as the original `output` method.

Ignoring the second `elseif` statement for now, if `output_local` returns `null`, the output action is considered successful. Otherwise it fails with the result of the local output action.

In practice you wouldn't use the `OutputtableTrait` directly, but you'd use the `OutputLocalTrait` only since it already "imports" the `OutputtableTrait`:

```php
<?php

namespace DeepWebSolutions\Plugins\MyTestPlugin\Actions;

use DeepWebSolutions\Framework\Foundations\Actions\OutputtableInterface;
use DeepWebSolutions\Framework\Foundations\Actions\Outputtable\OutputFailureException;
use DeepWebSolutions\Framework\Foundations\Actions\Outputtable\OutputLocalTrait;

class MyOutput implements OutputtableInterface {
    use OutputLocalTrait; // USE THIS
    
    protected bool $success;
    
    public function __construct( bool $success ) {
        $this->success = $success;
    }
    
    protected function output_local(): ?OutputFailureException {
        if ( true === $this->success ) {
            return null;
        } else {
            return new OutputFailureException( 'Local output failed for some reason' ); 
        }
    }
}

$my_output = new MyOutput( true );
$my_output->output(); // equals null

$my_output = new MyOutput( false );
$my_output->output()->getMessage(); // equals 'Local output failed for some reason'

```

{% hint style="info" %}
The page uses the output action as an example but all the concepts carry over to all the other actions as well.
{% endhint %}

{% hint style="warning" %}
The article mentions that the traits will return an error if the action method is called twice. That is true, but there exists **one exception**: if an object is both runnable and resettable and uses both default traits, then it is possible to call the `run` method again after calling the `reset` method and the `reset` method again after calling the `run` method indefinitely.
{% endhint %}


# Extension action traits

Similarly to the [local action traits](/foundations-module/actions/local-action-traits) explored on the page before, extension action traits allow you to hook into an action method without overriding it directly thus maintaining the default trait logic. Moreover, since they're traits, they're easily reusable!

We'll continue using the output action for consistency. An output extension trait must make use of the `OutputtableExtensionTrait` like this:

```php
<?php

namespace DeepWebSolutions\Plugins\MyTestPlugin\Actions;

use DeepWebSolutions\Framework\Foundations\Actions\Outputtable\OutputFailureException;
use DeepWebSolutions\Framework\Foundations\Actions\Outputtable\OutputtableExtensionTrait;

trait MyOutputExtensionTrait {
    use OutputtableExtensionTrait; // USE THIS
    
    protected function my_output_extension(): ?OutputFailureException {
        // do something
        
        return null;
    }
}
```

Just like with the local action trait, it's enough to "import" your extension trait into your class -- no need to use the default `OutputtableTrait` too. And just like with the local action traits, the concepts explained here apply to **all** defined actions (you just need to use the corresponding extension trait).

There is one thing you need to pay attention to -- the name of the extension method. It's no coincidence that the example above uses the method `my_output_extension`. The name of the method is derived from the name of the trait. Basically these are the rules:

* If the trait has the suffix `Trait`, it is removed.
* Before every capital letter, an underscore is added.
* The string is turned to lowercase.

Therefore, since my example trait is named `MyOutputExtensionTrait`, the method **must** be named `my_output_extension`. If you misname it, it will simply be ignored.

{% hint style="info" %}
The Foundations module comes with a few pre-built extension traits, but they usually don't make sense unless their context is fully understood. We will explore them on other pages.
{% endhint %}


# Integration action traits

As opposed to [local action traits](/foundations-module/actions/local-action-traits) and [extension action traits](/foundations-module/actions/extension-action-traits), integration action traits apply **only** to *initializable* and *setupable* objects. They are normally used for piping other actions at the end of the current one, if the current action is completed successfully.

They are similar to the extension action traits but have a few notable differences:

* Their methods are always prefixed with `integrate_`.
* The methods are called *after* the extension traits.
* The methods ***can*** return a different exception type so, in case of failure, the result may be wrapped in an exception of the proper type.
* The integration traits inherit different corresponding traits.

Let's use as an example the default `InitializableTrait` that you can find [here](https://github.com/deep-web-solutions/wordpress-framework-foundations/blob/master/src/includes/Actions/Initializable/InitializableTrait.php). If you check the `initialize` method, all the points above should be obvious by looking at the second `elseif` statement.

A good example of an integration trait is the [`SetupOnInitializationTrait`](https://github.com/deep-web-solutions/wordpress-framework-foundations/blob/master/src/includes/Actions/Initializable/Integrations/SetupOnInitializationTrait.php) which automagically calls the `setup` method of an object that initialized successfully and is also setupable.

{% hint style="info" %}
The Foundations module comes with a few pre-built piping actions. Make sure to check them out on GitHub for the initializable objects [here ](https://github.com/deep-web-solutions/wordpress-framework-foundations/tree/master/src/includes/Actions/Initializable/Integrations)and for the setupable objects [here](https://github.com/deep-web-solutions/wordpress-framework-foundations/tree/master/src/includes/Actions/Setupable/Integrations).
{% endhint %}


# States

If you understood the concept of [Actions](/foundations-module/actions), then States should be simple to grasp. This namespace contains interfaces that describe objects which can be in a certain state. The following interfaces are declared

* [`ActiveableInterface`](https://github.com/deep-web-solutions/wordpress-framework-foundations/blob/master/src/includes/States/ActiveableInterface.php) -- describes an objects that implements an `is_active` method
* [`DisableableInterface`](https://github.com/deep-web-solutions/wordpress-framework-foundations/blob/master/src/includes/States/DisableableInterface.php) -- describes an object that implements an `is_disabled` method

The key difference to actions is that state methods return a plain boolean value.

{% hint style="info" %}
There are semantic differences between the two states. An object is expected to be active and *not* disabled by default. Should an object implement both states, disablement should take precedence.
{% endhint %}

Just like with actions, states also come with a set of local and extension traits. There are no integration traits however. The only difference is that the local and extension methods return a boolean instead of a nullable exception. You can look over the traits for the active state [here ](https://github.com/deep-web-solutions/wordpress-framework-foundations/tree/master/src/includes/States/Activeable)and the traits for the disabled state [here](https://github.com/deep-web-solutions/wordpress-framework-foundations/tree/master/src/includes/States/Disableable).


# Utilities


# Stores

Stores are objects that implement READ/UPDATE/DELETE operations against a storage medium for objects that implement the [StorableInterface](https://github.com/deep-web-solutions/wordpress-framework-foundations/blob/master/src/includes/Utilities/Storage/StorableInterface.php) interface. In a nutshell, an object is storable if it has an ID (see the [StorableTrait ](https://github.com/deep-web-solutions/wordpress-framework-foundations/blob/master/src/includes/Utilities/Storage/StorableTrait.php)and [AbstractStorable](https://github.com/deep-web-solutions/wordpress-framework-foundations/blob/master/src/includes/Utilities/Storage/AbstractStorable.php) for a simple implementation). All classes belonging to the Storage namespace can be found [here](https://github.com/deep-web-solutions/wordpress-framework-foundations/tree/master/src/includes/Utilities/Storage).

There are 3 stores that the Foundations Module comes with:

* [A memory store](https://github.com/deep-web-solutions/wordpress-framework-foundations/blob/master/src/includes/Utilities/Storage/Stores/MemoryStore.php) for storing objects in-memory during the current request.
* [An options table store](https://github.com/deep-web-solutions/wordpress-framework-foundations/blob/master/src/includes/Utilities/Storage/Stores/OptionsStore.php) for persistent database storage across requests in the WP options table.
* [A user meta table store](https://github.com/deep-web-solutions/wordpress-framework-foundations/blob/master/src/includes/Utilities/Storage/Stores/UserMetaStore.php) for persistent database storage across request in the WP user meta table.

{% hint style="info" %}
Stores are storable as well. It is possible to create a store that stores other stores! Check the [`MultiStoreAwareInterface`](https://github.com/deep-web-solutions/wordpress-framework-foundations/blob/master/src/includes/Utilities/Storage/MultiStoreAwareInterface.php) and [`MultiStoreAwareTrait`](https://github.com/deep-web-solutions/wordpress-framework-foundations/blob/master/src/includes/Utilities/Storage/MultiStoreAwareTrait.php) for examples.
{% endhint %}

Here is a simple example of a dummy storable object stored in a memory store:

```php
<?php

namespace DeepWebSolutions\Plugins\MyTestPlugin\Storage;

use DeepWebSolutions\Framework\Foundations\Utilities\Storage\AbstractStorable;
use DeepWebSolutions\Framework\Foundations\Utilities\Storage\Stores\MemoryStore;

class MyStorable extends AbstractStorable {
    public string $storable_property;
}

$my_storable1 = new MyStorable( 'unique-id-1' );
$my_storable1->storable_property = 'test value 1';

$my_storable2 = new MyStorable( 'unique-id-2' );
$my_storable1->storable_property = 'test value 2';

$memory_store = new MemoryStore( 'my-memory-store' );
$memory_store->add( $my_storable1 );
$memory_store->add( $my_storable2 );

echo $memory_store->count(); // echoes 2
echo $memory_store->get( 'unique-id-1' )->storable_property; // echoes 'test value 1'

$my_storable3 = new MyStorable( 'unique-id-1' ); // same as $my_storable1
$my_storable3->storable_property = 'test value 3';
$memory_store->update( $my_storable3 );

echo $memory_store->get( 'unique-id-1' )->storable_property; // echoes 'test value 3'

```

{% hint style="danger" %}
There is no guarantee that your storable object will be stored properly when using the options or user meta stores. The two stores rely on WordPress' own [`update_option`](https://developer.wordpress.org/reference/functions/update_option/) and [`update_user_meta`](https://developer.wordpress.org/reference/functions/update_user_meta/) functions respectively and those both rely on PHP's [`serialize`](https://www.php.net/manual/en/function.serialize.php) function. If you have trouble storing your objects, implement the magic methods `__serialize` and `__unserialize` for better handling.
{% endhint %}


# Handlers and Services

[Handlers ](https://github.com/deep-web-solutions/wordpress-framework-foundations/tree/master/src/includes/Utilities/Handlers)and [Services ](https://github.com/deep-web-solutions/wordpress-framework-foundations/tree/master/src/includes/Utilities/Services)are two distinct concepts, but they were designed together and are being used together. Specifically, services make use of handlers. Handlers, however, can be freely used in other contexts as well.

Handlers are [storable objects](/foundations-module/utilities/stores) that also implement a `get_type` method. For example, handlers for the [logging service](/foundations-module/utilities/handlers-and-services/logging-service) are of the *logging* type.

Services are meant to be central hubs (i.e., singleton instances) for performing certain actions. It's not mandatory, but we designed all of our services to delegate the responsibility of performing the actions to a handler. For example, a service inheriting the [`AbstractHandlerService`](https://github.com/deep-web-solutions/wordpress-framework-foundations/blob/master/src/includes/Utilities/Services/AbstractHandlerService.php) class always performs the actions with the same handler whereas a service inheriting the [`AbstractMultiHandlerService`](https://github.com/deep-web-solutions/wordpress-framework-foundations/blob/master/src/includes/Utilities/Services/AbstractMultiHandlerService.php) class needs to be instructed which registered handler to use.

{% hint style="info" %}
Handlers are not meant to be used directly. An object usually has one-or-more registered handlers that it can perform actions with. That's why the [`HandlerAwareInterface`](https://github.com/deep-web-solutions/wordpress-framework-foundations/blob/master/src/includes/Utilities/Handlers/HandlerAwareInterface.php) (and the corresponding [trait](https://github.com/deep-web-solutions/wordpress-framework-foundations/blob/master/src/includes/Utilities/Handlers/HandlerAwareTrait.php)) and the [`MultiHandlerAwareInterface`](https://github.com/deep-web-solutions/wordpress-framework-foundations/blob/master/src/includes/Utilities/Handlers/MultiHandlerAwareInterface.php)  (and the corresponding [trait](https://github.com/deep-web-solutions/wordpress-framework-foundations/blob/master/src/includes/Utilities/Handlers/MultiHandlerAwareTrait.php)) are very important.
{% endhint %}

The handlers are also prime candidates for [extension action traits](/foundations-module/actions/extension-action-traits). There are 3 traits that the foundations module comes with:

* [`OutputHandlersTrait`](https://github.com/deep-web-solutions/wordpress-framework-foundations/blob/master/src/includes/Utilities/Handlers/Actions/OutputHandlersTrait.php) -- using objects will call the `output` method of their registered handlers.
* [`RunHandlersTrait`](https://github.com/deep-web-solutions/wordpress-framework-foundations/blob/master/src/includes/Utilities/Handlers/Actions/RunHandlersTrait.php) -- using objects will call the `run` method of their registered handlers
* [`ResetHandlersTrait`](https://github.com/deep-web-solutions/wordpress-framework-foundations/blob/master/src/includes/Utilities/Handlers/Actions/ResetHandlersTrait.php) -- using objects will call the `reset` method of their registered handlers.

For example, a [multi-handler-aware-service](https://github.com/deep-web-solutions/wordpress-framework-foundations/blob/master/src/includes/Utilities/Services/AbstractMultiHandlerService.php) implementing the [`OutputtableInterface`](https://github.com/deep-web-solutions/wordpress-framework-foundations/blob/master/src/includes/Actions/OutputtableInterface.php) and using the `OutputHandlersTrait` mentioned above will automagically call the `output` method of all its registered handlers also implementing the `OutputtableInterface` when the service's own `output` method is called. Pretty neat, huh?


# Logging Service

The [logging service](https://github.com/deep-web-solutions/wordpress-framework-foundations/tree/master/src/includes/Logging) is the only example of a service provided in the foundations module. That's because we believe that every plugin should use logging (hence also why every service is forced to implement the [`LoggingServiceAwareInterface`](https://github.com/deep-web-solutions/wordpress-framework-foundations/blob/master/src/includes/Logging/LoggingServiceAwareInterface.php) interface).

In short, the logging service is a multi-handler service that accepts any handler implementing the [`LoggingHandlerInterface`](https://github.com/deep-web-solutions/wordpress-framework-foundations/blob/master/src/includes/Logging/LoggingHandlerInterface.php) interface. It's expected to provide the service with two handlers, one with the ID *framework* and one with the ID *plugin*.&#x20;

By default, the logging service attempts to log using the *plugin* handler, whereas messages logged by framework modules will always use the *framework* handler. In order to include sensitive data in the log messages, you need to instantiate the service with the second parameter set to `true`.

{% hint style="danger" %}
The logging service doesn't understand what data is of sensitive nature and which is not. It's your responsibility to mark it accordingly when composing the logged message.
{% endhint %}

{% hint style="info" %}
If you want to disable logging for your plugin, it's enough to not register the two aforementioned handlers. The service will simply default to using the [NullLogger](https://github.com/php-fig/log/blob/master/Psr/Log/NullLogger.php).
{% endhint %}

The [default logging handler](https://github.com/deep-web-solutions/wordpress-framework-foundations/blob/master/src/includes/Logging/LoggingHandler.php) requires an ID and a [PSR-3](https://www.php-fig.org/psr/psr-3/) logger. We recommend using [Monolog](https://packagist.org/packages/monolog/monolog) for your PSR-3 logger needs, but if you're building a WooCommerce plugin, please be aware that the [WooCommerce module](https://packagist.org/packages/deep-web-solutions/wp-framework-woocommerce) provides a handler compatible with the WooCommerce logger.

Here is a simple example for instantiating the logging service using Monolog loggers:

```php
<?php

namespace DeepWebSolutions\Plugins\MyTestPlugin;

use DeepWebSolutions\Framework\Foundations\Logging\LoggingHandler;
use DeepWebSolutions\Framework\Foundations\Logging\LoggingService;
use DeepWebSolutions\Framework\Helpers\WordPress\Request;

use Monolog\Handler\RotatingFileHandler as MonologRotatingFileHandler;
use Monolog\Logger as MonologLogger;

use function DeepWebSolutions\Framework\dws_wp_framework_get_temp_dir_path;


$min_log_level = Request::has_debug() ? MonologLogger::DEBUG : MonologLogger::ERROR;
$logs_path     = dws_wp_framework_get_temp_dir_path() . 'my-test-plugin' . DIRECTORY_SEPARATOR;

$monolog_handler = new MonologRotatingFileHandler( $logs_path . 'errors.log', 30, $min_log_level );
$dws_handlers    = array(
    new LoggingHandler( 'framework', new MonologLogger( 'framework', array( $monolog_handler ) ) ),
    new LoggingHandler( 'plugin', new MonologLogger( 'plugin', array( $monolog_handler ) ) ),
);

$plugin_instance     = dws_test_plugin_instance();
$dws_logging_service = new LoggingService( $plugin_instance, $dws_handlers, Request::has_debug() );

```

The logging service provides two public methods:

* `log_event` -- returns an instance of the [`LogMessageBuilder`](https://github.com/deep-web-solutions/wordpress-framework-foundations/blob/master/src/includes/Logging/LogMessageBuilder.php) class which can be further configured to perform other actions before logging the message.
* `log_event_and_finalize` -- shortcut for calling the `log_event` method and finalizing the message.

Instances of the `LogMessageBuilder` class need to have the finalize method called on them for the message to be logged and the other actions performed as well.

{% hint style="warning" %}
If you don't call `finalize` on `LogMessageBuilder` objects, the message will never be logged!
{% endhint %}

A few things that the message builder can do:

* If the service is configured to ignore sensitive content, it removes all the text wrapped in `<sensitive></sensitive>` tags.
* It can log the message using WordPress' [`_doing_it_wrong`](https://developer.wordpress.org/reference/functions/_doing_it_wrong/) as well.
* By default, it returns `null` when calling `finalize`, but it can be configured to return the logged message wrapped in an exception or a given throwable object.

And here are examples on how to use the message builder (we'll assume the logging service instantiated above is present in this context as well):

```php
<?php

use DeepWebSolutions\Framework\Foundations\Exceptions\NotFoundException;
use Psr\Log\LogLevel;

// The following two lines are EQUIVALENT.
$dws_logging_service->log_event( 'Error happened' )
                ->set_log_level( LogLevel::DEBUG )
                ->finalize();

$dws_logging_service->log_event_and_finalize( 'Error happened' );

// This message will be logged with WP too.
$dws_logging_service->log_event( 'Error happened in function' )
                ->doing_it_wrong( 'my_awesome_func', '1.3.5' )
                ->finalize();

// This message will return an exception.
$exception = $dws_logging_service->log_event_and_finalize( 'Property A not found' )
                ->return_exception( NotFoundException::class )
                ->finalize();
echo get_class( $exception ); // echoes 'NotFoundException'
echo $exception->getMessage(); // echoes 'Property A not found'
```


# Plugin


# Main Plugin Instance

Your plugin should have exactly one class that implements the [`PluginInterface`](https://github.com/deep-web-solutions/wordpress-framework-foundations/blob/master/src/includes/Plugin/PluginInterface.php) interface. If you have a very simple plugin, it can be the only class you have, but you need to have it. For convenience, the [`PluginTrait`](https://github.com/deep-web-solutions/wordpress-framework-foundations/blob/master/src/includes/Plugin/PluginTrait.php) trait provides a basic implementation for most methods.

Basically what this interface enforces is a way to retrieve the most useful information from the plugin's [header comment](https://developer.wordpress.org/plugins/plugin-basics/header-requirements/). The [`AbstractPlugin`](https://github.com/deep-web-solutions/wordpress-framework-foundations/blob/master/src/includes/Plugin/AbstractPlugin.php) class even goes a step further and actually retrieves all the values from said comment during the [local initialization action](/foundations-module/actions/local-action-traits).

Therefore it would be enough to have a file `Plugin.php` that looks a bit like this:

```php
<?php

namespace DeepWebSolutions\Plugins\MyTestPlugin;

use DeepWebSolutions\Framework\Foundations\Plugin\AbstractPlugin;

\defined( 'ABSPATH' ) || exit;

class MyPlugin extends AbstractPlugin {
    public function get_plugin_file_path(): string {
        return $path_to_file_with_plugin_header_comment;
    }
}

$plugin = new MyPlugin();
$plugin->initialize();

echo $plugin->get_plugin_version(); // echoes whatever the version header line is set to

```

As always, our [example plugin](https://github.com/deep-web-solutions/wordpress-plugins-utility) provides a more complex example (albeit it relies on the extended classes provided by the [Core Module](https://packagist.org/packages/deep-web-solutions/wp-framework-core)).


# Plugin Components

While the main plugin instance class of your project should implement the `PluginInterface` interface, the other classes should implement the [`PluginComponentInterface`](https://github.com/deep-web-solutions/wordpress-framework-foundations/blob/master/src/includes/PluginComponent/PluginComponentInterface.php) interface. Obvious exceptions are classes designed to be [utilities](/foundations-module/utilities) -- and anything else that you think shouldn't (we don't know your project!).&#x20;

Plugin components are simple though. They simple posses an ID, a name, and a means to get the main plugin instance. For example, our [Locked Payment Methods plugin](https://www.deep-web-solutions.com/plugins/locked-payment-methods-for-woocommerce/) has a class for each unlock strategy and each of those classes is a plugin component. The name of the user profile unlock strategy is simply *User Meta Unlock Strategy* and its ID is an autogenerated hash.

{% hint style="info" %}
The ID of a plugin component can be anything that identifies it uniquely, whereas the name is designed to be spelled out in plain English for human understanding.
{% endhint %}

{% hint style="warning" %}
As a rule of thumb, plugin components are singletons. This is not enforced, but be sure to know what you're doing if you instantiate the same component multiple times.
{% endhint %}

As you probably expected by now, there is a [`PluginComponentTrait`](https://github.com/deep-web-solutions/wordpress-framework-foundations/blob/master/src/includes/PluginComponent/PluginComponentTrait.php) trait offered that provides a basic implementation of the interface methods. Moreover, the [`AbstractPluginComponent`](https://github.com/deep-web-solutions/wordpress-framework-foundations/blob/master/src/includes/PluginComponent/AbstractPluginComponent.php) class also provides sensible defaults and magic use of your getters and setters.


# Hierarchies

One thing that shows up often in Computer Science are graphs. It should be no surprise then that we make use of them too! The relevant namespace is called Hierarchy and the files are found [here](https://github.com/deep-web-solutions/wordpress-framework-foundations/tree/master/src/includes/Hierarchy).

{% hint style="warning" %}
This document is not meant to replace a basic understanding of [trees](https://en.wikipedia.org/wiki/Tree_\(data_structure\)) or [linked lists](https://en.wikipedia.org/wiki/Linked_list). If those concepts are unfamiliar to you, you should first brush up on those topics before reading the rest of this page.
{% endhint %}

The two key concepts of a hierarchy are the so-called *parents* and the so-called *children*. The foundations module offers abstractions for children that have 0-or-1 parents and for parents that have 0-or-more children. Those are the [`ParentInterface`](https://github.com/deep-web-solutions/wordpress-framework-foundations/blob/master/src/includes/Hierarchy/ParentInterface.php) interface (obligatory [`ParentTrait`](https://github.com/deep-web-solutions/wordpress-framework-foundations/blob/master/src/includes/Hierarchy/ParentTrait.php) trait) and the [`ChildInterface`](https://github.com/deep-web-solutions/wordpress-framework-foundations/blob/master/src/includes/Hierarchy/ChildInterface.php) interface (obligatory [`ChildTrait`](https://github.com/deep-web-solutions/wordpress-framework-foundations/blob/master/src/includes/Hierarchy/ChildTrait.php) trait).

{% hint style="info" %}
Because of the one parent constraint, the resulting graph will always be a *tree* where the only node without a parent is the so-called *root*.
{% endhint %}

More interesting, however, are objects that can be both a parent and a child. Those are called *nodes* and are modelled by the [`NodeInterface`](https://github.com/deep-web-solutions/wordpress-framework-foundations/blob/master/src/includes/Hierarchy/NodeInterface.php) interface. A basic implementation is provided by the [`NodeTrait`](https://github.com/deep-web-solutions/wordpress-framework-foundations/blob/master/src/includes/Hierarchy/NodeTrait.php) trait. The only noteworthy addition is the ability to query an instance's *depth* within the tree. The root has depth 0, its children have depth 1, its grandchildren have depth 2, and so on...

So far, these abstractions have universal applications. You can use them worry-free for anything that can be modelled as a tree. For example, you could build an abstract model of a table where the root is an instance of an imaginary `Table` class and the children are instances of an imaginary `Column` class.

However, the main reason why these abstractions were created was to offer the ability to create a plugin tree with a `PluginInterface`-implementing object as the root and `PluginComponentInterface`-implementing objects as the rest of the nodes. If you've skipped [the Plugin section](/plugin), that's where those interfaces are explained.

Therefore, two new abstract classes arise: the [`AbstractPluginRoot`](https://github.com/deep-web-solutions/wordpress-framework-foundations/blob/master/src/includes/Hierarchy/Plugin/AbstractPluginRoot.php) class and the [`AbstractPluginNode`](https://github.com/deep-web-solutions/wordpress-framework-foundations/blob/master/src/includes/Hierarchy/Plugin/AbstractPluginNode.php) class which extend the [`AbstractPlugin`](https://github.com/deep-web-solutions/wordpress-framework-foundations/blob/master/src/includes/Plugin/AbstractPlugin.php) and [`AbstractPluginComponent`](https://github.com/deep-web-solutions/wordpress-framework-foundations/blob/master/src/includes/PluginComponent/AbstractPluginComponent.php) classes, respectively.

All the concepts presented in [the Plugin section](/plugin) still apply. The only difference is that we now have a logical connection between all the individual plugin components. The root is at the top and everything else belongs somewhere in the abstract plugin tree structure. Getters like `get_plugin` now default to a simple tree traversal algorithm for retrieving the root.

The introduction of hierarchical plugin components also brings new [extension traits](/foundations-module/actions/extension-action-traits) and [integration traits](/foundations-module/actions/integration-action-traits) for both [actions ](/foundations-module/actions)and [states](/foundations-module/states). You can find them all in their respective folders inside [the Hierarchy namespace on GitHub](https://github.com/deep-web-solutions/wordpress-framework-foundations/tree/master/src/includes/Hierarchy), but here is a selection:

* [`ActiveParentTrait`](https://github.com/deep-web-solutions/wordpress-framework-foundations/blob/master/src/includes/Hierarchy/States/ActiveParentTrait.php) -- the current instance is active only if its direct parent is active too.
* [`DisabledParentTrait`](https://github.com/deep-web-solutions/wordpress-framework-foundations/blob/master/src/includes/Hierarchy/States/DisabledParentTrait.php) -- if the current instance's direct parent is disabled, it is disabled too
* [`InitializeChildrenTrait`](https://github.com/deep-web-solutions/wordpress-framework-foundations/blob/master/src/includes/Hierarchy/Actions/InitializeChildrenTrait.php) -- upon successful initialization, initialize the instance's children too.
* [`MaybeSetupChildrenTrait`](https://github.com/deep-web-solutions/wordpress-framework-foundations/blob/master/src/includes/Hierarchy/Actions/MaybeSetupChildrenTrait.php) -- after setting up, set up all active and not disabled children too.

Here is a very basic example of a plugin tree:

```php
<?php

namespace DeepWebSolutions\Plugins\MyTestPlugin;

use DeepWebSolutions\Framework\Foundations\Actions\InitializableInterface;
use DeepWebSolutions\Framework\Foundations\Actions\SetupableInterface;
use DeepWebSolutions\Framework\Foundations\Hierarchy\Plugin\AbstractPluginRoot;
use DeepWebSolutions\Framework\Foundations\Hierarchy\Plugin\AbstractPluginNode;
use DeepWebSolutions\Framework\Foundations\Hierarchy\Actions\InitializeChildrenTrait;
use DeepWebSolutions\Framework\Foundations\Hierarchy\Actions\MaybeSetupChildrenTrait;
use DeepWebSolutions\Framework\Foundations\Hierarchy\States\ActiveParentTrait;
use DeepWebSolutions\Framework\Foundations\Hierarchy\States\DisabledParentTrait;
use DeepWebSolutions\Framework\Foundations\States\ActiveableInterface;
use DeepWebSolutions\Framework\Foundations\States\DisableableInterface;
// Exceptions import and Local traits import ommitted for brevity

class MyPlugin extends AbstractPluginRoot implements InitializableInterface, SetupableInterface {
    use InitializeChildrenTrait;
    use MaybeSetupChildrenTrait;
    use SetupLocalTrait;
    use SetupOnInitializationTrait;
    
    public function get_plugin_file_path(): string {
        return $path_to_file_with_plugin_header_comment;
    }
    
    protected function setup_local(): ?SetupFailureException {
        // do some local setup ... like registering some actions and filters
        return null;
    }
}

class GenericComponents extends AbstractPluginNode implements InitializableInterface, SetupableInterface, ActiveableInterface, DisableableInterface {
    use InitializeChildrenTrait;
    use InitializeLocalTrait;
    use MaybeSetupChildrenTrait;
    use SetupLocalTrait;
    use ActiveLocalTrait;
    use ActiveParentTrait;
    use DisabledLocalTrait;
    use DisabledParentTrait;
    
    protected function is_active_local(): bool {
        // add your own logic for this node (and all of its descendants) to be active
        // for example, a setting in the WP admin area
        return true;
    }
    
    protected function is_disabled_local(): bool {
        // add your own logic for this node (and all of its descendants) to be disabled
        // for example, this plugin branch could be for compatibility with another plugin
        // and thus, if that plugin is not active, nothing here should run
        return false;
    }
    
    protected function initialize_local(): ?InitializationFailureException {
        // do some local initialization, basically just making sure that
        // everything is in order for the 'setup_local' call
        return null;
    }
    
    protected function setup_local(): ?SetupFailureException {
        // do some local setup, like registering actions and filters,
        // registering shortcodes, setting up REST routes,
        // adding admin notices, whatever
        return null;
    }
}

$plugin     = new MyPlugin();
$component1 = new GenericComponent();
$component2 = new GenericComponent();
$component3 = new GenericComponent();

$plugin->add_child( $component1 );
$component1->add_child( $component2 );
$component1->add_child( $component3 );

// automagically run everything!
$plugin->initialize();

```

In case you're still confused about what happens in the example above, here is the plugin tree structure:

![Plugin tree structure](/files/-MXrwZz6OjR0Mcej_NdL)

... and here is the full call stack trace, *spelled out*, after calling `initialize` (noop method calls ommitted for brevity):

```php
$plugin->initialize();
$plugin->initialize_local(); // see AbstractPlugin class in the Plugin namespace
$plugin->integrate_initialize_children();

$component1->initialize();
$component1->initialize_local();
$component1->integrate_initialize_children();
$component2->initialize();
$component2->initialize_local();
$component3->initialize();
$component3->initialize_local();

// full plugin tree has been initialized successfully

$plugin->setup(); // setup method called automagically because of the action integration trait
$plugin->setup_local();
$plugin->integrate_maybe_setup_children();

$component1->is_disabled();
$component1->is_disabled_local();
$component1->is_active();
$component1->is_active_local();
$component1->setup();
$component1->setup_local();
$component1->integrate_maybe_setup_children();

$component2->is_disabled();
$component2->is_disabled_local();
$component1->is_disabled(); // because of the parent checking trait
$component2->is_active();
$component2->is_active_local();
$component1->is_active(); // because of the parent checking trait
$component2->setup();
$component2->setup_local();

$component3->is_disabled();
$component3->is_disabled_local();
$component1->is_disabled();
$component3->is_active();
$component3->is_active_local();
$component1->is_active();
$component3->setup();
$component3->setup_local();
```

You read that right. All of the above happens automagically in the background upon calling `$plugin->initialize()` thanks to the traits we included. The call stack gets *short-circuited* if a local action method returns a corresponding exception or if a local state method returns the opposite boolean value of what we pre-configured in the example above.

{% hint style="success" %}
Congratulations! If you understood the example above, then you understand exactly how to use the Foundations Module to build your own plugins -- just **mix-and-match** action and state traits in your plugin components to achieve the desired results. Or just skip it all and use the pre-built logic provided by the Core Module.
{% endhint %}


# Helpers

For those of you that have looked through[ the code of the Helpers Module](https://github.com/deep-web-solutions/wordpress-framework-helpers) on GitHub, you should've stumbled upon the [`HooksHelpersTrait`](https://github.com/deep-web-solutions/wordpress-framework-helpers/blob/master/src/includes/WordPress/Hooks/HooksHelpersTrait.php) and the [`AssetsHelpersTrait`](https://github.com/deep-web-solutions/wordpress-framework-helpers/blob/master/src/includes/WordPress/Assets/AssetsHelpersTrait.php) traits. They provide methods for generating programmatically hook tags and asset handles, respectively.

The Foundations Module extends upon the methods defined in those two traits by taking into account the role of the using class. Specifically, it takes into account whether the using class implements any of the `PluginComponentInterface`, `PluginAwareInterface`, or `PluginInterface` interfaces in this order.

You can check out the enhanced versions of these traits [here](https://github.com/deep-web-solutions/wordpress-framework-foundations/tree/master/src/includes/Helpers). It's recommended to use them every time you work with hooks and assets in order have a consistent naming scheme.


# Motivation and How to use

The Utilities Module is where all the other services are. If you don't remember from the foundations module's documentation, [services and handlers](/foundations-module/utilities/handlers-and-services) are a abstract wrappers around concrete implementations for fulfilling given actions. For example, the foundations module  comes with pre-packaged with [a logging service](/foundations-module/utilities/handlers-and-services/logging-service).

{% hint style="info" %}
Services are meant to be singletons. Usually they register one or multiple handlers for performing the actual actions with (like how the logging service required two logging handlers, one for the framework itself and one for the actual plugin).
{% endhint %}

The module is available for free installation through [Composer](/key-concepts-and-dev-tools/dependency-management-composer) [on Packagist](https://packagist.org/packages/deep-web-solutions/wp-framework-utilities). We'll explore the pre-packages services in this documentation.

{% hint style="danger" %}
As of April 2021, the Utilities Module is still considered in beta. Beta modules don't have automated tests yet and can change significantly until the release. However, the overall structure is clear and done. You may use it but it might be wise to keep an eye out for undocumented changes.
{% endhint %}

{% hint style="info" %}
If you get confused while reading the documentation, don't forget to take a look over our [example plugin on GitHub](https://github.com/deep-web-solutions/wordpress-plugins-utility). There are examples there of using some of the services described here.
{% endhint %}


# Hooks Service

The hooks service is first-of-all [a single-handler service](/foundations-module/utilities/handlers-and-services) and second-of-all a [runnable and resettable](/foundations-module/actions) object. It's a service designed to work with WordPress actions and filters (commonly referred to as hooks). Basically the service provides the following public methods:

* `add_action` - registers an action with the handler
* `remove_action` - removes an action registered with the handler
* `remove_all_actions` - removes all actions registered with the handler
* `add_filter` - registers a filter with the handler
* `remove_filter` - remove a filter registered with the handler
* `remove_all_filters` - removes all filters registered with the handler

All of these methods are just wrappers against the registered handler. Any handler implementing the [`HooksHandlerInterface`](https://github.com/deep-web-solutions/wordpress-framework-utilities/blob/master/src/includes/Hooks/HooksHandlerInterface.php) can be registered with the hooks service, but you may also decide to simply use the default handler instantiated if no handler is passed on in the constructor. The default handler is an instance of the [`DefaultHooksHandler`](https://github.com/deep-web-solutions/wordpress-framework-utilities/blob/master/src/includes/Hooks/Handlers/DefaultHooksHandler.php) inspired [by the loader](https://github.com/DevinVinson/WordPress-Plugin-Boilerplate/blob/master/plugin-name/includes/class-plugin-name-loader.php) defined in the [WordPress Plugin Boilerplate by DevinVinson](https://github.com/DevinVinson/WordPress-Plugin-Boilerplate).

{% hint style="info" %}
The intention is to only register the hooks with the WordPress system if the plugin was successfully initialized. If an error occurred, we don't want any half-hooks being called.
{% endhint %}

The default handler maintains all of the registered hooks in protected arrays and calls WordPress' own `add_action` and `add_filter` functions on its own `run` action.

{% hint style="info" %}
The handler's `run` and `reset` methods are automatically called when the hooks service's respective methods are called.
{% endhint %}

### Bypassing the late registration

This approach arguably has its downsides. For example, you can't use any of your own hooks during plugin initialization (because that's when you're supposed to call `run` on the service). If you want to bypass this, there are 2 options available:

1. Just don't use the service. We think the advantages outweigh the disadvantages, but that's for you to decide.
2. Write your own custom handler implementing the [`HooksHandlerInterface`](https://github.com/deep-web-solutions/wordpress-framework-utilities/blob/master/src/includes/Hooks/HooksHandlerInterface.php) interface and have it call the WP API directly.

### Available Traits

There are 3 traits available for working with the hooks service.&#x20;

First there is the [`HooksServiceAwareTrait`](https://github.com/deep-web-solutions/wordpress-framework-utilities/blob/master/src/includes/Hooks/HooksServiceAwareTrait.php) and the corresponding [`HooksServiceAwareInterface`](https://github.com/deep-web-solutions/wordpress-framework-utilities/blob/master/src/includes/Hooks/HooksServiceAwareInterface.php). Basically this allows you to call upon the hooks service instance from anywhere within the object. Technically, you can also use more than one service in your plugin and register different ones with different objects.

```php
<?php

namespace DeepWebSolutions\Plugins\MyPlugin;

use DeepWebSolutions\Framework\Utilities\Hooks\HooksService;
use DeepWebSolutions\Framework\Utilities\Hooks\HooksServiceAwareInterface ;
use DeepWebSolutions\Framework\Utilities\Hooks\HooksServiceAwareTrait;

defined( 'ABSPATH' ) || exit;

class MyClass implements HooksServiceAwareInterface {
    use HooksServiceAwareTrait;
    
    public function register_my_hooks() {
        $hooks_service = $this->get_hooks_service();
        $hooks_service->add_filter( 'dws_myplugin_filter', $this, 'filter_value' );
    }
    
    public function filter_value( $value_to_filter ) {
        // ...modify 'value_to_filter'
        return $value_to_filter;
    }
}

$hooks_service = new HooksService( $plugin_instance, $logging_service_instance );

$my_class = new MyClass();
$my_class->set_hooks_service( $hooks_service );
$my_class->register_my_hooks();

$hooks_service->run();

```

The second method involves injecting the hooks service from outside the instance. This behavior is modelled by the [`HooksServiceRegisterInterface`](https://github.com/deep-web-solutions/wordpress-framework-utilities/blob/master/src/includes/Hooks/HooksServiceRegisterInterface.php) interface and the [`HooksServiceRegisterTrait`](https://github.com/deep-web-solutions/wordpress-framework-utilities/blob/master/src/includes/Hooks/HooksServiceRegisterTrait.php).

```php
<?php

namespace DeepWebSolutions\Plugins\MyPlugin;

use DeepWebSolutions\Framework\Utilities\Hooks\HooksService;
use DeepWebSolutions\Framework\Utilities\Hooks\HooksServiceRegisterInterface;
use DeepWebSolutions\Framework\Utilities\Hooks\HooksServiceRegisterTrait;

defined( 'ABSPATH' ) || exit;

class MyClass implements HooksServiceRegisterInterface {
    use HooksServiceRegisterTrait;
    
    public function register_hooks( HooksService $hooks_service ) {
        $hooks_service->add_filter( $this->get_hook_tag( 'dws_myplugin_filter' ), $this, 'filter_value' );
    }
    
    public function filter_value( $value_to_filter ) {
        // ...modify 'value_to_filter'
        return $value_to_filter;
    }
}

$hooks_service = new HooksService( $plugin_instance, $logging_service_instance );

$my_class = new MyClass();
$my_class->register_hooks( $hooks_service );

$hooks_service->run();

```

The recommended way, however, is to use the [`SetupHooksTrait`](https://github.com/deep-web-solutions/wordpress-framework-utilities/blob/master/src/includes/Actions/Setupable/SetupHooksTrait.php) action trait. It's an [action extension trait](/foundations-module/actions/extension-action-traits) for automagically calling the aforementioned `register_hooks` methods upon the `setup` action. If attempts to obtain an instance of the `HooksService` either from the object itself (if it implements the `HooksServiceAwareInterface` interface) or from a[ dependency injection](/key-concepts-and-dev-tools/dependency-injection-php-di) container.

There is also an accompanying [`InitializeHooksServiceTrait`](https://github.com/deep-web-solutions/wordpress-framework-utilities/blob/master/src/includes/Actions/Initializable/InitializeHooksServiceTrait.php) action trait. This one attempts to set the hooks service on the instance by first querying its parent and lastly the [dependency injection](/key-concepts-and-dev-tools/dependency-injection-php-di) container for an instance.

Putting it all together, your code could look something like this:

```php
<?php

namespace DeepWebSolutions\Plugins\MyPlugin;

use DeepWebSolutions\Framework\Foundations\Actions\InitializableInterface;
use DeepWebSolutions\Framework\Foundations\Actions\Initializable\InitializableTrait;
use DeepWebSolutions\Framework\Foundations\Actions\SetupableInterface;
use DeepWebSolutions\Framework\Foundations\Actions\Setupable\SetupableTrait;

use DeepWebSolutions\Framework\Foundations\Utilities\DependencyInjection\ContainerAwareInterface;
use DeepWebSolutions\Framework\Foundations\Utilities\DependencyInjection\ContainerAwareTrait;

use DeepWebSolutions\Framework\Utilities\Actions\Initializable\InitializeHooksServiceTrait;
use DeepWebSolutions\Framework\Utilities\Actions\Setupable\SetupHooksTrait;

use DeepWebSolutions\Framework\Utilities\Hooks\HooksService;
use DeepWebSolutions\Framework\Utilities\Hooks\HooksServiceRegisterInterface;
use DeepWebSolutions\Framework\Utilities\Hooks\HooksServiceRegisterTrait;

defined( 'ABSPATH' ) || exit;

class MyClass implements ContainerAwareInterface, InitializableInterface, SetupableInterface {
    use ContainerAwareTrait;
    use InitializeHooksServiceTrait;
    use InitializableTrait;
    use SetupableTrait;
    use SetupHooksTrait;
    
    public function register_hooks( HooksService $hooks_service ) {
        // register your hooks in here...
    }
}

$my_class = new MyClass();
$my_class->set_container( $my_dependency_injection_container );

$my_class->initialize(); // the hooks service will be set on the instance from the DI container
$my_class->setup(); // the 'register_hooks' method will be automagically called


```

{% hint style="info" %}
If the number of imported interfaces and traits in the example above is scarring you, you can find some comfort in the fact that this is an extreme example built from scratch! Normally you would create pre-built abstract objects that implement most of these features and simply extend them. That's basically what our Core Module does!
{% endhint %}


# Scoped Handler

In addition to the default hooks handler explained on the previous page, the Utilities Module comes pre-packaged with one more hooks handler -- the so-called [`ScopedHooksHandler`](https://github.com/deep-web-solutions/wordpress-framework-utilities/blob/master/src/includes/Hooks/Handlers/ScopedHooksHandler.php).

The scoped handler inherits the `DefaultHooksHandler` so it still keeps a list of hooks arrays and registers them on `run`. However, the hooks registered have a so-called *scope* which is defined by a starting hook and an ending hook.&#x20;

Basically this handler will automagically register all its hooks an a constructor-given hook and will unregister them on another constructor-given hook. This is useful for scenarios where you only want to enqueue some hooks during a specific method call, for example, and don't want them interfering with the rest of the request. Your custom filter for modifying SQL queries should really not bring the whole page down, but only your own custom output if something should go wrong.

You can use it like this:

```php
<?php

use DeepWebSolutions\Framework\Utilities\Hooks\Handlers\ScopedHooksHandler;

class MyClass {
    public function output_my_content() {
        do_action( 'before-my-awesome-output' );
        
        // output ...
        
        do_action( 'after-my-awesome-output' );
    }
}

$scoped_handler = new ScopedHooksHandler( 
        'my-class-output-handler', 
        array( 'hook' => 'before-my-awesome-output' ), 
        array( 'hook' => 'after-my-awesome-output' )
    );
$scoped_handler ->add_filter( ... );
$scoped_handler ->remove_action( ... );

$my_class = new MyClass();
$my_class->output_my_content();
```

{% hint style="warning" %}
The scoped handler uses different semantics for the methods `remove_filter` and `remove_action`. Basically their purpose is to instruct the handler to temporarily unregister those hooks during the given scope.

If you want to unregister hooks that you've added to the handler using `add_action` and `add_filter`,  please use the methods `remove_added_filter` and `remove_added_action`, respectively.
{% endhint %}

Of course, it's also possible to call the `run` and `reset` action methods manually by simply not setting the start and end hooks in the constructor:

```php
<?php

$scoped_handler = new ScopedHooksHandler( 'my-class-output-handler' );
$scoped_handler ->add_filter( ... );
$scoped_handler ->remove_action( ... );

$my_class = new MyClass();

$scoped_handler->run();
$my_class->output_my_content();
$scoped_handler->reset();
```


# Shortcodes Service

The shortcodes service is actually extremely similar [to the hooks service](/utilities-module/hooks-service) described previously. It's a [single-handler service](/foundations-module/utilities/handlers-and-services) with [a runnable and a resettable action](/foundations-module/actions). It provides the following public methods:

* `add_shortcode` - registers a shortcode with the handler
* `remove_shortcode` - removes a shortcode registered with the handler
* `remove_all_shortcodes` - removes all shortcodes registered with the handler

It accepts any handler implementing the [`ShortcodesHandlerInterface`](https://github.com/deep-web-solutions/wordpress-framework-utilities/blob/master/src/includes/Shortcodes/ShortcodesHandlerInterface.php) and, just like the hooks service, comes with a default handler that first stores all registered shortcodes in an array and registers them with WP on the `run` action.

The similarities don't end there though! All the traits and interfaces mentioned for the hooks service are also available for the shortcodes service:

* [`ShortcodesServiceAwareInterface`](https://github.com/deep-web-solutions/wordpress-framework-utilities/blob/master/src/includes/Shortcodes/ShortcodesServiceAwareInterface.php) and [`ShortcodesServiceAwareTrait`](https://github.com/deep-web-solutions/wordpress-framework-utilities/blob/master/src/includes/Shortcodes/ShortcodesServiceAwareTrait.php) for a getter/setter pair
* [`ShortcodesServiceRegisterInterface`](https://github.com/deep-web-solutions/wordpress-framework-utilities/blob/master/src/includes/Shortcodes/ShortcodesServiceRegisterInterface.php) and [`ShortcodesServiceRegisterTrait`](https://github.com/deep-web-solutions/wordpress-framework-utilities/blob/master/src/includes/Shortcodes/ShortcodesServiceRegisterTrait.php) for injecting the service externally
* [`InitializeShortcodesTrait`](https://github.com/deep-web-solutions/wordpress-framework-utilities/blob/master/src/includes/Actions/Initializable/InitializeShortcodesServiceTrait.php) for automagically setting the instance on the objec
* [`SetupShortcodesTrait`](https://github.com/deep-web-solutions/wordpress-framework-utilities/blob/master/src/includes/Actions/Setupable/SetupShortcodesTrait.php) for automagically calling the `register_shortcodes` method on setup


# Templating Service

The templating service is the only service that does NOT use a handler. That might change in the future if we decide to support different templating systems like Twig, but for now we only plan to support WordPress' templating system for the time being.

It's a smart wrapper around WordPress' own `locate_template` and `load_template` functions inspired by WooCommerce's own methods for this purpose. There are 5 public methods:

* `load_template_part` - for loading parts of a larger template file
* `load_template` - for loading a whole template file
* `locate_template` - for figuring out which template was used; theme overrides take priority to the plugin's default files
* `get_template_html` - for returning the HTML content of a template file as string
* `get_template_part_html` - for returning the HTML content of a template part file as string

This service is supposed to offer an easy way to support WordPress best practices when it comes to loading template files. That means giving first priority to the child theme, and then to the template theme, before loading the plugin's bundled file and providing enough hooks all around for extending the service.

If you're new to WP templating, we recommend you [read the Codex](https://codex.wordpress.org/Templates) for more information. Of particular interest is [this article about the template hierarchy](https://developer.wordpress.org/themes/basics/template-hierarchy/).


# Assets Service

The assets service is an example [of a multi-handler service](/foundations-module/utilities/handlers-and-services). WordPress differentiates between two types of assets: scripts (JS files) and styles (CSS files). The service itself *tries* to be as agnostic as possible of this in order to let you build handlers for other types of assets as well.

However, the WP scripts API is similar but slightly different from the WP styles API. Trying to find a common denominator was not easy -- the only thing the two have in common is the hook that they should be enqueued on! For this reason, the Assets Service is unique because *it **doesn't** have any public method and most interactions happen at the handler level*. The basic function of the service, therefore, is to act as a container for the assets handlers and to call their `run` action method on the proper hook.

As you probably guessed by now, the assets handlers need to inherit the [`AssetsHandlerInterface`](https://github.com/deep-web-solutions/wordpress-framework-utilities/blob/master/src/includes/Assets/AssetsHandlerInterface.php) interface. Because of no unified WordPress API for working with assets, the interface doesn't implement any methods and simply acts as a way to validate handlers registered with the service.

There are 2 handlers that come pre-packaged with the module:

* The [`ScriptsHandler`](https://github.com/deep-web-solutions/wordpress-framework-utilities/blob/master/src/includes/Assets/Handlers/ScriptsHandler.php) for working with the WP scripts API
* The [`StylesHandler`](https://github.com/deep-web-solutions/wordpress-framework-utilities/blob/master/src/includes/Assets/Handlers/StylesHandler.php) for working with the WP styles API

Both of them behave similarly to the [default hooks handler](/utilities-module/hooks-service) and to the [default shortcodes handler](/utilities-module/shortcodes-service), namely they store the scripts and styles to be registered and enqueued in their own arrays, respectively, until the `run` action method is called on the handler instance. This ensures that errors during the plugin's initialization prevent the service from enqueueing any extraneous asset files.

The handlers perform two crucial tasks automatically though:&#x20;

* cache busting based on the file's last modified time
* automagically enqueueing the minified version, if it exists

Basically, both handlers look at the registered assets and look for a file containing the notorious `.min` extension at the same location. If said file is present and the constant `SCRIPT_DEBUG` is not set to true, the minified file will be enqueued instead. Moreover, the file's version will be the output of the [`filemtime`](https://www.php.net/manual/en/function.filemtime.php) function. If that fails, it falls back to a given fallback version.

{% hint style="info" %}
For assets enqueued from a CDN (or, in general, an external URL), the given version string is used by default instead.
{% endhint %}

### Working with the service

As mentioned above, the assets service is unique as being the only service that delegates most of the work to its handlers. Therefore, it's recommended to use one of the 3 setup traits in order to get the singleton handler instance automagically:

* the `SetupStylesTrait` for calling the `register_styles` method on setup
* the `SetupScriptsTrait` for calling the `register_scripts` method on setup
* the `SetupScriptsStylesTrait` for calling the `register_scripts_and_styles` method on setup

The coding example is similar to the one presented on the [Hooks Service](/utilities-module/hooks-service) page.


# Scripts Handler

[The scripts handler](https://github.com/deep-web-solutions/wordpress-framework-utilities/blob/master/src/includes/Assets/Handlers/ScriptsHandler.php) exposes the following public methods:

* `register_public_script` for adding a script to the internal frontend registration queue
* `deregister_public_script` for removing a script from the internal frontend registration queue
* `enqueue_public_script` for adding a script to the internal frontend enqueueing queue
* `dequeue_public_script` for removing a script from the internal frontend enqueueing queue
* `register_admin_script` for adding a script to the internal admin-side registration queue
* `deregister_admin_script` for removing a script from the internal admin-side registration queue
* `enqueue_admin_script` for adding a script to the internal admin-side enqueueing queue
* `dequeue_admin_script` for removing a script from the internal admin-side enqueueing queue
* `add_inline_script` for registering a JS string to be outputted before or after another enqueued file
* `localize_script` for including a JS object variable to be outputted before another enqueued file is

The methods follow almost 1-to-1 the WP scripts API, in particular the [`wp_register_script`](https://developer.wordpress.org/reference/functions/wp_register_script/) function, the [`wp_enqueue_script`](https://developer.wordpress.org/reference/functions/wp_enqueue_script/) function, the [`wp_add_inline_script`](https://developer.wordpress.org/reference/functions/wp_add_inline_script/) function, and the [`wp_localize_script`](https://developer.wordpress.org/reference/functions/wp_localize_script/) function.

{% hint style="info" %}
The `register_admin_script` and `enqueue_admin_script` methods accept a specialized argument `$hook_suffixes`. By default it's `null`, but it can be set to an array to conditionally register/enqueue the scripts only when the global variable `$hook_suffix` is set to one of the values.
{% endhint %}

As mentioned on the [Assets Service](/utilities-module/assets-service) page, the handler will automatically attempt to register/enqueue the minified version of your script (if it exists in the same folder and has the `.min.js` extension) and will attempt to set the file version to the result of the PHP `filemtime` function.

{% hint style="info" %}
For assets being loaded from an external URL, the `$fallback_version` argument will be used by default instead of trying to call `filmemtime` on the script.
{% endhint %}


# Styles Handler

[The styles handler](https://github.com/deep-web-solutions/wordpress-framework-utilities/blob/master/src/includes/Assets/Handlers/StylesHandler.php) exposes the following public methods:

* `register_public_style` for adding a style to the internal frontend registration queue
* `deregister_public_style` for removing a style from the internal frontend registration queue
* `enqueue_public_style` for adding a style to the internal frontend enqueueing queue
* `dequeue_public_style` for removing a style from the internal frontend enqueueing queue
* `register_admin_style` for adding a style to the internal admin-side registration queue
* `deregister_admin_style` for removing a style from the internal admin-side registration queue
* `enqueue_admin_style` for adding a style to the internal admin-side enqueueing queue
* `dequeue_admin_style` for removing a style from the internal admin-side enqueueing queue
* `add_inline_style` for registering a CSS string to be outputted before or after another enqueued file

The methods follow almost 1-to-1 the WP scripts API, in particular the [`wp_register_style`](https://developer.wordpress.org/reference/functions/wp_register_style/) function, the [`wp_enqueue_style`](https://developer.wordpress.org/reference/functions/wp_enqueue_style/) function, and the [`wp_add_inline_style`](https://developer.wordpress.org/reference/functions/wp_add_inline_style/) function.

{% hint style="info" %}
The `register_admin_style` and `enqueue_admin_style` methods accept a specialized argument `$hook_suffixes`. By default it's `null`, but it can be set to an array to conditionally register/enqueue the scripts only when the global variable `$hook_suffix` is set to one of the values.
{% endhint %}

As mentioned on the [Assets Service](/utilities-module/assets-service) page, the handler will automatically attempt to register/enqueue the minified version of your script (if it exists in the same folder and has the `.min.css` extension) and will attempt to set the file version to the result of the PHP `filemtime` function.

{% hint style="info" %}
For assets being loaded from an external URL, the `$fallback_version` argument will be used by default instead of trying to call `filmemtime` on the script.
{% endhint %}


# CRON Events Service

The CRON Events Service is again [a multi-handler service](/foundations-module/utilities/handlers-and-services) that exhibits a `run` [action method](/foundations-module/actions). A CRON event is an event that should happen at a particular point in time -- like literally when the real clocks of the world reach a certain point. This service is designed to work with such events and it provides the following public methods:

* `schedule_single_event`&#x20;
* `unschedule_single_event`&#x20;
* `schedule_recurring_event`
* `unschedule_recurring_event`

The method names should be pretty self-explanatory. A single event is one that should happen exactly once at a given point in time while a recurring event is one that should happen with some regularity, like every hour or every day. If you're unfamiliar with the concept, we recommend reading [the WordPress Developer documentation on this topic](https://developer.wordpress.org/plugins/cron/).

Setting up a CRON event requires you to make a few conscious decisions, but we've tried to simplify the process by providing some helpful defaults. For example, for both types of events you need to provide a UNIX timestamp as to when the first (and maybe only) event should take place. If you simply omit this value, the service will default to next midnight based on the website's timezone.

Similarly, for recurring events you need to provide a recurrence value. WordPress provides some default values like `daily`, `twicedaily`, or `weekly`, but that might not cover your specific use-case. To help with this, you can simply make use of our [`CronIntervalsEnum`](https://github.com/deep-web-solutions/wordpress-framework-utilities/blob/master/src/includes/CronEvents/CronIntervalsEnum.php) enum. This will provide you with more recurrence values which, when used together with our service, will automagically handle everything in the background for WordPress to understand what you mean.

Obviously, being a handler service, the service expects to have at least one handler registered. It accepts handlers implementing the [`CronEventsHandlerInterface`](https://github.com/deep-web-solutions/wordpress-framework-utilities/blob/master/src/includes/CronEvents/CronEventsHandlerInterface.php) interface. There are two handlers that the module comes pre-packaged with, and one of them gets registered by default (so if you omit to provide any handler whatsoever, there will be a default one set up automagically).

As you might expect, the default handler used the WordPress API. You can check out how it works [here](https://github.com/deep-web-solutions/wordpress-framework-utilities/blob/master/src/includes/CronEvents/Handlers/DefaultCronEventsHandler.php) and you can read more about scheduling events with WordPress CRON API [here](https://developer.wordpress.org/plugins/cron/scheduling-wp-cron-events/).

### How to use the service

Just like with all the services so far, the recommended method is using the setup action trait, [`SetupCronEventsTrait`](https://github.com/deep-web-solutions/wordpress-framework-utilities/blob/master/src/includes/Actions/Setupable/SetupCronEventsTrait.php). You don't have to though and you're free to use any of the other traits and interfaces provided in the CRON Events namespace [here](https://github.com/deep-web-solutions/wordpress-framework-utilities/tree/master/src/includes/CronEvents).


# Action Scheduler Handler

Apart from the default WordPress handler, the utilities package provides a CRON Events Handler for working with the famous Action Scheduler library of WooCommerce. You can read more about the library [here](https://actionscheduler.org/).

{% hint style="info" %}
This handler is not part of the WooCommerce Module simply because it's possible to use the Action Scheduler library *outside* of WooCommerce.
{% endhint %}

In order to work with it, you should register it with your CRON Events Service like this:

```php
<?php

use DeepWebSolutions\Framework\Utilities\CronEvents\CronEventsService;
use DeepWebSolutions\Framework\Utilities\CronEvents\Handlers\ActionSchedulerCronEventsHandler;

$as_handler = new ActionSchedulerCronEventsHandler( 'my-handler-id' );

// you can register the handler in the constructor...
$cron_service = new CronEventsService( $my_plugin, $my_logging_service, $my_hooks_service, array( $as_handler ) );
// ...or alternatively you can also do this
$cron_service->register_handler( $as_handler );

// now to use it ... if you set your handler's ID to 'default', you can skip the last argument
$cron_service->schedule_single_event( 'my-hook', null, array(), 'my-handler-id' );

```


# Admin Notices Service

The Admin Notices Service is again [a multi-handler service](/foundations-module/utilities/handlers-and-services) but this time it implements the `output` [action method](/foundations-module/actions). If you've used WordPress before, you've probably come across admin notices before such as the ones exemplified [in this article](https://digwp.com/2016/05/wordpress-admin-notices/). This service attempts to standardize the registration and output of those notices,

This service is probably the most complicated one we have so it will be a bit of a challenge to explain how it works, but we'll try our best. The first thing you should understand is that notices have different flavors. A notice is actually quite a complicated abstraction -- at a minimum it has a type (supported notice types are stored comfortably in the [`AdminNoticeTypesEnum`](https://github.com/deep-web-solutions/wordpress-framework-utilities/blob/master/src/includes/AdminNotices/AdminNoticeTypesEnum.php) class) and a text. We'll call those simple notices. A notice, however, can also be dismissed by the user. Those are dismissible notices. These are the 2 types of notices [supported by default ](https://github.com/deep-web-solutions/wordpress-framework-utilities/tree/master/src/includes/AdminNotices/Notices)but you can create your own custom notice by simply implementing the [`AdminNoticeInterface`](https://github.com/deep-web-solutions/wordpress-framework-utilities/blob/master/src/includes/AdminNotices/AdminNoticeInterface.php) interface.

Each notice type has a corresponding handler. Simple notices need a handler that is simply capable of outputting their HTML whereas dismissible notices require a handler that can *handle* the dismiss request. Subsequently those are the two handlers pre-packaged with the module ([here](https://github.com/deep-web-solutions/wordpress-framework-utilities/tree/master/src/includes/AdminNotices/Handlers)), but you can always implement your own by implementing the [`AdminNoticesHandlerInterface`](https://github.com/deep-web-solutions/wordpress-framework-utilities/blob/master/src/includes/AdminNotices/AdminNoticesHandlerInterface.php) interface.

As you might've guessed, by default, both handlers are automagically registered with the service on instantiation. If you've looked over the code so far, you probably noticed that multi-handler services use[ a memory store](/foundations-module/utilities/stores) for storing the registered handlers. The admin notices service does that too, but the memory store is actually 2-dimensional this time! That is because on top of the handlers, the service also keep a list of [stores](/foundations-module/utilities/stores) and registers by default a memory store (`dynamic`), an options store (`options`), and a user-meta store (`user-meta`).

That is because notices have different scopes and lifecycles. For example, an error notice for an employee that tried to perform an action (s)he is not authorized could be stored in the dynamic store if it's not that important and should disappear on next page load **or** it could be stored in the user-meta store if it's dismissible and needs to stick around until the user has actively dismissed it.

Another example will become clear when we dig deeper into [the dependencies service](/utilities-module/dependencies-service). Certain dependencies are mandatory (like WooCommerce being active for a WooCommerce extension plugin) or they could be optional (like a recommendation for certain PHP settings). Mandatory dependencies need to be checked on every request so these notices are probably simply stored in the memory store and added again on each request. Optional dependencies, however, would output a *dismissible* notice and will **not** prevent the plugin [from being active](/foundations-module/states) if an admin has dismissed said notice. Therefore, these notices would go into the options store and be shared by all admins -- if one dismisses it, it's dismissed for all.

The admin notices service provides the following public methods:

* `add_notice` for adding a notice to a given store
* `get_notice` for retrieving a notice from a given store
* `update_notice` for updating a notice in a given store
* `remove_notice` for removing a notice from a given store

The output of the notices happens on the WP hook `admin_notices`. For obvious reasons, the methods `update_notice` and `remove_notice` don't do much after the aforementioned hook is executed.

### How to use the service

The recommended way is by using the [`SetupAdminNoticesTrait`](https://github.com/deep-web-solutions/wordpress-framework-utilities/blob/master/src/includes/Actions/Setupable/SetupAdminNoticesTrait.php) setup trait. You are free, however, to make use of any traits and interfaces available [in the admin notices namespace](https://github.com/deep-web-solutions/wordpress-framework-utilities/tree/master/src/includes/AdminNotices).


# Dependencies Service

The dependencies service is [a multi-handler service](/foundations-module/utilities/handlers-and-services) with no implemented [action methods](/foundations-module/actions). The purpose of this service is to provide a unified way of checking whether dependencies are fulfilled or not. It provides the following public methods:

* `get_dependencies` for retrieving a list of dependencies from a given handler
* `get_missing_dependencies` for retrieving a list of missing dependencies from a given handler
* `are_dependencies_fulfilled` for retrieving a list of boolean values determining whether the dependencies of a given handler are fulfilled or not

You must be used by now to the fact that every service has its quirks. In the case of the dependencies service, the quirk is that it has no default handlers because each handler is supposed to be tied to a particular class instance.

Dependency handlers all implement the [`DependenciesHandlerInterface`](https://github.com/deep-web-solutions/wordpress-framework-utilities/blob/master/src/includes/Dependencies/DependenciesHandlerInterface.php) and are in essence little more than containers for dependency checkers. Dependency checkers, in turn, all implement the [`DependenciesCheckerInterface`](https://github.com/deep-web-solutions/wordpress-framework-utilities/blob/master/src/includes/Dependencies/DependenciesCheckerInterface.php) interface.

Let's start from the bottom-up. The utilities module comes pre-packaged with 4 dependencies checker. They are [here ](https://github.com/deep-web-solutions/wordpress-framework-utilities/tree/master/src/includes/Dependencies/Checkers)and, in no particular order, provide checking for the following types of dependencies: [PHP extensions](https://github.com/deep-web-solutions/wordpress-framework-utilities/blob/master/src/includes/Dependencies/Checkers/PHPExtensionsChecker.php), [PHP functions](https://github.com/deep-web-solutions/wordpress-framework-utilities/blob/master/src/includes/Dependencies/Checkers/PHPFunctionsChecker.php), [PHP settings](https://github.com/deep-web-solutions/wordpress-framework-utilities/blob/master/src/includes/Dependencies/Checkers/PHPIncompatibleSettingsChecker.php), and [WP plugins](https://github.com/deep-web-solutions/wordpress-framework-utilities/blob/master/src/includes/Dependencies/Checkers/WPPluginsChecker.php).

At its core, a checker accepts a list of dependencies (each checker might have a different format) and knows how to check whether said dependencies are fulfilled or not. Calling `get_missing_dependencies` on a checker will return a list of unfulfilled dependencies and calling `are_dependencies_fulfilled` will return a simple boolean value answering the question.

Continuing with the handlers, the module comes pre-packaged with 2 handlers. The so-called [single-checker handler](https://github.com/deep-web-solutions/wordpress-framework-utilities/blob/master/src/includes/Dependencies/Handlers/SingleCheckerHandler.php) and the so-called [multi-checker handler](https://github.com/deep-web-solutions/wordpress-framework-utilities/blob/master/src/includes/Dependencies/Handlers/MultiCheckerHandler.php). As their names suggest, the former can store one checker whereas the latter can store multiple checkers. This is a necessary abstraction for supporting the services model.

The difference between the two is that most functions of the single-checker handler will return an array whereas the same functions of the multi-checker handler will return a matrix.

{% hint style="warning" %}
It might come as a surprise to find out the the method `are_dependencies_fulfilled` of the single-checker handler returns an array with a single entry instead of a simple boolean value. This is done for consistency with the multi-checker handler.
{% endhint %}

### How to use the dependencies service

The dependencies service comes with two traits that try to automagically set things up for you. For example, the [`InitializeDependenciesHandlersTrait`](https://github.com/deep-web-solutions/wordpress-framework-utilities/blob/master/src/includes/Dependencies/Actions/InitializeDependenciesHandlersTrait.php) trait lets you define a protected `get_dependencies_handlers` method inside your class and its output will be automagically registered with the dependencies service on initialization.

Similarly [the Dependencies/States namespace](https://github.com/deep-web-solutions/wordpress-framework-utilities/tree/master/src/includes/Dependencies/States) contains two traits that let you automagically turn an instance inactive or disabled based on registered dependencies handlers.

Last but not least, the [`SetupDependenciesAdminNoticesTrait`](https://github.com/deep-web-solutions/wordpress-framework-utilities/blob/master/src/includes/Dependencies/Actions/SetupDependenciesAdminNoticesTrait.php) trait goes a step further and will automagically register appropriate admin notices for dependency handlers that influence the activation state of an instance.

{% hint style="warning" %}
Watch out for the `SetupDependenciesAdminNoticesTrait` trait! It uses the `SetupableInactiveTrait` which will cause your instance to setup even if inactive. You need to design your code around this.
{% endhint %}


# Validation Service

The validation service is again [a multi-handler service](/foundations-module/utilities/handlers-and-services) with no [action methods](/foundations-module/actions). Its purpose is to standardize validating a value against a given type and a known default before using it in your code. It provides these public methods:

* `validate_value` which is just a central hub for calling the other methods
* `validate_boolean_value` for turning a value into a boolean or returning the default
* `validate_integer_value` for turning a value into an integer or returning the default
* `validate_float_value` for turning a value into a float or returning the default
* `validate_callback_value` for checking whether a value is a valid callback or returning the default
* `validate_supported_value` for checking whether a value is part of a supported list of values or returning the default

As you're probably expecting by now, all of these methods simply pass on the parameters to a given handler. The handler is free to decide what to do with those values -- the only non-negotiable aspect of this all is the return type of the validation operation. A boolean validation must return a boolean value.

There is just one type of handler pre-packaged with the module and that is the so-called [container validation handler](https://github.com/deep-web-solutions/wordpress-framework-utilities/blob/master/src/includes/Validation/Handlers/ContainerValidationHandler.php). Basically this handler expects to be provided with a PSR-11-compatible container that contains exactly two 2 keys: `defaults` and `options`. Both keys should store an array. The former array is used for returning the default values and the latter for checking for supported options (for the supported value validation). The actual type validation is performed using the validation helpers from [the Helpers Module](/helpers-module/motivation).

If you need a different logic, you may use your own custom handler that implements the [`ValidationHandlerInterface`](https://github.com/deep-web-solutions/wordpress-framework-utilities/blob/master/src/includes/Validation/ValidationHandlerInterface.php) interface.


# Motivation and How to use

The module is available for free installation through [Composer](/key-concepts-and-dev-tools/dependency-management-composer) [on Packagist](https://packagist.org/packages/deep-web-solutions/wp-framework-core).

{% hint style="danger" %}
As of April 2021, the Core Module is still considered in beta. Beta modules don't have automated tests yet and can change significantly until the release. However, the overall structure is clear and done. You may use it but it might be wise to keep an eye out for undocumented changes.
{% endhint %}


# Plugin Tree


# Plugin Root


# Plugin Functionality


# Plugin Components


# Internationalization


# Installation / Upgrade / Uninstallation


# Motivation and How to use

The module is available for free installation through [Composer](/key-concepts-and-dev-tools/dependency-management-composer) [on Packagist](https://packagist.org/packages/deep-web-solutions/wp-framework-settings).

{% hint style="danger" %}
As of April 2021, the Settings Module is still considered in beta. Beta modules don't have automated tests yet and can change significantly until the release. However, the overall structure is clear and done. You may use it but it might be wise to keep an eye out for undocumented changes.
{% endhint %}


# Settings Service


# WordPress Handler


# MetaBox Handler


# ACF Handler


# Validated Settings


# Motivation and How to use

The module is available for free installation through [Composer](/key-concepts-and-dev-tools/dependency-management-composer) [on Packagist](https://packagist.org/packages/deep-web-solutions/wp-framework-woocommerce).

{% hint style="danger" %}
As of April 2021, the WooCommerce Module is still considered in beta. Beta modules don't have automated tests yet and can change significantly until the release. However, the overall structure is clear and done. You may use it but it might be wise to keep an eye out for undocumented changes.
{% endhint %}


# Extended WC Logger


# WC Settings Handler


