FortAwesome / wordpress-fontawesome

Font Awesome Official WordPress Plugin
Other
56 stars 19 forks source link

Modifying currently active theme to add this package throws error and fails to initialize. #117

Closed ChrissiQ closed 3 years ago

ChrissiQ commented 3 years ago

Version: 4.0.0-rc22

I am working on a theme purpose-built for a client site - the site does not have any other themes installed and we are not switching to the theme - rather, it's the default active on installation, and is the only theme installed, so it might never be deactivated. It currently cannot even be deactivated since no other themes are installed on the site.

When I add the code to the theme to register with FA as per the guide and the theme-mu example integration, I receive an error in the wp-admin panel:

The Font Awesome plugin caught a fatal error.

When trying to load Font Awesome, the plugin's configuration was invalid. Try deactivating, uninstalling, and re-activating the Font Awesome plugin.

This is the code I am including in my theme:

use FortAwesome\FontAwesome_Loader;
use function FortAwesome\fa;

[...excerpted...]

include_once __DIR__ . '/../../vendor/fortawesome/wordpress-fontawesome/index.php';

add_action('font_awesome_preferences', function () {
    fa()->register([
        'name' => '[theme name]',
    ]);
});
add_action('after_switch_theme', function () {
    FontAwesome_Loader::initialize();
});
add_action('switch_theme', function () {
    FontAwesome_Loader::maybe_deactivate();
    FontAwesome_Loader::maybe_uninstall();
});

I tried adding FontAwesome_Loader::initialize(); via add_action('init', ... but that still throws the same error.

Is there a way to get this to work in the active theme without having to install another theme so that it can be disabled/re-enabled? Having to switch away from the currently active theme is not currently something that would be simple to do, so I need to be able to use the FA package without doing that.

At the same time, we never know what the client may do in the future, so it will still need to work if one day in the future the theme is disabled/re-enabled - I don't want to break this functionality of course.

I am not dead-set on including the package as a dependency of the theme - we could use it as a normal wordpress plugin, except that we are controlling plugins via composer, and this package will not install correctly as a plugin using composer/installers because it does not have its type defined. But even then, I don't think this package is meant to be used this way, since configuring the package as a wordpress-plugin for composer/installers would probably break existing usage for many people. So I am not sure what I can do other than abandon use of this package and instead install FA via some other means.

robmadole commented 3 years ago

Hi @ChrissiQ. We will take a look at this today.

mlwilkerson commented 3 years ago

Hi @ChrissiQ I'm investigating.

I'm not familiar with the options and trade-offs regarding composer/installers and the implications of defining the type, as you've mentioned. Could you shed any more light on that, or point me to the relevant resources? I don't know that our solution is down that path, but it seems like something I should know more about in this dev ecosystem.

ChrissiQ commented 3 years ago

@mlwilkerson Sure, though I am not an expert or anything. Thank you for investigating.

composer/installers allows a package to be installed in a location other than vendor. For WordPress, it is extremely useful in order to manage themes and plugins - but this depends on the theme/plugin registering itself as a wordpress-theme or wordpress-plugin type in its composer.json.

If your plugin has composer/installers included in its dependencies and defines a type that matches a currently supported package type, the package consumer it may define extra:installer-paths in their composer.json, allowing, for example, wordpress themes to be installed in wp-content/themes and plugins to be installed in wp-content/plugins where wordpress expects them to be, so they don't need to be registered in any other way and will behave the same as any other drop-in plugin or theme, but can be managed via composer.

However, I believe I've found the solution I was looking for, and I'm not sure why I didn't find this earlier - I am able to install this package as a wordpress plugin from wpackagist.

wpackagist maintains a list of wordpress plugins from the main plugin repository and modifies them to be compatible with composer/installers. If I composer require wpackagist-plugin/font-awesome I can use this package as a wordpress plugin and everything seems to be working peachy!

Thanks again!

mlwilkerson commented 3 years ago

OK, reasoning through this:

(You replied, seemingly resolved, while I was in the midst of writing this response. So it may no longer be relevant. But I'll complete my thought in case in comes in handy to you, my future self reviewing this issue later, or someone else who stumbles onto this.)

  1. The error you're seeing is just the generic ConfigCorruptionException. That gets thrown when there's some undefined state in the database that really should never be the case.

    • Like, somehow the plugin code is running without having been properly activated, so the font-awesome option in the options table doesn't exist, or it somehow has been corrupted such that format of the data stored there is bad.
    • So the reason for the suggestion to try deactivating, uninstalling, and re-installing is just to run all of the cleanup and activation logic from scratch. Basically, "try powering off, and then powering back on" 😄 .
  2. In your case, I suspect that the activation logic just hadn't ran yet before the main run() logic of the plugin, which depends on having been activated.

    • yet you tried to get it to run by calling it on an init hook. I do expect that this should have worked (except that you probably wouldn't want to run initialize on the init of every page load.)
    • if I were going to take a closer look, I'd be scrutinizing this point right here: was it actually running the initialization logic successfully? If not, then you'd definitely see that ConfigCorruptionException when later the lifecycle the plugin does its main run() logic.
  3. If one were in a similar situation as this, where a facility needs to be provided to the WP admin user to make it convenient to run the deactivation and uninstall logic in order to clean up, but you can't hook into the after_switch_theme or switch_theme actions, then I'd recommend just adapting the principle to whatever you can do.

    • Somehow, run these to clean up:

      FortAwesome\FontAwesome_Loader::maybe_deactivate();
      FortAwesome\FontAwesome_Loader::maybe_uninstall();
    • And then run this to re-initialize:

      FortAwesome\FontAwesome_Loader::initialize();
    • An added challenge here is the "tentativeness" of the "maybe deactivate" and "maybe uninstall". These utilities in FontAwesome_Loader are designed to respect the possibility that multiple plugins may have dependencies on the Font Awesome plugin. Multiple composer bundles may be hooking in down at the lower FontAwesome_Loader level like you'd be doing in your theme. If so--if there are any others that the loader knows about--then calling maybe_deactivate() and maybe_uninstall() won't actually do the clean up work, because it will want to leave things alone for the sake of the others.

      • If you know that you actually need to force this kind of cleanup and re-initialization logic, even if your theme is not the only client of FontAwesome_Loader, then you may need to directly invoke the corresponding methods in the deactivator and activator classes that don't include the "maybe":
        FontAwesome_Deactivator::deactivate();
        FontAwesome_Deactivator::uninstall();
        FontAwesome_Activator::activate();