Download the PHP package snicco/better-wp-hooks without Composer

On this page you can find all versions of the php package snicco/better-wp-hooks. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.

FAQ

After the download, you have to make one include require_once('vendor/autoload.php');. After that you have to import the classes with use statements.

Example:
If you use only one package a project is not needed. But if you use more then one package, without a project it is not possible to import the classes with use statements.

In general, it is recommended to use always a project to download your libraries. In an application normally there is more than one library needed.
Some PHP packages are not free to download and because of that hosted in private repositories. In this case some credentials are needed to access such packages. Please use the auth.json textarea to insert credentials, if a package is coming from a private repository. You can look here for more information.

  • Some hosting areas are not accessible by a terminal or SSH. Then it is not possible to use Composer.
  • To use Composer is sometimes complicated. Especially for beginners.
  • Composer needs much resources. Sometimes they are not available on a simple webspace.
  • If you are using private repositories you don't need to share your credentials. You can set up everything on our site and then you provide a simple download link to your team member.
  • Simplify your Composer build process. Use our own command line tool to download the vendor folder as binary. This makes your build process faster and you don't need to expose your credentials for private repositories.
Please rate this library. Is it a good library?

Informations about the package better-wp-hooks

BetterWPHooks - A 2022 redesign of the WordPress hooks system (PSR-14-compatible)

codecov Psalm Type-Coverage Psalm level PhpMetrics - Static Analysis PHP-Versions

BetterWPHooks is a small library that allows you to write modern, testable and object-oriented code in complex WordPress projects.

Table of contents

  1. Motivation
  2. Installation
  3. Usage
    1. Event listeners
    2. Dispatching events
    3. The Event interface
    4. Event subscribers
    5. Removing listeners
    6. Mapping events to core/third-party hooks
      1. Ensuring your event fires first
      2. Ensuring your event fires last
    7. Exposing (some of) your events to WordPress
    8. A better alternative to apply_filters
    9. Stopping event flow/propagation
  4. Testing
  5. Contributing
  6. Issues and PR's
  7. Security

Motivation

BetterWPHooks is a central component in the Snicco project and was developed because the [WordPress hook system]( ) suffers the following problems:

  1. You have no type-safety at all when using add_action and add_filter. Anything can be returned.
  2. An event (hook) should ideally be immutable, meaning that it can't be changed. Using apply_filters the original arguments are immediately lost as soon as the first callback is run.
  3. There is no proper place to define hooks and callbacks. Many developers default to putting hooks into the class constructor which is a bad solution for many reasons.
  4. Dependency injection is not supported. You can't lazily instantiate class callbacks.This leads to either massive pollution of the global namespace with custom functions, or instantiating all classes of a codebase on each and every request. Not quite performant.
  5. There is no way to define which hooks are for public usage and which one are internal to your codebase.
  6. It's extremely difficult to remove hooks that are registered as closures or object methods.
  7. It's very hard to test hooks without using additional test frameworks like WP_Mock or Brain Monkey . (mocking sucks)

While throwing in a quick action here and there is completely fine for small projects, for enterprise level projects or complex distributed plugins WordPress hooks become a maintenance and testability burden.

Installation

Usage

Creating an event dispatcher

By default, your event listeners (WordPress calls them hook callbacks) are assumed to be newable classes ($instance = new MyClass()).

Optionally (but strongly recommended), you can resolve your listeners using any PSR-11 container.


Event listeners

These are the valid ways to attach listeners to any event:


Dispatching events

Any event is dispatched by using the dispatch method on your WPEventDispatcher instance.

The dispatch method accepts any object. By default, the class name of the event will be used to determine the listeners that should be created and called.

Since BetterWPHooks is PSR-14 compliant, every call to dispatch will return the same object instance that was being passed.

You can create generic events on the fly if for some reason you don't want to create a dedicated event class: The first constructor argument of GenericEvent is the event name, the second one an array of arguments that will be passed to all listeners.


The Event interface

BetterWPHooks comes with an interface that you can use to fully customize the behaviour of your events.

Assuming the OrderCreated event implements this interface:

Your code would now look like this:


Event Subscribers

Instead of defining all your listeners using the listen method you can also implement the EventSubscriber interface and use the subscribe method on the WPEventDispatcher.


Removing event listeners

In most cases, your event dispatcher should be immutable after the bootstrapping phase of your application/plugin. If however you want to remove events/listeners you can do it like so:

If you want to prevent the removal of a specific listener you can implement the Unremovable interface. If an unremovable listener is being removed an CantRemoveListener exception will be thrown.


Mapping core and third party actions.

BetterWPHooks comes with a very useful EventMapper class. The EventMapper allows you transform WordPress core or other third-party actions/filters into proper event objects.

It serves as a thin layer in between your code and external hooks.

Mapped events MUST either implement MappedHook or MappedFilter

Implement MappedHook if you are mapping your event to and action, MappedFilter if you are mapping to a filter that expects are return value.

Utilizing the EventMapper, you get to keep all the benefits of BetterWPHooks like lazy-loading your listeners while still being able to interacts with third-party code the same way as before.

The shouldDispatch method on the MappedHook interface gives you great control over your event flow. If shouldDispatcher returns (bool) false all attached listeners will not be called.

This allows you to build highly customized and performant integrations with third-party code.

An example for mapping to an action:

(This event will only be dispatched if the user performing the order is logged in)

An example for mapping to a filter:

(This event will always be dispatched since we return true)

Ensuring your mapped event fires first

Using the mapFirst method on the EventMapper your event listeners will always be run before any other hook callbacks registered with WordPress.

Ensuring your mapped event fires last

Using the mapLast method on the EventMapper your event listeners will always be run after any other hook callbacks registered with WordPress. This is especially useful for filters where you want to control the final result.

Exposing (some of) your events to the WordPress hook system

The WordPress hook system is globally available. This is a problem. Both your code as a developer and for users who want to interact with the custom events created by your application/plugin.

There is no way to enforce which events are safe to rely upon and which events might disappear tomorrow because you refactored your code.

The ExposeToWP interface helps with this.

By default, every time you dispatch an event your internal listeners will be called first.

If the dispatched event object implements the ExposeToWP interface the event object will be passed to the WordPress hook system so that third-party developers can interact with your code within the scope that you define.

If the dispatched event object does not implement ExposeToWP it will not be available to WordPress hooks.

An example:

A better alternative to apply_filters

The PSR-14 meta documentation defines four common goals of an event system:

Most of the time using apply_filters in your code means that you want to enhance behaviour or allow other developers to customize the behaviour of your code. (Object enhancement)

apply_filters is not ideal for this as its return type is mixed. There is nothing stopping a third-party developer mistakenly returning (int) 0 when you are expecting (bool) false.

Event objects allow you to enforce type-safety so that you don't have to manually type-check the end-result of every filter.

Here is what we recommend and use in our code:


Stopping event flow/propagation

In some cases, it may make sense for a listener to prevent any other listeners from being called. In other words, the listener needs to be able to tell the dispatcher to stop all propagation of the event to future listeners (i.e. to not notify any more listeners).

In order for this to work your event object must implement the PSR-14 StoppableEventInterface.

An example:

Testing

BetterWPHooks comes with dedicated testing utilities for phpunit.

First, install:

This package should be installed as dev dependency with composer. It's not intended for production use.

Now, in your tests, you should wrap your configured WPEventDispatcher with the TestableEventDispatcher. How you do that depends on how you structured your codebase.

The TestableEventDispachter wraps the WPEventDispatcher and can make assertions about the dispatched events in your tests.

Furthermore, you can fake events so that they will not be passed to the real WPEventDispatcher.

The dispatch, listen, subscribe, remove methods will be proxied to the WPEventDispatcher. The following assertions methods are available.

Certain events can be faked like this:

Contributing

This repository is a read-only split of the development repo of the Snicco project.

This is how you can contribute.

Reporting issues and sending pull requests

Please report issues in the Snicco monorepo.

Security

If you discover a security vulnerability within BetterWPHooks, please follow our disclosure procedure.


All versions of better-wp-hooks with dependencies

PHP Build Version
Package Version
Requires php Version ^7.4|^8.0
ext-json Version *
snicco/better-wp-api Version ^2.0
snicco/event-dispatcher Version ^2.0
Composer command for our command line client (download client) This client runs in each environment. You don't need a specific PHP version etc. The first 20 API calls are free. Standard composer command

The package snicco/better-wp-hooks contains the following files

Loading the files please wait ....