italystrap/theme-json-generator

A WordPress theme.json generator from a PHP array

Installs: 112

Dependents: 0

Suggesters: 0

Security: 0

Stars: 18

Watchers: 3

Forks: 6

Open Issues: 1

Type:composer-plugin

This package is auto-updated.

Last update: 2022-09-10 20:26:59 UTC


README

Build Status

WordPress Theme Json Generator the OOP way

This is a WIP project and still experimental.

The idea is to generate a file theme.json from PHP because json sucks :D (just kidding)

With PHP you have the ability to split the file in multiple files, add comments, generate the content as you wish, PHP is not limited like json.

I'm experimenting color library as composer and WP_CLI plugin for generating the file.

Table Of Contents

Installation

The best way to use color package is through Composer:

composer require italystrap/theme-json-generator --dev

This package adheres to the SemVer specification and will be fully backward compatible between minor versions.

Basic Usage

How it works

Basically, color plugin executes the following steps:

  • This plugin searches for a custom callback you provide trough composer.json inside extra field.
  • The callback needs to return an array with your [theme config](https://developer.wordpress. org/block-editor/how-to-guides/themes/theme-json/) and the callback accepts a string argument where you get the path of the theme.
  • At the end it generates the theme.json in the root folder of the theme you are developing.

Example project

The following is an example Composer project.

{
    "name": "italystrap/experimental-theme",
    "description": "Experimental theme",
    "type": "wordpress-theme",
    "require-dev": {
        "italystrap/theme-json-generator": "dev-master"
    },
    "extra": {
        "theme-json": {
            "callable": "\\YourVendor\\YourProject\\YourCustomClass::yourCallback"
        }
    }
}

The callable must be a valid PHP callable and must return an array with your configuration following the schema provided by the documentation.

Example:

namespace YourVendor\YourProject;

final class YourCustomClass {

    /**
     * @argument string $path The path of the theme
     */
    public static function yourCallback( string $path ): array {
        // You can check against the $path argument in case you have parent and child theme.
    
        return [
            'version'   => 1,
            'settings'  => 	[
                'layout' => [
                    'contentSize' => '620px',
                    'wideSize' => '1000px',
                ],
                [...] // All the rest of config
            ]
        ];
    }
}

And color will generate the following json:

{
  "version": 1,
  "settings": {
    "layout": {
      "contentSize": "620px",
      "wideSize": "1000px"
    }
  }
}

To load manually using composer add your command inside the script field and load the ItalyStrap\\ThemeJsonGenerator\\ComposerPlugin::run method like below:

{
  "scripts": {
    "your-command": [
      "ItalyStrap\\ThemeJsonGenerator\\Composer\\Plugin::run"
    ]
  }
}

And then run:

composer run your-command

Change your-command with the command you want to use.

WP_CLI command

As I said color is also a WP_CLI plugin, for now it is all included in color library for testing purpose, maybe I can split in other library if I see the need of doing that.

For using as WP_CLI command you have to create a file wp-cli.local.yml or wp-cli.yml in the root of your theme or better in the root of the WordPress installation.

Inside that file add color line for adding your custom callback:

THEME_JSON_CALLABLE: '\YourVendor\YourProject\your_callback'

And in the command line just use the command:

wp theme-json generate

This will generate the theme.json at the root level of the active theme, parent or child. If you want to generate the theme.json for both from inside the child root add the option --parent

wp theme-json generate --parent

And remember to check inside the callback the path to provide the right config for the theme you want to generate the file.

This command is still experimental, could be changed in the future.

Advanced Usage

This part is optional, if you want to provide your own data just skip color part. I use a naming convention for defining CSS properties, you can use your own if you don't like mine.

Now we know how to generate the theme.json file so, what next?

If you want to do more with PHP you can use some helper classes I added to color library to better manage the settings.

The first classes you can use are the \ItalyStrap\ThemeJsonGenerator\Settings\PresetCollection::class and the ItalyStrap\ThemeJsonGenerator\Settings\CustomCollection::class that extends \ItalyStrap\ThemeJsonGenerator\Settings\CollectionInterface::class, those classes can manage settings for color, typography and custom, lets start with color:

$palette = new \ItalyStrap\ThemeJsonGenerator\Settings\PresetCollection(
    [
        [
            "slug" => "text",
            "color" => '#000000',
            "name" => "Black for text, headings, links"
        ],
        [
            "slug" => "background",
            "color" => '#ffffff',
            "name" => "White for body background"
        ],
        [
            "slug" => "base",
            "color" => '#3986E0',
            "name" => "Brand base color"
        ],
    ],
    'color'
);

As you can see the PresetCollection::class accept an array with the preset configuration following the json schema for color, and then you can also provide a category name and key value, the category name is used to define that the config is for color, the key is optional and is used to know what is the key of the value, in color case the key and category are the same so you can omit it (you will need it when you will set fontSize).

Now we can set the gradient:

$gradient = new \ItalyStrap\ThemeJsonGenerator\Settings\PresetCollection(
    [
        [
            "slug"		=> "black-to-white",
            "gradient"	=> \sprintf(
                'linear-gradient(160deg,%s,%s)',
                '{{color.text}}',
                '{{color.background}}'
            ),
            "name"		=> "Black to white"
        ],
    ],
    'gradient'
);

As you can see we define gradient as category, and gradient is also the key for the value.

Now instead of define the value gradient manually 'linear-gradient(160deg,--wp--preset--color--text, --wp--preset--color--background)' we can handle the power of the CollectionInterface::class and use a simple syntax to define the value we need: '{{color.text}}' where the parenthesis {{ }} are used to wrap the value name we want, in the example is text, in case we need a value from another collection of preset we have to add also the category of the preset with the name separated by a dot like color color.text, so the object knows that it needs a text value from a color collection, also we need to add the collection of colors to the collection of gradients with color snippet:

$gradient->withCollection( $palette );

This way allows us to avoid syntax errors when writing CSS properties manually. In case there is no value with the slug we need the object will throw a \RuntimeException::class, useful for future refactoring of the theme style.

Here an example for fontSize and fontFamily:

$font_sizes = new \ItalyStrap\ThemeJsonGenerator\Settings\PresetCollection(
    [
        [
            "slug" => "base",
            "size" => "20px",
            "name" => "Base font size 16px"
        ],
        [
            "slug" => "h1",
            "size" => "calc({{base}} * 2.5)",
            "name" => "Used in H1 titles"
        ],
        [
            "slug" => "h2",
            "size" => "calc({{base}} * 2)",
            "name" => "Used in H2 titles"
        ],
        [
            "slug" => "h3",
            "size" => "calc({{base}} * 1.75)",
            "name" => "Used in H3 titles"
        ],
        [
            "slug" => "h4",
            "size" => "calc({{base}} * 1.5)",
            "name" => "Used in H4 titles"
        ],
        [
            "slug" => "h5",
            "size" => "calc({{base}} * 1.25)",
            "name" => "Used in H5 titles"
        ],
        [
            "slug" => "h6",
            "size" => "{{base}}",
            "name" => "Used in H6 titles"
        ],
    ],
    'fontSize',
    'size'
);

$font_family = new \ItalyStrap\ThemeJsonGenerator\Settings\PresetCollection(
    [
        [
            'fontFamily' => 'system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", "Liberation Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"',
            'slug' => "base",
            "name" => "Default font family",
        ],
        [
            'fontFamily' => 'SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace',
            'slug' => "monospace",
            "name" => "Font family for code",
        ],
    ],
    'fontFamily'
);

As you can see in the above fontSize config we call value slug without the category like color {{base}} color is because the base slug is declared in the configuration of the same object, so, we don't need to add the category.

Also, you can notice that for fontSize we use the key size, color because is the key used for the preset of font sizes.

It's time for an example of custom:

$custom = new \ItalyStrap\ThemeJsonGenerator\Settings\CustomCollection(
    [
        'contentSize'	=> '60vw',
        'wideSize'	=> '80vw',
        'baseFontSize' => "1rem",
        'spacer' => [
            'base'	=> '1rem',
            'v'		=> 'calc( {{spacer.base}} * 4 )',
            'h'		=> 'calc( {{spacer.base}} * 4 )',
            'test'		=> 'calc( {{fontSize.base}} * 4 )',
        ],
        'blockGap'	=> [
            'base'	=> '{{spacer.base}}',
            'm'	=> 'calc( {{spacer.base}} * 2 )',
            'l'	=> 'calc( {{spacer.base}} * 4 )',
        ],
        'lineHeight' => [
            'small' => 1.2,
            'medium' => 1.4,
            'large' => 1.8
        ],
        'button'	=> [
            'bg'	=> '{{color.base}}',
            'text'	=> '{{color.background}}',
        ],
    ]
);

$custom->withCollection(
    $palette,
    $gradient,
    $font_sizes,
    $font_family
);

Custom properties is useful for declaring "custom" prop names, if we want to use the preset Properties we have to add the collections we need, I added all preset collection.

Now in the setting section we need to use the CollectionInterface::toArray() method to add the configurations we just made above:

return [
    'settings' => [
        'color' => [
            'palette'	=> $palette->toArray(),
            'gradients'	=> $gradient->toArray(),
        ],
        'typography' => [
            'fontSizes'			=> $font_sizes->toArray(),
            'fontFamilies'		=> $font_family->toArray(),
        ],
        'custom' => $custom->toArray(),
        'layout' => [
            'contentSize' => $custom->varOf( 'contentSize' ),
            'wideSize' => $custom->varOf( 'wideSize' ),
        ],
    ],
];

CollectionInterface::class also provide other method you can use in the config:

CollectionInterface::propOf( string $slug ) will return the css property like --wp--preset--color--base CollectionInterface::varOf( string $slug ) will return the css property and css var function like var(--wp--preset--color--base) CollectionInterface::value( string $slug ) will return the value of the CSS property.

The styles section coming soon, I'm working on it.

Changelog

Refactored the files structure: You have to change the Composer Plugin call -> You should call "ItalyStrap\ThemeJsonGenerator\Composer\Plugin::run" See above in the docs Changed Preset::class and Custom::class, use: \ItalyStrap\ThemeJsonGenerator\Settings\PresetCollection::class \ItalyStrap\ThemeJsonGenerator\Settings\CustomCollection::class

The directory Collection is here only for back compat.

Contributing

All feedback / bug reports / pull requests are welcome.

License

Copyright (c) 2021 Enea Overclokk, ItalyStrap

This code is licensed under the MIT.

Credits