WordPress.org

Make WordPress Core

Opened 9 years ago

Last modified 8 hours ago

#22316 new enhancement

Plugin Dependencies (Yet Another Plugin Dependencies Ticket)

Reported by: Viper007Bond Owned by:
Milestone: 5.9 Priority: normal
Severity: normal Version: 3.4.2
Component: Upgrade/Install Keywords: dev-feedback has-patch
Focuses: Cc:

Description

Previously: #10190 #11308 #13296 and I'm sure many more

It's been a few years since we looked at plugin dependencies and this still seems to be a feature people really, really want, especially for shared functionality that isn't a plugin in itself. For example a PHP library that isn't popular enough to be in core but is popular enough to be bundled in multiple plugins.

A bunch of us sat down and talked about this at this year's WordPress Community Summit and there was a lot of enthusiasm for this type of functionality.

We didn't know about the existing tickets at the time but the general summary of what we came up with was this:

  • Plugins list WP.org slugs of their dependencies in their readme.txt, or perhaps better their plugin's header.
  • When you go to install a plugin via the plugin directory UI in the admin area, the WP.org API returns a list of dependencies along with the data about the plugin being installed. WP would say like "these following dependencies will also be installed". This means it's seamless to the user -- they install a plugin and the other plugin(s) that are needed get installed too.
  • No versioning support. It's too complicated and what if one plugin wants an older version of a dependency than another plugin does? If your plugin is listing another as a dependency, then it's your job to make sure it stays compatible with the latest version of the dependency. On the flip side, hopefully plugins that get listed as dependencies are made to be forwards and backwards compatible.
  • Probably not allowing the disabling of plugins that are dependencies while their dependents are active. This seems better than disabling the dependents when the dependency is disabled ("why did Foo get disabled? I only disabled Bar!").
  • On plugin re-activation or on activation of a plugin uploaded via FTP, make sure it's dependencies are already installed. If not, offer to install them. If installed but disabled, just enable them for the user.

So while the previous tickets were closed as wontfix in the past, I think this is worth taking another look at. A lot of planning and thought will be required though to get this right.

Attachments (2)

gravityforms-install-activate-deactivate-screen.png (91.5 KB) - added by pbiron 5 days ago.
gravityperks-install-activate-deactivate-screen.png (41.3 KB) - added by pbiron 5 days ago.

Download all attachments as: .zip

Change History (206)

#1 @batmoo
9 years ago

  • Cc batmoo@… added

#2 @danielbachhuber
9 years ago

  • Cc danielbachhuber added

#3 @mordauk
9 years ago

  • Cc pippin@… added

#4 @apeatling
9 years ago

  • Cc apeatling added

#5 @husobj
9 years ago

  • Cc ben@… added

#6 @DJPaul
9 years ago

  • Cc djpaul@… added

#7 @tollmanz
9 years ago

  • Cc tollmanz@… added

#8 @sc0ttkclark
9 years ago

  • Cc lol@… added

#9 @kraftbj
9 years ago

  • Cc bk@… added

#10 @blobaugh
9 years ago

  • Cc ben@… added

#11 @beaulebens
9 years ago

  • Cc beau@… added

#12 @boonebgorges
9 years ago

  • Cc boonebgorges@… added

I'm working on a project where we've built an implementation of plugin dependencies on top of scribu's solution. It includes versioning support, so that you can require a minimum or maximum version of a given plugin. We've also got support for auto-installing dependent plugins.

See https://github.com/cuny-academic-commons/commons-in-a-box/blob/master/admin/plugins-loader.php for the basic dependency stuff + versioning, and https://github.com/cuny-academic-commons/commons-in-a-box/blob/master/admin/plugin-install.php for the plugin installation/upgrade dependency logic.

#13 @williamsba1
9 years ago

  • Cc brad@… added

#14 @griffinjt
9 years ago

  • Cc thomasgriffinmedia@… added

#15 @goldenapples
9 years ago

  • Cc goldenapplesdesign@… added

#16 @nvwd
9 years ago

  • Cc nowell@… added

#17 @scribu
9 years ago

  • Cc scribu added

#18 @sabreuse
9 years ago

  • Cc sabreuse added

#19 @griffinjt
9 years ago

On the topic of versioning dependencies, I discussed this at length with a friend of mine who is a PHP/Java developer and we came up with this: https://github.com/bubba-h57/PHP-Library-Version-Framework. Using namespaces plus a factory was the only viable way we could find to fix the issue of class version dependencies, but that can't even be considered until WordPress support PHP 5.3 and most plugin devs won't be able to implement something like it.

While I think header comments are nice, I think a more robust API should be created for handling this, especially when you start getting into the issue of forcing activation/deactivation with dependencies. Maybe header comments could be used to initialize the API, and from there plugin dev could utilize a class with hooks/filters.

External plugin dependencies (e.g. commercial plugins) should also at least be considered should something like this make it into core. There doesn't need to be a specific way to handle external items but at least some hooks or filters to allow commercial plugins to make use of it.

I'd be more than happy to contribute to the planning and development process of this. It's why I created TGM Plugin Activation in the first place. :-)

#20 @wpsmith
9 years ago

  • Cc travis@… added

#21 @kurtpayne
9 years ago

  • Cc kurtpayne added

#22 follow-up: @scribu
9 years ago

Replying to griffinjt:

While I think header comments are nice, I think a more robust API should be created for handling this, especially when you start getting into the issue of forcing activation/deactivation with dependencies.

Header comments are preffered because they can be parsed without activating the plugin first.

On the issue of forcing activation, when you specify a dependency, you say "I _need_ this to be active".

If you don't need it to be active, it's not a dependency; it's a nice-to-have, which should be specified using a separate header or some other method.

The issue is: is it safe for plugin X be auto installed and activated? For example, you wouldn't want BuddyPress to be auto-installed and activated, since it changes your site in a 100 ways.

But, I think this should be specified by the library, with a header like "Provides: metabox". Besides providing a stable name for the library, it could also signal that it's safe to auto-activate.

#23 @rmccue
9 years ago

We want to make sure that we think about circular dependencies as well, just to make sure we don't get stuck in infinite loops.

In terms of working out a dependency tree, Composer ported openSUSE's Libzypp dependency solver, which seems complex but might be a good start to actually doing that if we strip it down (and de-PHP5.3 it).

#24 @jbobich
9 years ago

  • Cc jbobich added

#25 follow-up: @rmccue
9 years ago

Replying to griffinjt:

On the topic of versioning dependencies, I discussed this at length with a friend of mine who is a PHP/Java developer and we came up with this: https://github.com/bubba-h57/PHP-Library-Version-Framework. Using namespaces plus a factory was the only viable way we could find to fix the issue of class version dependencies, but that can't even be considered until WordPress support PHP 5.3 and most plugin devs won't be able to implement something like it.

We discussed this and decided that we'd only implement it at a basic level, since resolving multiple versions is going to be a whole new layer of complexity. It then becomes the plugin's problem to ensure that they maintain forwards- and backwards-compatibility.

External plugin dependencies (e.g. commercial plugins) should also at least be considered should something like this make it into core. There doesn't need to be a specific way to handle external items but at least some hooks or filters to allow commercial plugins to make use of it.

I think as long as there are filters for this, it should be fine. i.e. Depends: abc def othersite:ghi would work, I think.

#26 @griffinjt
9 years ago

Replying to scribu:

Header comments are preffered because they can be parsed without activating the plugin first.

On the issue of forcing activation, when you specify a dependency, you say "I _need_ this to be active".

If you don't need it to be active, it's not a dependency; it's a nice-to-have, which should be specified using a separate header or some other method.

You are correct, and I see the benefit of header comments now.

The issue is: is it safe for plugin X be auto installed and activated? For example, you wouldn't want BuddyPress to be auto-installed and activated, since it changes your site in a 100 ways.

But, I think this should be specified by the library, with a header like "Provides: metabox". Besides providing a stable name for the library, it could also signal that it's safe to auto-activate.

+1 to this

#27 in reply to: ↑ 25 @griffinjt
9 years ago

Replying to rmccue:

I think as long as there are filters for this, it should be fine. i.e. Depends: abc def othersite:ghi would work, I think.

That would be perfect. Nothing drastic, but at least a way to commercial plugin devs to take advantage of it, kind of like how you can tap into plugins_api for updates outside of the repo.

#28 follow-up: @MikeSchinkel
9 years ago

  • Cc mike@… added

Ironically I brought up a discussion on wp-hackers yesterday to address this issue, but proposed "libraries" for this use case because of the past pushback to adding plugin dependency support into core.

One aspect of the library proposal is that libraries would be hidden from users and I think it's critical that if address this. Plugins add a lot of conceptual overhead for the user and we all know that many blog posts and peer-to-peer discussions at WordPress meetup groups tell users "limit the number of plugins you use."

Imagine a plugin that uses four (4) other plugins as dependencies; if a user installs that plugin now they have five (5) active visible plugins and their anxiety shoots through the roof. This will cause plugin and theme developers to avoid using many or any dependencies even if modularity is the best solution otherwise because they know uninformed users will tell their peers "Avoid that theme/plugin; it adds too many other plugins" even when the code of adding those plugins are essential to accomplish the task.

Drupal has had module dependencies for when I started using it in 2008 and the conceptual overload for users was a problem with it too.

An example of this type of dependent plugin would be an API client SDK for a company like MailChimp or FreshBooks. Why does the user need to see that a plugin that wraps one of those APIs is active? Would it not be much better to simply to have them see the plugin that uses it?

Proposal: Consider doing one of the following:

  1. Allow plugins to market themselves as a library and if marked can't be activated by themselves and would be invisible to the user.
  2. Display dependent plugins only when the admin user clicks a "Show dependent plugins" link in the plugin list.
  3. Implement the library proposal from wp-hackers instead.

Another question to ponder is: "How much overhead does each plugin add vs. using require() or a class auto-loader?" Will 100 plugins being activated slow down a site vs. require()ing 100 PHP files? If so, we may seriously consider a "library" concept instead of or in addition to plugin dependencies.

Last edited 9 years ago by MikeSchinkel (previous) (diff)

#29 in reply to: ↑ 22 @MikeSchinkel
9 years ago

Replying to scribu:

But, I think this should be specified by the library, with a header like "Provides: metabox". Besides providing a stable name for the library, it could also signal that it's safe to auto-activate.

This would be nice because it would require officially delineating a list of "features" that a plugin could add. That could then be used as metadata on WordPress.org plugin search as well as other locations.

Last edited 9 years ago by MikeSchinkel (previous) (diff)

#30 @taylorde
9 years ago

  • Cc td@… added

#31 @stephenh1988
9 years ago

  • Cc contact@… added

#32 in reply to: ↑ 28 ; follow-up: @Viper007Bond
9 years ago

Replying to MikeSchinkel:

Another question to ponder is: "How much overhead does each plugin add vs. using require() or a class auto-loader?" Will 100 plugins being activated slow down a site vs. require()ing 100 PHP files? If so, we may seriously consider a "library" concept instead of or in addition to plugin dependencies.

Why don't you test and see? ;)

Active plugins being loaded are just done via an <code>include()</code> or <code>require()</code>. There's basically no difference. For that matter the include itself has a trivial amount of overhead.

As the saying goes, it's quality not quantity. You could run 500 plugins if you wanted to.

But this is off-topic from this ticket. :)

#33 in reply to: ↑ 32 @MikeSchinkel
9 years ago

Replying to Viper007Bond:

Why don't you test and see? ;)

Isn't one of the benefits a community provides being to multiply the time and effort of its participants? It seems like a foolish waste of time to set up a benchmark when one question can potentially leverage the experience of someone else who has already evaluated.

Active plugins being loaded are just done via an <code>include()</code> or <code>require()</code>. There's basically no difference. For that matter the include itself has a trivial amount of overhead.

As the saying goes, it's quality not quantity. You could run 500 plugins if you wanted to.

My memory was that more happened during plugin load than it does (I just reviewed the code.) OTOH running 500 plugins would do 500 include()s for every page load whereas having the ability to load on demand would be useful for PHP files that provide supporting functionality to only selected URLs.

Maybe a "Load" header for "on-demand" or "always" would be useful and then a "require_plugin()" function that would load if not already loaded?

But this is off-topic from this ticket. :)

Really? Seems a discussion of potential ramifications of dependencies would be on-topic.

#34 follow-up: @scribu
9 years ago

The performance concern is valid. I've heard tales of ruby gems having 20+ dependencies, most of which weren't warranted.

We should be able to do on demand loading, especially if we use the WP_Dependencies class, but it's something we can easily add in a v2.0 iteration.

#35 in reply to: ↑ 34 @MikeSchinkel
9 years ago

Replying to scribu:

We should be able to do on demand loading, especially if we use the WP_Dependencies class, but it's something we can easily add in a v2.0 iteration.

That's cool, it'll be less of a problem early on. Just as long as we don't for some reason paint ourselves into a corner that won't let us address later.

#36 @pogidude
9 years ago

  • Cc pogidude added

#37 follow-ups: @dougal
9 years ago

  • Cc dougal@… added

From what I've seen in the Drupal space, dependencies help encourage devs to collaborate on common APIs that they can all use for their own modules. For example, a CDN caching API plugin -- One author can build an S3 plugin on top of it, another dev could build a MaxCDN plugin, or Rackspace Cloud, or whatever. Or a base Twitter API module could be available to build upon. Can you image how much repeated code/effort has gone into the bajillion Twitter plugins currently in the directory?

#38 in reply to: ↑ 37 @sc0ttkclark
9 years ago

Major +1 on this discussion, heavily needed and +1 on @dougal's specific notes:

via dougal:

dependencies help encourage devs to collaborate on common APIs that they can all use for their own modules

#39 @pbaylies
9 years ago

  • Cc pbaylies added

#40 in reply to: ↑ 37 @MikeSchinkel
9 years ago

Replying to dougal:

Dependencies help encourage devs to collaborate on common APIs that they can all use for their own modules. ... Can you image how much repeated code/effort has gone into the bajillion Twitter plugins currently in the directory?

+1000.

#41 in reply to: ↑ 37 @sabreuse
9 years ago

Replying to dougal:

dependencies help encourage devs to collaborate on common APIs that they can all use for their own modules.... Can you image how much repeated code/effort has gone into the bajillion Twitter plugins currently in the directory?

I want this for the twitter factor alone. But on top of that, I want to see how much of a shift there can be toward looking at the whole plugin sphere as potentially interrelated (hookable, contributable...) and not just each as its own separate little world.

#42 @alexkingorg
9 years ago

  • Cc public@… added

#43 @MikeSchinkel
9 years ago

Something else to consider about dependent plugins which I'd like to pose as somewhat rhetorical questions:

  • Are plugins that themes and other plugins depend on mostly things an end-user would install independently, or are they mostly things that an end-user would likely never install on their own?
  • If the former, what are some examples? But if the latter would it make sense to treat these "depended on" plugins differently than existing plugins?

Specifically, if these "depended on" plugins are mostly API/libraries would it not make sense to consider (also) pulling them from GitHub instead of the WordPress plugin repository where end-users go to search for plugins? GitHub is emerging as the place developers post code to share and collaborate (note: I personally prefer Hg for version control, but GitHub has no peer in enabling collaboration.) The primary benefit to GitHub IMO is the fork/pull model that allows developers to more easily collaborate.

The current plugin repository makes it very difficult to collaborate (I believe that issue was discussed at the summit, directly or indirectly regarding abandoned plugins?) If API/libraries are pulled from GitHub then these emergent APIs will likely be fewer in number but much better in depth and robustness. Rather than have every developer create yet another API/library for the same purpose it will be easier to make an enhancement to an existing API/library because of forking, and easier to get the original developer to accept the enhancement because of pull requests.

Which brings up a corollary, should API/library plugins even be included in the WordPress plugin repository where end-users go looking for plugins to install?

#44 @toscho
9 years ago

  • Cc info@… added

#45 @johnciacia
9 years ago

  • Cc johnciacia added

#46 @mzaweb
9 years ago

  • Cc mzaweb added

#47 @whiteshadow
9 years ago

  • Cc whiteshadow added

#48 @jbrinley
9 years ago

  • Cc jonathanbrinley@… added

#49 @ashfame
9 years ago

  • Cc ashishsainiashfame@… added

#50 @jleedy
9 years ago

  • Cc joseph@… added

#51 @georgestephanis
9 years ago

In the scope of the discussion, are we also talking about letting themes be dependent on named plugins via a method in core? I've seen http://tgmpluginactivation.com/ fill something of a need for that already -- but I see that as a much larger use case. We could potentially abstract out a lot of functionality code from themes, and into plugins, and make them more interchangeable. And the code to do it for both plugins and themes having the dependencies should cross-pollinate nicely.

#52 @mbijon
9 years ago

  • Cc mike@… added

The workflow for TMG Plugin Activation is one I think could work for a broad pool of WordPress users. It has pre-install notices and makes all installed plugins visible to users, no hidden libs or invisible activations.

As for the plugin-proliferation that any dependency manager might expose, we already have that and worse. Having many named and shared plugins/libs seems better than having just a few plugins where each has it's own copy of jQueryUI + different lightboxes + overlapping OAuth libs. The overlapping code means even more total code is loaded and there's a greater risk of errors. Even a basic dependency manager would help resolve that.

I don't like the idea of "Provides: metabox" though. Not because of circular dependencies, but because until the WP.org repository resolves issues regarding social/pull coding and ownership transitions we'll be better served to have as little overlap as possible between plugins. If there is overlap we would need to provide a way to filter/set which of many provided libs is used by each of many different plugins.

What might be making this more complex for WordPress is that plugins are so often standalone data, logic and view bundles. That's a bit by necessity of just getting things working, but as a community we also don't recognize good, base plugins enough. An example is the Twitter plugin comment: if people want to compete with 20 other Twitter plugins on features or UX that's *great*. The more of that we have the better for finding what works. ...but if each competing plugin writes their own and/or bundles OAuth code, that's the problem I think we need to solve here. There should be a whole set of OAuth plugins, and a whole other set of Twitter/Facebook/sharing plugins that don't have their own OAuth code.

#53 @mbijon
9 years ago

It may be worth looking at the Composer JSON schema, https://github.com/composer/composer/blob/master/res/composer-schema.json

The info provided there might not all fit in our Header comments, but if the WP.org plugin repo made the rest of it available then dependency/library management in core or as a plugin would be a lot easier. It might also help non-WP.org repos to be more functional. They already exist, but tend to be hacked together and tied to the owner's own plugin "frameworks." Why not support them, but raise the bar for interop a bit?

#54 @mrwweb
9 years ago

  • Cc info@… added

In response to @MikeSchinkel, I would certainly hope that theme dependencies on plugins are included in the scope of this ticket, and I also think that's where you would see a lot of plugins that end users would install on their own. Tons of themes bundle widgets, shortcodes, custom post types, etc. that are also already offered by plugins. Getting that stuff out of themes and into plugins would be a big win for theme developers (and users).

However, it raises the issue of whether this ticket would address themes/plugins that support integration with a plugin but don't require it. I love that modularized approach that would lead to lighter-weight sites and cleaner admins, but integrating with a plugin is definitely different than depending on it.

#55 @norcross
9 years ago

  • Cc andrew@… added

re: visual overhead

is there any reason there couldn't be a 'dp-plugins' (for dependencies) similar to the mu-plugins folder for these things to be stored? Adding another tab on the top row (next to 'must use' or whatever). This will allow them to stay contained, be useful, and not overload / scare a user when seeing a bunch of new plugins.

#56 @jltallon
9 years ago

  • Cc jltallon@… added

Plugin *and* Theme dependencies:


We have found ourselves needing certain functionalities from (activated) plugins for themes to work properly (modular code), specially w.r.t. Custom Post Types: the CPT in a plugin, with some code to help use it, while the display logic is in the theme itself.

I hereby propose extending the functionality to theme headers too. Versioned dependencies are a must if we want to enable code sharing.
For a good example on what *definitively* works, look at Debian. We can use the same format, too:

-- cpt-shared-3/cpt-shared-plugin.php --

/*
 Plugin: cpt-shared
 Version: 3
*/

-- cpt-foo-plugin-1.0/foo-plugin.php --

/*
 Plugin: CPT FOO Functionality
 Version: 1.0
 Provides: cpt-foo
 Depends: cpt-shared (>= 2)
*/

-- my-super-duper-theme/functions.php --

/*
 Theme: My Super Duper Theme 1
 Depends: cpt-foo (>= 1.0)
*/

#57 @jltallon
9 years ago

Shared library / on-demand loading functionality:


I would certainly split this issue into a separate issue.

What we have done (I'm ready to share the code if wanted) is to implement our shared functionality into a series of plugins:

  • A shared "framework" plugin, which registers an autoloader and registers a base namespace where most *base* functionality resides (i.e. base and utility/shared classes)
  • Functionality-providing plugins, which depend on the framework, each providing a certain set of functionalities (usually within classes derived from the interfaces contained into the framework, so that one can mix and match components)
  • The plugin-dependencies plugin (v1.2 by Scribu + patches) to try and avoid an inconsistent mess

Hence, the "libraries" versioning here is not based on particular class versions (which has the potential of becoming messy) but of *library* versions (just like it is done with sonames)

E.g.: "library" A v1.2 provides versions x, y and z of classes Foo, Bar and Baz respectively. So another plugin depending on this shared functionality needs only "Depends: library (>= 1.2)"

#58 @jltallon
9 years ago

SUMMARY PROPOSAL:

  1. plugin-dependencies (w/ versioned dependencies and theme dependencies) into core
  1. Class Loader (we can certainly even use the UniversalClassLoader from Symfony here) into core
  1. "Library" plugins have one index.php file which just registers their (sub-)namespace with the ClassLoader. All later loading is demand-based. The declare "Provides:" and "Version:" à la Debian
  1. Functionality plugins work as usual (perfect backwards compatibility), though they can (and should, IMHO) use "libraries" when possible. They declare dependencies if at all posible, so that we can fail gracefully if pre-conditions are not met (as opposed to just WSOD'ing)
  1. Themes can optionally depend on certain functionalities to be present (via de same "Depends" mechanism). The theme chooser UI would need to be refreshed to include some feedback for this, though.

Ideally, and with the auto-loader within core, quite some of WordPress' itself can be demand-loaded: most of the admin (e.g. WP_Table/WP_List), RSS functionality, image processing, etc.
The performance boost can indeed be huge (we have benchmarked the performance gain of doing this with plugins, I expect the gain for WP itself to be even more noticeable)

Last edited 9 years ago by SergeyBiryukov (previous) (diff)

#59 @ethitter
9 years ago

  • Cc erick@… added

#60 @coolmann
9 years ago

  • Cc coolmann added

#61 @atimmer
9 years ago

  • Cc atimmermans@… added

#62 @retlehs
8 years ago

  • Cc retlehs added

#63 @a.hoereth
8 years ago

  • Cc a.hoereth@… added

#64 @pauldewouters
8 years ago

  • Cc pauldewouters@… added

#65 @bobbingwide
8 years ago

  • Cc herb@… added

I've been delivering plugins with plugin dependency logic since April 2012. I developed the "full" solution in the oik base plugin and provided lazy code in the dependent plugins.
Since there's no core API, each plugin that has a dependency needs to deliver the same basic code. I tried to develop a solution that worked during activation; but that was a nightmare. I plumped for responding to "admin_notices".

add_action( "admin_notices", "oiku_activation" );
/**
 * Implement the "admin_notices" action for oik-user
 */ 
function oiku_activation() {
  static $plugin_basename = null;
  if ( !$plugin_basename ) {
    $plugin_basename = plugin_basename(__FILE__);
    add_action( "after_plugin_row_" . $plugin_basename, __FUNCTION__ );   
    require_once( "admin/oik-activation.php" );
  }  
  $depends = "oik:2.0-alpha.0329,oik-fields:1.18.0325";
  oik_plugin_lazy_activation( __FILE__, $depends, "oik_plugin_plugin_inactive" );
}

See http://plugins.svn.wordpress.org/oik-nivo-slider/trunk/admin/oik-activation.php

This solution works for dependent plugins which are: missing, inactive, not at the required minimum version. With the right API built into core the above code could reduce to a one line filter.

Note: plugins which are dependent on others wait for the appropriate "plugin loaded" signal before attempting to use those plugins APIs.

The challenge I now face is where the missing or out-of-date dependent plugin's repository isn't wordpress.org. e.g. oik-fields. I have a similar challenge when it comes to determining which jQuery libraries are available!

#66 @whiteshadow
8 years ago

  • Cc whiteshadow removed

#67 @whiteshadow
8 years ago

  • Cc whiteshadow@… added

#68 @jarednova
8 years ago

  • Cc jarednova added

#69 @ocean90
7 years ago

#30550 was marked as a duplicate.

#70 @DrewAPicture
7 years ago

#31152 was marked as a duplicate.

This ticket was mentioned in Slack in #themereview by greenshady. View the logs.


6 years ago

This ticket was mentioned in Slack in #core by swissspidy. View the logs.


6 years ago

#73 @swissspidy
4 years ago

#42383 was marked as a duplicate.

#74 follow-up: @tazotodua
4 years ago

I will add my thoughts, probably they are worth to be said (I dont talk about "Plugin dependency") :


There are many frameworks (like Visual-Composer, Gantry or many other PHP libraries and frameworks).
On WordPress repository, maybe thousands of themes/plugins use the same package...
Thus while I have 20 plugins and 5 themes installed on my site, i have same library installed 5-10 times (in individual plugin/theme folders).

What if WordPress created a flexible repository for Frameworks/libraries, that can be called from plugins/themes easily. For example, in "my-xyz-plugin".

<?php 
/*  
   Plugin Name: My XYZ Plugin
   ....
*/

wp_include_framework('guzzle', '4.15');

...
...
?>

so, the "wp_include_framework" should be native WP function, which will do the following (phseudo-code):

function wp_include_framework($name, $version){
  check if folder doesnt exist
  if(!is_dir(ABSPATH.'/wp-content/frameworks/guzzle/4.15/')){
    download_and_unzip("svn.wordpress.org/frameworks/guzzle/4.15.zip");
    }
  include_once(ABSPATH.'/wp-content/frameworks/guzzle/4.15/loader.php');
}

So, advantages:

  • when framework is updated by vendor, then all of the plugin(or theme) developers dont have to download them by theselves.
  • plugin developers only submit 1 changed line in the code (i.e. 4.16) without submitting whole library to SVN (which obviously causes overload of WP SVN LOGS & REVISION SYSTEM)
  • the SVN.WORDPRESS.ORG/FRAMEWORKS (or whatever it will be) will be much more visible place, where volunteers can monitor&fix security issues.
  • WP repository will need take less space :) (maybe, not a big deal, but ...)
  • I dont know what "cons" does that idea has.

This was the key of the success of Composer, right?

p.s. if someone need to explicitly include the library into own plugin/theme folder, he can still do that of course.

Last edited 4 years ago by tazotodua (previous) (diff)

#75 @tazotodua
4 years ago

p.s. I have to add:

1) similar should be done for *JS* libraries too.
I think that will make things more standartised...

2) once in a while, wp-cron-job can loop thought active plugins and delete all folders in wp-content/frameworks/ which are not used in any active plugins by the function wp_include_framework.

#76 @ideag
4 years ago

I had a free weekend some time ago, so I built a proof-of-concept plugin that illustrates a simple way, how plugins could declare some dependencies via plugin headers: https://github.com/ideag/tinylibraries

#77 follow-ups: @tazotodua
4 years ago

With my opinion, plugin dependency in "plugin header" is the most undesired way.
I think "dependencies" list should be dynamic (dynamic function is much flexible), within plugins own variable, like:

//========= with PHP libraries =======//
foreach (array("LibraryXYZ", "libraryABC") as $e) { wp_include_framework($e) };



//========= with JS libraries =======//
foreach (array("jquery-ui", "fancybox", "bootstrap") as $e) { wp_ensure_to_download_library_if_not_exists($e) };
...
<script src="<?php echo $WP_FrameWork_URLS_Global_Array['jquery-ui']['js']; ?>"
<link rel="stylesheet ......="<?php echo $WP_FrameWork_URLS_Global_Array['bootstrap']['css']; ?>"

I think that shared JS libraries will solve MUCH JS conflicts caused plugins (which incorrectly enqueue same js/jquery scripts)

Last edited 4 years ago by tazotodua (previous) (diff)

#78 in reply to: ↑ 77 ; follow-up: @ideag
4 years ago

Replying to tazotodua:

With my opinion, plugin dependency in "plugin header" is the most undesired way.
I think "dependencies" list should be dynamic (dynamic function is much flexible),

The reason I went for more static approach, is that I do not want to have any footprint in runtime. If I'm resolving dependencies on activation/deactivation, that means I do not need to run any additional calls on pageload, frontend or wp-admin side.

#79 in reply to: ↑ 78 ; follow-up: @tazotodua
4 years ago

Replying to ideag:
In the terms of what you said, that is worse, because the activated plugin, during update (if in new update a new library is added) wont be called with "activation" hook, thus, it will break with update.

So, as @nacin advised, it should be checked on every new pageload (but while is_admin()), saving the state as transient or option.

#80 in reply to: ↑ 77 ; follow-up: @MikeSchinkel
4 years ago

Replying to ideag:

I had a free weekend some time ago, so I built a proof-of-concept plugin that illustrates a simple way, how plugins could declare some dependencies via plugin headers: https://github.com/ideag/tinylibraries

Replying to tazotodua:

With my opinion, plugin dependency in "plugin header" is the most undesired way.
I think "dependencies" list should be dynamic (dynamic function is much flexible), within plugins own variable, like:

My two cents: Plugin Header is the way to go and then WordPress core should just "handle it."

@ideag: That said, how does TinyLibraries handle incompatible versions? Let's say I have Foo plugin and Bar plugin and they both use Baz library, but Foo uses 1.3 and Bar uses 2.5. Assuming SemVer then you'd have a situation where either Foo or Bar would be run on the site but not Foo and Bar at the same time because their different versions of Baz would conflict.

I wrote a library 5 years ago(!) called Imperative whose goal was to allow inclusion of a library that would (theoretically) never change and thus any plugin could load it and be confident they had the right version. In it is a register_library()method that allows a plugin to register the libraries it needs.

Imperative uses the rules of SemVer which means that if Foo plugin uses Baz library 1.3 and and Bar plugin uses Baz library 1.7 then Imperative would load only 1.7 which should theoretically satisfy both Foo and Bar. But if a new version of Bar came alone with Baz library 2.0 then Imperative would tell the user they could not activate Baz unless they disable Foo. It also suggests to contact the developer of Foo to get them to upgrade to Baz 2.0.

But what I found out was that Imperative was rather fragile because WordPress did not have enough hooks and was very inconsistent in how core works with plugins in the areas that Imperative needed to deal with and that the core team was not interested in addressing any of the issues so I gave up on developing plugins (and focused on the individually more profitable approach of developing complex websites for clients.)

Even so I would still love to see dependencies addressed in core. But to do so would require dealing with incompatible library versions if they are to be shared among plugins and themes. Although I fear it will never happen.


#81 in reply to: ↑ 80 ; follow-up: @ideag
4 years ago

Replying to MikeSchinkel:

My two cents: Plugin Header is the way to go and then WordPress core should just "handle it."

@ideag: That said, how does TinyLibraries handle incompatible versions? Let's say I have Foo plugin and Bar plugin and they both use Baz library, but Foo uses 1.3 and Bar uses 2.5. Assuming SemVer then you'd have a situation where either Foo or Bar would be run on the site but not Foo and Bar at the same time because their different versions of Baz would conflict.

I completely agree, that this should be a part of the Core. My plugin is just an attempt to display one way how this could be handled.

Regarding versioning, I think WordPress should always update libraries to the latest stable version. If a new version of the library comes out, WordPress would update it the same way it updates itself, themes, plugins and translations. And plugin developers would need to stay up to date with that. The same way they have to stay up to date with core API's and Core version of jQuery, etc. I know that's a bit idealistic, but I think this would be good for the ecosystem as a whole. And Core would not need to deal with the mess of 12 different plugins requiring 12 different versions of the same library.

#82 in reply to: ↑ 79 @ideag
4 years ago

Replying to tazotodua:

Replying to ideag:
In the terms of what you said, that is worse, because the activated plugin, during update (if in new update a new library is added) wont be called with "activation" hook, thus, it will break with update.

Are you talking about situations where update happens not via WP Admin?

#83 in reply to: ↑ 81 ; follow-up: @MikeSchinkel
4 years ago

Replying to ideag:

Regarding versioning, I think WordPress should always update libraries to the latest stable version. If a new version of the library comes out, WordPress would update it the same way it updates itself, themes, plugins and translations. And plugin developers would need to stay up to date with that.

While I agree that it is theoretically ideal I don't think such a strategy could ever be practical.

One of WordPress' core principles is to minimize problems for end users, and part of that means no breaking things that the end users have no expertise to fix. So if a plugin requires version 1.x of a library and core were to force install 2.x of the library -- which by definition would include a breaking change -- then the end user would feel the pain and not have the knowledge or skill to fix the problem (it might require major code changes in the plugin or theme!)

In the case of the plugin or theme developer they could be using an older version of a library that is perfectly acceptable for their needs and for which there are no security concerns. Or maybe they are using an older version because the older one is better! For example it is possible that v2.x of a library requires twice the memory of v1.x and thus the developer chooses to stick with the earlier version of the library. Or the newer version could have bugs the older version does not have.

And let's say all plugins on the site use v1.x out of choice so it would be a very bad idea to force them both to a breaking change in v2.x just because it is a newer version.

Plugins and theme choices are the domain of the end user but libraries are the domain of the developer so I think whatever would happen with libraries would need to be 100% invisible to end users and library support should cater to the needs of developers, not end-users. And forcing upgrades could potentially cause problems for both without certain benefit in many cases.

Bottom line, whatever is done, if anything is done, it has to be pragmatic and have almost zero possibility of negatively impacting end users.

Anyway, #jmtcw

P.S.The more I think about it the more I wonder if we shouldn't use add our own namespaces to libraries so that plugins could use different versions of the same libraries and just handle it that way?

Version 3, edited 4 years ago by MikeSchinkel (previous) (next) (diff)

#84 in reply to: ↑ 83 @tazotodua
4 years ago

and what if the libraries were requested by version (from the parent plugin), like:

require_library('library-name', '1.32');

thus, WP can create the structure of frameworks, like this:

wp-content/framework/library-name/1.32
wp-content/framework/library-name/1.31
.... 
wp-content/framework/library-name/latest    //<---- this could always be a latest version

and once in a while, WP should check all plugins/themes, and not-requested libraries/frameworks should be removed from site.

Last edited 4 years ago by tazotodua (previous) (diff)

#86 in reply to: ↑ 74 @SergeyBiryukov
2 years ago

Replying to tazotodua:

There are many frameworks (like Visual-Composer, Gantry or many other PHP libraries and frameworks).
On WordPress repository, maybe thousands of themes/plugins use the same package...
Thus while I have 20 plugins and 5 themes installed on my site, i have same library installed 5-10 times (in individual plugin/theme folders).

Related: #21107, #46370, #47285.

#87 @TimothyBlynJacobs
8 months ago

#52400 was marked as a duplicate.

#88 @joppuyo
8 months ago

Here's some perspective about issues I've had when developing WordPress plugins that use Composer to manage dependencies.

Many plugin developers use Composer to manage PHP dependencies in their plugins, however, this may cause hard-to-debug issues if two plugins use the same library. Because of how Composer works, it will only load one version of that dependency at a time. Imagine the following scenario:

  1. Plugin Developer 1 creates a plugin named Foo that uses version 2.0 of a library Bar
  2. Library Bar developer releases version 3.0 of their library which renames function get_baz() to get_qux().
  3. Plugin Developer 2 creates a plugin name Quuz that uses version 3.0 of the library Bar

An user installs both plugins at the same time. Now their site crashes because one of the plugins calls a missing function.

There are some ways developers have worked around this, for example using https://github.com/coenjacobs/mozart , https://github.com/TypistTech/imposter-plugin or https://github.com/humbug/php-scoper which add an extra unique namespace to files defined as Composer dependencies but these tools are error-prone and don't work if the library checks dependencies in runtime.

I think it could be great to have some sort of way to fix this in the core. According to the Composer developers, Composer was never meant to be used on plugin level, only at the project level where each plugin would be its own dependency and Composer could calculate any dependency conflicts run time.

I think two ways to fix this would be:

  1. Install WordPress (and its plugins) using Composer like Drupal does https://www.drupal.org/docs/extending-drupal/installing-modules . I think this would be the best way to fix this but it's not really that great if the majority of WordPress installations are on shared hosting and can't run Composer. Drupal has a thing named Ludwig https://www.drupal.org/project/ludwig which works from the Drupal admin interface and allows you to manually download and install the required dependencies.
  1. Distribute libraries on WordPress.org plugin directory. This used to an option but now libraries are explicitly disallowed in the plugin directory https://make.wordpress.org/plugins/2016/03/01/please-do-not-submit-frameworks/ . If libraries would be distributed on WordPress.org, you could at least check if the library is the correct version in your plugin before using it. There's also the issue of ownership, who will upload the libraries and keep them up to date?

Without any solution to this plugin developers who want to use libraries will have to use workarounds or simply hope that users do not install libraries with different versions. Please note that this issue is not unique to Composer, you can run into the same problem even if two plugins require the library manually.

Some more info about this issue is in this blog post: https://deliciousbrains.com/php-scoper-namespace-composer-depencies/

This ticket was mentioned in PR #1547 on WordPress/wordpress-develop by aristath.


6 weeks ago

  • Keywords has-patch added

This patch adds the ability to define plugin dependencies using a dependencies.json file.

With this implementation, a plugin can add a dependencies.json file in its root folder. Example of such a file:
{{{json
[

{

"slug": "gutenberg",
"name": "Gutenberg",
"version": "11.0"

},
{

"slug": "woocommerce",
"name": "WooCommerce"

}

]
}}}
so it's an array of objects.
Each item in the array must include a slug and a name. The slug is used to install the plugin, and the name is used to properly word the requirements notifications.
Optionally they can define a version, which is the minimum required version.
By using the "version" arg as a minimum-required version we don't have issues with versions conflicts and over-complicating things. All plugins should at all times be at their latest version. Having a minimum-required version will simply prevent a plugin from being activated if one of its dependencies is older than the minimum-required.

When we try to activate a plugin with the above JSON file, the user sees this:
https://i0.wp.com/user-images.githubusercontent.com/588688/128348980-92b3d51b-b37f-4e48-bc94-a73323dbd393.png

  • There is a new notice on the top of the screen, urging users to install and activate the dependencies
  • The plugin with unmet dependencies doesn't actually get activated, but instead gets added to a queue (database option) and will only be activated once the dependencies are met.
  • The plugin with unmet dependencies gets a notification added to its row, explaining why the plugin is not activated.
  • The "activate" link is replaced with a "Cancel activation request" link. If users click on that link, the plugin is removed from the queue and its dependencies notifications are dismissed.

When a dependency is installed, it gets a notice that the plugin is a dependency, and also the "deactivate" link gets removed from the UI:
https://i0.wp.com/user-images.githubusercontent.com/588688/128349687-5ef9631f-e26a-4458-9345-f2b36858af2e.png

Trac ticket: https://core.trac.wordpress.org/ticket/22316

#90 @SergeyBiryukov
6 weeks ago

  • Milestone changed from Awaiting Review to 5.9

Moving to the milestone to discuss PR #1547 by @aristath.

In my testing, it looks good as a proof of concept and seems like a viable approach to solve plugin dependencies.

Any feedback welcome :)

Last edited 6 weeks ago by SergeyBiryukov (previous) (diff)

#91 @prbot
6 weeks ago

Chrico commented on PR #1547:

You should use ComPoser and the composer.json for that.

#92 @prbot
6 weeks ago

aristath commented on PR #1547:

composer.json is a different beast. Composer handles packages, and it does that brilliantly. But plugin-dependencies are not, and should not, be treated the same as packages.
If I need plugin dependencies on my plugin but don't use composer, then a composer.json file is meaningless. It's a file specific to an implementation that my plugin doesn't use, and therefore using that name for plugin dependencies is probably not the best choice for all developers.
A dedicated dependencies.json file is unambiguous, and allows developers to use simpler syntax, without nesting things inside extra. It's only an extra if I'm using composer, otherwise there's nothing extra about it.
Additionally, composer is one of many package managers, and package managers come and go. It would be unwise to tie our naming convention for something that has nothing to do with packages, to a specific package-managing tool that may or may not exist in the future when some better tool comes along.

#93 @prbot
6 weeks ago

Chrico commented on PR #1547:

Composer handles packages, and it does that brilliantly. But plugin-dependencies are not, and should not, be treated the same as packages.

Sry, that's not true. Composer handles dependencies, not (only) packages. You can even define PHP-versions or extensions. Why should "plugin-dependencies" (or Theme, MU-Plugin, php-extension, php-version, ...) not be treated as dependencies to your website or even to your Plugin?

---

If I need plugin dependencies on my plugin but don't use composer, then a composer.json file is meaningless.

A Composer file is never meaningless. It provides a lot of information which could be useful in many cases.

---

A dedicated dependencies.json file is unambiguous, and allows developers to use simpler syntax, without nesting things inside extra.

True, it's simpler, but it also rebuilds what is already there and does not cover everything i posted. If that extra-field is too much, you could even add wordpress to the root-level of the composer.json:

`json
{

"name": "vendor/my-plugin",
"description: "....",
/* snip */
"wordpress": {

...

}

}

---

Additionally, composer is one of many package managers, and package managers come and go. It would be unwise to tie our naming convention for something that has nothing to do with packages, ...

You know more "PHP package managers"? 🤔 I mean.....yeah, there was Pear https://pear.php.net/ some long long long time ago and https://www.phpclasses.org/ ...but i guess (hope) you're not talking about those..?

Even it would tie it to Composer (i mean, everything is tied to something, right?), we still would build on top of an excisting eco-system which can be used, but hasn't to be used and already provides enough information to work with.

#94 @prbot
6 weeks ago

gmazzap commented on PR #1547:

The biggest problem Composer solves is not _what_ to install, but the version constraint.

This implementation "simplifies" that problem by making the version the "minimum required version".

That means that if a plugin requires 11.0 and the other 12.0 this system will only accept 12.0+.

But if 12.0 introduced breaking changes, the plugin that is requiring 11.0 will probably break.

This means that this functionality relies on the fact that everyone writes endlessly backward compatible code, like core (in theory) does, and that is simply not the reality (nor is desirable IMO because only brings technical debt, as core as proved in all these years).

That said, the PR only checks if the plugins are active, do not retrieve or download them, or anything like that. That means that this system _could_ survive side-by-side with Composer (and for what it's worth, if merged, that's how I'll use it) as they solve two different problems.

That said, I think that the version constraint should be removed: it is not capable of guarantee anything, and will probably block a future implementation that could handle it better, considering that if this PR will be merged WP will want to maintain compatibility with the JSON schema it requires.

If it is _really_ wanted to have a version constraint, why not using a constraint definition that all the package managers, of all languages, are using? That is, instead of "version": "11.0", it could be "version": ">=11.0".

It does not mean that WordPress at this point will have to support all the possible version constraints, it would only mean that that door is kept open.

I still think it would be better to remove version support at all until a better solution to the version problem is found, but at least using industry standards for the version requirements would be an improvement.

Moreover, again for the ability to evolve in the future, I think the configuration schema right now is optimistically too simple: what will happen if the same thing would be needed for themes? What if in the future Gutenberg blocks will be published in a separate registry and we'd want to declare dependencies for them?

Something like this:

{{{json
{

"plugin-dependencies": [

{

"slug": "gutenberg",
"name": "Gutenberg"

},
{

"slug": "woocommerce",
"name": "WooCommerce"

}

]

}
}}}

Will keep the possibility to evolve the file without breaking backward compatibility with its schema.


Now that I provided feedback about the PR, let me add a few more considerations:

  • people in the WordPress space are using Composer already (johnpbloch/wordpress and roots/wordpress have, combined, around 7.5 million downloads, and that is only a small portion of the Composer usage in WordPress, considering that the *great* majority uses Composer only at package level and not at website level (an example that might be familiar to you)
  • as others have pointed out for many years now composer.json would provide industry-standard machine-readable information to those that want to consume it, without requiring WordPress to do anything (just to mention the first stuping thing, GitHub would recognize the license and show it)
  • The argument about not wanting to couple with Composer because _"package managers come and go"_ is, permit me the expression, a bit "bizarre", considering that, unlike in Javascript, Composer is the _only_ package manager for PHP, and that is used by the _entire_ PHP ecosystem (only excluding WordPress core). If something else will come in the future (and that's a big _if_) it will need to be compliant with Composer to have even a minimal chance to get adopted, in the exact same way when Yarn appeared in the scene it needed to be compatible with npm.
  • WordPress is already relying on package managers, and have published more than a hundred packages in a proprietary packages registry. Why the PHP in WordPress has always to be treated so differently than Javascript?

That for me means that what this PR is doing, could have done _on top_ of Composer, as other CMS have done, but this PR goes in the direction of doing it the "WordPress way". Sad, but not surprising.

Imagine a world where this would be a plugin's composer.json:

{{{json
{

"name": "acme/my-awesome-plugin",
"description": "My plugin is awesome",
"license": "GPLv3",
"extra": {

"wordpress": {

"plugin-dependencies": [

{

"slug": "gutenberg",
"name": "Gutenberg"

},
{

"slug": "woocommerce",
"name": "WooCommerce"

}

]

}

}

}
}}}

The code currently in place in this PR could still be used as is, only the source of JSON would be different.

WordPress would not need to support (at least not for now) all the Composer properties, e.g. any require could be ignored. But the people who use Composer could type additional properties (like require), then use Composer on their own to install the dependencies, and rely on WordPress to do what this PR does.

Of course, using "extra" property in composer.json instead of a separate file is not a requirement to follow the approach of compatibility with Composer, but it would be a push for the introduction of Composer support (even if partial support), reducing the distance from WordPress to the wider PHP community, all of that requiring literally zero additional effort comparing to what this PR is requiring.

And that's why I hope that version constraint is removed from this PR, it will keep the door open to let Composer handle version constraints, something that Composer is very good at doing.

#95 @prbot
6 weeks ago

tomjn commented on PR #1547:

I don't understand the need for this, composer already solves all these problems, as well as others you've not accounted for. The justification rests on faulty premises. WP CLI already uses composer internally for package management.

composer.json is a different beast. Composer handles packages, and it does that brilliantly. But plugin-dependencies are not, and should not, be treated the same as packages.

_This is demonstrably false._

Composer handles dependences, and plugins are packages. _Many people already use composer to install plugins as well as plugin dependencies_, dependencies that are themselves plugins. There's even an official package type for WordPress themes and WP plugins. Not all packages are libraries.

Many people install WordPress itself as a composer package.

If I need plugin dependencies on my plugin but don't use composer, then a composer.json file is meaningless. It's a file specific to an implementation that my plugin doesn't use, and therefore using that name for plugin dependencies is probably not the best choice for all developers.

I do not see how this would be different if the file was renamed to dependencies.json.

A dedicated dependencies.json file is unambiguous, and allows developers to use simpler syntax, without nesting things inside extra. It's only an extra if I'm using composer, otherwise there's nothing extra about it.

Core itself can handle the activation, extra is just for automation. Otherwise there are no advantages to dependencies.json that aren't already covered by composer.json.

Additionally, composer is one of many package managers, and package managers come and go. It would be unwise to tie our naming convention for something that has nothing to do with packages, to a specific package-managing tool that may or may not exist in the future when some better tool comes along.

Composer is almost a decade old and has no viable competitors, and overwhelming backing from the wider PHP community and many people in the WP community.

---

I believe there are some fundamental misunderstandings about what Composer _is_:

  • Composer is not a popular niche tool with numerous rivals, the closest is PEAR for historical reasons ( composers predecessor ). Composers closest rival is likely the .org plugin repo, which it supports via WPackagist.
  • Composer is not a package manager for libraries, it's a dependency management tool. You can install WordPress, themes, and plugins using Composer without ever touching libraries
  • Composer doesn't have to be run as a CLI tool, it can and does get run in browser requests though this is rarer
  • By reading composer.json you:
    • get instant support out of the box or several plugins that already implement this via composer
    • automatically get free CLI support for those who need it via the composer tool
    • can warn users who haven't installed non-WP composer dependencies that extra steps are needed, avoiding a common mistake when grabbing plugins from github
    • can use battle hardened tooling and libraries from the wider PHP community
  • WP CLI already uses composer internally so there is precedent and prior art within the WordPress project itselff


People seem to have weird ultra specific ideas about what a package is.

---

_If the goal here is just to focus on activation, why was a line in the plugin header not considered?_

#96 @TJNowell
6 weeks ago

Noting that my comment updates were not carried over by PRBot. Specifically

Even then, why not use a line in the plugin header?

<?php
/**
 * Plugin Name:  Foo
 * Requires Plugins: Bar, Gutenberg
 * Requires PHP: 7.2.0
 * etc...

We already have code and precedents for this covering PHP and WordPress versions, and we have a widespread syntax for version handling that composer npm yarn bundler and many other package managers already use, e.g. gutenberg@~10.0.

This also avoids the future issue of a plugin.json being introduced that duplicates this further should the plugin information be moved out of the PHP header, or issues is a JS tool uses the generic dependencies.json filename.

#97 @prbot
6 weeks ago

Mte90 commented on PR #1547:

I think that now we have 2 proposals that deserves a better evaluation:

  • Composer support, for those plugin dependencies using the extra parameter. This as explained can help all the devs already using composer but also open to others this technology. At the same time we are talking of a json file that often is already included and maybe in the future can be used also for other things like the Tide project to do automatic scans of the code based on the dependence used. Maybe it will open the doors to add in the repository information extracted from the file itself like if has unit tests because has phpunit or codeception as dev-dependence.
  • Plugin header, this probably should get the priority as everyone use it and it is the most simple and standard way to do things (like with the new recent parameters like PHP version or woocommerce version minimum required). The issue with that is that is not so dev friendly and code friendly itself. As now this require from WP a search for php files in every plugin folder that include it, parse it and get the information from it. This is not performance friendly from a side (instead to look for a specific json file and using PHP native methods to read them) and it is something very WordPress way to do things (that is just used in this technology and not others).

![](https://imgs.xkcd.com/comics/standards.png)

To me the best solution is to use composer, that opens the doors to a lot of things and also can be a decision changer and move the WP developers to discover the new PHP stuff from the glorious php 5.2 release. It offers a lot of opportunity without creating another new custom standard (whatever it is) and not create problems to already is using it but just open new situation to evolve the very old way of develop plugins and move forward the backward WP world.

#98 @prbot
6 weeks ago

tomjn commented on PR #1547:

As now this require from WP a search for php files in every plugin folder that include it, parse it and get the information from it.

We already do this in order to get plugin name/slug/version and other dependencies during this process, and have existing tested code to parse the header. The plugin header suggestion would be no slower than what we have right now for just plugin slugs

#99 @prbot
6 weeks ago

tomjn commented on PR #1547:

I would also note there's the scope for malpractice by including the plugin name as a local field. A plugin may claim to install Yoast SEO when the plugin slug is for a completely unrelated plugin

#100 @prbot
6 weeks ago

Mte90 commented on PR #1547:

As now this require from WP a search for php files in every plugin folder that include it, parse it and get the information from it.

We already do this in order to get plugin name/slug/version and other dependencies during this process, and have existing tested code to parse the header. The plugin header suggestion would be no slower than what we have right now for just plugin slugs

Sure, we have already the code for that. Mine was just 2 cents about that we are doing something that is not so dev/code friendly and just in the WP ecosystem.

I would also note there's the scope for malpractice by including the plugin name as a local field. A plugin may claim to install Yoast SEO when the plugin slug is for a completely unrelated plugin

This is another issue that I think was fixed also in a recent WP version to let use a textdomain of a plugin in the repo but without getting updates alert and so on. In any case it is a problem, maybe it should as reference only the WP repository and not other sources like Packagist or GitHub to avoid any risks.

#101 @prbot
6 weeks ago

aristath commented on PR #1547:

Thank you all for the feedback! Apparently, my comment above struck a nerve with many. I am not a composer expert, and obviously, people use it for far more than I could imagine.

As per the suggestions above, I changed the implementation and it now uses the plugin headers:

<?php
/**
 * Plugin Name: Sample
 * Requires Plugins: woocommerce, gutenberg
 */

It's simple and it works.
This change also means that for simplification purposes, version checks were removed and now plugin authors just add comma-separated slugs.

I updated the OP to reflect these changes

#102 @prbot
6 weeks ago

Chrico commented on PR #1547:

As per the suggestions above, I changed the implementation and it now uses the plugin headers:

this will not work, since , is a valid character for Plugin Name:

<?php
/**
 * Plugin Name: My, super, duper, plugin
 */

$pluginData = get_plugin_data(__FILE__);

will result in:

https://i0.wp.com/user-images.githubusercontent.com/3417446/128677336-b43dc7cb-3d87-4327-a138-03ae289721f5.png

#103 @prbot
6 weeks ago

aristath commented on PR #1547:

In the Requires Plugins header we define the plugin slug, not its name. Plugin names are not constant and can change at any time. Plugin slugs however are unique and can never, ever change - which is why they are the safer option.

#104 @prbot
6 weeks ago

Chrico commented on PR #1547:

The Plugin slug can change as well. Aside from that, basically the same: Folder/file-name which is used for plugin slug can contain , or whitespace as a valid char as well. :)

#105 @prbot
6 weeks ago

aristath commented on PR #1547:

The Plugin slug can change as well.

If the slug of a plugin changes, WP throws an error that the installed plugin could not be found and was deactivated. If a slug changes, then it's considered a different plugin.

Folder/file-name which is used for plugin slug can contain , or whitespace as a valid char as well. :)

I don't think I've ever seen a plugin with a slug like that... Is it even allowed in the w.org repository?

what about Themes? A Theme can require Plugins as well. And vise versa.

Themes on w.org are not allowed to require a plugin. They can _recommend_ a plugin, but not require it.

#106 @prbot
6 weeks ago

gmazzap commented on PR #1547:

@aristath thanks for the change.

The plugin header is indeed a better approach than dependencies.json, and thanks for @tomjn for suggesting (and I hope that wp-plugin.json Tom mentioned will see the light at some point).

The only note is that, as @Chrico pointed out, commas and spaces are valid file/folder names, which means they could be used in valid plugin slugs.

You can try yourself: create a file named my, plugin.php with a plugin header in it, and try to activate it.

I checked wp.org guidelines, and there's nothing telling you should not use command and/or spaces in plugin folder/file names.

This is an edge case, butIMO before this PR is merged:

  • you should first check that wp.org has no plugin with thier folder/main plugin file containing commas and/or spaces.
  • a note should be added in plugin guidelines that says that comma/spaces are not allowed in plugin folder/main plugin file.

Alternatively, you can use a different approach of using a different separator/format.

One possible approach could be that if the plugins slug contains special characters like commas and/or spaces it must be in between quotes.

So in the great majority of cases a thing like the following will be fine:

Requires Plugins: woocommerce, gutenberg

But for special cases:

Requires Plugins: woocommerce, gutenberg, "some, weird, plugin, slug"

This will surely make the parsing a bit more complex, but not more than adding a single regex. I can help with that if you want.

#107 @prbot
6 weeks ago

aristath commented on PR #1547:

This will surely make the parsing a bit more complex, but not more than adding a single regex. I can help with that if you want.

@gmazzap Sure! My regex skills are limited, so if you can help with that, it would be awesome :+1:

#108 @prbot
6 weeks ago

gmazzap commented on PR #1547:

@aristath the following should work, but needs testing ;)

{{{php
/

  • A plugin slug can contain spaces/commas, not only by spaces/commas. *
  • @param string $slug
  • @return bool */

function is_valid_plugin_slug($slug)
{

return trim($slug, ", \t\n\r\0\x0B") !== ;

}

/

  • @param array $data Data coming from get_plugin_data
  • @return array list of plugin slugs */

function extract_required_plugins_from_header($data)
{

$required = empty($dataRequires Plugins?) ? : $dataRequires Plugins?;
Optimization: not worth further processing if not even a quotes couple is there.

if (!$required
(substr_count($required, '"') < 2)) {

return $required ? wp_parse_list(str_replace('"', , $required)) : [];

}

Remove quotes with nothing inside: that break the regex.
$required = str_replace('""', , $required);
preg_match_all('#"(["]+)"#', $required, $matches);

Remove from the header the slugs already parsed, then parse the rest.
$slugs = wp_parse_list(strtr($required, array_fill_keys($matches[0], )));

return array_merge(array_filter($matches[1], 'is_valid_plugin_slug'), $slugs);

}
}}}

It accounts for edge cases like a single quote, quotes with nothing inside, and via the is_valid_plugin_slug function, plugins slugs made only by spaces/commas.

Sorry the code is not using WP code styling, I'm not really used to those.

#109 @prbot
6 weeks ago

carolinan commented on PR #1547:

The wordpress.org themes team are open for allowing themes to require plugins, should the meta team change their mind about allowing it, and as long as solutions for the theme previewers can be agreed on.
https://meta.trac.wordpress.org/ticket/3863

#110 @prbot
6 weeks ago

tomjn commented on PR #1547:

Wouldn't str_getcsv be easier for handling the parsing?

{{{php
$data = '"slug,1", slug 2, test, "slug, 3"';

$plugins = str_getcsv( $data );
var_dump( $plugins );
}}}

array(4) {
  [0]=>
  string(6) "slug,1"
  [1]=>
  string(7) " slug 2"
  [2]=>
  string(5) " test"
  [3]=>
  string(7) "slug, 3"
}

Quoted, unquoted, single word values, etc all handled by native PHP. Just needs whitespace trimming afterwards

#111 @prbot
6 weeks ago

aristath commented on PR #1547:

@tomjn That's perfect! It didn't even cross my mind... Tested and pushed, works brilliantly

#112 @prbot
6 weeks ago

gmazzap commented on PR #1547:

That's very good @tomjn!

Still a few edge cases to consider, maybe, and whitespace trimming can't be done, because the whole point of having quotes is to be able to allow spaces (and commas) in plugin slugs, because they are valid characters.

The filtering by is_valid_plugin_slug is still needed IMO.

See https://3v4l.org/YWsue

#113 @prbot
6 weeks ago

aristath commented on PR #1547:

Hmmm I think that may be too much of an edge case... A foldername of a plugin ('cause that's what a slug is) with extra whitespace in the beginning or the end is clearly a mistake/typo and should be fixed :thinking:

#114 @prbot
6 weeks ago

tomjn commented on PR #1547:

a user is far more likely to mentioon foobar and put spaces and commas between them then wonder why it failed than they are to have a folder that starts or ends in a space

#115 @prbot
6 weeks ago

gmazzap commented on PR #1547:

I use to write unit tests for my code, and that simply don't pass unit tests (not even with space trimming) :)

https://3v4l.org/Uudsc

And in the case someone has a space at the end of a file name, that is maybe a typo, but they are not gonna change it, because once published the filename has to stay as-is.

#116 @prbot
6 weeks ago

tomjn commented on PR #1547:

It's also not possible to have a plugin with the folder name foo . I created such a plugin and when activated WP says the plugin file does not exist:

<img width="593" alt="Screenshot 2021-08-09 at 12 47 20" src="https://user-images.githubusercontent.com/58855/128701531-42ee2787-269c-48e0-b282-d4da116d6d44.png">

The scenario we're concerned about cannot happen

#117 @prbot
6 weeks ago

aristath commented on PR #1547:

The slug is not about filenames, but the main plugin folder-name. All plugins on .org go through a review and I believe these get automatically trimmed?

#118 @prbot
6 weeks ago

gmazzap commented on PR #1547:

The slug is not about filenames, but the main plugin folder-name

Do you know that plugins can be a single file name?
You can have a plugin with a single foo .php file, and it'll be fine.

I believe these get automatically trimmed?

Ask who manages the repo.

In any case, even with trimmed, if you want to do a proper parsing you have to skip things like ",", "'", '.

If you can decide to ignore edge cases, and that si a possibility I guess, you can just use explode: plugins with commas/spaces are edge cases anyway.

But if you decide to handle edge cases, you should handle them IMO.

#119 @prbot
6 weeks ago

tomjn commented on PR #1547:

Core itself appears to do trimming, in the case of " foo " it strips the first space out

#120 @prbot
6 weeks ago

gmazzap commented on PR #1547:

@tomjn only for folders, and only for leading spaces. Check my previous comment. a plugin with a single file named foo .php is fine for WP.

#121 @prbot
6 weeks ago

gmazzap commented on PR #1547:

The point is for me:

Do you want to support edge cases of plugins named , foo .php?

No -> use explode

Yes -> use something like what I posted.

#122 @prbot
6 weeks ago

aristath commented on PR #1547:

single-file plugins cannot be installed though... A user can create them, use them etc, but these are one-off plugins (with the exception of Hello Dolly for historical reasons). When WordPress Core installs a plugin, it always creates a folder for it.

#123 @prbot
6 weeks ago

tomjn commented on PR #1547:

I can confirm that a single file plugin that begins with a space ( " foo .php" ) fails to activate with the same issues as folders. This edge case is not currently handled by core

#124 @prbot
6 weeks ago

gmazzap commented on PR #1547:

@tomjn I've just installed a plugin named , foo .php and it works perfectly.

#125 @prbot
6 weeks ago

gmazzap commented on PR #1547:

Plugin content:

https://i0.wp.com/user-images.githubusercontent.com/2208282/128704019-3b9a6b36-9a9b-4c13-9260-26107bf09c64.png

In plugins screen:

https://i0.wp.com/user-images.githubusercontent.com/2208282/128704020-b8af5352-a8cc-44cb-9fdc-c6e67174bd58.png

On activation:

https://i0.wp.com/user-images.githubusercontent.com/2208282/128704025-79175958-a599-492f-9b49-7ef98da01116.png

#126 @prbot
6 weeks ago

gmazzap commented on PR #1547:

Again, I don't think it is *extremely important* to support the edge cases... but if you don't want to, then just use explode.

#127 @prbot
6 weeks ago

aristath commented on PR #1547:

I believe if we get something in core, we can handle edge-cases as they come, and improve the implementation as we go. There is no "perfect" solution, but the current solution covers most cases. Since single-file plugins are not installable, they cannot be used as dependencies anyway, so not a concern IMO.
It is possible to depend on a single-file plugin in a custom-built, one-off plugin for a custom site, but in that case, it's saner to just use a correct filename for the single-file plugin :shrug:

#128 @prbot
6 weeks ago

aristath commented on PR #1547:

I believe if we get something in core, we can handle edge-cases as they come, and improve the implementation as we go. There is no "perfect" solution, but the current solution covers most cases. Since single-file plugins are not installable, they cannot be used as dependencies anyway, so not a concern IMO.
It is possible to depend on a single-file plugin in a custom-built, one-off plugin for a custom site, but in that case, it's saner to just use a correct filename for the single-file plugin :shrug:

#129 @prbot
6 weeks ago

gmazzap commented on PR #1547:

Again, then use explode as you did.

The idea of str_getcsv was proposed to handle quotes. And quotes were proposed to handle single-file plugins with edge case naming.

If you don't want to handle those, then use explode. It's faster, it's simpler.

#130 @prbot
6 weeks ago

tomjn commented on PR #1547:

I think it's reasonable to require plugins that start or end in spaces to be wrapped in strings. Otherwise we'll need code to test if it really does include spaces or if the developer separated them for whitespace purposes, and I can see some mismatched expectations happening there

explode doesn't cover the user of other special characters such as ,

#131 @prbot
6 weeks ago

SergeyBiryukov commented on PR #1547:

As it looks like there might have been some initial confusion about the PR, just wanted to clarify that we're not building a PHP package manager, the PR is mostly focused on WP admin plugin UI improvements to account for dependencies. The title is now updated to reflect that 🙂

#132 @prbot
6 weeks ago

kraftner commented on PR #1547:

@SergeyBiryukov Maybe now, but I'm afraid this is a slippery slope that might lead to exactly creating a half-baked package manager in the long term when this partial solution shows as incomplete and is then slowly expanded fix after fix.

To summarize what I said on the parallel uproar on Twitter:

Do it right or don't do it at all. Composer or nothing. Everything else complicates an already terribly complicated and messy situation further.

#133 @prbot
6 weeks ago

SergeyBiryukov commented on PR #1547:

As for plugins having spaces or commas in their slugs, I think that is quite an edge case that does not necessarily has to be solved in this initial implementation, and can be solved it later if needed.

I don't have any strong objections against keeping str_getcsv(), other than it would be the only instance in WordPress core.

For now, explode( ',' ... ) along with trim() would probably also work just fine.

#134 @prbot
6 weeks ago

gmazzap commented on PR #1547:

@tomjn when I say explode, I mean: array_filter(array_map('trim', explode(',', $data))).

If you use str_getcsv you'll still need to do array_filter(array_map('trim', str_getcsv($data))).

What you won't cover in both cases is:

  • single plugin files that have trailing spaces in the slug
  • probable result of a typo, e.g.: a spare quote (foo, ") or empty double quotes (foo, ""), a comma in quotes (foo, ","), and other edge cases

What you'll cover with str_getcsv but _not_ with explode:

  • plugin slug which contains comma/spaces "in the middle"

Do you think it is worth using str_getcsv just for that? If so, then go :)

#135 @prbot
6 weeks ago

gmazzap commented on PR #1547:

@kraftner even if Composer support would be added, Composer can't do anything about _activating_ plugins, but only put plugins in place.

This means that a WP proprietary system _on top_ of Composer is needed anyway to handle that kind of stuff.

If Composer support would be there, there would likely be a WordPress Composer plugin, that would handle this kind of stuff, taking configuration from a wp-plugin.json or something like that. That is the "desired direction".

That's why I was _so_ against the original dependencies.json and the definition of dependencies versions (which have nothing to do with plugin activation mechanism): that would be very against that "desired direction".

Having a plugin header don't think will be against that: I assume at some point WordPress will want to have Javascript-only plugins (🙈) and at that point, I can imagine plugin headers will be migrated to a wp-plugin.json or something like that.

And that file will be readable by Composer and by a WP Composer plugin...

#136 @prbot
6 weeks ago

gmazzap commented on PR #1547:

@kraftner even if Composer support would be added, Composer can't do anything about _activating_ plugins, but only put plugins in place.

This means that a WP proprietary system _on top_ of Composer is needed anyway to handle that kind of stuff.

If Composer support would be there, there would likely be a WordPress Composer plugin, that would handle this kind of stuff, taking configuration from a wp-plugin.json or something like that. That is the "desired direction".

That's why I was _so_ against the original dependencies.json and the definition of dependencies versions (which have nothing to do with plugin activation mechanism): that would be very against that "desired direction".

Having a plugin header don't think will be against that: I assume at some point WordPress will want to have Javascript-only plugins (🙈) and at that point, I can imagine plugin headers will be migrated to a wp-plugin.json or something like that.

And that file will be readable by Composer and by a WP Composer plugin...

#137 @prbot
6 weeks ago

tomjn commented on PR #1547:

I think then we can agree:

  • this is for plugin activation and installation
  • specifically plugins hosted on .org
  • plugins with spaces and commas in their names aren't on .org, but this edge case can be handled in iterations
  • we're moving forward with a plugin header, not a dedicated JSON file

I think any discussion of using composer.json or a dedicated JSON file for plugin headers is an interesting discussion, but one for a new ticket/PR. We should focus on the task of activating and declaring a plugin depends on another plugin within the scope of .org. 3rd party sources and repositories are out of scope.

#138 @prbot
6 weeks ago

kraftner commented on PR #1547:

@gmazzap Yes, but as you've perfectly pointed out before there are plenty of issues with versions and alike when just handling the activation use case.
That is why I think it either needs to be handled fully (version conflicts, installation, activation,...) or not at all. With nothing, like now, it is at least obvious that these things are on you and you better be careful. Half a solution projects this feeling of "Great, WP now handles dependencies. Brain off." From the point of view of the user as well as from the point of view of a dev who might skip checking for a plugin dependency now with the wrong assumption of WP handling this.
To talk in pictures: When standing on a cliff I think the raw edge is much safer than a railing that looks nice but snaps as soon as I lean against it.

(I am aware this might be my personal disdain for "Move fast and break things" and releasing alpha-grade "solutions" with the arguments of "better than nothing" and "iterative approach". I can see how this is a fundamental believe not everyone agrees with, still I felt like this needs to be at least mentioned here.)

#139 @prbot
6 weeks ago

Chrico commented on PR #1547:

this is for plugin activation and installation

no! installation is not activation :D Installation (resolving dependencies) is what Composer does. This PR should focus _only_ on activation.

plugins with spaces and commas in their names aren't on .org, but this edge case can be handled in iterations

You can, but you shouldn't, ignore that. You need to handle all valid chars for file and folder namse for plugin/theme slugs. You cannot simply ignore them, because: , foo .php !== ,foo .php !== ,foo.php !== foo .php. You either need to sanitze _now_ those slugs to ensure that those "duplications" are not existent, or you need to support those "special cases". All in all: write Unit Tests! :)

#140 @prbot
6 weeks ago

tomjn commented on PR #1547:

Lets not forget this PR is for this trac ticket https://core.trac.wordpress.org/ticket/22316 which _does_ cover installation, citing installation of a plugin from wp.org explicitly

#141 @prbot
6 weeks ago

gmazzap commented on PR #1547:

So this is also for installation? @tomjn

The description in here does not mention that.

That is a so bad decision IMO.

Among the "let's invent here a package manager" that @kraftner was pointing (and now I get why he said that) as soon as I write a custom plugin from my client that happen to have same slug of plugin in wp.org things will explode.

Not to mention that a plugin can force on my site a plugin I don't know nothing about?

I don't want any of clients' sites to ever having the deal with this.

I have client that want security & privacy assessment for every single line of code that is added to their website, this would mean that code can land on their websites without nobody being able to review... (I wonder how hostings like wp.com VIP Go that do pre-deployment code review will like this).

Please reconsider this. Please stop this.

Or at very least introduce an opt-out mechanism: a constant, a filter, whatever.

WP does not want Composer? Too bad, we use it anyway, and it is like having a Ferrari and being forced to drive a scrap.

#142 @prbot
6 weeks ago

tomjn commented on PR #1547:

There are already opt outs and filters that were added in 5.8 for that
exact situation, and the context is .org plugin installation. This PR is
not the ticket, and comments here are not the complete discussion. Refer to
Trac for that discussion and the context.

The purpose of the ticket and PR is not to implement a composer competitor
or a package manager, but to facilitate .org repo plugins that have
dependencies on .org.

As a PR this is not a place to argue for the tickets scope and nature to be
fundamentally changed. Implementing composer is a different task.

#143 @prbot
6 weeks ago

tomjn commented on PR #1547:

Also as someone who did WP.com VIP and VIP Go review I can say with
relative certainty that they have UI based plugin installation disabled.
This would be a non-issue as it relates to a feature those platforms and
most other enterprise WP platforms do not use or enable.

#144 @prbot
6 weeks ago

gmazzap commented on PR #1547:

The purpose of the ticket and PR is not to implement a composer competitor or a package manager, but to facilitate .org repo plugins that have dependencies on .org.

That is exactly a dependency-solving issue, which is exactly what a "dependency manager" (Composer) does. So to me sounds like: _"the purpose of this ticket is not to implement a Composer competitor, but a WordPress-specific Composer alternative"_.

Which s as equally bad IMO.

There are already opt outs and filters that were added in 5.8 for that exact situation

Can you point me to those filters?

can say with relative certainty that they have UI based plugin installation disabled.

How that is relevant? If I commit a plugin that depends on one or more plugins, once that plugin is online it will install the other plugins (if I understood correctly), but the PR that caused the deployment did not include the required plugins, hence those landed online without review.
Or am I missing something?

#145 @prbot
6 weeks ago

tomjn commented on PR #1547:

That is exactly a dependency-solving issue, which is exactly what a "dependency manager" (Composer) does. So to me sounds like: "the purpose of this ticket is not to implement a Composer competitor, but a WordPress-specific Composer alternative".

We already have our own system, implementing minimal dependencies is not the same as replacing the entire .org plugin and theme system with composer. That is a huge undertaking that should be a separate issue.

Keep in mind that the plugin header system can be integrated into WPackagist, improving support in existing Composer based setups.

Can you point me to those filters?

At least one of them:

https://make.wordpress.org/core/2021/06/29/introducing-update-uri-plugin-header-in-wordpress-5-8/

.org plugins having slugs that also match a local plugins name, and other naming conflicts would not be a new problem.

The proposed header is unique to .org plugins, this is not a generic package manager with arbitrary dependencies. Nobody has specified that git repos, zip URLs, subversion tags, and other resources as a dependency in a plugin header. The suggestion that a non .org plugin may be declared in this plugin header does not fit the proposed feature on the trac ticket.

How that is relevant?

You mentioned it. The feature this PR and the ticket is focused on simply does not apply to those platforms, and would be disabled by those platforms if it did. If a user of those platforms were to commit such a plugin without its dependencies I do not see how it would be any different before or after this features implementation. Even if it were implemented today using a composer.json without a build process and vendor folder.

but the PR that caused the deployment did not include the required plugins, hence those landed online without review.

Assuming there was no review and no testing, this could happen but that is already the case and this feature would not change that for those platforms, nor is it within the scope. composer would not change this either unless there was some kind of CI step which could catch this issue, which would be the job of the platform.

#146 @prbot
6 weeks ago

SergeyBiryukov commented on PR #1547:

If I commit a plugin that depends on one or more plugins, once that plugin is online it will install the other plugins (if I understood correctly), but the PR that caused the deployment did not include the required plugins, hence those landed online without review.
Or am I missing something?

No, that does not happen automatically.

As shown on the screenshot from the PR description, if a plugin requires a few other plugins that are not currently installed or activated, installing and activating them is an explicit manual action for clarity.

#147 @prbot
6 weeks ago

Chrico commented on PR #1547:

As shown on the screenshot from the PR description, if a plugin requires a few other plugins that are not currently installed or activated, installing and activating them is an explicit manual action for clarity.

But this is kind of "manual" dependency resolving by trying to install (download) until it breaks. If Plugin A requires Plugin B, then you need to install Plugin B, Plugin B requires C and D and C requires F and J and D requires A - but not in the version you currently have it installed...at some point it just breaks.

#148 @prbot
6 weeks ago

gmazzap commented on PR #1547:

I feel like I've spent too much time on this issue, but anyway can't help but have to answer one again.

@SergeyBiryukov is saying that this PR is only about checking the _activation_ of plugins' dependencies.

@tomjn is saying that the track ticket this PR refers to is about _installing_ plugins' dependencies.

The difference is not trivial.

In the first case, WordPress is not acting as a dependency manager, not being able to install dependencies.

In the second case, WordPress is acting as a dependency manager. A pretty broken one TBH.

A _proper_ dependency manager takes care of installing the proper version of dependencies, takes into account updates, and many other things. The fact that dependencies are limited to .org plugins doesn't change it.

Let's imagine that WP will install .org plugin dependencies based on a plugin header:

  • What will happen when that plugin is (auto-)updated and changes its requirements?
  • What will happen if DISALLOW_FILE_MODS is true and so WordPress itself is not supposed to change the file system?
  • What happens if a dependency is removed/suspended from the wp.org repo? Is there a mechanism to check which other plugins are depending on it?
  • How do we want to deal with abuses? That is plugins vendors to force the installations of all their plugins for marketing purposes? Assuming the wp.org plugins review team will check if there's a real dependency, what will stop vendors to use a single plugin function from other plugins for no real reason but just to claim it is a "real" dependency?
  • What will happen if the "main" plugin has Requires PHP: 5.6, but the latest version of dependencies has Requires PHP: 7.0 and Requires PHP: 7.1? Imagine that when the main plugin introduced the dependencies they had no that requirements, but they got updated and now they have.

These are only a few of the open questions that would be needed to answer before introducing such "automatic installation" of dependencies, and I'm pretty sure some of the answers will never be satisfactory. Because handling dependencies is a complex problem, and a trivial dependency manager doesn't make dependency management trivial.

Answering those questions in the best possible way would mean building a full-fledged dependency management system, something that really makes no sense.

So, please, leave the dependencies installation alone.

If a plugin _A_ depends on plugins _B_ and _C_, WordPress can surely check if those plugins are installed and activated, if so will continue with plugin _A_ installation, otherwise will stop it and show a notification. _Eventually_ providing a link that will trigger a one-click installation of _B_ and _C_ (if DISALLOW_FILE_MODS is false).

If the dependencies are not there/not activated it will be up to the site owner to evaluate which version of the dependencies to install and *how* to install: UI, WP CLI, Composer... WP should not be concerned, just like is not concerned right now.

This is what this PR will do (as far as I understood), and I see no problem with that.

---

To answer @tomjn:

At least one of them:

Having a filter that prevents conflicts between a local and a wp.org plugin is nice, thank you, but the opt-out mechanism I want is something that prevents WordPress to automatically install dependencies, if that becomes a thing. But I hope that setting DISALLOW_FILE_MODS to false will already do it.

We already have our own system, implementing minimal dependencies is not the same as replacing the entire .org plugin and theme system with composer.

Nobody wants to replace .org plugin and theme system. Those are SVN repositories and Composer works with SVN repositories. Writing a script that creates a Composer repository from the wp.org repos is trivial.

Keep in mind that the plugin header system can be integrated into WPackagist, improving support in existing Composer based setups.

First of all, WPackagist is a proprietary thing, maintained for free by a company that has said doesn't have interests in maintaining it. An "official" WordPress WPackagist equivalent will need to provide a composer.json for plugins/themes generating one if not provided by the user, and will need to ship an official Composer installer. And have something to deal with translation packages.
And I've personally written Composer plugins that read plugins headers to extend Composer functionality.
But plugins headers are not fit for the scope, not being able to store structured data, will never be able to support the needs of a dependency management system. Unless we want to start writing JSON in the headers...
And I'm waiting for the moment when it will be realized that Gutenberg extensions can be written without the need of any PHP, and people will write plugin headers just to make those extensions installable. How long before someone will say _"let's enable js-only plugins and get over plugins headers"_. I'm sure that from there to a wp-plugin.json the step will be extremely short considering that pushing JS is the only change-driver these days in WP.

I do not see how it would be any different before or after this features implementation. Even if it were implemented today using a composer.json without a build process and vendor folder.

That's exactly the point. Using Composer you can have a build process that pulls vendors and runs static analysis and tests. If dependencies are installed by WordPress, to obtain the same result you need a working installation of WordPress, something that is a few orders of magnitude harder than running composer install && composer lint && composer tests in a CI.

#149 @prbot
6 weeks ago

kraftner commented on PR #1547:

But this is kind of "manual" dependency resolving by trying to install (download) until it breaks. If Plugin A requires Plugin B, then you need to install Plugin B.
Plugin B requires C and D and C requires F and J and D requires A - but not in the version you currently have it installed...at some point it just breaks.

And then this will be bad UX and it will be improved upon incrementally and very quick this is *exactly* the slippery slope I am talking about. Use composer or stop it right here before it can do any harm, please, pretty please!

#150 @prbot
6 weeks ago

SergeyBiryukov commented on PR #1547:

Plugin B requires C and D and C requires F and J and D requires A - but not in the version you currently have it installed...

That's why we had the ability to specify a minimum required version in the initial implementation, though it was removed per some earlier feedback here.

@SergeyBiryukov is saying that this PR is only about checking the _activation_ of plugins' dependencies.

No, I'm not saying that :) I'm saying that both installing and activating is an explicit manual action in this implementation and does not happen automatically, for clarity and transparency. This way the user is aware of any dependencies and can make the choice to either install and activate them too, or cancel the initial activation request.

Let's imagine that WP will install .org plugin dependencies based on a plugin header:

I think these are all very valid questions that can be addressed individually.

#151 @prbot
6 weeks ago

gmazzap commented on PR #1547:

And then this will be bad UX and it will be improved upon incrementally and very quick

Plugins that require plugins are not a new thing. Right now, if you try to install a WooCommerce or a Gravity Forms extension without those plugins being active, you got a notice, and the plugin is not activated.

If WP is willing to do that on behalf of single plugins owners (which end up in different types of notifications and inconsistent behavior) I don't see that as a huge issue.

The fact that declaring dependencies becomes easier will increase this practice? I bet. But to be honest, as long as there's an opt-out mehanism that makes me (who use Composer and have DISALLOW_FILE_MODS to false) don't have to deal with that thing... I'm fine.

And once again, even if Composer support is added, WordPress will still need to handle these kinds of things, because even being able to declare in Composer that acme/woocommerce-extension depends on woocommerce/woocommerce, would not exempt WordPress to _activate_ WooCommerce when the extension is activated.

If this kind of mechanism is built now, without Composer, I don't see a problem because in an imaginary future where Composer support is added, that mechanism can be kept as-is.

#152 @prbot
6 weeks ago

gmazzap commented on PR #1547:

I'm saying that both installing and activating is an explicit manual action in this implementation and does not happen automatically, for clarity and transparency.

@SergeyBiryukov Manual installation and activation are already possible :) So the _new_ things this PR does are:

  • check the dependencies
  • inform the user about unmet dependencies

what happens after that (manual installation and activation) is not a new thing. And in my personal opinion, if the work done on this ticket limits to that, I see no issues.

What I am only asking is to stop there, and don't do any additional step in the direction of "dependency management", or make sure that the steps in that direction involve Composer.

#153 @prbot
6 weeks ago

kraftner commented on PR #1547:

And then this will be bad UX and it will be improved upon incrementally and very quick

Plugins that require plugins are not a new thing. Right now, if you try to install a WooCommerce or a Gravity Forms extension without those plugins being active, you got a notice, and the plugin is not activated.

If WP is willing to do that on behalf of single plugins owners (which end up in different types of notifications and inconsistent behavior) I don't see that as a huge issue.

The fact that declaring dependencies becomes easier will increase this practice? I bet. But to be honest, as long as there's an opt-out mehanism that makes me (who use Composer and have DISALLOW_FILE_MODS to false) don't have to deal with that thing... I'm fine.

And once again, even if Composer support is added, WordPress will still need to handle these kinds of things, because even being able to declare in Composer that acme/woocommerce-extension depends on woocommerce/woocommerce, would not exempt WordPress to _activate_ WooCommerce when the extension is activated.

If this kind of mechanism is built now, without Composer, I don't see a problem because in an imaginary future where Composer support is added, that mechanism can be kept as-is.

Because devs now know WP does nothing about it so they handle it on their own. If WP now suggests it *does* handle this I bet it will get sloppy pretty fast in reality since the responsibility is now assumed to be on WP. So *if* WP does anything in this realm it should be done better than the home-grown solutions of plugins right now. And my opinion is that that would need to include full dependency resolution which in turn mandates composer.

#154 @prbot
6 weeks ago

gmazzap commented on PR #1547:

@kraftner I agree that if this PR is merged the next step will be _"how about installing the dependencies"_?

And at that point, only two possibilities will be there: homegrown a package manager or use Composer. And I hope who will take that decision will be savvy enough to don't attempt building a package manager.

So this PR, if merged, will be a push in the direction of dependencies management, let's just hope it's not a push into a ravine.

#155 @prbot
6 weeks ago

tomjn commented on PR #1547:

My expectation is that if I install Foo, and it depends on Bar, that WP will tell me that and offer to install Bar via the UI, then to activate it, or both at the same time.

I think the installation of dependencies is being conflated with the automatic installation of dependencies.

I also think these issues are being introduced which the ticket did not provide scope for:

  • unreviewed plugins that are not on .org
  • dependencies of dependencies
    • circular dependency detection

I would also make a final note on the subject of composer. If everybody aligned and WP added full native support for composer in every possible way, bundling composer internally, using it to install plugins themes and any of their library dependencies, autoloaders etc we would still need to operate and maintain the wp.org system, and it would still something we'd want basic dependencies for. If this PR introduced a WP package system then that package system was introduced more than a decade ago and predates composer. The WP.org plugin repo isn't going away, and it's not a replacement for composer.

#156 @prbot
6 weeks ago

aristath commented on PR #1547:

I think there was a misunderstanding in this ticket.... We're not trying to build a package manager here. I'll use WooCommerce for this example because it's something most people are familiar with.
What we need, is a way to show users that a WooCommerce addon they installed will not work unless they also install WooCommerce. A way to guide them through that installation and activation, and a way to prevent the activation of the addon unless WooCommerce is also installed, in order to avoid errors on the site.
That's all this PR is trying to achieve, that's what the focus was, and from reading core tickets that's what most plugin authors have been asking for for years.
Building a package manager the way it is presented above would be an exercise in futility and yes, if that's what we wanted to achieve then composer would be the way to go. But that's not what we're trying to achieve here... All that "plugin dependencies" means here, is that "Plugin A needs plugin B in order to function, so please install plugin B before activating plugin A". That's it.

#157 @prbot
6 weeks ago

aristath commented on PR #1547:

unreviewed plugins that are not on .org

Since the implementation uses the plugin headers in order to provide a list of slugs, the WordPress API is used for the installation of these plugins. Now, if a plugin hooks in the updater and changes the requests in order to install an unreviewed plugin from a 3rd-party site, there's nothing we can do about it. It's not something new, and they can do that already if they want to. Nothing changes.

dependencies of dependencies

If plugin A requires plugin B and plugin B requires plugin C, then when activating plugin A there is a prompt to activate plugin B. When plugin B gets activated, there is a prompt to install plugin C. Ideally when activating plugin A there would be a prompt to install both plugins B & C, but that may require a tweak in the .org API, or at least an extra ping in the plugins API to get the dependencies of dependencies. It's possible, but it's something that can only be explored after there are a couple of plugins on .org with dependencies defined so we can further iterate.

circular dependency detection

I have not tested that, but it should be easy to test and fix if we decide to proceed.

#158 @prbot
6 weeks ago

tomjn commented on PR #1547:

I have not tested that, but it should be easy to test and fix if we decide to proceed.

Given that this is user UI driven, if we have a circular dependency they'd have to install the next plugin in the chain at each step, when they come around full circle they'd find the plugin already installed and WP would be satisfied. I'm unsure about activation

#159 @prbot
6 weeks ago

aristath commented on PR #1547:

Given that this is user UI driven, if we have a circular dependency they'd have to install the next plugin in the chain at each step, when they come around full circle they'd find the plugin already installed and WP would be satisfied. I'm unsure about activation

Yeah, the activation part is what will need a couple of tweaks... Plugin A is not actually activated until its dependencies are met, which requires plugin B to be activated, but it can't be activated because its dependencies are not met since plugin A is not active. But it's an easy fix :+1:

#160 @prbot
6 weeks ago

kraftner commented on PR #1547:

@aristath @tomjn You're *already* talking about a dependency resolution algorithm with conflict management and the added "benefit" of a "mechanical turk" aka user to sidestep automation, aren't you?

#161 @prbot
6 weeks ago

gmazzap commented on PR #1547:

@tomjn

The WP.org plugin repo isn't going away, and it's not a replacement for composer.

I never said that, and I think nobody wants that.

And TBH I don't think that is something that makes sense.

The WP.org plugin repo is a repository, Composer is a package manager that searches repositories, resolves dependencies, and then installs packages from the repositories.
Composer can't do anything if there's no repository. And nobody is expecting that WP will move to Packagist as a repository registry. (At least, I'm not).
Composer have also a mechanism to install packages (aka download from the repo and place them in the proper folder). That mechanism can be extended/overridden via custom installers and is likely what WP will need to do if it wants to integrate Composer.
Nobody thinks that the installation via UI .org plugins/themes will ever go away. But I don't see why the two can't survive side by side. And I am aware that would require effort. In WP code, but not only in code.

---

@aristath

That's all this PR is trying to achieve, that's what the focus was, and from reading core tickets that's what most plugin authors have been asking for for years.

Yep, and as I said multiple times I'm see nothing wrong with that. But what I and others are saying is that as soon as this will be added, the "desire" to have those dependencies installed automatically will surely raise, and we want to avoid doing that using a homegrown solution.
That "desire" will raise very soon when people will start using this mechanism and dependencies of dependencies, of dependencies... will be a thing, and the users will need 30 clicks to install a plugin.
On top of that, what I personally would like to see is an opt-out mechanism from all of that. And considering the whole process, as you describe it, is based on UI, please make sure that when plugin management via UI is disabled (e.g. when DISALLOW_FILE_MODS is true) the changes in this PR don't apply.

If plugin A requires plugin B and plugin B requires plugin C, then when activating plugin A there is a prompt to activate plugin B. When plugin B gets activated, there is a prompt to install plugin C.

When you say "activate" you mean "install and activate" (assuming is not installed), correct?

But please be sure that before merging you test the UX in the scenario in which A requires B, and B requires C, D, E, F, G, H, I, L, M, and _each_ of those requires _a few_ dependencies, and so on.
And also please consider what happens when one or more of those dependencies _can't_ be installed, because requires a PHP version that is not available, or can't be found in the wp.org API (removed/suspended).
And also please consider the case one or more of the dependencies is _Network only_ but the user is in the site-specific plugin screen.
And also please consider the case one of the dependencies as a fatal error and so is forcefully disabled.

_"That's it"_ makes it look simpler than it is, IMO.

#162 @prbot
6 weeks ago

aristath commented on PR #1547:

Yep, and as I said multiple times I'm see nothing wrong with that. But what I and others are saying is that as soon as this will be added, the "desire" to have those dependencies installed automatically will surely raise, and we want to avoid doing that using a homegrown solution.

Automatically installing and/or activating something without the user's explicit consent is a big no-no for this implementation. We all like automation, but we can't know why the user has chosen to have a plugin deactivated. Maybe that plugin when activated breaks their entire site and they spent a week debugging it. We cannot in good conscience auto-activate something without their permission.

That "desire" will raise very soon when people will start using this mechanism and dependencies of dependencies, of dependencies... will be a thing, and the users will need 30 clicks to install a plugin.

I agree. But let's get a basic implementation first and not get ahead of ourselves... A dependency of a dependency of a dependency, or a plugin with 10 dependencies are highly unlikely. In most scenarios I can think of, a plugin shouldn't have to require more that 1-2 plugins in order to function. But even if we do get to a point of deeply-nested dependencies and plugins that require 10 plugins, clicking 30 times is easier than searching the repo for the dependencies manually and installing them one by one.
Is it perfect? Of course not, nothing is! But it's better than what we have now, it's a start, and it's something we can iterate on as we go. But we can't iterate on something that currently doesn't exist. The current problem is that there is no way to define dependencies or guide users on what they have to do in order to get their plugin to work. If and when we come across deep-nested dependencies, we can fix the issue then. Maybe it will never happen... No reason to over-engineer a solution that may never be needed when the current solution - though imperfect - will still work and guide users.

On top of that, what I personally would like to see is an opt-out mechanism from all of that.

Opt-out of what exactly? The notification that will be shown, urging you to activate WooCommerce when you install a plugin that depends on WooCommerce? Or opt-out from the fact that a woocommerce addon will not be enabled unless woo is also installed & activated?

And considering the whole process, as you describe it, is based on UI, please make sure that when plugin management via UI is disabled (e.g. when DISALLOW_FILE_MODS is true) the changes in this PR don't apply.

I don't understand... If DISALLOW_FILE_MODS is true, then you manage everything via the CLI or some other way - in which case you are responsible as an admin for everything. So you are responsible for installing Woo when you install an addon. What exactly from this PR would you like to see not apply in this case? Can you please elaborate?

And also please consider what happens when one or more of those dependencies can't be installed, because requires a PHP version that is not available, or can't be found in the wp.org API (removed/suspended).

If a dependency can't be activated, then the plugins that depend on it will also not be activated. And that makes perfect sense... If Woo for some reason can't work or be installed on my site, then what use is an activated woo addon?

And also please consider the case one or more of the dependencies is Network only but the user is in the site-specific plugin screen.

Excellent point, thank you!

And also please consider the case one of the dependencies as a fatal error and so is forcefully disabled.

If WooCommerce is forcefully deactivated, then its dependencies will also be deactivated since the plugin they depend on is no longer active - and therefore their dependencies are not met. When that happens, they get added to a "pending plugin activations" queue (using a pending_plugin_activations option). That makes the notices show up in the dashboard guiding users to activate Woo, and as soon as the user resolves their fatalities and the plugin is reactivated, all woo addons that were previously active will be auto-activated. The user has the option to cancel that at any point by clicking on the "Cancel activation request" link in the addons that are pending activation.

#163 @prbot
6 weeks ago

gmazzap commented on PR #1547:

@aristath

Automatically installing and/or activating something without the user's explicit consent is a big no-no for this implementation.

👍🏻


But even if we do get to a point of deeply-nested dependencies and plugins that require 10 plugins, clicking 30 times is easier than searching the repo for the dependencies manually and installing them one by one.

People *will* use this for marketing purposes. So a plugin that requires 3 plugins will not be that hard to find. And if each of those 3 will require one additional plugin (and I stop there) it's 6 plugins. 2 clicks each (install and update) + 2 clicks for the "main" plugin and we're 14 clicks. That is not that unlikely.
It is better than searching the repo for the dependencies manually? Yes.
Can we expect this will cause _more_ dependencies to be created? I'm quite sure.
Will people ask to automate this process? I'm ready to bet.


Opt-out of what exactly? The notification that will be shown, urging you to activate WooCommerce when you install a plugin that depends on WooCommerce? Or opt-out from the fact that a woocommerce addon will not be enabled unless woo is also installed & activated?

Considering I manage dependencies via Composer, I don't even login into WordPress most of the time. So, ideally, if I had the possibility to have the _current_ behavior (no notification, no preventing installation, no anything this PR contains) I would take that possibility. And if there's a fatal error because the WooCommerce addon is activated without WooCommerce, that will help me to spot the issue and add WooCommerce to my composer.json.


What exactly from this PR would you like to see not apply in this case? Can you please elaborate?

See above. I would like the Requires plugins header to be ignored at all. If things will break, will break. No notifications will be there, and so on. If the notification will be there... I'll not see it most of the time, but will not harm. But "preventing installation" because of unmet dependencies is something I would like to opt-out of.
But assuming a situation when a user can't install plugins from the UI, and they are seeing a notice that says:

_"You need to install and activate WooCommerce to use X, click here to do it"_

Then they "click there", and they get an error. So at least, make sure no input is presented to users to install a plugin if they can't do it.

And if you present an input that says:

_"You need to install and activate WooCommerce to use X"_

(without "click here"...) do you think it is useful to tell users they have to do something they can't do?


and therefore their dependencies are not met. When that happens, they get added to a "pending plugin activations" queue (using a pending_plugin_activations option).

Simple case A requires B that requires C.

C can't be installed for some reason. That will make _two_ pending installations right? One for _A_ and one for _B_. If the problem I have with _C_ is not something I can/want fix, I will need to cancel both pending installations, right?
And if things get a bit more complex, that means it is possible to have multiple "pending installations" that need to be canceled?
It would be possible that all nested requirements refer to the "root" installation request and canceling that all the other are canceded? In the prev example, canceling the request for A, would cancel the request also for B.

#164 @prbot
5 weeks ago

aristath commented on PR #1547:

People will use this for marketing purposes.

If they do, they'll be _doing_it_wrong. A "requirement" is what it says: A requirement. Not a recommendation or a "good to have" item. For better or worse we can't prevent people from doing the wrong thing, but then again this is open-source. If they want to abuse this like they have been abusing all other APIs (like the admin-notifications) then they will.

ideally, if I had the possibility to have the current behavior (no notification, no preventing installation, no anything this PR contains) I would take that possibility.

Done. Added a check for a DISALLOW_PLUGIN_DEPENDENCIES constant.

make sure no input is presented to users to install a plugin if they can't do it.

The code already includes current_user_can checks. As per your suggestion, I added an extra check for DISALLOW_FILE_MODS.

#165 @prbot
5 weeks ago

gmazzap commented on PR #1547:

If they want to abuse this like they have been abusing all other APIs (like the admin-notifications) then they will.

That's what said, they will :) And that will disrupt users experience. Just like admin notifications.
If you could back in time when admin notifications API was added, knowing what you know now, would you try to make the abuse less user-impacting? Would you at least factor-in the abuse you know will happen into your decision making process?

---

Added a check for a DISALLOW_PLUGIN_DEPENDENCIES constant.
I added an extra check for DISALLOW_FILE_MODS.

Thank you.

---

@aristath I was thinking something. I see that when a package is a dependency, it can't be disabled/unistalled.

Now imagine the situation in which _A_ requires _B_, _B_ requires _C_ and _C_ requires _A_. Or any other circular dependency situation, even just _A_ requires _B_, _B_ requires _A_.
Because _B_ is a dependency of _A_ it can't be disabled. And because _B_ is a dependency of _A_ it can't be disabled either.
Does it mean that in case of circular dependencies people will need to keep all the plugins forever?

#166 @prbot
5 weeks ago

aristath commented on PR #1547:

Now imagine the situation in which A requires B, B requires C and C requires A. Or any other circular dependency situation, even just A requires B, B requires A.
Because B is a dependency of A it can't be disabled. And because B is a dependency of A it can't be disabled either.
Does it mean that in case of circular dependencies people will need to keep all the plugins forever?

Circular dependencies are not yet handled here, this is the missing piece IMO and I'm currently working on it :heart:

#167 @prbot
5 weeks ago

aristath commented on PR #1547:

Update: Circular dependencies are now properly handled.

#168 @brianhenryie
3 weeks ago

I'm really surprised to have read all this and see no mention of [afragen/wp-dependency-installer](https://github.com/afragen/wp-dependency-installer) which addresses what the recent PR is addressing, although the PR's approach of using the plugin's header is neater. Here's an [example implementation](https://github.com/BrianHenryIE/woo-manage-fraud-orders/blob/address/src/Admin/class-dependencies.php).

I've admonished a few plugin authors for writing is_plugin_active() checks that end in die, so to some extent this is an improvement.

I certainly welcome a dismissable admin notice saying ~"WooCommerce is required, without it plugin-x will not work correctly, you should consider activating it."

But I don't think there's a good reason to deny activating the plugin when e.g. WooCommerce is not active. The correct approach is to hook only to appropriate actions of the parent, and some sparse function checks. I know this isn't always available, I just today opened [an issue with Action Scheduler](https://github.com/woocommerce/action-scheduler/issues/749) with a feature request for better actions to facilitate this!

If I want to install and activate a plugin, I should be able to activate, e.g. EasyPost shipping plugin, without being told I MUST also activate WooCommerce. I use that example because I use a third party EasyPost plugin for purchasing shipping labels – my plugin automates it, it provides the UI I need. Admittedly I am using and do need WooCommerce, but it's not hard to imagine another e-commerce plugin either forking WooCommerce or trying to work upon a compatible set of actions and filters to give itself access to the breath of relevant plugins that are already written.

In the simplest case, I create a plugin which is really just a facade on WooCommerce (which is probably in my /vendor/ directory) such that all the WooCommerce classes are available, most of the functionality is being used, but my plugin's slug is brian-commerce instead. All WooCommerce's plugins CAN and SHOULD work, but if they have REQUIRED rather than SUGGESTED WooCommerce, then they will never work.

I think this is antithetical to the philosophy of open source, as WordPress says in "Our Bill of Rights": The freedom to run the program, for any purpose.

So, I do like the PR, but it should just suggest, not enforce.

Composer is a different topic!

#169 @nwjames
3 weeks ago

Sorry to come late to this. I can only see the discussion of required plugins to have before activation. There is nothing about incompatible plugins (though I may have missed it).

I have a plug-in that is a drop-in replacement for another that was last updated 9 years ago - and uses the same options file, etc.

I really wouldn't want my plugin to be automatically activated (obviously it can be installed) if the other one is currently active.

[I see the job of my plugin to only define my incompatibilities, believing that it would be their job to state their incompatibilies if any. In my case I don't have any, but in the general case, this can give rise to a set of blockers.]

#170 @afragen
9 days ago

Plugin Dependency Thoughts

Activation
We should not be concerned whether a plugin is active or not if it doesn't have dependencies installed and active. It is the plugin developers responsibility to ensure their code gracefully degrades and does not fatal if active without its dependencies.

Version of dependencies
We should install the most recent release version of all plugin dependencies and allow them to be updated.

A JSON file is not Composer
A JSON config file, or a coded array that resides within the plugin, is more efficient and allows for future expansion if needed.

While a header that contains the slug of dependencies has the value of simplicity it has greater drawbacks. Header parsing is required and there will likely be an increased support burden associated when unsophisticated devs use incorrect data in their header.

Plugin dependency inclusion should be easy, but it's not foolproof and it should require an understanding by developers.

Headers also don't allow for recommended vs required dependencies, unless there are 2 different headers.

Using a JSON file or coded array is more performant as it also requires a small bit of code to run the dependency installer. This avoids the looping over every plugin and parsing headers, only then to run code on the results.

Additionally, having the developer run a small piece of initiation code allows this solution to work for themes without additional code.

Recommended vs Required
I think it's a non-starter to automatically install and activate a plugin without user interaction. However, messaging and function can be a bit different.

Required dependencies should have an indication in the plugin row that they are dependencies and what plugin they are dependencies for.

My personal thought is that once required plugins are installed or activated, they cannot be deactivated or deleted until the plugin that requires the dependency is deactivated. This avoid the issue of a user not remembering why a specific plugin is present and active, assuming they don't notice the other indicators. This can be easily removed from the example.

Hidden problem
Some sort of time dismissible notice is required and not yet available in core.

Solutions
I've been developing both a plugin dependency installer and helped with development of a time dismissible admin notice for a while.

https://github.com/afragen/wp-dependency-installer

https://github.com/w3guy/persist-admin-notices-dismissal

I have created an opinionated first pass for a feature plugin in https://github.com/afragen/plugin-dependency-feature

It uses a modified version of the wp-dependency-installer. It will need to have many other features removed to be acceptable to core.

Feel free to change the JSON file to add your own required and recommended dependencies. Refer to the wp-dependency-installer wiki for information on setup etc.

Non dot org dependencies
I realize that plugins are not allowed to install plugins from outside of dot org, but we should at least ask whether this is acceptable to be in core. Those features exist in the wp-dependency-installer code but can easily be removed.

#171 @prbot
9 days ago

afragen commented on PR #1547:

I have added my thoughts to the trac ticket. Putting a link here for completeness.

https://core.trac.wordpress.org/ticket/22316#comment:170

#172 @afragen
9 days ago

  • Component changed from Plugins to Upgrade/Install

This ticket was mentioned in Slack in #core-auto-updates by afragen. View the logs.


9 days ago

#174 @prbot
7 days ago

pbiron commented on PR #1547:

I'm just starting to review this PR. Initial impressions are that it is mostly working as I expect it to.

The first thing that jumps out at me tho, is that I think the notices should be changed a little (but in styling and content).

The follow screenshot is how I would expect them to be:

  • notices appear to be "within" the plugin's row (no box-shadow/border on top and with margins left and right), just like update available notices are
  • notices for plugins that are dependencies of another active plugin should be "warnings" instead of "infos"
  • the notice text for plugins that are dependencies of another active plugin should explicitly say that the plugin can't be activated

The last 2 points are to help the user realize why the Deactivate row action isn't present

https://i0.wp.com/user-images.githubusercontent.com/3824560/132957127-2ee6ac89-0b4e-4868-a83a-ed3bf68aa360.png

@aristath If you agree that notices would be better as above, what do you suggest is the best way for incorporate the necessary changes? I can push changes to your fork so you can update the PR.

#175 @prbot
7 days ago

pbiron commented on PR #1547:

Another thing I've noticed is that if I try to activate a plugin that depends on another one (which is installed, but not active), I correctly get the "Plugin X depends on plugin Y to be activated. Activate plugin" admin notice.

But I also get the "Plugin activated." admin notice, which should not appear in this case.

I haven't yet investigated how easy it will be to suppress that "success" admin notice, just want to note it here so I don't forgot to mention it :-)

#176 @afragen
7 days ago

I've mostly converted Plugin Dependency Feature to what should be a core patch.

When I get the opportunity I will add a PR. In the meantime feel free to kick the plugin around.

#177 @prbot
6 days ago

aristath commented on PR #1547:

what do you suggest is the best way for incorporate the necessary changes? I can push changes to your fork so you can update the PR.

@pbiron @dingo-d I added you as collaborators in the PR so you should be able to push changes after accepting the invitation :+1:

#178 @prbot
6 days ago

aristath commented on PR #1547:

notices appear to be "within" the plugin's row (no box-shadow/border on top and with margins left and right), just like update available notices are

Makes sense. Took a bit of tweaking but I believe it's OK now.

notices for plugins that are dependencies of another active plugin should be "warnings" instead of "infos"

I'm not sure about that... :thinking:
I'm thinking of scenarios like for example a woocommerce addon that requires woocommerce. In that case, woocommerce can be activated on its own, and works fine. The addon however requires woo. So the notice in woocommerce's row can be an info since it's technically not a "warning"... The notice in the addon however is a warning

the notice text for plugins that are dependencies of another active plugin should explicitly say that the plugin can't be deactivated

Good point. Fixed in https://github.com/WordPress/wordpress-develop/pull/1547/commits/412d94f05cfe9d74b87dc3b38ee69f9e077a269e

#179 @prbot
5 days ago

spacedmonkey commented on PR #1547:

How does this work in multisite and network activated plugins?

#180 @prbot
5 days ago

pbiron commented on PR #1547:

How does this work in multisite and network activated plugins?

that's on my list of things to test :-)

#181 @pbiron
5 days ago

One thing that we have to be aware of is that many plugins that support "addons", have their own UI (in addition to the core plugins screen) where such addons can be installed/activated/deactivated.

The above 2 screenshots show 2 such screens. The first one is for Gravity Forms, the 2nd is for Gravity Perks (which is a Gravity Forms addon that supports it's own addons :-).

I think it completely out of scope for core to try to "police" such additional ways of installing/activating/deactivating plugins. And the current PR respects that (i.e., it does NOT propose to change the behavior of activate_plugin() (and cousins).

I'm just mentioning this here so that someone doesn't suggest that this ticket should somehow address that problem :-)

This ticket was mentioned in PR #1674 on WordPress/wordpress-develop by afragen.


5 days ago

This PR based on https://github.com/afragen/wp-dependency-installer and https://github.com/collizo4sky/persist-admin-notices-dismissal.

Need to load the new dependency installer class in all plugins and themes where dependencies exist.
require_once ABSPATH . '/wp-admin/includes/class-wp-plugin-dependency-installer.php';

Uses either a JSON config file or an array of data passed in code.

JSON config file named wp-dependencies.json resides at the root of the plugin or theme.
Call as follows. WP_Plugin_Dependency_Installer::instance( __DIR__ )->run();

{{{json
[

{

"name": "Query Monitor",
"slug": "query-monitor/query-monitor.php",
"uri": "https://wordpress.org/plugins/query-monitor/",
"required": false

},
{

"name": "WooCommerce",
"slug": "woocommerce/woocommerce.php",
"uri": "https://wordpress.org/plugins/woocommerce/",
"required": true

}

]
}}}

Array example
Call as follows. WP_Plugin_Dependency_Installer::instance( __DIR__ )->register( $config )->run();

{{{php
$config = array(

array(

'name' => 'Hello Dolly',
'slug' => 'hello-dolly/hello.php',
'uri' => 'https://wordpress.org/plugins/hello-dolly',
'required' => true,

),

);
}}}

Example images. Plugin Dependency Feature (modified to use patch) and TwentyNineteen theme both have dependencies. Theme only has dependency for Hello Dolly.

<img width="857" alt="screenshot_89" src="https://user-images.githubusercontent.com/1296790/133168512-b0a935ac-d460-4e9a-86a0-050a9afaeeb2.png">

Clicking on the Install link for Hello Dolly shows the following.

<img width="853" alt="screenshot_90" src="https://user-images.githubusercontent.com/1296790/133168577-1b9c32e1-af83-48cf-8108-4e6890a4f3bd.png">

Page reload

<img width="860" alt="screenshot_91" src="https://user-images.githubusercontent.com/1296790/133168602-4d2ba06c-c45d-4f8a-a6fc-f83853485480.png">

After clicking on Activate link for Hello Dolly

<img width="852" alt="screenshot_92" src="https://user-images.githubusercontent.com/1296790/133168667-9b89890b-72dc-4cf6-8a1f-0ef3dbb9de42.png">

Page reload
<img width="854" alt="screenshot_93" src="https://user-images.githubusercontent.com/1296790/133168745-0f9265bb-2e3e-4a5b-ba24-763d63b6c1b6.png">

Query Monitor installed via link

<img width="839" alt="screenshot_94" src="https://user-images.githubusercontent.com/1296790/133168812-ea6ea9e9-d917-454a-9b69-e875c5b641a0.png">

Feature Plugin
https://github.com/afragen/plugin-dependency-feature

Trac ticket: https://core.trac.wordpress.org/ticket/22316

This ticket was mentioned in Slack in #core-auto-updates by afragen. View the logs.


4 days ago

This ticket was mentioned in Slack in #hosting-community by javier. View the logs.


4 days ago

This ticket was mentioned in Slack in #hosting-community by jadonn. View the logs.


3 days ago

#186 @amykamala
3 days ago

Would adding a hook for plugin devs to utilize to send plugin data to Site Health be a reasonable solution? That way WP core doesn't have to aggregate plugin data, but rather puts the onus on plugin (and theme) devs to provide for their users, while also offering a path to do so.

This ticket was mentioned in Slack in #core by afragen. View the logs.


3 days ago

#188 @prbot
3 days ago

afragen commented on PR #1674:

Add differentiation between required and recommended plugin dependencies.

https://i0.wp.com/user-images.githubusercontent.com/1296790/133506975-5b1b2516-7912-47e6-9e19-5e2b0824ab06.png

Last edited 3 days ago by afragen (previous) (diff)

#189 @prbot
3 days ago

tomjn commented on PR #1674:

There's discussion in the other PR that's relevant here:

  • There was a lot of discussion around composer and that a dependency .json file is redundant, lots of people were opposed to the idea
  • A dependency JSON file would be obsolete and an additional tech debt burden if a wp-plugin.json or wp-theme.json file was introduced
  • Precedents already exist for using the plugin header to define plugin slugs, and the other PR adopted such a field for defining .org plugin slugs
  • A URI implies that 3rd party plugins can be specified, but the tickets scope is confined to .org repo plugins
  • including the name and URL in the JSON file opens this up to malicious actions, for example:

{{{json
[

{

"name": "Super Safe Plugin Monitor",
"slug": "site-deleter-plugin/delete-site.php",
"uri": "https://wordpress.org/plugins/safe-plugin/",
"required": true

}

]
}}}

#190 @prbot
3 days ago

afragen commented on PR #1674:

@tomjn i did read all of the discussion on the other ticket. Respectfully, I disagree with the concept that having a JSON configuration file means "we should just use composer". There are huge differences and the ability to use a JSON config file, or in this PR, an associative array, provides for much more flexibility.

I believe that using a plugin header is much more restrictive and less performant. There is no need to loop through every installed plugin just to find the appropriate header and act on it.

Notice that this PR can also be used by themes.

There is no ability to designate a recommended plugin in a header. There is here.

Entering data into the configuration that does not conform to an actual plugin in the dot org repository will result in an installation failure. The PR specifically is restricted to dot org plugins. There is no ability to successfully designate an plugin that is not hosted on dot org.

@tomjn install the test plugin. Change the configuration and see what happens.

#191 @prbot
3 days ago

tomjn commented on PR #1674:

Respectfully, I disagree with the concept that having a JSON configuration file means "we should just use composer".

That is not what I said, a dependency file duplicates composer functionality. The consensus on the other PR was that if we add a JSON file it should be general replacement for the plugin header in the future.

There is no ability to designate a recommended plugin in a header. There is here.

Recommendations were not a part of the tickets scope.

I believe that using a plugin header is much more restrictive and less performant. There is no need to loop through every installed plugin just to find the appropriate header and act on it.

WP would already do this, and caches the result, it's necessary in order to identify which file is the plugin file and which isn't. There is no performance cost that isn't already being paid.

The PR specifically is restricted to dot org plugins.

This does not limit the scope of abuse or mismatched expectations.

#192 @prbot
3 days ago

aristath commented on PR #1547:

Summing up what this PR does when plugin A depends on plugin B:

  • When both plugins A & B are deactivated, plugin A has an inline notice (info) with the message Plugin "A" depends on the following plugin(s): B.
  • When the user clicks the "Activate" link on plugin A, the following happens:
    • If plugin B is not installed, there's an admin notice (warning) added with the text Plugin "A" depends on plugin "B" to be installed. Install and activate "B". "Install and activate B" is a link.
    • If plugin B is installed, there's an admin notice (warning) added with the text Plugin "A" depends on plugin "B" to be activated. Activate plugin. "Activate plugin" is a link.
    • Plugin A does NOT get activated until all its dependencies are met. Instead, it gets added in a queue and the "Activate" link inline the plugin row gets replaced with a "Cancel activation request" link. Additionally, plugin A gets an inline notice (warning) with the following message: Plugin "A" has unmet dependencies. Once all required plugins are installed the plugin will be automatically activated. Alternatively you can cancel the activation of this plugin by clicking on the "cancel activation request" link above.
    • Once plugin B gets activated, plugin A gets auto-activated because the user previously requested it. The "Deactivate" and "Delete" actions are removed from plugin B and a notice (info) gets added to that row with the message Plugin B cannot be deactivated because it is a dependency for the "A" plugin.

This PR does NOT force-activate anything, it simply guides users to install and/or activate dependencies.
This PR does not handle "recommended" plugins. "Requiring" and "recommending" a plugin are completely different scenarios and this is a simple implementation to avoid errors when a dependency is not installed. Recommended plugins can be used for marketing and complementary purposes and I am not sure Core would be the right place to do something like that.

A valid scenario would be for example installing a plugin addon, without the "root" plugin being installed. If I install a woocommerce addon, or a contact-form addon, or any plugin addon without woocommerce/contact-form/whatever activated, then without a dependencies implementation the following can (and frequently do) happen:

  • The addon depeloper hasn't properly tested what happens when the parent plugin is not activated and the result can be PHP warnings/errors etc (because there's no chance anyone would install woo-payment-gateway-X without Woo installed, right?)
  • There are no errors, but there's an active plugin that does nothing at all except run on every page request, looking for its parent
  • The addon developer reinvents the wheel every time and they throw notices to the user that they should install the parent plugin
  • There is no proper feedback and the user doesn't know why the plugin they installed does nothing

#193 @prbot
3 days ago

ideag commented on PR #1674:

One thing I'd like to point out about JSON files is that they will be publicly accessible in plugin directories and will contain information about other plugins in the system and maybe even their versions. In plugin header that information is automatically protected from outside access, with JSON, there would need to be an additional .htaccess rule to restrict that.

#194 @prbot
2 days ago

afragen commented on PR #1674:

@tomjn I will revise the PR to remove recommended plugins. It is out of scope.

Respectfully, I disagree with the concept that having a JSON configuration file means "we should just use composer".

That is not what I said, a dependency file duplicates composer functionality. The consensus on the other PR was that if we add a JSON file it should be general replacement for the plugin header in the future.

Creating a JSON replacement for all plugin headers is way out of scope and not like to happen.

Why does it matter if a JSON file duplicated composer functionality? Composer isn't used for core.

#195 @prbot
2 days ago

afragen commented on PR #1674:

@ideag the only data in the JSON file is data related to plugins in dot org. How is that sensitive.

Given that we actively encourage keeping plugins up to date, installing an old, outdated version seems unwise.

#196 @prbot
2 days ago

tomjn commented on PR #1674:

Why does it matter if a JSON file duplicated composer functionality? Composer isn't used for core.

There was an _enormous_ discussion about this in the other ticket, initially started precisely because core does not use composer. A wp-dependency.json file is reinventing the wheel that is composer.json. It would make more sense to just implement composer.json, or, implement a wp-plugin.json. Both are outside the scope of the ticket. There are lots of reasons not to use a dependency JSON file in this case, and lots of existing precedents supporting the plugin header approach.

#197 @prbot
2 days ago

dingo-d commented on PR #1547:

I've created a small fix PR that adds some code improvements and cleanup: https://github.com/aristath/wordpress-develop/pull/2

#198 @prbot
2 days ago

afragen commented on PR #1674:

Honestly it's not simply a choice between composer or a header. I really did read the other discussion and the moment using a JSON config was mentioned the discussion went to that duplicates composer functionality.

It's not reinventing composer. The point that it does we should transition to using composer. That time is not now.

Composer isn't used it core, it's a non-starter. That doesn't mean a configuration file cannot be used.

We all admit that a configuration file is more flexible for future use. Why not just start there?

#199 @prbot
2 days ago

tomjn commented on PR #1674:

As a part of a wp-plugin.json yes, as a wp-dependency.json file no. Right now the only non-problematic value in the file is the plugin slug, and no benefits have been outlined for putting it in a separate file.

There's also nothing to distinguish the dependency between a plugin and a theme other than the file extension on the end of the slug value. The slug also doesn't map to .org plugin slugs.

#200 @prbot
44 hours ago

afragen commented on PR #1674:

As a part of a wp-plugin.json yes, as a wp-dependency.json file no. Right now the only non-problematic value in the file is the plugin slug, and no benefits have been outlined for putting it in a separate file.

The slug is used internally, I could change it to the basename( $slug ), what is usually thought of as the slug, woocommerce or query-monitor.

There's also nothing to distinguish the dependency between a plugin and a theme other than the file extension on the end of the slug value. The slug also doesn't map to .org plugin slugs.

The slug isn't to tell the difference between a plugin and a theme.

Have you tried actually running the code? Do you have actual issues with it or is this really all about preferences?

I really don't mean to sound snarky, it's just been a long day fighting Darwin in the trauma center.

#201 @prbot
42 hours ago

aristath commented on PR #1547:

@dingo-d Thank you for the cleanup & improvements! Merged :+1:

#202 @prbot
33 hours ago

karmatosed commented on PR #1547:

I'd like to offer some design help here so jumping in to offer that. Just looking back at a few comments I have a little bit of feedback. I am settling into understanding here so please correct my course if I am off track.

  • I think what is being added makes a lot of sense based on what exists.
  • I think the notice probably falls into 'information' so that color use makes absolute sense.
  • Similar the warning does.

My big concern would be where we have double messaging coloring:

https://i0.wp.com/user-images.githubusercontent.com/253067/133805618-14acf95c-1057-4783-bdba-cac78d3d4fdc.png

I wonder if we need to embed the notices? Typically this doesn't happen and the interface really looks not too awesome with that.

Beyond those thoughts, I think looking at deciding what should or shouldn't be seen right away might be useful. For example could a simple notice of dependency show on the plugin listing? I suggest this as I can see at a scale otherwise it could get a lot. I think that might be useful in later versions though.

#203 @prbot
19 hours ago

afragen commented on PR #1674:

Latest commit removes JSON in favor of config array. @tomjn I use the slug (woocommerce/woocommerce.php) to target the plugin row.

Having some issues with the dismissible notice giving me a console error that dismissible_notice.nonce is undefined. 😖

#204 @prbot
8 hours ago

afragen commented on PR #1674:

🙌 JS should be working again.

Note: See TracTickets for help on using tickets.