wecodemore / wpstarter

Easily bootstrap whole site Composer packages for WordPress.
https://wecodemore.github.io/wpstarter/
MIT License
246 stars 35 forks source link

v3.0.0-beta.10: mu-plugins "monorepo" only gets first file installed? #125

Closed lkraav closed 1 year ago

lkraav commented 1 year ago

Describe the bug

I'm trying to design a WPS monorepo like

packages/mu-plugins/composer.json
packages/mu-plugins/mup-1.php
packages/mu-plugins/mup-2.php
...
composer.json
...
public/wp-content/mu-plugins
...
{
  ...
  "repositories": [
    {
      "type": "path",
      "url": "packages/mu-plugins"
    }
  ],
  ...
  "extra": {
    "installer-paths": {
      "public/wp-content/mu-plugins/muppets": [
        "icodemore/mu-plugins"
      ]
    }
  }

But only mup-1.php gets copied.

To Reproduce

Described above.

Expected behavior

It seems like WPS has the idea that mu-plugins are single-file / repo, but I feel like it could easily copy and load everything it finds. Because why not?

System (please complete the following information):

gmazzap commented 1 year ago

@lkraav WPS is not doing anything in your case, it is Composer that should symlink (not copy) your "path" repository. Composer resorts to copying when symlink fails for any reason. See docs

The local package will be symlinked if possible, in which case the output in the console will read Symlinking from ../../packages/my-package. If symlinking is not possible the package will be copied. In that case, the console will output Mirrored from ../../packages/my-package. Instead of default fallback strategy you can force to use symlink with "symlink": true or mirroring with "symlink": false option. Forcing mirroring can be useful when deploying or generating package from a monolithic repository.

Besides, if you use this approach, you have to require the MU plugins, and I don't see that.

So, your folder structure should look like this:

|-composer.json
|-public/
|-packages/
   |-mu-plugins/
       |-composer.json
       |-mup-1.php
       |-mup-2.php

The packages/mu-plugins/composer.json should be like this:

{
    "name": "lkraav/mu-plugins",
    "type": "wordpress-muplugin",
    "require": {
        "composer/installers": "^2.2"
    }
}

The /composer.json should be like this:

{
    "name": "lkraav/project",
    "type": "project",
    "repositories": [
        {
            "type": "path",
            "url": "./packages/mu-plugins"
        }
    ],
    "require": {
        "composer/installers": "^2.2",
        "lkraav/mu-plugins": "@dev"
    },
    "config": {
        "allow-plugins": {
            "composer/*": true
        }
    },
    "extra": {
        "installer-paths": {
            "public/wp-content/mu-plugins/": ["type:wordpress-muplugin"]
        }
    }
}

And then Composer should symlink everything in place on install. Note how WPS is not part of any of this, it is a pure-Composer thing.


That said.

If I understood correctly, you want to have your MU plugins in the same "project" repo, and let WPS symlink those for you in the right wp-content place.

Is that correct?

If so, WPS has a feature for it, is called "Content Development Path", and it works not only for MU plugins but also for plugins, themes, dropins, and languages (anything inside wp-content, hence the name).

Having a structure like this:

|-composer.json
|-public/
|-content-dev/
   |-mu-plugins/
       |-mup-1.php
       |-mup-2.php
   |- plugins/
       |-plugin-1/
           |-plugin.php
       |-plugin-2/
           |-plugin.php

WPS will symlink content-dev/mu-plugins/* inside public/wp-content/mu-plugins/*, and content-dev/plugins/* inside public/wp-content/plugins/*.

Of course, it will consider any customization you might have for the wp-content folder path.

Two options control this feature:

It seems the feature is not documented yet, but you can read the code here.

The code is here: https://github.com/wecodemore/wpstarter/blob/dev/src/Step/ContentDevStep.php

And the class doc block documents the feature a bit.

Please note: this is not a mono-repo. Because any composer.json in the content-dev folder would be symlinked (or copied), but it will not be considered, so dependencies will not be created, and autoload not be generated. For MU plugins, that should be a problem, I guess. But if you want to do monorepo for plugins, you should make the Composer path work for you.

lkraav commented 1 year ago

Thanks for the detailed write, but I think you might have been over-thinking this. :smile:

I figured out how to Xdebug composer plugins (hello non-obvious COMPOSER_ALLOW_XDEBUG=1), and discovered all I needed to do for my multi-mu-plugin single package, is add "Plugin Name" header to each individual mu-plugin.

https://github.com/wecodemore/wpstarter/blob/d6cfceac1cf6c0f1dd326279de95cc9bbc1a383b/src/Util/MuPluginList.php#L87-L103 apparently has different file collection logic paths for single- vs multi-mu-plugin packages.

Is this documented? I certainly wasn't able to find it without Xdebug. Perhaps this issue could be refactored and connected to a documentation upgrade PR?

gmazzap commented 1 year ago

WP Starter can't just load all PHP files in a package that declate itslef as a MU plugin.

Imagine you have a file that loads other files, if WP Starter would also load all files, there would be problems.

So WP Starter needs a way to determine which files to load and which not.

If there's only one PHP file in the root of the package, that's an easy choice :)

If the package contains multiple files, then WP Starter needs something to determine which files to load, and the only thing it can rely on is the plugin headers.

So if you have a package with multiple MU-plugins, you either put the plugin header on them, or you create an interal loader.

E.g. a file with:

<?php

/* Plugin Name: My MU-Plugins Collection */

forach (glob(__DIR__ . "/*.php" as $file)) {
   if ($file !== __FILE__) { // not load itself
       require_once $file;
   }
}

Now you can put this file in the same folder with a ton of other MU plugins. WP Starter will load this, and it'll do the rest.

And ,yes, maybe we can document all of this...

lkraav commented 1 year ago

And ,yes, maybe we can document all of this...

Yes, logic makes sense. For now, I went with Plugin Name headers, because they each had a description anyway.

https://github.com/wecodemore/wpstarter/blob/version-3/docs/05-WP-Starter-Steps.md#muloaderstep seems to be an appropriate location to add this information. I'll see if I can PR something.