-
Notifications
You must be signed in to change notification settings - Fork 0
Modularise theme.json into preset files #4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,96 @@ | ||
| <?php | ||
| namespace ls_theme\includes; | ||
|
|
||
| /** | ||
| * Register Modular Theme.json Presets. | ||
| * | ||
| * Loads separate JSON preset files from /styles/presets/ and merges them | ||
| * into theme.json via the wp_theme_json_data_theme filter. This allows | ||
| * design tokens (colours, typography, spacing, shadows, radii, borders, | ||
| * layout) and CSS utility classes (aspect ratios, flex/grid helpers, | ||
| * spacing utilities, text truncation) to be maintained in individual | ||
| * files for better organisation and reusability across projects. | ||
| * | ||
| * @package ls_theme\includes | ||
| * @since 1.0.0 | ||
| */ | ||
|
|
||
| if ( ! defined( 'ABSPATH' ) ) { | ||
| exit; | ||
| } | ||
|
|
||
| /** | ||
| * Merges modular preset JSON files into the theme's theme.json data. | ||
| * | ||
| * Automatically discovers and loads all .json files from the /styles/presets/ | ||
| * directory and its subdirectories (e.g., /styles/presets/blocks/). Each preset | ||
| * file contains a slice of `settings` or `styles` that would otherwise live | ||
| * directly in theme.json. Files are loaded alphabetically, and WordPress's | ||
| * native WP_Theme_JSON::merge() handles the merging logic. | ||
| * | ||
| * @since ls_theme 1.0 | ||
| * | ||
| * @param WP_Theme_JSON_Data $theme_json The theme JSON data object. | ||
| * @return WP_Theme_JSON_Data The modified theme JSON data object. | ||
| */ | ||
| function merge_preset_files( $theme_json ) { | ||
| $preset_dir = get_template_directory() . '/styles/presets/'; | ||
|
|
||
| // Automatically discover all JSON files in the presets directory. | ||
| if ( ! is_dir( $preset_dir ) ) { | ||
| return $theme_json; | ||
| } | ||
|
|
||
| // Recursively find all JSON files in presets directory and subdirectories. | ||
| $preset_files = get_preset_files_recursive( $preset_dir ); | ||
|
|
||
| if ( empty( $preset_files ) ) { | ||
| return $theme_json; | ||
| } | ||
|
|
||
| // Sort alphabetically for predictable loading order. | ||
| sort( $preset_files ); | ||
|
|
||
| foreach ( $preset_files as $file ) { | ||
| $preset_data = json_decode( file_get_contents( $file ), true ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents | ||
|
|
||
| if ( ! is_array( $preset_data ) ) { | ||
| continue; | ||
| } | ||
|
|
||
| // Use WordPress's native merge method via update_with(). | ||
| $theme_json->update_with( $preset_data ); | ||
| } | ||
|
|
||
| return $theme_json; | ||
| } | ||
|
|
||
| /** | ||
| * Recursively retrieves all JSON files from a directory and its subdirectories. | ||
| * | ||
| * @since ls_theme 1.1 | ||
| * | ||
| * @param string $directory The directory path to scan for JSON files. | ||
| * @return array Array of file paths to JSON files. | ||
| */ | ||
| function get_preset_files_recursive( $directory ) { | ||
| $files = array(); | ||
|
|
||
| // Get JSON files in the current directory. | ||
| $json_files = glob( $directory . '*.json' ); | ||
| if ( ! empty( $json_files ) ) { | ||
| $files = array_merge( $files, $json_files ); | ||
| } | ||
|
|
||
| // Get subdirectories and recursively scan them. | ||
| $subdirs = glob( $directory . '*', GLOB_ONLYDIR ); | ||
| if ( ! empty( $subdirs ) ) { | ||
| foreach ( $subdirs as $subdir ) { | ||
| $files = array_merge( $files, get_preset_files_recursive( trailingslashit( $subdir ) ) ); | ||
| } | ||
| } | ||
|
|
||
| return $files; | ||
| } | ||
|
|
||
| add_filter( 'wp_theme_json_data_theme', __NAMESPACE__ . '\merge_preset_files' ); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| { | ||
| "$schema": "https://schemas.wp.org/trunk/theme.json", | ||
| "version": 3, | ||
| "styles": { | ||
| "blocks": { | ||
| "core/button": { | ||
| "variations": { | ||
| "outline": { | ||
| "border": { | ||
| "color": "var:preset|color|brand-500", | ||
| "style": "solid", | ||
| "width": "2px", | ||
| "radius": "var:preset|border-radius|200" | ||
| }, | ||
| "color": { | ||
| "background": "var:preset|color|base", | ||
| "text": "var:preset|color|contrast" | ||
| }, | ||
| "spacing": { | ||
| "padding": { | ||
| "top": "1rem", | ||
| "right": "4rem", | ||
| "bottom": "1rem", | ||
| "left": "1.5rem" | ||
| } | ||
| }, | ||
| "typography": { | ||
| "fontSize": "var:preset|font-size|200", | ||
| "fontWeight": "700", | ||
| "letterSpacing": "0.08em" | ||
| }, | ||
| "css": "&{--ls-button-outline-accent-background:var(--wp--preset--color--brand-500);--ls-button-outline-accent-colour:var(--wp--preset--color--base);--ls-button-outline-icon-radius:var(--wp--preset--border-radius--100);}" | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,40 @@ | ||
| { | ||
| "$schema": "https://schemas.wp.org/trunk/theme.json", | ||
| "version": 3, | ||
| "settings": { | ||
| "custom": { | ||
| "button-padding": { | ||
| "top": "1rem", | ||
| "right": "4rem", | ||
| "bottom": "1rem", | ||
| "left": "1.5rem" | ||
| } | ||
| } | ||
| }, | ||
| "styles": { | ||
| "elements": { | ||
| "button": { | ||
| "color": { | ||
| "text": "var:preset|color|base" | ||
| }, | ||
| "border": { | ||
| "radius": "var:preset|border-radius|200" | ||
| }, | ||
| "spacing": { | ||
| "padding": { | ||
| "top": "1rem", | ||
| "right": "4rem", | ||
| "bottom": "1rem", | ||
| "left": "1.5rem" | ||
| } | ||
| }, | ||
| "typography": { | ||
| "fontSize": "var:preset|font-size|200", | ||
| "fontWeight": "700", | ||
| "letterSpacing": "0.08em" | ||
| }, | ||
| "css": "&{--ls-button-fill-background:var(--wp--preset--color--brand-500);--ls-button-fill-icon-colour:var(--wp--preset--color--base);--ls-button-fill-hover-text:var(--wp--preset--color--contrast);--ls-button-fill-duration:500ms;--ls-button-fill-enter-delay:80ms;--ls-button-active-scale:0.98;}" | ||
| } | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| { | ||
| "$schema": "https://schemas.wp.org/trunk/theme.json", | ||
| "version": 3, | ||
| "settings": { | ||
| "appearanceTools": true, | ||
| "layout": { | ||
| "contentSize": "800px", | ||
| "wideSize": "1360px" | ||
| }, | ||
| "useRootPaddingAwareAlignments": true | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,18 @@ | ||||||
| { | ||||||
| "$schema": "https://schemas.wp.org/trunk/theme.json", | ||||||
| "version": 3, | ||||||
| "styles": { | ||||||
| "elements": { | ||||||
| "link": { | ||||||
| "color": { | ||||||
| "text": "var(--wp--preset--color--accent-500)" | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For better consistency with other preset files (like
Suggested change
|
||||||
| }, | ||||||
| ":hover": { | ||||||
| "color": { | ||||||
| "text": "var(--wp--preset--color--accent-two-500)" | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||||||
| } | ||||||
| } | ||||||
| } | ||||||
| } | ||||||
| } | ||||||
| } | ||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| { | ||
| "$schema": "https://schemas.wp.org/trunk/theme.json", | ||
| "version": 3, | ||
| "settings": { | ||
| "border": { | ||
| "radius": true, | ||
| "radiusSizes": [ | ||
| { | ||
| "name": "none", | ||
| "slug": "0", | ||
| "size": "0" | ||
| }, | ||
| { | ||
| "name": "small", | ||
| "slug": "100", | ||
| "size": "4px" | ||
| }, | ||
| { | ||
| "name": "medium", | ||
| "slug": "200", | ||
| "size": "8px" | ||
| }, | ||
| { | ||
| "name": "large", | ||
| "slug": "300", | ||
| "size": "16px" | ||
| }, | ||
| { | ||
| "name": "x-large", | ||
| "slug": "400", | ||
| "size": "24px" | ||
| }, | ||
| { | ||
| "name": "round", | ||
| "slug": "500", | ||
| "size": "9999px" | ||
| } | ||
| ] | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| { | ||
| "$schema": "https://schemas.wp.org/trunk/theme.json", | ||
| "version": 3, | ||
| "settings": { | ||
| "shadow": { | ||
| "defaultPresets": false, | ||
| "presets": [ | ||
| { | ||
| "name": "Tiny", | ||
| "slug": "100", | ||
| "shadow": "0.5px 2px 3px 0.5px rgba(17, 17, 17, 0.2)" | ||
| }, | ||
| { | ||
| "name": "Base", | ||
| "slug": "200", | ||
| "shadow": "0.5px 2px 6px 1px rgba(17, 17, 17, 0.2)" | ||
| }, | ||
| { | ||
| "name": "Small", | ||
| "slug": "300", | ||
| "shadow": "1px 4px 12px 4px rgba(17, 17, 17, 0.2)" | ||
| }, | ||
| { | ||
| "name": "Medium", | ||
| "slug": "400", | ||
| "shadow": "1px 4px 12px 4px rgba(17, 17, 17, 0.3)" | ||
| }, | ||
| { | ||
| "name": "Large", | ||
| "slug": "500", | ||
| "shadow": "1px 4px 12px 4px rgba(17, 17, 17, 0.3)" | ||
| }, | ||
| { | ||
| "name": "X-Large", | ||
| "slug": "600", | ||
| "shadow": "2px 6px 12px 6px rgba(17, 17, 17, 0.3)" | ||
| } | ||
| ] | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,85 @@ | ||
| { | ||
| "$schema": "https://schemas.wp.org/trunk/theme.json", | ||
| "version": 3, | ||
| "settings": { | ||
| "spacing": { | ||
| "defaultSpacingSizes": false, | ||
| "spacingSizes": [ | ||
| { | ||
| "name": "XXS", | ||
| "slug": "5", | ||
| "size": "clamp(0.250rem, calc(0.227rem + 0.006vw), 0.312rem)" | ||
| }, | ||
| { | ||
| "name": "XS", | ||
| "slug": "10", | ||
| "size": "clamp(0.500rem, calc(0.454rem + 0.012vw), 0.625rem)" | ||
| }, | ||
| { | ||
| "name": "S", | ||
| "slug": "20", | ||
| "size": "clamp(0.875rem, calc(0.736rem + 0.036vw), 1.250rem)" | ||
| }, | ||
| { | ||
| "name": "M", | ||
| "slug": "30", | ||
| "size": "clamp(1.250rem, calc(1.018rem + 0.060vw), 1.875rem)" | ||
| }, | ||
| { | ||
| "name": "L", | ||
| "slug": "40", | ||
| "size": "clamp(1.625rem, calc(1.300rem + 0.083vw), 2.500rem)" | ||
| }, | ||
| { | ||
| "name": "XL", | ||
| "slug": "50", | ||
| "size": "clamp(2.062rem, calc(1.668rem + 0.101vw), 3.125rem)" | ||
| }, | ||
| { | ||
| "name": "XXL", | ||
| "slug": "60", | ||
| "size": "clamp(2.312rem, calc(1.779rem + 0.137vw), 3.750rem)" | ||
| }, | ||
| { | ||
| "name": "XXXL", | ||
| "slug": "70", | ||
| "size": "clamp(2.625rem, calc(1.975rem + 0.167vw), 4.375rem)" | ||
| }, | ||
| { | ||
| "name": "XXXXL", | ||
| "slug": "80", | ||
| "size": "clamp(3.000rem, calc(2.257rem + 0.190vw), 5.000rem)" | ||
| }, | ||
| { | ||
| "name": "Gigantic", | ||
| "slug": "90", | ||
| "size": "clamp(3.500rem, calc(2.711rem + 0.202vw), 5.625rem)" | ||
| }, | ||
| { | ||
| "name": "Colossal", | ||
| "slug": "100", | ||
| "size": "clamp(4.000rem, calc(3.164rem + 0.214vw), 6.250rem)" | ||
| } | ||
| ], | ||
| "units": [ | ||
| "%", | ||
| "em", | ||
| "px", | ||
| "rem", | ||
| "vh", | ||
| "vw" | ||
| ] | ||
| } | ||
| }, | ||
| "styles": { | ||
| "spacing": { | ||
| "blockGap": "var(--wp--preset--spacing--30)", | ||
| "padding": { | ||
| "bottom": "0", | ||
| "left": "var(--wp--preset--spacing--20)", | ||
| "right": "var(--wp--preset--spacing--20)", | ||
| "top": "0" | ||
| } | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The current implementation performs recursive directory scanning and JSON decoding on every execution of the
wp_theme_json_data_themefilter. This can lead to unnecessary disk I/O and CPU overhead, especially on sites with many preset files or without persistent object caching.Additionally, using
wp_json_file_decode()is more idiomatic in WordPress and provides better handling for JSON files compared tofile_get_contents()andjson_decode().Consider caching the decoded preset data in a
staticvariable to improve performance.