Using Bedrock / Capistrano with a custom plugin that uses composer and PSR-4 autoloading

I’m using Bedrock with Capistrano to deploy. All is well. Most of my WP plugins are included as dependencies in composer.json. Some of the plugins I needed were unavailable on wpackagist, so I either included them as git subtrees and then added exceptions to gitignore so they’d be included in the repo (probably a better way to do this?), or just added the source and then added the exception in gitignore.

I have one custom plugin though, and I am using Composer with PSR-4 autoloading. This plugin sits in web/app/plugins/plugin-name/ and it has its own composer.json. When I deploy with capistrano, nothing works until I manually go into this plugin’s directory and run composer update, presumably because the vendor directory and the autoloading functionality isn’t being deployed along with the rest of the plugin.

How can I accomplish this? A site built with Bedrock, deployed with Capistrano, containing a custom plugin which itself uses Composer and PSR-4 autoloading.

Sorry in advance if this is glaringly obvious and I’ve missed something I shouldn’t have, and let me know if there’s anything I need to clarify on or anything.

As mentioned above, I’m pretty sure there is a better way to handle those plugins I’m using which are not available within wpackagist, but which are available on github. I’d like to address this issue and figure out the correct way to include them (rather than just adding them as a git subtree and then adding an exception within gitignore as I am now), but my primary concern is figuring out what to do about this custom plugin I’ve written which is using PSR-4 and Composer, as it is preventing me from being able to do a one-step deploy with Capistrano since I have to manually go into the plugin’s directory and run composer update each time I deploy.

Well shit, I got it working… Somehow. Which is kinda the worst type of “got it working”.

I pulled the plugin out of my main bedrock project, created its own git repo for it. Then in bedrocks composer.json I added the (bitbucket) git repo to the repositories, and added it to the requires.

At that point, I was still running into the issue with the autoload not working, and this is where I’m a bit confused. I’m guessing that the fix was to remove the vendor dir from git ignore on my plugin repo.

At any rate, it seems to be working now. I’ve included the plugin via composer.json, and am able to use Capistrano to deploy and it works without having to manually run composer install within the plugin dir. Unfortunately, I have a project to finish so I’m gonna have to leave it at that for now. However, if anyone else runs into a similar issue feel free to reply and I’ll certainly look further into it when I am able to.

Also, if anyone happens to know what I did “right” to get it working and/or how I should be doing this, I’d love to know for the future.

In my opinion, that’s the correct solution. If you have a library/package with its own dependencies then it should be included in your main composer.json as an external dependency.

If you wanted to keep it as part of your site/Bedrock project, I’d just move that plugin’s requires/dependencies to the main project’s composer.json and take advantage of the global autoload.

1 Like

Thanks for the insight. What I have now feels correct to me, for what that’s worth lol. My plugin doesn’t actually have any dependencies; I’m only using composer for the PSR-4 autoloading. Is that a mistake? The overhead of having a composer.json seems minimal, and I basically just prefer to do things this way lately.

I have a nifty sublime text package that auto-corrects some PSR issues and notifies me of the rest, and then I have the SublimeLinter extension that also notifies me of PSR issues, which has made it pretty easy to just follow all of the PSR standards when developing something.

As far as the autoloading itself is concerned, I’ve been trying to adhere to best practices and follow an object oriented approach during development which means I end up creating classes for stuff (I’m trying to actually follow OOP principles rather than just stuffing procedural/functional code into classes), and so the autoloading functionality has been pretty nice to have.

I digress (majorly)… Given that my plugin does not in fact have any dependencies, does it still make sense to include it the way I am (as a composer package hosted in its own bitbucket repo and then required in the main project composer.json)? I’m leaning towards yes, if only because I really can’t see any other way to avoid the aforementioned issue where I was having to manually run composer update in the plugin directory after deploying with Capistrano.

I had the same issue lately. I created a custom plugin with several dependencies. My approach was to normally create composer.json in the custom plugin, specifying its name and type: "wordpress-plugin". After that, I’ve also added composer/installers as a dependency to that custom plugin. For example this is the custom plugin’s composer.json

{
    "name": "lamosty/blog-helper",
    "type": "wordpress-plugin",
    "authors": [
        {
            "name": "Rastislav Lamos",
            "email": "lamos.rasto@gmail.com"
        }
    ],
    "require": {
        "lamosty/wp-plugin-stack": "~1.0",
        "composer/installers": "1.0.21"
    },
    "autoload": {
        "psr-4": {
            "Lamosty\\Blog_Helper\\": "src/"
        }
    }
}

As you can see, I’m also using psr-4 autoloading feature of composer. However, you can’t simply do

require_once( 'vendor/autoload.php');

in your custom plugin’s main PHP file because if the plugin is specified as your main project’s (Bedrock) dependency, composer install won’t run in the custom plugin’s directory so no vendor folder is created. What composer does is to look into your custom plugin’s composer.json, see for its dependencies (in my case

 "lamosty/wp-plugin-stack": "~1.0",
 "composer/installers": "1.0.21"

) and resolve these dependencies into the global vendor folder located in the root of your Bedrock site. That’s why I’ve changed my custom plugin’s main PHP file to be as:

$autoload_path = __DIR__ . '/vendor/autoload.php';

if ( file_exists( $autoload_path ) ) {
    require_once( $autoload_path );
}

So, before loading local vendor/autoload.php, it detects that there is no such a file. It doesn’t matter because the Bedrock’s vendor autoloader is in use (looking into web/wp-config.php we can see require_once(dirname(__DIR__) . '/vendor/autoload.php');) and our custom plugin will be able to autoload your classes in its src folder just fine.

I also recommend putting your custom plugin on a GitHub repo (or Bitbucket) and adding it to the Packagist.org. If the plugin is too private, just use the custom repo composer’s functionality as you’ve done.

4 Likes

I’m taking the same approach right now.

My problem is something i assume you must have sorted out:

Project is “live” on a staging server, including the plugin (installed via composer).
Plugin is still under development but locally linked as a symlink
Deployment happens via Capistrano
My Problem: I need to add the plugin and its repo in the main projects composer.json so it gets deployed right onto the staging server. On the other hand i don’t want composer to overwrite my local symlink every time i run composer update.

Is there a easy way for this? I assume that im not the first person having this issue.
Im also aware that this is not necessarily a Herbert Issue.

Thanks for you best practices!

If you’re using Trellis or some kind of VM setup for development, you can mount the plugin onto the VM at their proper location, rather than symlinking it locally. That’s how I get around this issue.

The other possibility is to use --prefer-source in your composer update step and just develop right out of the composer-installed directory (if that’s an acceptable approach for you).

Side question: you’re using Herbert? What do you think about it? I like the idea, but -1 for 5.4+ only and -1 for using its own DB connection, personally.

1 Like

Actually im not using Vagrant at the Moment (tough i should). So mounting is not an option right now.

Wow. Its as easy as that. Of course --prefer-source works…i guess. Going to try that right now.

About Herbert:

Yes, i’m using it and i consider it pretty powerful. Only 5.4+ isn’t a downside to me, since for reasons of performance and security i don’t see any reasons for using < 5.4 in any newly developed applications. If you are of course developing for the masses that might be a downside. But even in that case, it would for me be more like a -0.1 =)

About the DB connection: Working with the doctrine layer for custom usecases is just way more powerful than any “shitty” working around the WP database layer to me. Also it has two big advantages: Being independent from Wordpress’ changing database structure (tough they always have good legacy support). AND: The Code you write is reusable in any other type of framework using Doctrine and the Symfony essentials (such as Symfony of course, Drupal, Silex etc.) which makes you more flexible in terms of reusing solid code for different cases.

+: Automatic officially recommends PHP 5.6 for runnig Wordpress.

Edit: --prefer-source works fine so far!

So you’ve been using Herbert primarily to build WordPress applications, rather than for plugins you’ve been distributing? That makes more sense, if you’ve have full control over the environment; I wonder how well it would work (if at all) for distributed plugins.

Also curious if you’ve tried Themosis. Both seem like they’re trying to import Laravel-y ideas into a WordPress context. Did you start as a WordPress developer or start outside WordPress (Symphony, etc) before you started using Herbert?