How to integrate Composer in a WordPress plugin in WordPress

Contents

Why integrate Composer into a WordPress plugin?

Using Composer inside a WordPress plugin brings dependency management, modern autoloading (PSR-4), reproducible installs, and the ability to consume third-party libraries reliably. It enables you to keep plugin code modular and unit-testable, avoid reinventing utilities like HTTP clients or validation, and create a predictable build process. However, integration must be done carefully to avoid conflicts with other plugins and to make packaging for distribution seamless.

High-level approaches

  • Vendor the dependencies in the plugin — include the vendor directory inside the plugin and require vendor/autoload.php from your main plugin file. This is the simplest and most common approach for releasing to WordPress.org because WP.org updates do not run Composer.
  • Share dependencies at the site level — use a shared Composer-managed root for the entire site and place shared libraries in a central vendor. This can reduce duplicate copies but requires site-level Composer management and careful autoloader handling.
  • Package-only dev and build step — run Composer during development, then build a release artifact that bundles an optimized vendor and optionally scopes/prefixes dependencies to avoid conflicts (using tools like PHP-Scoper).

Prerequisites

  • PHP compatible with your dependencies (specify in composer.json with platform or require).
  • Composer installed locally or available via composer.phar. See https://getcomposer.org/.
  • Basic knowledge of WordPress plugin structure and PHP namespaces.

Step-by-step tutorial

1) Create plugin skeleton and enable namespacing

Decide on a namespace for your plugin — e.g., AcmeMyPlugin. Place PSR-4 classes under src/ and the plugin bootstrap/entry file in the plugin root (e.g., acme-my-plugin.php).

2) Create composer.json

At the plugin root create composer.json. Minimal example with PSR-4 and a third-party dependency (Guzzle):

{
  name: acme/acme-my-plugin,
  description: Acme My Plugin for WordPress,
  type: wordpress-plugin,
  require: {
    php: >=7.4,
    guzzlehttp/guzzle: ^7.0
  },
  autoload: {
    psr-4: {
      AcmeMyPlugin: src/
    }
  },
  config: {
    optimize-autoloader: true,
    sort-packages: true
  }
}

3) Add PHP class files (PSR-4)

Example file: src/Bootstrap.php


4) Main plugin file — require Composer autoloader

Create the plugin header and require vendor/autoload.php. Use an existence check so activation doesnt fatal if vendor is missing during development (but include vendor for production releases).

Composer vendor directory is missing. Run composer install.

} ) } // Bootstrap the plugin plugin = new AcmeMyPluginBootstrap() plugin->run()

5) Install dependencies locally

From the plugin root, run:

composer install

For production packaging use:

composer install --no-dev --prefer-dist --optimize-autoloader

6) Use third-party libraries

Example using Guzzle inside a service:

client = new Client([
            timeout => 10,
        ])
    }

    public function get(string url) {
        response = this->client->get(url)
        return (string) response->getBody()
    }
}

7) Optimize autoloader and classmap

For releases run:

composer dump-autoload -o

This generates an optimized classmap and reduces autoload overhead.

8) Exclude dev dependencies for release

When packaging for distribution, always run composer install --no-dev. WordPress.org will not run Composer during plugin updates, so your release must include the vendor directory.

Advanced topics and best practices

Avoiding dependency conflicts

Example: PHP-Scoper basic workflow

Add as dev dependency and run a build that prefixes vendor classes.

composer require --dev humbug/php-scoper
# Run after composer install and after files are in place
vendor/bin/php-scoper add-prefix AcmeMyPluginPrefix --output-dir build
# The build dir will contain a prefixed version of your plugin that you can zip and release.

Note: php-scoper has many configuration options. Test thoroughly since scoping can break code that relies on string-based class names or global symbols.

Conditional autoloading for performance

If parts of your plugin are only needed in admin or on specific requests, you can delay requiring heavy libraries until they are needed:

if ( is_admin() ) {
    require_once __DIR__ . /vendor/autoload.php
    // initialize admin-only services
}

But be careful: any class referenced before the autoloader is required will cause fatal errors. A common pattern is to do a lightweight bootstrap that registers a function to require the autoloader when needed.

Composer scripts and build tasks

Use composer scripts to automate building a packaged artifact:

{
  scripts: {
    build: [
      composer install --no-dev --prefer-dist --optimize-autoloader,
      rm -rf build/,
      cp -R . build/,
      vendor/bin/php-scoper add-prefix AcmeMyPluginPrefix --output-dir build_scoped
    ]
  }
}

WordPress-specific Composer packages

Packaging for WordPress.org

  1. Run composer install --no-dev --prefer-dist --optimize-autoloader.
  2. Ensure vendor/ is included in your plugin ZIP that you upload to the WordPress.org plugin repository.
  3. Do not rely on Composer being available on the target server bundle everything needed.
  4. Document plugin dependencies and recommended PHP version in the plugin header or README.

Common pitfalls and troubleshooting

Example plugin file tree

acme-my-plugin/
  • acme-my-plugin.php (main plugin file)
  • composer.json
  • composer.lock
  • vendor/ (bundled on release)
  • src/
    • Bootstrap.php
    • HttpService.php
    • ... other classes ...
  • readme.txt or README.md

Security considerations

Summary checklist before release

Quick reference commands



Acepto donaciones de BAT's mediante el navegador Brave 🙂



Leave a Reply

Your email address will not be published. Required fields are marked *