Larva Plugin for PMC Themes
This plugin contains functionality WordPress themes need to use the Larva design system on PMC's publishing sites.
Overview of Functionality
- Themes provide a class to configure this PMC Larva plugin
- Themes initialize Larva with an instance of the \PMC\Larva\Config class
- This plugin provides the build artifacts (PHP and JSON) and helper methods required for WP themes to use Larva patterns
- This plugin provides controllers for patterns with default data
- Themes call controllers from this plugin with contextual options
Updating Larva packages
The Larva packages installed in pmc-plugins/pmc-larva/_core/ make tools contributed to the Larva Github repo available to themes using this plugin.
To update the packages to the latest version:
cdinto pmc-plugins/pmc-larva/_core- Run
npm run update-larva - Carefully confirm the changes in the Git history and test them on QA.
Adding PMC Larva Plugin to a Theme
Install Larva in a theme per this How To Guide (opens in a new tab).
Example of configuration
Larva\Config::get_instance()->init(
[
'brand_name' => self::BRAND_NAME,
'brand_url' => get_stylesheet_directory_uri() . '/assets',
'brand_directory' => IW_TEMPLATE_DIR . '/assets',
'brand_templates_directory' => IW_TEMPLATE_DIR . '/template-parts/patterns',
]
);Module Controllers
A Larva module controller corresponds directly with a Larva module (i.e. those modules listed on the leftmost column of the menu in a Larva static site (opens in a new tab)), and handles the mapping of actual data to the object structure of a pattern. These are called "modules" in this codebase.
Each module extends a base class and provides it's own default options structure. This options structure is used to ensure all instances of the module adhere to the same structure. Additional methods that provide actual data from the database can be added, but should not be called in the init method, rather, they should be passed to the module instance in a template.
For example:
// template-parts/article/breadcrumbs.php
$data = \PMC\Larva\Modules\Breadcrumbs::get_instance()->get_breadcrumb_data();
$variant = \Sportico\Inc\Featured_Article::get_instance()->is_featured_article() ? 'featured-article' : '';
\PMC\Larva\Breadcrumbs::get_instance()->init([
'data' => $data,
'variant' => $variant
])->render( true );Contributing Modules
Modules should extend the base class Module\Base, and set up the data structure with default values for a given module. Refer to an example module in Mock_Breadcrumbs for an example use case.
The following are required in each module subclass:
string $pattern_shortpath
For example: 'modules/breadcrumbs'. This will be formed into a path to retrieve the pattern template and JSON from either the theme or the core plugin.
We should only create these classes for modules, not for objects or components.
final function get_default_options(): array
This method returns an array structure to contain data and options for a module. It should not contain calls to the database, rather, it sets up an object contract all contextual data must adhere to.
This method should be final because this object contract should not be modifiable should consuming projects further extend a module (see below).
function populate_pattern_data( array $pattern, array $data ): array
This method should contain all code that plugs actual data into a pattern object. This is sometimes referred to as "controller code", and looks something like this:
$o_nav_list_item = $pattern['o_nav']['o_nav_list_items'][0];
$pattern['o_nav']['o_nav_list_items'] = [];
$o_nav_list_item['c_link_text'] = $data['first_item']['name'];
$o_nav_list_item['c_link_url'] = $data['first_item']['url'];
// ...
return $pattern;The $data parameter is is the data key of the contractual object outlined in get_default_options. The base class handled retrieving the pattern JSON.
Extending Modules
Module classes contributed to this plugin can be extended in themes and other plugins to provide custom data methods or to accommodate project-level pattern structures.
Future: Using Template Parts and Rendering Modules with Data
At present, the module base class does provide an interface for actual data retrieval for a pattern. This can be handled in a couple of ways:
- Template parts – Common modules with data that are useful for redesigns can be available from the template-parts directory in this plugin. This could ultimately reflect the template parts available in the PMC Spark starter theme (opens in a new tab).
- A init_with_data method, or similar – A method that instantiates and retrieves data.
Available Filters
pmc_larva_json_pattern_name - Filter the name of the pattern JSON name.
Useful for themeing by including different JSON based on server side logic e.g. Variety VIP (is_variety_vip) or Art in America on Artnews site (is_aia).
add_filter( 'pmc_larva_json_pattern_name', function( $pattern_name ) {
if ( Brand::is_special_theme() ) {
// e.g. breadcrumbs.special
$pattern_name = str_replace( 'prototype', 'special', $pattern_name );
return $pattern_name;
}
return $pattern_name;
});See this example in pmc-artnews-2019 (opens in a new tab).
Asset Configuration
Through the Larva configuration, common assets are enqueued for specific contexts, such as when displaying a single post or an archive that includes supported post objects.
Contexts
To support Larva in themes that predate its existence, Larva's assets can be limited to supported contexts. For example, a theme may introduce a new feature that leverages Larva without disrupting the rest of the theme. Conversely, for themes that fully leverage Larva, the context can be set to load Larva assets universally, without enumerating every context that Larva should apply to.
To load Larva assets for limited contexts, the Larva config will include an
array of supported post types under the context key:
PMC\Larva\Config::get_instance()->init(
[
'context' => [
'post',
'page',
],
]
);To load Larva in all contexts, set the context key to true:
PMC\Larva\Config::get_instance()->init(
[
'context' => true,
]
);Errata
For now, supported contexts are tied to post types, not to queries or query
conditionals. A future update will add support for query conditionals, such as
is_home() or is_page_template().
CSS
Larva's common stylesheet is available in two versions, one designed for themes
whose CSS has high specificity, and one for themes whose CSS does not. By
default, the latter is enqueued automatically for any supported contexts. If a
theme requires the high-specificity variant, it loads it by setting the css
argument of the Larva config to larva-important:
PMC\Larva\Config::get_instance()->init(
[
'css' => 'larva-important',
]
);Setting css to larva matches the default behaviour.
Compatibility CSS
In some cases, themes require compatibility CSS to ensure the larva.css library works correctly. The compatibility stylesheet should be contributed to the Larva Github repo and published to npm, where the compiled assets will be copied into this theme upon an update. The CSS should be added following this workflow (opens in a new tab), and can be enqueued in the publishing sites by adding the compat_css config value.
PMC\Larva\Config::get_instance()->init(
[
'brand_name' => 'variety',
'compat_css' => true,
'contexts' => [ 'post' ],
]
);The above configuration will add a body class 'lrv-variety-compat' to all posts and will inline the stylesheet called variety.compat.css.
JS
Larva provides various scripts that may or may not be required in all contexts where Larva is enabled. Accordingly, scripts can be configured to load in all supported contexts, or only for the contexts enumerated in the configuration. Consider the following example:
PMC\Larva\Config::get_instance()->init(
[
'contexts' => [
'post',
'page',
],
'js' => [
'common',
'standalone/video-showcase' => [
'post',
],
],
]
);The common JS bundle will be loaded for both the post and page contexts,
while the standalone/video-showcase script will only be loaded for the post
context.
For any script that should be loaded in all contexts, its handle is
included in the js array as a string value (no key, or a numeric key); for a
context-limited script, its handle becomes the key in the js array, with its
value an array of contexts in which to enqueue the script.
Adding a new script
New scripts should be contributed to the @penskemediacorp/larva-js package. Read more about contributing to packages here (opens in a new tab).
Tokens
To load a brand's tokens, set the tokens configuration key to the string
representing the brand's entry in the larva-tokens package, such as default,
or indiewire. Larva will inline the tokens with the priority needed to include
them before any stylesheets that reference them.
PMC\Larva\Config::get_instance()->init(
[
'tokens' => 'default',
]
);Links
- Larva monorepo (opens in a new tab) – this repo contains the shared front-end assets for the design system.
- Larva wiki (opens in a new tab) - a collection of Larva documentation.
History and Changelog
This plugin was created in the context of the Gutenberg Phase 1 Project for Indiewire Hubs in order to use Larva on themes that are not on pmc-core-v2, and to experiment with creating theme pattern libraries in a plugin vs. the theme to ease the process of updating Larva in themes.
Please see this plugin's CHANGELOG.md for detailed changes since its creation.
Support
Please use the #larva channel for support regarding features specific to Larva, and the #engineering channel for PHP-specific questions.