init
This commit is contained in:
306
theme/inc/theme-generator.php
Normal file
306
theme/inc/theme-generator.php
Normal file
@@ -0,0 +1,306 @@
|
||||
<?php
|
||||
/**
|
||||
* Theme Generator — Builds and caches a CSS file from saved design tokens.
|
||||
*
|
||||
* Reads theme-mods written by the admin settings page and produces a
|
||||
* static CSS file in the uploads directory. The file is enqueued after
|
||||
* main.css so that custom values override defaults.
|
||||
*
|
||||
* @package OTS_Theme
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the absolute filesystem path of the generated CSS file.
|
||||
*
|
||||
* Multi-site aware — each site gets its own file.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function oribi_generated_css_path() {
|
||||
$upload_dir = wp_upload_dir();
|
||||
$blog_id = get_current_blog_id();
|
||||
return trailingslashit( $upload_dir['basedir'] ) . "oribi-theme-{$blog_id}-custom.css";
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the public URL of the generated CSS file.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function oribi_generated_css_url() {
|
||||
$upload_dir = wp_upload_dir();
|
||||
$blog_id = get_current_blog_id();
|
||||
return trailingslashit( $upload_dir['baseurl'] ) . "oribi-theme-{$blog_id}-custom.css";
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper: convert a hex colour like #D83302 to its "r,g,b" string.
|
||||
*
|
||||
* @param string $hex Hex colour with or without leading #.
|
||||
* @return string e.g. "216,51,2"
|
||||
*/
|
||||
function oribi_hex_to_rgb( $hex ) {
|
||||
$hex = ltrim( $hex, '#' );
|
||||
if ( strlen( $hex ) === 3 ) {
|
||||
$hex = $hex[0] . $hex[0] . $hex[1] . $hex[1] . $hex[2] . $hex[2];
|
||||
}
|
||||
if ( strlen( $hex ) !== 6 ) {
|
||||
return '0,0,0';
|
||||
}
|
||||
$r = hexdec( substr( $hex, 0, 2 ) );
|
||||
$g = hexdec( substr( $hex, 2, 2 ) );
|
||||
$b = hexdec( substr( $hex, 4, 2 ) );
|
||||
return "{$r},{$g},{$b}";
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the CSS string from current theme-mod values.
|
||||
*
|
||||
* @return string Complete CSS content.
|
||||
*/
|
||||
function oribi_build_css() {
|
||||
|
||||
$s = 'oribi_get_setting'; // shorthand
|
||||
|
||||
// Gather values.
|
||||
$primary = $s( 'color_primary' );
|
||||
$primary_dk = $s( 'color_primary_dk' );
|
||||
$primary_lt = $s( 'color_primary_lt' );
|
||||
$accent = $s( 'color_accent' );
|
||||
$accent_dk = $s( 'color_accent_dk' );
|
||||
$accent_lt = $s( 'color_accent_lt' );
|
||||
$dark = $s( 'color_dark' );
|
||||
$dark_2 = $s( 'color_dark_2' );
|
||||
$text = $s( 'color_text' );
|
||||
$text_muted = $s( 'color_text_muted' );
|
||||
$border = $s( 'color_border' );
|
||||
$bg = $s( 'color_bg' );
|
||||
$bg_alt = $s( 'color_bg_alt' );
|
||||
|
||||
// Dark mode.
|
||||
$dk_primary = $s( 'dark_primary' );
|
||||
$dk_primary_dk = $s( 'dark_primary_dk' );
|
||||
$dk_primary_lt = $s( 'dark_primary_lt' );
|
||||
$dk_accent = $s( 'dark_accent' );
|
||||
$dk_accent_dk = $s( 'dark_accent_dk' );
|
||||
$dk_accent_lt = $s( 'dark_accent_lt' );
|
||||
$dk_dark = $s( 'dark_dark' );
|
||||
$dk_dark_2 = $s( 'dark_dark_2' );
|
||||
$dk_text = $s( 'dark_text' );
|
||||
$dk_text_muted = $s( 'dark_text_muted' );
|
||||
$dk_border = $s( 'dark_border' );
|
||||
$dk_bg = $s( 'dark_bg' );
|
||||
$dk_bg_alt = $s( 'dark_bg_alt' );
|
||||
$dk_bg_dark = $s( 'dark_bg_dark' );
|
||||
$dk_heading = $s( 'dark_heading' );
|
||||
$dk_card_bg = $s( 'dark_card_bg' );
|
||||
|
||||
// Typography.
|
||||
$body_font_slug = $s( 'font_family' );
|
||||
$heading_font_slug = $s( 'font_heading' );
|
||||
$body_font_css = oribi_get_font_family_css( $body_font_slug );
|
||||
$heading_font_css = $heading_font_slug ? oribi_get_font_family_css( $heading_font_slug ) : $body_font_css;
|
||||
|
||||
// Border radii.
|
||||
$r_sm = intval( $s( 'radius_sm' ) );
|
||||
$r_md = intval( $s( 'radius_md' ) );
|
||||
$r_lg = intval( $s( 'radius_lg' ) );
|
||||
$r_xl = intval( $s( 'radius_xl' ) );
|
||||
|
||||
// Layout.
|
||||
$c_max = intval( $s( 'container_max' ) );
|
||||
$c_pad_min = floatval( $s( 'container_pad_min' ) );
|
||||
$c_pad_max = floatval( $s( 'container_pad_max' ) );
|
||||
$wide = intval( $s( 'wide_size' ) );
|
||||
|
||||
$primary_rgb = oribi_hex_to_rgb( $primary );
|
||||
$accent_rgb = oribi_hex_to_rgb( $accent );
|
||||
$dk_primary_rgb = oribi_hex_to_rgb( $dk_primary );
|
||||
|
||||
// Build CSS.
|
||||
$css = <<<CSS
|
||||
/* ================================================================
|
||||
OTS Theme — Generated Theme Overrides
|
||||
Generated: %s
|
||||
================================================================ */
|
||||
|
||||
/* ── WordPress preset colour overrides ─────────────────────────── */
|
||||
:root {
|
||||
--wp--preset--color--primary: {$primary};
|
||||
--wp--preset--color--primary-dk: {$primary_dk};
|
||||
--wp--preset--color--primary-lt: {$primary_lt};
|
||||
--wp--preset--color--accent: {$accent};
|
||||
--wp--preset--color--accent-dk: {$accent_dk};
|
||||
--wp--preset--color--accent-lt: {$accent_lt};
|
||||
--wp--preset--color--dark: {$dark};
|
||||
--wp--preset--color--dark-2: {$dark_2};
|
||||
--wp--preset--color--text: {$text};
|
||||
--wp--preset--color--text-muted: {$text_muted};
|
||||
--wp--preset--color--border: {$border};
|
||||
--wp--preset--color--bg: {$bg};
|
||||
--wp--preset--color--bg-alt: {$bg_alt};
|
||||
}
|
||||
|
||||
/* ── Light-mode aliases (consumed by main.css) ─────────────────── */
|
||||
:root,
|
||||
[data-theme="light"] {
|
||||
--color-primary: {$primary};
|
||||
--color-primary-dk: {$primary_dk};
|
||||
--color-primary-lt: {$primary_lt};
|
||||
--color-primary-rgb: {$primary_rgb};
|
||||
--color-accent: {$accent};
|
||||
--color-accent-dk: {$accent_dk};
|
||||
--color-accent-lt: {$accent_lt};
|
||||
--color-accent-rgb: {$accent_rgb};
|
||||
--color-dark: {$dark};
|
||||
--color-dark-2: {$dark_2};
|
||||
--color-text: {$text};
|
||||
--color-text-muted: {$text_muted};
|
||||
--color-border: {$border};
|
||||
--color-bg: {$bg};
|
||||
--color-bg-alt: {$bg_alt};
|
||||
--color-bg-dark: {$dark};
|
||||
--color-heading: {$dark};
|
||||
--header-scrolled-bg: rgba(255,255,255,.97);
|
||||
--header-scrolled-text: {$text};
|
||||
--card-bg: {$bg};
|
||||
--form-bg: {$bg_alt};
|
||||
--form-bg-focus: {$bg};
|
||||
|
||||
/* ── Typography ── */
|
||||
--font-sans: {$body_font_css};
|
||||
--font-heading: {$heading_font_css};
|
||||
|
||||
/* ── Border radii ── */
|
||||
--radius-sm: {$r_sm}px;
|
||||
--radius-md: {$r_md}px;
|
||||
--radius-lg: {$r_lg}px;
|
||||
--radius-xl: {$r_xl}px;
|
||||
--wp--custom--radius--sm: {$r_sm}px;
|
||||
--wp--custom--radius--md: {$r_md}px;
|
||||
--wp--custom--radius--lg: {$r_lg}px;
|
||||
--wp--custom--radius--xl: {$r_xl}px;
|
||||
|
||||
/* ── Layout ── */
|
||||
--container-max: {$c_max}px;
|
||||
--container-pad: clamp({$c_pad_min}rem, 5vw, {$c_pad_max}rem);
|
||||
--wp--custom--container--max: {$c_max}px;
|
||||
--wp--custom--container--pad: clamp({$c_pad_min}rem, 5vw, {$c_pad_max}rem);
|
||||
}
|
||||
|
||||
/* ── Dark mode overrides ───────────────────────────────────────── */
|
||||
[data-theme="dark"] {
|
||||
--wp--custom--dark--primary: {$dk_primary};
|
||||
--wp--custom--dark--primary-dk: {$dk_primary_dk};
|
||||
--wp--custom--dark--primary-lt: {$dk_primary_lt};
|
||||
--wp--custom--dark--accent: {$dk_accent};
|
||||
--wp--custom--dark--accent-dk: {$dk_accent_dk};
|
||||
--wp--custom--dark--accent-lt: {$dk_accent_lt};
|
||||
--wp--custom--dark--dark: {$dk_dark};
|
||||
--wp--custom--dark--dark-2: {$dk_dark_2};
|
||||
--wp--custom--dark--text: {$dk_text};
|
||||
--wp--custom--dark--text-muted: {$dk_text_muted};
|
||||
--wp--custom--dark--border: {$dk_border};
|
||||
--wp--custom--dark--bg: {$dk_bg};
|
||||
--wp--custom--dark--bg-alt: {$dk_bg_alt};
|
||||
--wp--custom--dark--bg-dark: {$dk_bg_dark};
|
||||
--wp--custom--dark--heading: {$dk_heading};
|
||||
--wp--custom--dark--card-bg: {$dk_card_bg};
|
||||
|
||||
--color-primary: {$dk_primary};
|
||||
--color-primary-dk: {$dk_primary_dk};
|
||||
--color-primary-lt: {$dk_primary_lt};
|
||||
--color-primary-rgb: {$dk_primary_rgb};
|
||||
--color-accent: {$dk_accent};
|
||||
--color-accent-dk: {$dk_accent_dk};
|
||||
--color-accent-lt: {$dk_accent_lt};
|
||||
--color-dark: {$dk_dark};
|
||||
--color-dark-2: {$dk_dark_2};
|
||||
--color-text: {$dk_text};
|
||||
--color-text-muted: {$dk_text_muted};
|
||||
--color-border: {$dk_border};
|
||||
--color-bg: {$dk_bg};
|
||||
--color-bg-alt: {$dk_bg_alt};
|
||||
--color-bg-dark: {$dk_bg_dark};
|
||||
--color-heading: {$dk_heading};
|
||||
--header-scrolled-bg: rgba(15,23,36,.97);
|
||||
--header-scrolled-text: {$dk_text};
|
||||
--card-bg: {$dk_card_bg};
|
||||
--form-bg: {$dk_card_bg};
|
||||
--form-bg-focus: #1A2538;
|
||||
}
|
||||
|
||||
/* ── Typography application ────────────────────────────────────── */
|
||||
body {
|
||||
font-family: var(--font-sans);
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6,
|
||||
.wp-block-heading {
|
||||
font-family: var(--font-heading, var(--font-sans));
|
||||
}
|
||||
|
||||
/* ── WordPress layout overrides ────────────────────────────────── */
|
||||
.wp-site-blocks > .wp-block-group,
|
||||
.wp-site-blocks > .alignfull {
|
||||
max-width: none;
|
||||
}
|
||||
|
||||
body > .is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)) {
|
||||
max-width: {$c_max}px;
|
||||
}
|
||||
|
||||
CSS;
|
||||
|
||||
return sprintf( $css, gmdate( 'Y-m-d H:i:s' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the generated CSS file to disk.
|
||||
*
|
||||
* @return bool|WP_Error True on success, WP_Error on failure.
|
||||
*/
|
||||
function oribi_write_generated_css() {
|
||||
|
||||
$css = oribi_build_css();
|
||||
$path = oribi_generated_css_path();
|
||||
|
||||
// Ensure directory exists.
|
||||
$dir = dirname( $path );
|
||||
if ( ! file_exists( $dir ) ) {
|
||||
wp_mkdir_p( $dir );
|
||||
}
|
||||
|
||||
// Use WP_Filesystem for safe file writing.
|
||||
require_once ABSPATH . 'wp-admin/includes/file.php';
|
||||
global $wp_filesystem;
|
||||
if ( ! WP_Filesystem() ) {
|
||||
return new WP_Error( 'fs', __( 'Could not initialise filesystem.', 'ots-theme' ) );
|
||||
}
|
||||
|
||||
$result = $wp_filesystem->put_contents( $path, $css, FS_CHMOD_FILE );
|
||||
if ( ! $result ) {
|
||||
return new WP_Error( 'write', __( 'Could not write generated CSS file.', 'ots-theme' ) );
|
||||
}
|
||||
|
||||
// Bump version number so browsers cache-bust.
|
||||
$version = intval( get_theme_mod( 'oribi_css_version', 0 ) ) + 1;
|
||||
set_theme_mod( 'oribi_css_version', $version );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Regenerate the CSS file if it doesn't exist yet (e.g. first page load).
|
||||
*
|
||||
* Hooked early so the file is ready before wp_enqueue_scripts fires.
|
||||
*/
|
||||
add_action( 'init', function () {
|
||||
if ( ! file_exists( oribi_generated_css_path() ) ) {
|
||||
oribi_write_generated_css();
|
||||
}
|
||||
} );
|
||||
Reference in New Issue
Block a user