10up / wp-scaffold

10up WordPress project scaffold.
MIT License
201 stars 47 forks source link

Proposal for Modular WP Scaffold using Composer #104

Open dsawardekar opened 2 years ago

dsawardekar commented 2 years ago

Is your enhancement related to a problem? Please describe.

Currently, WP Scaffold is used to bootstrap new projects at 10up. After the project is underway it can be useful to re-integrate updates to the scaffold. At the moment, such an update has to be done manually. Similarly it is difficult to pull bug fixes back into the project. Lastly, any new features that are added to the wp-scaffold are not readily available to projects started with an older version of wp-scaffold.

Designs

To address these issues I'm proposing a modular composer based approach outlined below.

1) wp-library composer package

The code inside the wp-scaffold would move to this wp-library repo. For MVP, This can be a GitHub repo with a composer.json. The wp-library would be imported into the wp-scaffold using configuration like this in the composer.json.

{
    "repositories": [
        {
            "url": "https://github.com/10up/wp-library",
            "type": "git"
        }
    ],
    "require": {
        "10up/wp-library": "~1.0.0"
    }
}

In the future we can publish a package to packagist to reduce this to a simpler require,

{
    "require": {
        "10up/wp-library": "~1.0.0"
    }
}

With this in place, projects using the wp-scaffold can upgrade to a newer 1.1.0 release by doing a composer update to that version of the wp-library.

{
    "require": {
        "10up/wp-library": "~1.1.0"
    }
}

2) Scaffold extends Theme

The wp-library would implement a Theme object that provides common functionality refactored from includes/core.php. In the wp-scaffold theme, we can extend the Theme in the wp-library.

class Theme extends \TenUp\Theme {

}

In a project with such a setup, The Theme class methods can be customized per the project requirements while retaining the parent wp-library functionality while still supporting upgrade paths.

class Theme extends \TenUp\Theme {

  public function js_detection() {
    parent::js_detection();

    // adds a has-notification class if the browser supports Web Notification API
    echo '<script type="javascript"> if (window.Notification ) { document.documentElement.className += 'has-notification'; } </script>'; 
  }

}

3) Theme Supports

Once we have a separate wp-library package we can let the wp-scaffolded projects determine what features should be enabled on the Theme using the add_theme_support api.

For instance, in the wp-library we could implement the above javascript detection behind a theme support condition like,

if ( get_theme_support( 'js_detection' ) ) {
  // do js detection here
}

And in the wp-scaffold theme, this can be managed with,

add_theme_support( 'js_detection' );

This approach combined with the composer.json versioning, allows us a lot of flexibility to add & improve features while maintaining backwards compatibility. For instance, if a new version of js_detection needs to be implemented in the same release it can be given a new theme support name.

After upgrading, projects can opt-in to the new release with something like,

add_theme_support( 'experimental_js_detection' );

4) Shared Features

By allowing projects to opt-in to the wp-library features we can introduce other shared features that are used across projects based on type, hosting provider etc.

Examples:

5) Scaffold extends Plugin

Similarly the wp-library can provide shared functionality to custom plugins while maintaining an upgrade path for bug fixes and improvements.

class Plugin extends \TenUp\Plugin {

}

Describe alternatives you've considered

This approach requires a composer install step to pull in the wp-library dependency. This is something that is typically incorporated into a build step in Gitlab CI, Circle CI, etc. This approach may not be suitable for projects that don't use Continuous Integration.

Code of Conduct

dsawardekar commented 2 years ago

Following up with examples from the previous meeting.

1) Fieldmanager Based Site Settings

We can standardize on Site Settings using the Fieldmanager plugin. The settings can have default fields like Social URLs which are used on most sites. And this feature would only be enabled if the theme declares support for site-settings. Another common pattern is to have Site Settings available as a Dropdown in the Admin Menu.

This can be extended to Headless projects by providing a site-settings endpoint that sends the saved Site Settings over REST.

2) New Relic Profiling

The New Relic theme support feature can be used to help identify common bottlenecks on projects. For example we could wrap New Relic around WP HTTP request calls using hooks like pre_http_request. By monitoring performance of such external APIs we can identify any resulting slow requests.

3) Yoast SEO Tuning

A theme support like yoast_seo_defaults can customize Yoast to match typical 10up defaults. This can include,

4) ElasticPress Tuning

Different tiers of ElasticPress.io could have different profiles.

The overall goal here is to provide good defaults that don't need to be re-implemented on every project. And at the same time keeping an upgrade path open for revisions and/or bug fixes.

claytoncollie-dmv commented 2 years ago

@dsawardekar I really like this idea and was thinking about it for my projects where I created invididual classes to 1) Disable XML RPC, 2) Clean up the wp_head, 3) Remove emojis 4) Clean up the dashboard widgets. Things that could be standardized, even written as small stand-alone plugins. I always go back and forth on whether to include this sort of stuff in the 10up-Experience plugin or within the theme or its own plugin.

As for your specific issue, I would also want to see these 4 use cases broken into their own repositories so that the theme can use composer to require them if necessary. That might save the extra step of using add_theme_support to toggle them off or on when bundled into a larger repo.

dsawardekar commented 2 years ago

@claytoncollie-dmv Separating bigger features into separate packages/plugins is definitely something we can do once we have switched to a modular scaffold. The examples you have noted are perfectly in the Goldilocks zone as wp-library features!

RE: add_theme_support

The add_theme_support has an advantage over separate packages because it works at runtime. For example, a different part of the theme code or plugin can choose to turn off a feature on some requests. With separate packages, it is a build time decision whether to include a package in the composer.json.

dainemawer commented 2 years ago

@dsawardekar this is a great proposal and makes a ton of sense to me. Would a setup like this be able to amend build tool configurations? Say eslint or babel ? Or even potentially output specific CSS partials depending on the configuration? With regards to Tailwind for instance we'd need to:

a) output a tailwind.config.js b) install some extra npm packages c) update CSS partials

I'd be interested to see just how flexibility composer could provide us here