Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 33 additions & 32 deletions includes/class-admin.php
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,36 @@ public function render_page() {
<input type="hidden" name="action" value="slashed_save_settings">
<?php wp_nonce_field( self::NONCE_ACTION, self::NONCE_KEY ); ?>

<h2 style="margin-top:1.5em;"><?php esc_html_e( 'Active integrations', 'slashed' ); ?></h2>
<p class="description"><?php esc_html_e( 'Enable the integrations for the builders you use. SLASHED loads its CSS and syncs design tokens only for active integrations.', 'slashed' ); ?></p>
<h2 style="margin-top:1.5em;"><?php esc_html_e( 'CSS framework', 'slashed' ); ?></h2>
<p class="description">
<?php esc_html_e( 'The SLASHED framework CSS loads automatically on your site — no page builder required. Choose the smallest bundle that covers your needs.', 'slashed' ); ?>
&nbsp;<a href="<?php echo esc_url( admin_url( 'admin.php?page=' . \Slashed_Token_Page::PAGE_SLUG ) ); ?>"><?php esc_html_e( 'Customize design tokens →', 'slashed' ); ?></a>
</p>

<table class="form-table" role="presentation">
<?php
$bundles = array(
'essential' => __( 'Essential — reset + design tokens only', 'slashed' ),
'optimal' => __( 'Optimal — + layout, typography, states, forms (recommended)', 'slashed' ),
'full' => __( 'Full — + utilities layer', 'slashed' ),
);
foreach ( $bundles as $value => $label ) :
?>
<tr>
<th scope="row" style="padding-top:6px;padding-bottom:6px;">
<label for="bundle-<?php echo esc_attr( $value ); ?>"><?php echo esc_html( $label ); ?></label>
</th>
<td style="padding-top:6px;padding-bottom:6px;">
<input type="radio" id="bundle-<?php echo esc_attr( $value ); ?>"
name="css_bundle" value="<?php echo esc_attr( $value ); ?>"
<?php checked( $css_bundle, $value ); ?>>
</td>
</tr>
<?php endforeach; ?>
</table>

<h2><?php esc_html_e( 'Builder integrations', 'slashed' ); ?></h2>
<p class="description"><?php esc_html_e( 'Optional deeper integration with your page builder. Adds builder-specific features on top of the core CSS delivery.', 'slashed' ); ?></p>

<table class="form-table" role="presentation">
<tr>
Expand All @@ -116,12 +144,10 @@ public function render_page() {
esc_html( BRICKS_VERSION )
);
} else {
esc_html_e( 'Bricks Builder not detected — integration will have no effect until Bricks is installed.', 'slashed' );
esc_html_e( 'Bricks Builder not detected.', 'slashed' );
}
?>
<?php if ( $integrations['bricks'] ) : ?>
&nbsp;&mdash;&nbsp;<a href="<?php echo esc_url( admin_url( 'admin.php?page=slashed-bricks' ) ); ?>"><?php esc_html_e( 'Manage Bricks token overrides →', 'slashed' ); ?></a>
<?php endif; ?>
<?php esc_html_e( 'Injects CSS variables into Global Variables, syncs the color palette, and enables the reBEMer class manager.', 'slashed' ); ?>
</p>
</td>
</tr>
Expand All @@ -133,36 +159,11 @@ public function render_page() {
<?php checked( $integrations['gutenberg'] ); ?>>
<?php esc_html_e( 'Enable', 'slashed' ); ?>
</label>
<p class="description"><?php esc_html_e( 'Loads SLASHED CSS in the block editor canvas and syncs the color palette.', 'slashed' ); ?></p>
<p class="description"><?php esc_html_e( 'Syncs SLASHED colors with the block editor palette and bridges the editor dark-mode toggle.', 'slashed' ); ?></p>
</td>
</tr>
</table>

<h2><?php esc_html_e( 'CSS bundle', 'slashed' ); ?></h2>
<p class="description"><?php esc_html_e( 'All active integrations load the same bundle. Choose the smallest bundle that covers your needs.', 'slashed' ); ?></p>

<table class="form-table" role="presentation">
<?php
$bundles = array(
'essential' => __( 'Essential — reset + design tokens only', 'slashed' ),
'optimal' => __( 'Optimal — + layout, typography, states, forms (recommended)', 'slashed' ),
'full' => __( 'Full — + utilities layer', 'slashed' ),
);
foreach ( $bundles as $value => $label ) :
?>
<tr>
<th scope="row" style="padding-top:6px;padding-bottom:6px;">
<label for="bundle-<?php echo esc_attr( $value ); ?>"><?php echo esc_html( $label ); ?></label>
</th>
<td style="padding-top:6px;padding-bottom:6px;">
<input type="radio" id="bundle-<?php echo esc_attr( $value ); ?>"
name="css_bundle" value="<?php echo esc_attr( $value ); ?>"
<?php checked( $css_bundle, $value ); ?>>
</td>
</tr>
<?php endforeach; ?>
</table>

<?php submit_button( __( 'Save settings', 'slashed' ) ); ?>
</form>

Expand Down
84 changes: 84 additions & 0 deletions includes/class-core-enqueue.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
<?php
/**
* Core SLASHED CSS enqueue — builder-agnostic.
*
* Registers and enqueues the `slashed-framework` stylesheet on every
* WordPress site where the plugin is active, regardless of which builder
* (if any) is installed. This makes SLASHED usable with custom themes,
* classic themes, or any setup that does not match a bundled integration.
*
* Builder integrations add their own inline rules on top of the
* `slashed-framework` handle (e.g. Bricks dark-mode bridge, Gutenberg
* dark-mode bridge). Token override CSS is injected separately by
* slashed_inject_token_overrides() at priority 20.
*
* @package SLASHED
*/

if ( ! defined( 'ABSPATH' ) ) {
exit;
}

/**
* Class Slashed_Core_Enqueue
*/
class Slashed_Core_Enqueue {

public function __construct() {
add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_frontend' ) );
add_action( 'enqueue_block_editor_assets', array( $this, 'enqueue_editor' ) );
}

/**
* Enqueue the framework stylesheet on the public frontend (and Bricks canvas iframe).
*
* Skips the Bricks builder-panel context: loading CSS resets into the
* builder admin chrome breaks Bricks' toolbar icons and colours.
* bricks_is_builder_main() returns true only for that panel — the canvas
* iframe and public frontend both pass this guard correctly.
*/
public function enqueue_frontend() {
if ( function_exists( 'bricks_is_builder_main' ) && bricks_is_builder_main() ) {
return;
}

$url = Slashed_CSS_Loader::get_url();
if ( '' === $url ) {
return;
}

wp_enqueue_style( 'slashed-framework', $url, array(), Slashed_CSS_Loader::get_version( $url ) );

// HTML font-size override — affects all rem-based framework values.
$settings = Slashed_Token_Store::get_plugin_settings();
$font_size = isset( $settings['html_font_size'] ) ? (string) $settings['html_font_size'] : '';
if ( '100' === $font_size || '62.5' === $font_size ) {
wp_add_inline_style( 'slashed-framework', 'html { font-size: ' . $font_size . '% !important; }' );
}
}

/**
* Enqueue the framework stylesheet in the block editor.
*
* Fires for both the post editor and FSE site editor. Styles are injected
* into the editor iframe so they affect the editing canvas without touching
* the surrounding wp-admin chrome.
*/
public function enqueue_editor() {
$url = Slashed_CSS_Loader::get_url();
if ( '' === $url ) {
return;
}
wp_enqueue_style( 'slashed-framework', $url, array(), Slashed_CSS_Loader::get_version( $url ) );

// Mirror the frontend rem-base override so the iframed editor canvas
// matches the public site. The block editor is always iframed in WP 6.4+
// (our declared minimum), so this rule targets the canvas <html>, not
// the surrounding wp-admin chrome.
$settings = Slashed_Token_Store::get_plugin_settings();
$font_size = isset( $settings['html_font_size'] ) ? (string) $settings['html_font_size'] : '';
if ( '100' === $font_size || '62.5' === $font_size ) {
wp_add_inline_style( 'slashed-framework', 'html { font-size: ' . $font_size . '% !important; }' );
}
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}
12 changes: 6 additions & 6 deletions includes/class-token-page.php
Original file line number Diff line number Diff line change
Expand Up @@ -97,14 +97,14 @@ public function enqueue_assets( $hook_suffix ) {
$css_version = file_exists( $css_path ) ? (string) filemtime( $css_path ) : $js_version;

wp_enqueue_style(
'slashed-bricks-admin-app',
'slashed-admin-app',
$plugin_url . 'assets/admin-app/app.css',
array(),
$css_version
);

wp_enqueue_script(
'slashed-bricks-admin-app',
'slashed-admin-app',
$plugin_url . 'assets/admin-app/app.js',
array(),
$js_version,
Expand All @@ -114,8 +114,8 @@ public function enqueue_assets( $hook_suffix ) {
add_filter( 'script_loader_tag', array( $this, 'mark_as_module' ), 10, 3 );

wp_localize_script(
'slashed-bricks-admin-app',
'slashedBricksApp',
'slashed-admin-app',
'slashedApp',
array(
'rest' => array(
'url' => esc_url_raw( rest_url( Slashed_REST_Controller::NAMESPACE ) ),
Expand Down Expand Up @@ -156,7 +156,7 @@ public static function get_class_hints() {
}

public function mark_as_module( $tag, $handle, $src ) {
if ( 'slashed-bricks-admin-app' !== $handle ) {
if ( 'slashed-admin-app' !== $handle ) {
return $tag;
}
return preg_replace( '/<script(\b[^>]*)>/', '<script type="module"$1>', $tag, 1 );
Expand Down Expand Up @@ -184,7 +184,7 @@ public function render_page() {

public function render_missing_bundle_notice() {
echo '<div class="notice notice-error"><p>';
esc_html_e( 'SLASHED admin SPA bundle is missing. Run `npm install && npm run build` inside integrations/bricks/admin-app/ to build it.', 'slashed' );
esc_html_e( 'SLASHED admin SPA bundle is missing. Run `npm install && npm run build` inside integrations/bricks/admin-app/ to generate it.', 'slashed' );
echo '</p></div>';
}
}
4 changes: 2 additions & 2 deletions integrations/bricks/admin-app/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@
<!--
Standalone dev harness used only by `vite dev`. The real WP page
prints an equivalent mount + hydration script via PHP. The shape
of `window.slashedBricksApp` here mirrors what wp_localize_script
of `window.slashedApp` here mirrors what wp_localize_script
writes in production so the same Svelte code works in both.
-->
<script>
window.slashedBricksApp = {
window.slashedApp = {
rest: {
// In dev, no real REST endpoint exists; api.js short-circuits
// when restUrl is empty and just logs the payload.
Expand Down
6 changes: 3 additions & 3 deletions integrations/bricks/admin-app/src/lib/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
* Thin REST client for the admin SPA.
*
* The PHP side exposes:
* POST /wp-json/slashed-bricks/v1/tokens - save a section
* POST /wp-json/slashed-bricks/v1/tokens/reset - reset a section or all
* POST /wp-json/slashed/v1/tokens - save a section
* POST /wp-json/slashed/v1/tokens/reset - reset a section or all
*
* Auth uses the WP REST nonce (X-WP-Nonce header). The nonce is generated
* server-side and passed through window.slashedBricksApp.rest.nonce, so
* server-side and passed through window.slashedApp.rest.nonce, so
* every request is automatically scoped to the logged-in admin.
*
* In the Vite dev harness rest.url is empty; we just log the payload and
Expand Down
8 changes: 4 additions & 4 deletions integrations/bricks/admin-app/src/lib/stores.svelte.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
* automatically re-render when it changes, and the live-preview derived
* CSS recomputes for free.
*
* Hydrated once at module load from window.slashedBricksApp. The shape
* mirrors the `slashed_bricks_tokens` wp_option exactly:
* Hydrated once at module load from window.slashedApp. The shape
* mirrors the `slashed_tokens` wp_option exactly:
*
* tokens.<section>.<key> = string
*
Expand All @@ -17,8 +17,8 @@
* so the store stays a flat key-value map.
*/

const bootstrap = typeof window !== 'undefined' && window.slashedBricksApp
? window.slashedBricksApp
const bootstrap = typeof window !== 'undefined' && window.slashedApp
? window.slashedApp
: { defaults: {}, settings: {}, tabs: {}, rest: { url: '', nonce: '' } };

/** Read-only metadata: factory defaults, available tabs, REST handshake, inventory, plugin settings. */
Expand Down
6 changes: 3 additions & 3 deletions integrations/bricks/admin-app/src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
* SLASHED admin SPA entry point.
*
* Mounts the Svelte app into the #slashed-admin-app element printed
* by class-admin-page-svelte.php. All hydration data comes from
* window.slashedBricksApp, which is populated server-side via
* wp_localize_script (see Slashed_Bricks_Admin_Page_Svelte::enqueue).
* by class-token-page.php. All hydration data comes from
* window.slashedApp, which is populated server-side via
* wp_localize_script (see Slashed_Token_Page::enqueue_assets).
*
* Why a single mount and not per-tab islands: every tab shares the
* same dirty-state, defaults, and live-preview state. Having one
Expand Down
22 changes: 11 additions & 11 deletions integrations/bricks/assets/admin-app/app.js

Large diffs are not rendered by default.

77 changes: 8 additions & 69 deletions integrations/bricks/includes/class-enqueue.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,91 +12,30 @@
/**
* Class Slashed_Bricks_Enqueue
*
* Handles loading the SLASHED CSS bundle on the frontend
* and within the Bricks Builder editor iframe.
* Adds Bricks-specific inline rules on top of the globally-registered
* `slashed-framework` handle (registered by Slashed_Core_Enqueue).
*/
class Slashed_Bricks_Enqueue {

/**
* Constructor. Register hooks.
*/
public function __construct() {
// Frontend AND the Bricks builder canvas iframe AND the Bricks
// builder admin chrome all fire wp_enqueue_scripts. The third one
// is the gotcha: loading the framework CSS into the builder panel
// would override Bricks' own UI styles (icons, colors, fonts). The
// handler below skips that case via bricks_is_builder_main().
add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_frontend_styles' ) );

// Reserved hook for intentional builder-panel tweaks (assets/editor.css).
// Currently a no-op stylesheet; left wired up so future panel styling
// can be dropped in without re-plumbing the hook chain.
add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_editor_styles' ) );
}

/**
* Enqueue SLASHED CSS on the frontend and in the Bricks editor iframe.
* Add Bricks-specific inline CSS on the frontend and canvas iframe.
*
* Bricks fires wp_enqueue_scripts in three contexts:
* 1. Public frontend - we want our CSS here.
* 2. Builder canvas iframe - we want our CSS here (preview rendering,
* color-picker swatch resolution, etc.).
* 3. Builder admin chrome - we DO NOT want our CSS here; loading
* resets / themes / base typography would
* bleed into Bricks' own UI and visibly
* change icons and colors in the toolbars.
*
* bricks_is_builder_main() returns true only on context (3), so the early
* return below is the canonical Bricks pattern for "frontend + canvas, not
* the panel" - documented in Bricks Academy under Child Theme guidance.
* `slashed-framework` is registered globally by Slashed_Core_Enqueue.
* This method only adds the dark-mode bridge that maps Bricks'
* data-brx-theme attribute to SLASHED's colour-scheme / --sf-is-dark
* system. The builder-panel context is skipped for the same reason the
* global enqueue skips it (see Slashed_Core_Enqueue::enqueue_frontend).
*/
public function enqueue_frontend_styles() {
if ( function_exists( 'bricks_is_builder_main' ) && bricks_is_builder_main() ) {
return;
}

$css_url = slashed_bricks_get_css_url();

if ( '' === $css_url ) {
return;
}

// Cache-busting: mtime for local files, version constant for CDN.
if ( class_exists( 'Slashed_CSS_Loader' ) ) {
$version = Slashed_CSS_Loader::get_version( $css_url );
} else {
$filename = basename( (string) wp_parse_url( $css_url, PHP_URL_PATH ) );
$repo_path = SLASHED_BRICKS_PATH . '../../dist/' . $filename;
$local_path = SLASHED_BRICKS_PATH . 'dist/' . $filename;

if ( '' !== $filename && file_exists( $repo_path ) ) {
$version = (string) filemtime( $repo_path );
} elseif ( '' !== $filename && file_exists( $local_path ) ) {
$version = (string) filemtime( $local_path );
} else {
$version = SLASHED_BRICKS_VERSION;
}
}

wp_enqueue_style(
'slashed-framework',
$css_url,
array(),
$version
);

// Inject HTML font-size override if configured.
$plugin_settings = get_option( 'slashed_bricks_settings', array() );
if ( is_array( $plugin_settings ) && ! empty( $plugin_settings['html_font_size'] ) ) {
$font_size = $plugin_settings['html_font_size'];
if ( '100' === $font_size || '62.5' === $font_size ) {
wp_add_inline_style(
'slashed-framework',
'html { font-size: ' . $font_size . '% !important; }'
);
}
}

// Bridge Bricks' dark mode toggle (data-brx-theme attribute) to SLASHED's theme system.
wp_add_inline_style(
'slashed-framework',
Expand Down
Loading