snicco/better-wp-api

This small package tries to solve the pain point of not being able to solve to scope code that references WordPress core code.

v1.9.0 2023-09-20 12:36 UTC

README

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

BetterWPAPI is a single class that contains proxy methods for some of the most use WordPress core methods.

It's meant to be used in distributed WordPress libraries and helps you to keep your library testable and scopable.

Table of contents

  1. Motivation
  2. Installation
  3. Usage
  4. Contributing
  5. Issues and PR's
  6. Security

Motivation

We developed this library for the WordPress related components of the Snicco project.

Directly interacting with core functions was problematic for us because:

  • Code becomes untestable without
    • a) booting the entire WordPress codebase or
    • b) using additional mocking frameworks (mocking sucks).
  • The code becomes really hard to scope using the de-facto standard tool PHPScoper.
  • Static analysers like Psalm and PHPStan go crazy over core functions.

If you can't relate to these issues, you probably don't need this library.

Edit: The scoping problem was solved, by us creating a command-line-programm that can be used to generate a list of all functions and classes in the entire WordPress core codebase. For now, the best example on how to use it is the scoper.inc.php configuration of the Google Web stories plugin.

Installation

composer require snicco/better-wp-api

Usage

This is the public API of BetterWPAPI. No public or protected methods will be added until a next major version.

The idea is to limit the interaction with WordPress core to this class.

This has worked very well for us in order to keep our code testable and scopable. You have a single class where you can see all interaction that your library has with core. During tests, you can then simply swap this class with a test double.

The important thing is that: All classes that need anything from WordPress must accept this class as a constructor dependency.

A simple example: (for a real example, check out the BetterWPMail component)

Assuming we have the following class:

use Snicco\Component\BetterWPAPI\BetterWPAPI;

class CSVImporter {

    public function __construct(BetterWPAPI $wp = null) {
        $this->wp = $wp ?: new BetterWPAPI();
    }
    
    public function import(string $file){
    
        if(!$this->wp->currentUserCan('import-csv')) {
            throw new Exception('Not authorized');
        }
        // import csv.
    }
    
}

This is how we use it in production code.

$importer = new CSVImporter();

$importer->import(__DIR__.'/orders.csv');

This is how we test the code. No bootstrapping WordPress needed.

class CSVImporterTest extends TestCase {

   /**
    * @test
    */
    public function that_missing_permissions_throw_an_exception() {
        
        $this->expectExceptionMessage('Not authorized');
        
        $wp = new class extends BetterWPAPI {
            public function currentUserCan():bool {
                return false;
            }
        }
        
        $importer = new CSVImporter($wp);
        $importer->import(__DIR__.'/test-users.csv');
    }

}

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 BetterWPAPI, please follow our disclosure procedure.