diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f8fa21f5..55b4f477 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,14 +8,40 @@ on: permissions: contents: read +# Cancel superseded runs on the same PR ref so CI only spends minutes on the +# newest commit. Pushes to main run to completion. +concurrency: + group: ci-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + jobs: + commitlint: + name: Lint commit messages + runs-on: ubuntu-latest + if: github.event_name == 'pull_request' + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + fetch-depth: 0 + - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + with: + node-version: 22 + cache: npm + - run: npm ci + - name: Validate PR commits against Conventional Commits + run: >- + npx --no -- commitlint + --from ${{ github.event.pull_request.base.sha }} + --to ${{ github.event.pull_request.head.sha }} + --verbose + build-editor-app: name: Build editor-app runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - uses: actions/setup-node@v6 + - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: node-version: 22 cache: npm @@ -24,6 +50,9 @@ jobs: - name: Install dependencies run: npm ci --prefix SLASHED-for-WP/integrations/bricks/editor-app + - name: Type-check (svelte-check) + run: npm --prefix SLASHED-for-WP/integrations/bricks/editor-app run check + - name: Build run: npm --prefix SLASHED-for-WP/integrations/bricks/editor-app run build @@ -31,9 +60,9 @@ jobs: name: Build admin-app runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - uses: actions/setup-node@v6 + - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: node-version: 22 cache: npm @@ -42,6 +71,9 @@ jobs: - name: Install dependencies run: npm ci --prefix SLASHED-for-WP/integrations/bricks/admin-app + - name: Type-check (svelte-check) + run: npm --prefix SLASHED-for-WP/integrations/bricks/admin-app run check + - name: Build run: npm --prefix SLASHED-for-WP/integrations/bricks/admin-app run build @@ -49,21 +81,25 @@ jobs: name: Lint, test, version & drift checks runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - uses: actions/setup-node@v6 + - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: node-version: 22 cache: npm - - uses: shivammathur/setup-php@v2 + - uses: shivammathur/setup-php@8358ee0e2e8afe63c2fb8253d1d52085811ab1e5 # v2 with: php-version: '8.2' coverage: none + tools: composer - - name: Install dependencies + - name: Install npm dependencies run: npm ci + - name: Install PHP dev dependencies + run: composer install --no-interaction --no-progress + - name: Unit tests (editor-app libs + version guard) run: npm test @@ -73,9 +109,20 @@ jobs: - name: Lint CSS (stylelint) run: npm run lint:css - - name: Lint PHP (php -l) + - name: Lint PHP syntax (php -l) run: npm run lint:php + - name: Register PHPCS standards + run: >- + vendor/bin/phpcs --config-set installed_paths + vendor/wp-coding-standards/wpcs,vendor/phpcsstandards/phpcsutils,vendor/phpcsstandards/phpcsextra,vendor/phpcompatibility/php-compatibility,vendor/phpcompatibility/phpcompatibility-paragonie,vendor/phpcompatibility/phpcompatibility-wp + + - name: Lint PHP (PHPCS / WordPress standards) + run: composer phpcs + + - name: Static analysis (PHPStan) + run: composer phpstan + - name: Cheatsheet coverage run: npm run check:cheatsheet @@ -85,3 +132,27 @@ jobs: echo "Cloning framework $REF for admin-app drift check" git clone --depth 1 --branch "$REF" https://github.com/codeslash-dev/SLASHED.git .framework SLASHED_FRAMEWORK_DIR=.framework npm run check:admin-app + + dependency-audit: + name: Dependency vulnerability audit + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + + - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + with: + node-version: 22 + cache: npm + + # Audit the root toolchain and both bundled Svelte apps. Fail only on + # high/critical advisories so routine low-severity noise doesn't block. + - name: Audit root dependencies + run: npm ci && npm audit --audit-level=high + - name: Audit editor-app dependencies + run: | + npm ci --prefix SLASHED-for-WP/integrations/bricks/editor-app + npm audit --audit-level=high --prefix SLASHED-for-WP/integrations/bricks/editor-app + - name: Audit admin-app dependencies + run: | + npm ci --prefix SLASHED-for-WP/integrations/bricks/admin-app + npm audit --audit-level=high --prefix SLASHED-for-WP/integrations/bricks/admin-app diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index efdca525..a0256120 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -21,13 +21,13 @@ jobs: matrix: language: [javascript-typescript, actions] steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - uses: github/codeql-action/init@v3 + - uses: github/codeql-action/init@b0c4fd77f6c559021d78430ec4d0d169ae74a4eb # v3 with: languages: ${{ matrix.language }} queries: security-extended - - uses: github/codeql-action/analyze@v3 + - uses: github/codeql-action/analyze@b0c4fd77f6c559021d78430ec4d0d169ae74a4eb # v3 with: category: /language:${{ matrix.language }} diff --git a/.github/workflows/framework-sync.yml b/.github/workflows/framework-sync.yml index e1b05b65..cbd90d41 100644 --- a/.github/workflows/framework-sync.yml +++ b/.github/workflows/framework-sync.yml @@ -22,9 +22,9 @@ jobs: sync: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - uses: actions/setup-node@v6 + - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: node-version: 22 cache: npm @@ -41,7 +41,7 @@ jobs: npm run update-framework -- --version="$VERSION" fi - - uses: shivammathur/setup-php@v2 + - uses: shivammathur/setup-php@8358ee0e2e8afe63c2fb8253d1d52085811ab1e5 # v2 with: php-version: '8.2' coverage: none @@ -59,7 +59,7 @@ jobs: echo "tag=$REF" >> "$GITHUB_OUTPUT" - name: Open PR if anything changed - uses: peter-evans/create-pull-request@v8 + uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v8 with: commit-message: "chore: sync bundled framework CSS to ${{ steps.ref.outputs.tag }}" branch: chore/framework-sync diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9b576440..afbb7e4f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -26,16 +26,18 @@ jobs: name: Build & publish WordPress plugin zip runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 0 # For workflow_dispatch, check out the specified tag. ref: ${{ github.event.inputs.tag || github.ref }} - - uses: actions/setup-node@v6 + # No dependency cache on the release path: a poisoned cache could be + # baked into the published plugin zip. Fetch fresh from the registry + # with integrity verification (flagged by zizmor: cache-poisoning). + - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: node-version: 22 - cache: npm - name: Install dependencies run: npm ci diff --git a/.gitignore b/.gitignore index a98fad90..5b1f392a 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,8 @@ SLASHED-for-WP/integrations/bricks/assets/editor-app/*.map .DS_Store .agents/ .claude/ + + +# PHP Composer dependencies (PHPCS/WPCS + PHPStan tooling). +# composer.json + composer.lock are tracked; the installed tree is not. +/vendor/ diff --git a/SLASHED-for-WP/includes/class-admin.php b/SLASHED-for-WP/includes/class-admin.php index 58145409..8f0faf7d 100644 --- a/SLASHED-for-WP/includes/class-admin.php +++ b/SLASHED-for-WP/includes/class-admin.php @@ -18,8 +18,8 @@ */ class Slashed_Admin { - const PAGE_SLUG = 'slashed'; - const NONCE_KEY = 'slashed_settings_save'; + const PAGE_SLUG = 'slashed'; + const NONCE_KEY = 'slashed_settings_save'; const NONCE_ACTION = 'slashed_save_settings'; public function __construct() { @@ -94,10 +94,12 @@ public function handle_save() { // phpcs:ignore WordPress.Security.NonceVerification.Missing $raw_class_hints = isset( $_POST['show_class_hints'] ); - Slashed_Token_Store::update_plugin_settings( array( - 'html_font_size' => in_array( $raw_font_size, $allowed_font_sizes, true ) ? $raw_font_size : '', - 'show_class_hints' => $raw_class_hints, - ) ); + Slashed_Token_Store::update_plugin_settings( + array( + 'html_font_size' => in_array( $raw_font_size, $allowed_font_sizes, true ) ? $raw_font_size : '', + 'show_class_hints' => $raw_class_hints, + ) + ); wp_safe_redirect( add_query_arg( 'slashed_saved', '1', admin_url( 'admin.php?page=' . self::PAGE_SLUG ) ) diff --git a/SLASHED-for-WP/includes/class-color-resolver.php b/SLASHED-for-WP/includes/class-color-resolver.php index f3737ab0..9b04ef47 100644 --- a/SLASHED-for-WP/includes/class-color-resolver.php +++ b/SLASHED-for-WP/includes/class-color-resolver.php @@ -326,7 +326,7 @@ private static function resolve_sources( $color_values ) { $sources = array(); foreach ( self::default_sources() as $family => $default_oklch ) { - $var_name = '--sf-color-' . $family . '-light'; + $var_name = '--sf-color-' . $family . '-light'; $oklch_str = $default_oklch; if ( isset( $color_values[ $var_name ] ) ) { @@ -398,10 +398,10 @@ private static function resolve_semantic_tokens( $hex_map, $sources ) { // ---- Border tokens ---- // Light-mode formula: oklch(from neutral_light, clamp(min, L + offset, max), chroma, hue). if ( isset( $sources['neutral'] ) ) { - list( $nl, , $nh ) = $sources['neutral']; + list( $nl, , $nh ) = $sources['neutral']; $hex_map['--sf-color-border'] = self::oklch_to_hex( max( 0.70, min( $nl + 0.35, 0.95 ) ), 0.005, $nh ); $hex_map['--sf-color-border--subtle'] = self::oklch_to_hex( max( 0.75, min( $nl + 0.40, 0.97 ) ), 0.005, $nh ); - $hex_map['--sf-color-border--strong'] = self::oklch_to_hex( max( 0.55, min( $nl + 0.10, 0.85 ) ), 0.02, $nh ); + $hex_map['--sf-color-border--strong'] = self::oklch_to_hex( max( 0.55, min( $nl + 0.10, 0.85 ) ), 0.02, $nh ); } else { $hex_map['--sf-color-border'] = '#d4d4de'; $hex_map['--sf-color-border--subtle'] = '#e5e5ec'; @@ -410,8 +410,8 @@ private static function resolve_semantic_tokens( $hex_map, $sources ) { $hex_map['--sf-color-border--muted'] = $hex_map['--sf-color-border--subtle']; // legacy alias $hex_map['--sf-color-border--focus'] = $hex_map['--sf-color-action'] ?? '#0097b4'; // disabled: desaturated border--subtle at 50% opacity over white. - $border_subtle_rgb = self::hex_to_rgb( $hex_map['--sf-color-border--subtle'] ); - $hex_map['--sf-color-border--disabled'] = self::rgb_to_hex( self::mix_rgb( $border_subtle_rgb, $white_rgb, 0.50 ) ); + $border_subtle_rgb = self::hex_to_rgb( $hex_map['--sf-color-border--subtle'] ); + $hex_map['--sf-color-border--disabled'] = self::rgb_to_hex( self::mix_rgb( $border_subtle_rgb, $white_rgb, 0.50 ) ); // translucent: neutral at 15% opacity over white. $hex_map['--sf-color-border--translucent'] = self::rgb_to_hex( self::mix_rgb( $neutral_rgb, $white_rgb, 0.15 ) ); @@ -419,19 +419,19 @@ private static function resolve_semantic_tokens( $hex_map, $sources ) { // Alpha-composited over white (opaque approximation of transparent overlays). $hex_map['--sf-color-bg--hover'] = self::rgb_to_hex( self::mix_rgb( $neutral_rgb, $white_rgb, 0.08 ) ); $hex_map['--sf-color-bg--active'] = self::rgb_to_hex( self::mix_rgb( $neutral_rgb, $white_rgb, 0.12 ) ); - $hex_map['--sf-color-bg--selected'] = self::rgb_to_hex( self::mix_rgb( $action_rgb, $white_rgb, 0.10 ) ); - $hex_map['--sf-color-bg--focus'] = self::rgb_to_hex( self::mix_rgb( $action_rgb, $white_rgb, 0.06 ) ); + $hex_map['--sf-color-bg--selected'] = self::rgb_to_hex( self::mix_rgb( $action_rgb, $white_rgb, 0.10 ) ); + $hex_map['--sf-color-bg--focus'] = self::rgb_to_hex( self::mix_rgb( $action_rgb, $white_rgb, 0.06 ) ); $hex_map['--sf-color-bg--disabled'] = $hex_map['--sf-color-surface']; // = well ≈ surface // ---- Well, raised, inverse, overlay ---- if ( isset( $sources['base'] ) ) { - list( $bl, $bc, $bh ) = $sources['base']; - $hex_map['--sf-color-inset'] = self::oklch_to_hex( max( 0.0, $bl - 0.02 ), $bc, $bh ); + list( $bl, $bc, $bh ) = $sources['base']; + $hex_map['--sf-color-inset'] = self::oklch_to_hex( max( 0.0, $bl - 0.02 ), $bc, $bh ); $hex_map['--sf-color-raised'] = self::oklch_to_hex( min( 1.0, $bl + 0.04 ), $bc, $bh ); $hex_map['--sf-color-inverse'] = self::oklch_to_hex( 1.0 - $bl, $bc, $bh ); $hex_map['--sf-color-overlay'] = $hex_map['--sf-color-surface']; } else { - $hex_map['--sf-color-inset'] = '#f0f2f5'; + $hex_map['--sf-color-inset'] = '#f0f2f5'; $hex_map['--sf-color-raised'] = '#ffffff'; $hex_map['--sf-color-inverse'] = '#0a0a12'; $hex_map['--sf-color-overlay'] = '#fafafa'; @@ -447,13 +447,13 @@ private static function resolve_semantic_tokens( $hex_map, $sources ) { // ---- Link states (light-mode approximation) ---- // Light-mode formula: min(L − offset, cap) keeps link contrast-safe vs page bg. if ( isset( $sources['action'] ) ) { - list( $al, $ac, $ah ) = $sources['action']; - $l_link = max( 0.0, min( $al - 0.07, 0.48 ) ); - $l_hover = max( 0.0, min( $al - 0.15, 0.40 ) ); - $l_active = max( 0.0, min( $al - 0.21, 0.34 ) ); - $hex_map['--sf-color-link'] = self::oklch_to_hex( $l_link, $ac, $ah ); - $hex_map['--sf-color-link--hover'] = self::oklch_to_hex( $l_hover, $ac, $ah ); - $hex_map['--sf-color-link--active'] = self::oklch_to_hex( $l_active, $ac, $ah ); + list( $al, $ac, $ah ) = $sources['action']; + $l_link = max( 0.0, min( $al - 0.07, 0.48 ) ); + $l_hover = max( 0.0, min( $al - 0.15, 0.40 ) ); + $l_active = max( 0.0, min( $al - 0.21, 0.34 ) ); + $hex_map['--sf-color-link'] = self::oklch_to_hex( $l_link, $ac, $ah ); + $hex_map['--sf-color-link--hover'] = self::oklch_to_hex( $l_hover, $ac, $ah ); + $hex_map['--sf-color-link--active'] = self::oklch_to_hex( $l_active, $ac, $ah ); // visited: same lightness clamp, +60° hue shift. $hex_map['--sf-color-link--visited'] = self::oklch_to_hex( $l_link, $ac, fmod( $ah + 60.0, 360.0 ) ); } else { @@ -465,7 +465,7 @@ private static function resolve_semantic_tokens( $hex_map, $sources ) { // underline: action at 30% opacity over white. $hex_map['--sf-color-link--underline'] = self::rgb_to_hex( self::mix_rgb( $action_rgb, $white_rgb, 0.30 ) ); // disabled: = text--disabled. - $hex_map['--sf-color-link--disabled'] = $hex_map['--sf-color-text--disabled']; + $hex_map['--sf-color-link--disabled'] = $hex_map['--sf-color-text--disabled']; // ---- Text-on-color contrast tokens ---- // CSS: oklch(clamp(0.1, sign(threshold − L) × 999, 0.95) 0 0) @@ -487,11 +487,11 @@ private static function resolve_semantic_tokens( $hex_map, $sources ) { // ---- Selection and mark ---- // selection-bg: action at light opacity; approximate as bg--selected. - $hex_map['--sf-color-selection-bg'] = $hex_map['--sf-color-bg--selected']; + $hex_map['--sf-color-selection-bg'] = $hex_map['--sf-color-bg--selected']; // selection-text / mark-text: both are `inherit` in CSS — show as current text color. $hex_map['--sf-color-selection-text'] = $dark_text; // mark-bg: warning at 25% opacity over white. - $hex_map['--sf-color-mark-bg'] = self::rgb_to_hex( self::mix_rgb( $warning_rgb, $white_rgb, 0.25 ) ); + $hex_map['--sf-color-mark-bg'] = self::rgb_to_hex( self::mix_rgb( $warning_rgb, $white_rgb, 0.25 ) ); $hex_map['--sf-color-mark-text'] = $dark_text; // ---- Status strong variants (light-mode: source L minus offset) ---- @@ -507,7 +507,7 @@ private static function resolve_semantic_tokens( $hex_map, $sources ) { if ( ! isset( $sources[ $family ] ) ) { continue; } - list( $sl, $sc, $sh ) = $sources[ $family ]; + list( $sl, $sc, $sh ) = $sources[ $family ]; $hex_map[ '--sf-color-' . $family . '-strong' ] = self::oklch_to_hex( max( 0.0, $sl - $l_offset ), $sc, @@ -549,7 +549,7 @@ private static function resolve_semantic_tokens_dark( $hex_map, $d, $light_sourc $hex_map['--sf-color-base'] = $surface_hex; $hex_map['--sf-color-surface'] = $surface_hex; $hex_map['--sf-color-bg'] = self::oklch_to_hex( min( 1.0, $bl + 0.02 ), $bc, $bh ); - $hex_map['--sf-color-inset'] = self::oklch_to_hex( max( 0.0, $bl - 0.02 ), $bc, $bh ); + $hex_map['--sf-color-inset'] = self::oklch_to_hex( max( 0.0, $bl - 0.02 ), $bc, $bh ); $hex_map['--sf-color-raised'] = self::oklch_to_hex( min( 1.0, $bl + 0.04 ), $bc, $bh ); $hex_map['--sf-color-overlay'] = $surface_hex; $hex_map['--sf-color-inverse'] = self::oklch_to_hex( max( 0.0, 1.0 - $bl ), $bc, $bh ); @@ -558,21 +558,21 @@ private static function resolve_semantic_tokens_dark( $hex_map, $d, $light_sourc // ---- Neutral-derived text + border (dark formulas) ---- if ( isset( $d['neutral'] ) ) { list( $nl, $nc, $nh ) = $d['neutral']; - $neutral_hex = isset( $hex_map['--sf-color-neutral'] ) ? $hex_map['--sf-color-neutral'] : self::oklch_to_hex( $nl, $nc, $nh ); - $neutral_rgb = self::hex_to_rgb( $neutral_hex ); - - $hex_map['--sf-color-text'] = self::oklch_to_hex( max( 0.70, min( $nl + 0.25, 1.0 ) ), $nc, $nh ); - $hex_map['--sf-color-heading'] = $hex_map['--sf-color-text']; - $hex_map['--sf-color-text--secondary'] = self::oklch_to_hex( max( 0.55, min( $nl + 0.1, 0.90 ) ), $nc, $nh ); - $hex_map['--sf-color-text--muted'] = $neutral_hex; - $hex_map['--sf-color-text--placeholder']= self::oklch_to_hex( max( 0.35, min( $nl - 0.1, 0.65 ) ), $nc, $nh ); - $hex_map['--sf-color-text--disabled'] = self::oklch_to_hex( max( 0.25, min( $nl - 0.2, 0.55 ) ), $nc, $nh ); - $hex_map['--sf-color-text--inverse'] = self::oklch_to_hex( max( 0.05, min( $nl - 0.4, 0.35 ) ), $nc, $nh ); - - $hex_map['--sf-color-border'] = self::oklch_to_hex( max( 0.25, min( $nl - 0.3, 0.55 ) ), 0.005, $nh ); - $hex_map['--sf-color-border--subtle'] = self::oklch_to_hex( max( 0.20, min( $nl - 0.38, 0.45 ) ), 0.005, $nh ); - $hex_map['--sf-color-border--strong'] = self::oklch_to_hex( max( 0.38, min( $nl - 0.1, 0.65 ) ), 0.02, $nh ); - $hex_map['--sf-color-border--muted'] = $hex_map['--sf-color-border--subtle']; + $neutral_hex = isset( $hex_map['--sf-color-neutral'] ) ? $hex_map['--sf-color-neutral'] : self::oklch_to_hex( $nl, $nc, $nh ); + $neutral_rgb = self::hex_to_rgb( $neutral_hex ); + + $hex_map['--sf-color-text'] = self::oklch_to_hex( max( 0.70, min( $nl + 0.25, 1.0 ) ), $nc, $nh ); + $hex_map['--sf-color-heading'] = $hex_map['--sf-color-text']; + $hex_map['--sf-color-text--secondary'] = self::oklch_to_hex( max( 0.55, min( $nl + 0.1, 0.90 ) ), $nc, $nh ); + $hex_map['--sf-color-text--muted'] = $neutral_hex; + $hex_map['--sf-color-text--placeholder'] = self::oklch_to_hex( max( 0.35, min( $nl - 0.1, 0.65 ) ), $nc, $nh ); + $hex_map['--sf-color-text--disabled'] = self::oklch_to_hex( max( 0.25, min( $nl - 0.2, 0.55 ) ), $nc, $nh ); + $hex_map['--sf-color-text--inverse'] = self::oklch_to_hex( max( 0.05, min( $nl - 0.4, 0.35 ) ), $nc, $nh ); + + $hex_map['--sf-color-border'] = self::oklch_to_hex( max( 0.25, min( $nl - 0.3, 0.55 ) ), 0.005, $nh ); + $hex_map['--sf-color-border--subtle'] = self::oklch_to_hex( max( 0.20, min( $nl - 0.38, 0.45 ) ), 0.005, $nh ); + $hex_map['--sf-color-border--strong'] = self::oklch_to_hex( max( 0.38, min( $nl - 0.1, 0.65 ) ), 0.02, $nh ); + $hex_map['--sf-color-border--muted'] = $hex_map['--sf-color-border--subtle']; $hex_map['--sf-color-border--translucent'] = self::rgb_to_hex( self::mix_rgb( $neutral_rgb, $surface_rgb, 0.15 ) ); $hex_map['--sf-color-border--disabled'] = self::rgb_to_hex( self::mix_rgb( self::hex_to_rgb( $hex_map['--sf-color-border--subtle'] ), $surface_rgb, 0.5 ) ); @@ -585,13 +585,13 @@ private static function resolve_semantic_tokens_dark( $hex_map, $d, $light_sourc // ---- Action-derived links (dark formulas: lighten toward a floor) ---- if ( isset( $d['action'] ) ) { list( $al, $ac, $ah ) = $d['action']; - $action_hex = isset( $hex_map['--sf-color-action'] ) ? $hex_map['--sf-color-action'] : self::oklch_to_hex( $al, $ac, $ah ); - $action_rgb = self::hex_to_rgb( $action_hex ); + $action_hex = isset( $hex_map['--sf-color-action'] ) ? $hex_map['--sf-color-action'] : self::oklch_to_hex( $al, $ac, $ah ); + $action_rgb = self::hex_to_rgb( $action_hex ); - $hex_map['--sf-color-link'] = self::oklch_to_hex( max( 0.68, $al ), $ac, $ah ); - $hex_map['--sf-color-link--hover'] = self::oklch_to_hex( max( $al + 0.10, 0.68 ), $ac, $ah ); - $hex_map['--sf-color-link--active'] = self::oklch_to_hex( max( $al + 0.15, 0.74 ), $ac, $ah ); - $hex_map['--sf-color-link--visited'] = self::oklch_to_hex( max( 0.68, $al ), $ac, fmod( $ah + 60.0, 360.0 ) ); + $hex_map['--sf-color-link'] = self::oklch_to_hex( max( 0.68, $al ), $ac, $ah ); + $hex_map['--sf-color-link--hover'] = self::oklch_to_hex( max( $al + 0.10, 0.68 ), $ac, $ah ); + $hex_map['--sf-color-link--active'] = self::oklch_to_hex( max( $al + 0.15, 0.74 ), $ac, $ah ); + $hex_map['--sf-color-link--visited'] = self::oklch_to_hex( max( 0.68, $al ), $ac, fmod( $ah + 60.0, 360.0 ) ); $hex_map['--sf-color-link--underline'] = self::rgb_to_hex( self::mix_rgb( $action_rgb, $surface_rgb, 0.30 ) ); $hex_map['--sf-color-bg--selected'] = self::rgb_to_hex( self::mix_rgb( $action_rgb, $surface_rgb, 0.10 ) ); @@ -620,9 +620,9 @@ private static function resolve_semantic_tokens_dark( $hex_map, $d, $light_sourc // ---- Selection + mark ---- // Dark selection-bg references action-LIGHT lightness; composite at ~0.55 over base. if ( isset( $light_sources['action'] ) ) { - list( $la, $lc, $lh ) = $light_sources['action']; - $sel_l = max( 0.62, min( 0.93 - $la * 0.4, 0.78 ) ); - $sel_rgb = self::hex_to_rgb( self::oklch_to_hex( $sel_l, $lc, $lh ) ); + list( $la, $lc, $lh ) = $light_sources['action']; + $sel_l = max( 0.62, min( 0.93 - $la * 0.4, 0.78 ) ); + $sel_rgb = self::hex_to_rgb( self::oklch_to_hex( $sel_l, $lc, $lh ) ); $hex_map['--sf-color-selection-bg'] = self::rgb_to_hex( self::mix_rgb( $sel_rgb, $surface_rgb, 0.55 ) ); } elseif ( isset( $hex_map['--sf-color-bg--selected'] ) ) { $hex_map['--sf-color-selection-bg'] = $hex_map['--sf-color-bg--selected']; @@ -646,7 +646,7 @@ private static function resolve_semantic_tokens_dark( $hex_map, $d, $light_sourc if ( ! isset( $d[ $family ] ) ) { continue; } - list( $sl, $sc, $sh ) = $d[ $family ]; + list( $sl, $sc, $sh ) = $d[ $family ]; $hex_map[ '--sf-color-' . $family . '-strong' ] = self::oklch_to_hex( max( 0.0, min( $sl + $l_offset, 1.0 ) ), $sc, $sh ); } diff --git a/SLASHED-for-WP/includes/class-css-generator.php b/SLASHED-for-WP/includes/class-css-generator.php index 8ee2eaa3..fffcbd40 100644 --- a/SLASHED-for-WP/includes/class-css-generator.php +++ b/SLASHED-for-WP/includes/class-css-generator.php @@ -428,10 +428,10 @@ private static function generate_layout_declarations( $settings, $vp_min = self: private static function generate_paired_clamp_declarations( $settings, $key_prefix, $mobile_var, $desktop_var, $computed_var, $vp_min = self::VIEWPORT_MIN, $vp_max = self::VIEWPORT_MAX ) { $declarations = array(); - $mobile_raw = $settings[ $key_prefix . '_mobile' ] ?? ''; + $mobile_raw = $settings[ $key_prefix . '_mobile' ] ?? ''; $desktop_raw = $settings[ $key_prefix . '_desktop' ] ?? ''; - $mobile_num = ( '' !== $mobile_raw && is_numeric( $mobile_raw ) ) ? (float) $mobile_raw : null; + $mobile_num = ( '' !== $mobile_raw && is_numeric( $mobile_raw ) ) ? (float) $mobile_raw : null; $desktop_num = ( '' !== $desktop_raw && is_numeric( $desktop_raw ) ) ? (float) $desktop_raw : null; if ( null === $mobile_num && null === $desktop_num ) { @@ -453,10 +453,10 @@ private static function generate_paired_clamp_declarations( $settings, $key_pref // zero (a collapsed header) and mobile may exceed desktop (a // header that shrinks as the viewport grows), so the clamp // bounds are the sorted pair, not mobile/desktop in order. - $slope = ( $desktop_num - $mobile_num ) / ( $vp_max - $vp_min ); - $lower = min( $mobile_num, $desktop_num ); - $upper = max( $mobile_num, $desktop_num ); - $middle = 'calc(' . round( $slope, 6 ) . ' * (100vw - ' . $vp_min . 'rem) + ' . round( $mobile_num, 4 ) . 'rem)'; + $slope = ( $desktop_num - $mobile_num ) / ( $vp_max - $vp_min ); + $lower = min( $mobile_num, $desktop_num ); + $upper = max( $mobile_num, $desktop_num ); + $middle = 'calc(' . round( $slope, 6 ) . ' * (100vw - ' . $vp_min . 'rem) + ' . round( $mobile_num, 4 ) . 'rem)'; $declarations[] = $computed_var . ': clamp(' . round( $lower, 4 ) . 'rem, ' . $middle . ', ' . round( $upper, 4 ) . 'rem);'; } } elseif ( null !== $mobile_num ) { @@ -506,9 +506,9 @@ private static function balanced_parens( $value ) { for ( $i = 0; $i < $len; $i++ ) { $ch = $value[ $i ]; if ( '(' === $ch ) { - $depth++; + ++$depth; } elseif ( ')' === $ch ) { - $depth--; + --$depth; if ( $depth < 0 ) { return false; } diff --git a/SLASHED-for-WP/includes/class-css-parser.php b/SLASHED-for-WP/includes/class-css-parser.php index 2ddbd961..76b72ad8 100644 --- a/SLASHED-for-WP/includes/class-css-parser.php +++ b/SLASHED-for-WP/includes/class-css-parser.php @@ -138,9 +138,9 @@ public static function empty_inventory() { /** * Extract --sf-color-* variable names and their declared values. * - * Captures both regular declarations (--sf-color-X: value;) and - * @property initial-value declarations. Returns an associative array - * mapping variable names to their raw declared values. + * Captures both regular declarations (--sf-color-X: value;) and the CSS + * `@property` at-rule initial-value declarations. Returns an associative + * array mapping variable names to their raw declared values. * * @param string $css CSS with comments removed. * @return array Map of variable name to declared value. diff --git a/SLASHED-for-WP/includes/class-framework-updater.php b/SLASHED-for-WP/includes/class-framework-updater.php index 7ed90f6f..3480fa36 100644 --- a/SLASHED-for-WP/includes/class-framework-updater.php +++ b/SLASHED-for-WP/includes/class-framework-updater.php @@ -24,14 +24,14 @@ class Slashed_Framework_Updater { const LOCAL_VER_OPTION = 'slashed_local_framework_version'; // Per-version CSS comes from the framework's GitHub Release assets (immutable // per tag). %1$s = version tag (e.g. v0.5.21), %2$s = bundle filename. - const CDN_BASE = 'https://github.com/codeslash-dev/SLASHED/releases/download/%s/%s'; + const CDN_BASE = 'https://github.com/codeslash-dev/SLASHED/releases/download/%s/%s'; // jsDelivr package metadata lists the framework repo's git tags (works // independently of where the built CSS lives). - const METADATA_URL = 'https://data.jsdelivr.com/v1/packages/gh/codeslash-dev/SLASHED'; + const METADATA_URL = 'https://data.jsdelivr.com/v1/packages/gh/codeslash-dev/SLASHED'; public function __construct() { - add_action( 'wp_ajax_slashed_check_framework_update', array( $this, 'ajax_check_update' ) ); - add_action( 'wp_ajax_slashed_do_framework_update', array( $this, 'ajax_do_update' ) ); + add_action( 'wp_ajax_slashed_check_framework_update', array( $this, 'ajax_check_update' ) ); + add_action( 'wp_ajax_slashed_do_framework_update', array( $this, 'ajax_do_update' ) ); add_action( 'wp_ajax_slashed_list_framework_versions', array( $this, 'ajax_list_versions' ) ); } @@ -126,11 +126,13 @@ public static function download_files( $version ) { ); if ( is_wp_error( $response ) ) { - foreach ( $staged as $f ) { $wp_filesystem->delete( $f ); } + foreach ( $staged as $f ) { + $wp_filesystem->delete( $f ); } return $response; } if ( 200 !== wp_remote_retrieve_response_code( $response ) ) { - foreach ( $staged as $f ) { $wp_filesystem->delete( $f ); } + foreach ( $staged as $f ) { + $wp_filesystem->delete( $f ); } return new WP_Error( 'download_failed', /* translators: %1$s: filename, %2$d: HTTP status code */ @@ -140,7 +142,8 @@ public static function download_files( $version ) { $content = wp_remote_retrieve_body( $response ); if ( ! $wp_filesystem->put_contents( $tmp_path, $content, FS_CHMOD_FILE ) ) { - foreach ( $staged as $f ) { $wp_filesystem->delete( $f ); } + foreach ( $staged as $f ) { + $wp_filesystem->delete( $f ); } return new WP_Error( 'write_failed', /* translators: %s: filename */ @@ -158,7 +161,8 @@ public static function download_files( $version ) { $final_path = $dist_dir . $filename; if ( ! $wp_filesystem->move( $tmp_path, $final_path, true ) ) { - foreach ( $staged as $f ) { $wp_filesystem->delete( $f ); } + foreach ( $staged as $f ) { + $wp_filesystem->delete( $f ); } return new WP_Error( 'rename_failed', /* translators: %s: filename */ @@ -193,13 +197,11 @@ public function ajax_list_versions() { if ( is_wp_error( $response ) || 200 !== wp_remote_retrieve_response_code( $response ) ) { wp_send_json_error( array( 'message' => __( 'Could not fetch version list. Try again later.', 'slashed' ) ) ); - return; } $body = json_decode( wp_remote_retrieve_body( $response ), true ); if ( ! is_array( $body ) || empty( $body['versions'] ) ) { wp_send_json_error( array( 'message' => __( 'No versions found.', 'slashed' ) ) ); - return; } $versions = array(); @@ -251,13 +253,11 @@ public function ajax_do_update() { } if ( ! $version ) { wp_send_json_error( array( 'message' => __( 'Could not determine version to download.', 'slashed' ) ) ); - return; } $result = self::download_files( $version ); if ( is_wp_error( $result ) ) { wp_send_json_error( array( 'message' => $result->get_error_message() ) ); - return; } wp_send_json_success( diff --git a/SLASHED-for-WP/includes/class-hooks-page.php b/SLASHED-for-WP/includes/class-hooks-page.php index a5ab95b9..d3e229ab 100644 --- a/SLASHED-for-WP/includes/class-hooks-page.php +++ b/SLASHED-for-WP/includes/class-hooks-page.php @@ -68,31 +68,31 @@ private static function get_hooks() { array( 'name' => 'slashed_bricks/variables', 'description' => 'Filter the raw grouped variable map (category label → --sf-* names) before it is turned into Bricks entries. Lower-level than registered_variables.', - 'params' => "\$variables (array) — Map of category label to array of --sf-* names.", + 'params' => '$variables (array) — Map of category label to array of --sf-* names.', 'example' => "add_filter( 'slashed_bricks/variables', function( \$variables ) {\n // Drop a whole category from pickers + autocomplete.\n unset( \$variables['Z-Index'] );\n return \$variables;\n} );", ), array( 'name' => 'slashed_bricks/inventory', - 'description' => "Replace the resolved inventory wholesale. Useful for tests, custom forks of the framework, or sites that want to ship their own token list.", + 'description' => 'Replace the resolved inventory wholesale. Useful for tests, custom forks of the framework, or sites that want to ship their own token list.', 'params' => "\$inventory (array) — Array with keys 'variables', 'sf_classes', 'is_classes'.", 'example' => "add_filter( 'slashed_bricks/inventory', function( \$inventory ) {\n \$inventory['variables'][] = '--sf-color-my-custom';\n return \$inventory;\n} );", ), array( 'name' => 'slashed_bricks/inventory_local_path', 'description' => 'Override the local CSS path the inventory parses. Return a string for a specific path, false to skip local resolution, or null (default) to use bundled candidates.', - 'params' => "\$path (string|false|null) — Override path or control flag.", + 'params' => '$path (string|false|null) — Override path or control flag.', 'example' => "// Use a child-theme copy of the bundle.\nadd_filter( 'slashed_bricks/inventory_local_path', function() {\n return get_stylesheet_directory() . '/assets/slashed.optimal.css';\n} );", ), array( 'name' => 'slashed_bricks/show_color_swatches', 'description' => 'Toggle the colour squares painted next to --sf-color-* entries in the Bricks variable-picker dropdown (builder-side only). Defaults to true.', - 'params' => "\$show (bool) — Whether to paint the picker swatches.", + 'params' => '$show (bool) — Whether to paint the picker swatches.', 'example' => "// Hide the variable-picker swatches.\nadd_filter( 'slashed_bricks/show_color_swatches', '__return_false' );", ), array( 'name' => 'slashed_bricks/show_color_panel', 'description' => 'Toggle the in-builder Color System Panel and its launcher pill. Defaults to true.', - 'params' => "\$show (bool) — Whether to load the Color System Panel.", + 'params' => '$show (bool) — Whether to load the Color System Panel.', 'example' => "// Hide the Color System panel.\nadd_filter( 'slashed_bricks/show_color_panel', '__return_false' );", ), ), diff --git a/SLASHED-for-WP/includes/class-inventory.php b/SLASHED-for-WP/includes/class-inventory.php index cd69cc91..1e5b4078 100644 --- a/SLASHED-for-WP/includes/class-inventory.php +++ b/SLASHED-for-WP/includes/class-inventory.php @@ -47,8 +47,8 @@ class Slashed_Inventory { * * @var array */ - private static $cache = array(); - private static $hex_map_cache = array(); + private static $cache = array(); + private static $hex_map_cache = array(); private static $hex_map_dark_cache = array(); // --------------------------------------------------------------- @@ -192,7 +192,7 @@ private static function sanitize_inventory( $inventory ) { foreach ( array_keys( $base ) as $key ) { // color_values is an associative map, not a sortable list. if ( 'color_values' === $key ) { - $raw_map = isset( $inventory[ $key ] ) && is_array( $inventory[ $key ] ) + $raw_map = isset( $inventory[ $key ] ) && is_array( $inventory[ $key ] ) ? $inventory[ $key ] : array(); $normalized = array(); @@ -308,7 +308,7 @@ private static function get_admin_color_overrides() { return array(); } - $settings = $tokens['colors']; + $settings = $tokens['colors']; $overrides = array(); // Brand families: 'base' is the source token (--sf-color-base-light); @@ -721,7 +721,11 @@ private static function derive_local_path_from_url( $url ) { * @return array Inventory shape (may be empty on read failure). */ private static function parse_path_with_cache( $path ) { - $mtime = @filemtime( $path ); + if ( ! is_readable( $path ) ) { + return Slashed_CSS_Parser::empty_inventory(); + } + + $mtime = filemtime( $path ); if ( false === $mtime ) { return Slashed_CSS_Parser::empty_inventory(); } @@ -732,7 +736,8 @@ private static function parse_path_with_cache( $path ) { return $cached; } - $css = @file_get_contents( $path ); + // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents -- reading a local bundled CSS file on disk, not a remote URL. + $css = file_get_contents( $path ); if ( false === $css || '' === $css ) { return Slashed_CSS_Parser::empty_inventory(); } diff --git a/SLASHED-for-WP/includes/class-rest-controller.php b/SLASHED-for-WP/includes/class-rest-controller.php index 75833b76..591891d3 100644 --- a/SLASHED-for-WP/includes/class-rest-controller.php +++ b/SLASHED-for-WP/includes/class-rest-controller.php @@ -131,7 +131,7 @@ public function register_routes() { 'type' => 'string', 'required' => false, 'sanitize_callback' => 'sanitize_text_field', - 'validate_callback' => function( $value ) { + 'validate_callback' => function ( $value ) { return in_array( (string) $value, array( '', '100', '62.5' ), true ); }, ), @@ -139,7 +139,7 @@ public function register_routes() { 'type' => 'string', 'required' => false, 'sanitize_callback' => 'sanitize_key', - 'validate_callback' => function( $value ) { + 'validate_callback' => function ( $value ) { return in_array( (string) $value, Slashed_Token_Store::ALLOWED_CSS_BUNDLES, true ); }, ), @@ -177,10 +177,12 @@ public function save_section( WP_REST_Request $request ) { $sanitized = Slashed_Token_Sanitizer::sanitize_section( $section, $values ); Slashed_Token_Store::update_section( $section, $sanitized ); - return rest_ensure_response( array( - 'section' => $section, - 'values' => $sanitized, - ) ); + return rest_ensure_response( + array( + 'section' => $section, + 'values' => $sanitized, + ) + ); } public function validate_section( WP_REST_Request $request ) { @@ -206,20 +208,28 @@ public function validate_section( WP_REST_Request $request ) { foreach ( $values as $key => $raw_value ) { $raw = (string) $raw_value; if ( ! array_key_exists( $key, $sanitized ) ) { - $changed[ $key ] = array( 'original' => $raw, 'sanitized' => '' ); + $changed[ $key ] = array( + 'original' => $raw, + 'sanitized' => '', + ); continue; } $clean = (string) $sanitized[ $key ]; if ( $raw !== $clean ) { - $changed[ $key ] = array( 'original' => $raw, 'sanitized' => $clean ); + $changed[ $key ] = array( + 'original' => $raw, + 'sanitized' => $clean, + ); } } - return rest_ensure_response( array( - 'section' => $section, - 'sanitized' => $sanitized, - 'changed' => $changed, - ) ); + return rest_ensure_response( + array( + 'section' => $section, + 'sanitized' => $sanitized, + 'changed' => $changed, + ) + ); } public function reset_section( WP_REST_Request $request ) { @@ -227,7 +237,12 @@ public function reset_section( WP_REST_Request $request ) { if ( '' === $section ) { Slashed_Token_Store::delete_settings(); - return rest_ensure_response( array( 'section' => '', 'settings' => array() ) ); + return rest_ensure_response( + array( + 'section' => '', + 'settings' => array(), + ) + ); } if ( ! $this->is_known_section( $section ) ) { @@ -240,7 +255,12 @@ public function reset_section( WP_REST_Request $request ) { } $all = Slashed_Token_Store::delete_section( $section ); - return rest_ensure_response( array( 'section' => $section, 'settings' => $all ) ); + return rest_ensure_response( + array( + 'section' => $section, + 'settings' => $all, + ) + ); } public function get_settings( WP_REST_Request $request ) { @@ -273,13 +293,15 @@ public function save_settings( WP_REST_Request $request ) { } public function export_tokens() { - return rest_ensure_response( array( - 'schema_version' => '1', - 'plugin_version' => SLASHED_VERSION, - 'exported_at' => gmdate( 'c' ), - 'tokens' => Slashed_Token_Store::get_settings(), - 'plugin_settings' => Slashed_Token_Store::get_plugin_settings(), - ) ); + return rest_ensure_response( + array( + 'schema_version' => '1', + 'plugin_version' => SLASHED_VERSION, + 'exported_at' => gmdate( 'c' ), + 'tokens' => Slashed_Token_Store::get_settings(), + 'plugin_settings' => Slashed_Token_Store::get_plugin_settings(), + ) + ); } public function import_tokens( WP_REST_Request $request ) { @@ -319,8 +341,8 @@ public function import_tokens( WP_REST_Request $request ) { if ( isset( $raw['css_bundle'] ) && in_array( (string) $raw['css_bundle'], Slashed_Token_Store::ALLOWED_CSS_BUNDLES, true ) ) { - $existing['css_bundle'] = (string) $raw['css_bundle']; - $settings_imported = true; + $existing['css_bundle'] = (string) $raw['css_bundle']; + $settings_imported = true; } if ( isset( $raw['html_font_size'] ) && in_array( (string) $raw['html_font_size'], array( '', '100', '62.5' ), true ) @@ -338,12 +360,14 @@ public function import_tokens( WP_REST_Request $request ) { } } - return rest_ensure_response( array( - 'imported' => $imported, - 'settings_imported' => $settings_imported, - 'tokens' => Slashed_Token_Store::get_settings(), - 'plugin_settings' => Slashed_Token_Store::get_plugin_settings(), - ) ); + return rest_ensure_response( + array( + 'imported' => $imported, + 'settings_imported' => $settings_imported, + 'tokens' => Slashed_Token_Store::get_settings(), + 'plugin_settings' => Slashed_Token_Store::get_plugin_settings(), + ) + ); } private function is_known_section( $section ) { diff --git a/SLASHED-for-WP/includes/class-settings.php b/SLASHED-for-WP/includes/class-settings.php index ed89cc90..5de29502 100644 --- a/SLASHED-for-WP/includes/class-settings.php +++ b/SLASHED-for-WP/includes/class-settings.php @@ -30,9 +30,9 @@ class Slashed_Settings { */ const KNOWN_INTEGRATIONS = array( 'bricks', 'gutenberg' ); - const ALLOWED_BUNDLES = array( 'essential', 'optimal', 'full' ); + const ALLOWED_BUNDLES = array( 'essential', 'optimal', 'full' ); - const ALLOWED_SOURCES = array( 'local', 'cdn' ); + const ALLOWED_SOURCES = array( 'local', 'cdn' ); /** * Read settings from the database, applying defaults. @@ -170,12 +170,15 @@ public static function save( array $data ) { $cdn_version = ''; } - return update_option( self::OPTION_KEY, array( - 'integrations' => $integrations, - 'css_bundle' => $bundle, - 'css_source' => $source, - 'cdn_version' => $cdn_version, - ) ); + return update_option( + self::OPTION_KEY, + array( + 'integrations' => $integrations, + 'css_bundle' => $bundle, + 'css_source' => $source, + 'cdn_version' => $cdn_version, + ) + ); } /** diff --git a/SLASHED-for-WP/includes/class-token-defaults.php b/SLASHED-for-WP/includes/class-token-defaults.php index 655cc217..4497e9c2 100644 --- a/SLASHED-for-WP/includes/class-token-defaults.php +++ b/SLASHED-for-WP/includes/class-token-defaults.php @@ -63,7 +63,7 @@ public static function get_section( $section ) { */ public static function get_colors() { return array( - 'brand' => array( + 'brand' => array( 'primary' => 'oklch(0.47 0.27 264)', 'secondary' => 'oklch(0.22 0.04 264)', 'tertiary' => 'oklch(0.42 0.22 295)', @@ -71,7 +71,7 @@ public static function get_colors() { 'neutral' => 'oklch(0.52 0.025 260)', 'base' => 'oklch(0.96 0.006 250)', ), - 'brand_dark' => array( + 'brand_dark' => array( 'primary' => '', 'secondary' => '', 'tertiary' => '', @@ -79,21 +79,21 @@ public static function get_colors() { 'neutral' => '', 'base' => '', ), - 'status' => array( + 'status' => array( 'success' => 'oklch(0.50 0.16 145)', 'warning' => 'oklch(0.75 0.17 80)', 'error' => 'oklch(0.50 0.20 25)', 'info' => 'oklch(0.48 0.18 235)', 'danger' => 'oklch(0.48 0.22 12)', ), - 'status_dark' => array( + 'status_dark' => array( 'success' => '', 'warning' => '', 'error' => '', 'info' => '', 'danger' => '', ), - 'brand_hex_hints' => array( + 'brand_hex_hints' => array( 'primary' => '#4a30d0', 'secondary' => '#141530', 'tertiary' => '#5c20cc', @@ -101,7 +101,7 @@ public static function get_colors() { 'neutral' => '#5e6880', 'base' => '#f8f9ff', ), - 'brand_dark_hex_hints' => array( + 'brand_dark_hex_hints' => array( 'primary' => '#9080f0', 'secondary' => '#c0c8e0', 'tertiary' => '#b07ae8', @@ -109,7 +109,7 @@ public static function get_colors() { 'neutral' => '#8a96b4', 'base' => '#141924', ), - 'status_hex_hints' => array( + 'status_hex_hints' => array( 'success' => '#1a8040', 'warning' => '#ca8a04', 'error' => '#c42010', @@ -133,7 +133,7 @@ public static function get_colors() { */ public static function get_typography() { return array( - 'font_families' => array( + 'font_families' => array( 'body' => 'system-ui, -apple-system, sans-serif', 'heading' => 'var(--sf-font-body)', 'mono' => 'ui-monospace, monospace', @@ -142,19 +142,55 @@ public static function get_typography() { 'geometric' => '"Avenir", "Montserrat", "Corbel", "URW Gothic", source-sans-pro, sans-serif', 'slab' => '"Rockwell", "Rockwell Nova", "Roboto Slab", "DejaVu Serif", "Sitka Small", serif', ), - 'font_sizes' => array( - '2xs' => array( 'min' => 0.51, 'max' => 0.53 ), - 'xs' => array( 'min' => 0.64, 'max' => 0.70 ), - 's' => array( 'min' => 0.80, 'max' => 0.94 ), - 'm' => array( 'min' => 1.00, 'max' => 1.25 ), - 'l' => array( 'min' => 1.25, 'max' => 1.67 ), - 'xl' => array( 'min' => 1.56, 'max' => 2.22 ), - '2xl' => array( 'min' => 1.95, 'max' => 2.96 ), - '3xl' => array( 'min' => 2.44, 'max' => 3.95 ), - '4xl' => array( 'min' => 3.05, 'max' => 5.26 ), - 'display-s' => array( 'min' => 2.40, 'max' => 3.00 ), - 'display-m' => array( 'min' => 3.00, 'max' => 4.00 ), - 'display-l' => array( 'min' => 3.75, 'max' => 5.33 ), + 'font_sizes' => array( + '2xs' => array( + 'min' => 0.51, + 'max' => 0.53, + ), + 'xs' => array( + 'min' => 0.64, + 'max' => 0.70, + ), + 's' => array( + 'min' => 0.80, + 'max' => 0.94, + ), + 'm' => array( + 'min' => 1.00, + 'max' => 1.25, + ), + 'l' => array( + 'min' => 1.25, + 'max' => 1.67, + ), + 'xl' => array( + 'min' => 1.56, + 'max' => 2.22, + ), + '2xl' => array( + 'min' => 1.95, + 'max' => 2.96, + ), + '3xl' => array( + 'min' => 2.44, + 'max' => 3.95, + ), + '4xl' => array( + 'min' => 3.05, + 'max' => 5.26, + ), + 'display-s' => array( + 'min' => 2.40, + 'max' => 3.00, + ), + 'display-m' => array( + 'min' => 3.00, + 'max' => 4.00, + ), + 'display-l' => array( + 'min' => 3.75, + 'max' => 5.33, + ), ), 'scale_multipliers' => array( 'text_scale' => 1, @@ -170,25 +206,52 @@ public static function get_typography() { */ public static function get_spacing() { return array( - 'space_scale' => 1, - 'viewport_min' => 22.5, - 'viewport_max' => 90, - 'space_sizes' => array( - '2xs' => array( 'min' => 0.51, 'max' => 0.84 ), - 'xs' => array( 'min' => 0.64, 'max' => 1.13 ), - 's' => array( 'min' => 0.80, 'max' => 1.50 ), - 'm' => array( 'min' => 1.00, 'max' => 2.00 ), - 'l' => array( 'min' => 1.25, 'max' => 2.67 ), - 'xl' => array( 'min' => 1.56, 'max' => 3.55 ), - '2xl' => array( 'min' => 1.95, 'max' => 4.74 ), - '3xl' => array( 'min' => 2.44, 'max' => 6.31 ), - '4xl' => array( 'min' => 3.05, 'max' => 8.42 ), + 'space_scale' => 1, + 'viewport_min' => 22.5, + 'viewport_max' => 90, + 'space_sizes' => array( + '2xs' => array( + 'min' => 0.51, + 'max' => 0.84, + ), + 'xs' => array( + 'min' => 0.64, + 'max' => 1.13, + ), + 's' => array( + 'min' => 0.80, + 'max' => 1.50, + ), + 'm' => array( + 'min' => 1.00, + 'max' => 2.00, + ), + 'l' => array( + 'min' => 1.25, + 'max' => 2.67, + ), + 'xl' => array( + 'min' => 1.56, + 'max' => 3.55, + ), + '2xl' => array( + 'min' => 1.95, + 'max' => 4.74, + ), + '3xl' => array( + 'min' => 2.44, + 'max' => 6.31, + ), + '4xl' => array( + 'min' => 3.05, + 'max' => 8.42, + ), ), - 'gutter' => 'var(--sf-space-l)', - 'gap' => 'var(--sf-space-m)', - 'content_gap' => 'var(--sf-space-s)', - 'component_pad' => 'var(--sf-space-m)', - 'section_pad' => 'var(--sf-section-pad--m)', + 'gutter' => 'var(--sf-space-l)', + 'gap' => 'var(--sf-space-m)', + 'content_gap' => 'var(--sf-space-s)', + 'component_pad' => 'var(--sf-space-m)', + 'section_pad' => 'var(--sf-section-pad--m)', ); } @@ -203,42 +266,42 @@ public static function get_spacing() { public static function get_layouts() { return array( // Containers - 'container_narrow' => '38rem', - 'container_prose' => '65ch', - 'container_default' => '75rem', - 'container_wide' => '90rem', + 'container_narrow' => '38rem', + 'container_prose' => '65ch', + 'container_default' => '75rem', + 'container_wide' => '90rem', // Grid - 'grid_min' => '16rem', - 'grid_min_xs' => '10rem', - 'grid_min_s' => '13rem', - 'grid_min_l' => '20rem', - 'grid_min_xl' => '24rem', - 'grid_min_2xl' => '28rem', + 'grid_min' => '16rem', + 'grid_min_xs' => '10rem', + 'grid_min_s' => '13rem', + 'grid_min_l' => '20rem', + 'grid_min_xl' => '24rem', + 'grid_min_2xl' => '28rem', // Switcher - 'switcher_threshold' => '30rem', + 'switcher_threshold' => '30rem', // Bento - 'bento_cols' => '3', - 'bento_row_default' => '10rem', - 'bento_row_compact' => '6rem', - 'bento_row_tall' => '16rem', + 'bento_cols' => '3', + 'bento_row_default' => '10rem', + 'bento_row_compact' => '6rem', + 'bento_row_tall' => '16rem', // Content grid - 'content_width' => 'var(--sf-container-default)', - 'breakout_width' => 'var(--sf-container-wide)', + 'content_width' => 'var(--sf-container-default)', + 'breakout_width' => 'var(--sf-container-wide)', // Sidebar - 'sidebar_width' => '18rem', - 'sidebar_min_width' => '50%', + 'sidebar_width' => '18rem', + 'sidebar_min_width' => '50%', // Cover - 'cover_min_height' => '100dvh', - 'cover_padding' => 'var(--sf-section-pad)', + 'cover_min_height' => '100dvh', + 'cover_padding' => 'var(--sf-section-pad)', // Frame - 'frame_ratio' => '16 / 9', + 'frame_ratio' => '16 / 9', // Reel - 'reel_item_width' => 'max-content', - 'reel_height' => 'auto', + 'reel_item_width' => 'max-content', + 'reel_height' => 'auto', // Imposter - 'imposter_margin' => 'var(--sf-space-m)', + 'imposter_margin' => 'var(--sf-space-m)', // Equal columns - 'equal_cols' => '2', + 'equal_cols' => '2', // Header & sticky (numeric rem values, empty = use framework default) 'header_height_mobile' => '', 'header_height_desktop' => '', diff --git a/SLASHED-for-WP/includes/class-token-page.php b/SLASHED-for-WP/includes/class-token-page.php index e5ceded9..42038f83 100644 --- a/SLASHED-for-WP/includes/class-token-page.php +++ b/SLASHED-for-WP/includes/class-token-page.php @@ -77,7 +77,7 @@ public function enqueue_assets( $hook_suffix ) { } if ( defined( 'SLASHED_URL' ) ) { - $plugin_url = SLASHED_URL . 'integrations/bricks/'; + $plugin_url = SLASHED_URL . 'integrations/bricks/'; $plugin_path = SLASHED_PATH . 'integrations/bricks/'; } else { // Standalone Bricks plugin: SLASHED_BRICKS_* already point to integrations/bricks/. diff --git a/SLASHED-for-WP/integrations/bricks/admin-app/jsconfig.json b/SLASHED-for-WP/integrations/bricks/admin-app/jsconfig.json new file mode 100644 index 00000000..be23135c --- /dev/null +++ b/SLASHED-for-WP/integrations/bricks/admin-app/jsconfig.json @@ -0,0 +1,13 @@ +{ + "compilerOptions": { + "moduleResolution": "bundler", + "target": "esnext", + "module": "esnext", + "allowJs": true, + "checkJs": false, + "strict": false, + "skipLibCheck": true, + "isolatedModules": true + }, + "include": ["src/**/*.js", "src/**/*.svelte"] +} diff --git a/SLASHED-for-WP/integrations/bricks/admin-app/package-lock.json b/SLASHED-for-WP/integrations/bricks/admin-app/package-lock.json index 7094c312..611b4667 100644 --- a/SLASHED-for-WP/integrations/bricks/admin-app/package-lock.json +++ b/SLASHED-for-WP/integrations/bricks/admin-app/package-lock.json @@ -10,6 +10,8 @@ "devDependencies": { "@sveltejs/vite-plugin-svelte": "^7.1.2", "svelte": "^5.56.3", + "svelte-check": "^4.6.0", + "typescript": "^6.0.3", "vite": "^8.0.16" } }, @@ -400,6 +402,16 @@ "acorn": "^8.9.0" } }, + "node_modules/@sveltejs/load-config": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@sveltejs/load-config/-/load-config-0.1.1.tgz", + "integrity": "sha512-BXXm+VOH/9X4N7Dd1iZ2MqA1h7M+9i2noI8QYuLDY8QcN2WHYn7D/VK/+IJNfcAmRw7ACNJ538UT9GXIhnBTiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 18.0.0" + } + }, "node_modules/@sveltejs/vite-plugin-svelte": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-7.1.2.tgz", @@ -478,6 +490,22 @@ "node": ">= 0.4" } }, + "node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/clsx": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", @@ -861,6 +889,16 @@ "@jridgewell/sourcemap-codec": "^1.5.5" } }, + "node_modules/mri": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", + "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/nanoid": { "version": "3.3.12", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz", @@ -943,6 +981,20 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/rolldown": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.3.tgz", @@ -977,6 +1029,19 @@ "@rolldown/binding-win32-x64-msvc": "1.0.3" } }, + "node_modules/sade": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz", + "integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==", + "dev": true, + "license": "MIT", + "dependencies": { + "mri": "^1.1.0" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", @@ -1015,6 +1080,31 @@ "node": ">=18" } }, + "node_modules/svelte-check": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/svelte-check/-/svelte-check-4.6.0.tgz", + "integrity": "sha512-KhVnDFDSid57mmZtHz8gfW8AAGylOZ0vPnOIzVmAL+urzwK8sBYXRss953gD8T0OdgAQ11mdWhE6uadmtOz8TQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.25", + "@sveltejs/load-config": "0.1.1", + "chokidar": "^4.0.1", + "fdir": "^6.2.0", + "picocolors": "^1.0.0", + "sade": "^1.7.4" + }, + "bin": { + "svelte-check": "bin/svelte-check" + }, + "engines": { + "node": ">= 18.0.0" + }, + "peerDependencies": { + "svelte": "^4.0.0 || ^5.0.0-next.0", + "typescript": ">=5.0.0" + } + }, "node_modules/tinyglobby": { "version": "0.2.17", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", @@ -1040,6 +1130,20 @@ "license": "0BSD", "optional": true }, + "node_modules/typescript": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", + "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, "node_modules/vite": { "version": "8.0.16", "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.16.tgz", diff --git a/SLASHED-for-WP/integrations/bricks/admin-app/package.json b/SLASHED-for-WP/integrations/bricks/admin-app/package.json index 23f41c30..136bb755 100644 --- a/SLASHED-for-WP/integrations/bricks/admin-app/package.json +++ b/SLASHED-for-WP/integrations/bricks/admin-app/package.json @@ -7,11 +7,14 @@ "scripts": { "dev": "vite", "build": "vite build", - "preview": "vite preview" + "preview": "vite preview", + "check": "svelte-check --tsconfig ./jsconfig.json" }, "devDependencies": { "@sveltejs/vite-plugin-svelte": "^7.1.2", "svelte": "^5.56.3", + "svelte-check": "^4.6.0", + "typescript": "^6.0.3", "vite": "^8.0.16" } } diff --git a/SLASHED-for-WP/integrations/bricks/editor-app/jsconfig.json b/SLASHED-for-WP/integrations/bricks/editor-app/jsconfig.json new file mode 100644 index 00000000..be23135c --- /dev/null +++ b/SLASHED-for-WP/integrations/bricks/editor-app/jsconfig.json @@ -0,0 +1,13 @@ +{ + "compilerOptions": { + "moduleResolution": "bundler", + "target": "esnext", + "module": "esnext", + "allowJs": true, + "checkJs": false, + "strict": false, + "skipLibCheck": true, + "isolatedModules": true + }, + "include": ["src/**/*.js", "src/**/*.svelte"] +} diff --git a/SLASHED-for-WP/integrations/bricks/editor-app/package-lock.json b/SLASHED-for-WP/integrations/bricks/editor-app/package-lock.json index 06dcd1ba..c5eb78cd 100644 --- a/SLASHED-for-WP/integrations/bricks/editor-app/package-lock.json +++ b/SLASHED-for-WP/integrations/bricks/editor-app/package-lock.json @@ -10,6 +10,8 @@ "devDependencies": { "@sveltejs/vite-plugin-svelte": "^7.1.2", "svelte": "^5.56.3", + "svelte-check": "^4.6.0", + "typescript": "^6.0.3", "vite": "^8.0.16" } }, @@ -400,6 +402,16 @@ "acorn": "^8.9.0" } }, + "node_modules/@sveltejs/load-config": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@sveltejs/load-config/-/load-config-0.1.1.tgz", + "integrity": "sha512-BXXm+VOH/9X4N7Dd1iZ2MqA1h7M+9i2noI8QYuLDY8QcN2WHYn7D/VK/+IJNfcAmRw7ACNJ538UT9GXIhnBTiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 18.0.0" + } + }, "node_modules/@sveltejs/vite-plugin-svelte": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-7.1.2.tgz", @@ -478,6 +490,22 @@ "node": ">= 0.4" } }, + "node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/clsx": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", @@ -861,6 +889,16 @@ "@jridgewell/sourcemap-codec": "^1.5.5" } }, + "node_modules/mri": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", + "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/nanoid": { "version": "3.3.12", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz", @@ -943,6 +981,20 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/rolldown": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.3.tgz", @@ -977,6 +1029,19 @@ "@rolldown/binding-win32-x64-msvc": "1.0.3" } }, + "node_modules/sade": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz", + "integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==", + "dev": true, + "license": "MIT", + "dependencies": { + "mri": "^1.1.0" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", @@ -1015,6 +1080,31 @@ "node": ">=18" } }, + "node_modules/svelte-check": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/svelte-check/-/svelte-check-4.6.0.tgz", + "integrity": "sha512-KhVnDFDSid57mmZtHz8gfW8AAGylOZ0vPnOIzVmAL+urzwK8sBYXRss953gD8T0OdgAQ11mdWhE6uadmtOz8TQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.25", + "@sveltejs/load-config": "0.1.1", + "chokidar": "^4.0.1", + "fdir": "^6.2.0", + "picocolors": "^1.0.0", + "sade": "^1.7.4" + }, + "bin": { + "svelte-check": "bin/svelte-check" + }, + "engines": { + "node": ">= 18.0.0" + }, + "peerDependencies": { + "svelte": "^4.0.0 || ^5.0.0-next.0", + "typescript": ">=5.0.0" + } + }, "node_modules/tinyglobby": { "version": "0.2.17", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", @@ -1040,6 +1130,20 @@ "license": "0BSD", "optional": true }, + "node_modules/typescript": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", + "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, "node_modules/vite": { "version": "8.0.16", "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.16.tgz", diff --git a/SLASHED-for-WP/integrations/bricks/editor-app/package.json b/SLASHED-for-WP/integrations/bricks/editor-app/package.json index 44423dbb..134987a4 100644 --- a/SLASHED-for-WP/integrations/bricks/editor-app/package.json +++ b/SLASHED-for-WP/integrations/bricks/editor-app/package.json @@ -7,11 +7,14 @@ "scripts": { "dev": "vite", "build": "vite build", - "preview": "vite preview" + "preview": "vite preview", + "check": "svelte-check --tsconfig ./jsconfig.json" }, "devDependencies": { "@sveltejs/vite-plugin-svelte": "^7.1.2", "svelte": "^5.56.3", + "svelte-check": "^4.6.0", + "typescript": "^6.0.3", "vite": "^8.0.16" } } diff --git a/SLASHED-for-WP/integrations/bricks/includes/class-classes.php b/SLASHED-for-WP/integrations/bricks/includes/class-classes.php index 5d76912d..c91ed522 100644 --- a/SLASHED-for-WP/integrations/bricks/includes/class-classes.php +++ b/SLASHED-for-WP/integrations/bricks/includes/class-classes.php @@ -6,7 +6,7 @@ */ if ( ! defined( 'ABSPATH' ) ) { - exit; + exit; } /** @@ -47,184 +47,190 @@ */ class Slashed_Bricks_Classes { - /** - * Prefix used on every class id and category id this integration injects. - * Used to identify our entries when stripping on save. - */ - const ID_PREFIX = 'slashed-'; - - /** - * Stable category ids. These live in `bricks_global_classes_categories` - * and each class entry references one via its `category` field. - */ - const CATEGORY_LAYOUT = 'slashed-cat-layout'; - const CATEGORY_STATE = 'slashed-cat-state'; - - /** - * Constructor. Register option filters. - */ - public function __construct() { - // Inject SLASHED classes when Bricks reads the option. Run late - // so any other plugin's additions are preserved. - add_filter( 'option_bricks_global_classes', array( $this, 'inject_classes' ), 20 ); - add_filter( 'default_option_bricks_global_classes', array( $this, 'inject_classes' ), 20 ); - - // Strip SLASHED classes before they are persisted back to the DB. - // pre_update_option_* hooks must never widen the stored type from - // array to scalar - that would break Bricks' own loader, which - // iterates over the option. - add_filter( 'pre_update_option_bricks_global_classes', array( $this, 'strip_classes' ), 10, 1 ); - - // Same managed/virtual pattern for class categories (Bricks 1.9.5+). - add_filter( 'option_bricks_global_classes_categories', array( $this, 'inject_categories' ), 20 ); - add_filter( 'default_option_bricks_global_classes_categories', array( $this, 'inject_categories' ), 20 ); - add_filter( 'pre_update_option_bricks_global_classes_categories', array( $this, 'strip_categories' ), 10, 1 ); - } - - /** - * Inject SLASHED classes into the Bricks global classes list. - * - * Idempotent: any existing SLASHED-prefixed entries are removed first - * so multiple read passes don't create duplicates. - * - * @param mixed $classes Existing value of bricks_global_classes option. - * @return array - */ - public function inject_classes( $classes ) { - if ( ! is_array( $classes ) ) { - $classes = array(); - } - - $classes = $this->strip_classes( $classes ); - - foreach ( $this->build_classes() as $entry ) { - $classes[] = $entry; - } - - return $classes; - } - - /** - * Remove SLASHED-prefixed entries from a global classes array. - * - * Always returns a clean array, even when the option is malformed. - * - * @param mixed $classes Value of bricks_global_classes option. - * @return array - */ - public function strip_classes( $classes ) { - return $this->strip_prefixed( $classes ); - } - - /** - * Inject SLASHED class category entries. - * - * @param mixed $categories Existing value of bricks_global_classes_categories option. - * @return array - */ - public function inject_categories( $categories ) { - if ( ! is_array( $categories ) ) { - $categories = array(); - } - - $categories = $this->strip_categories( $categories ); - - foreach ( $this->build_categories() as $cat ) { - $categories[] = $cat; - } - - return $categories; - } - - /** - * Remove SLASHED-prefixed categories from a categories array. - * - * @param mixed $categories Value of bricks_global_classes_categories option. - * @return array - */ - public function strip_categories( $categories ) { - return $this->strip_prefixed( $categories ); - } - - /** - * Shared "strip every entry whose id starts with our prefix" helper. - * - * @param mixed $entries Possibly malformed list of `{id,...}` entries. - * @return array - */ - private function strip_prefixed( $entries ) { - if ( ! is_array( $entries ) ) { - return array(); - } - - $kept = array(); - foreach ( $entries as $entry ) { - if ( is_array( $entry ) - && isset( $entry['id'] ) - && is_string( $entry['id'] ) - && 0 === strpos( $entry['id'], self::ID_PREFIX ) - ) { - continue; - } - $kept[] = $entry; - } - - return array_values( $kept ); - } - - /** - * Build SLASHED class entries from the inventory. - * - * Each entry follows the Bricks-native shape: - * { id, name, settings: { locked: true }, category } - * - * - `id` is a stable slashed-* slug so strip_classes() can find it - * reliably across read passes; Bricks accepts any unique string. - * - `name` is the actual class name users will apply (e.g. "sf-stack"). - * - `settings.locked` puts the entry in the Class Manager's Locked - * filter so framework classes aren't accidentally edited. - * - `category` references one of our stable category ids. - * - * @return array> - */ - public function build_classes() { - $entries = array(); - - foreach ( Slashed_Bricks_Inventory::get_sf_classes() as $name ) { - $entries[] = array( - 'id' => self::ID_PREFIX . sanitize_key( $name ), - 'name' => $name, - 'settings' => array( 'locked' => true ), - 'category' => self::CATEGORY_LAYOUT, - ); - } - - foreach ( Slashed_Bricks_Inventory::get_is_classes() as $name ) { - $entries[] = array( - 'id' => self::ID_PREFIX . sanitize_key( $name ), - 'name' => $name, - 'settings' => array( 'locked' => true ), - 'category' => self::CATEGORY_STATE, - ); - } - - /** - * Filter the SLASHED class entries before injection. - * - * @param array $entries Class entries. - */ - return apply_filters( 'slashed_bricks/registered_classes', $entries ); - } - - /** - * Build SLASHED class category entries. - * - * @return array> - */ - public function build_categories() { - return array( - array( 'id' => self::CATEGORY_LAYOUT, 'name' => __( 'SLASHED Layout', 'slashed-bricks' ) ), - array( 'id' => self::CATEGORY_STATE, 'name' => __( 'SLASHED State', 'slashed-bricks' ) ), - ); - } + /** + * Prefix used on every class id and category id this integration injects. + * Used to identify our entries when stripping on save. + */ + const ID_PREFIX = 'slashed-'; + + /** + * Stable category ids. These live in `bricks_global_classes_categories` + * and each class entry references one via its `category` field. + */ + const CATEGORY_LAYOUT = 'slashed-cat-layout'; + const CATEGORY_STATE = 'slashed-cat-state'; + + /** + * Constructor. Register option filters. + */ + public function __construct() { + // Inject SLASHED classes when Bricks reads the option. Run late + // so any other plugin's additions are preserved. + add_filter( 'option_bricks_global_classes', array( $this, 'inject_classes' ), 20 ); + add_filter( 'default_option_bricks_global_classes', array( $this, 'inject_classes' ), 20 ); + + // Strip SLASHED classes before they are persisted back to the DB. + // pre_update_option_* hooks must never widen the stored type from + // array to scalar - that would break Bricks' own loader, which + // iterates over the option. + add_filter( 'pre_update_option_bricks_global_classes', array( $this, 'strip_classes' ), 10, 1 ); + + // Same managed/virtual pattern for class categories (Bricks 1.9.5+). + add_filter( 'option_bricks_global_classes_categories', array( $this, 'inject_categories' ), 20 ); + add_filter( 'default_option_bricks_global_classes_categories', array( $this, 'inject_categories' ), 20 ); + add_filter( 'pre_update_option_bricks_global_classes_categories', array( $this, 'strip_categories' ), 10, 1 ); + } + + /** + * Inject SLASHED classes into the Bricks global classes list. + * + * Idempotent: any existing SLASHED-prefixed entries are removed first + * so multiple read passes don't create duplicates. + * + * @param mixed $classes Existing value of bricks_global_classes option. + * @return array + */ + public function inject_classes( $classes ) { + if ( ! is_array( $classes ) ) { + $classes = array(); + } + + $classes = $this->strip_classes( $classes ); + + foreach ( $this->build_classes() as $entry ) { + $classes[] = $entry; + } + + return $classes; + } + + /** + * Remove SLASHED-prefixed entries from a global classes array. + * + * Always returns a clean array, even when the option is malformed. + * + * @param mixed $classes Value of bricks_global_classes option. + * @return array + */ + public function strip_classes( $classes ) { + return $this->strip_prefixed( $classes ); + } + + /** + * Inject SLASHED class category entries. + * + * @param mixed $categories Existing value of bricks_global_classes_categories option. + * @return array + */ + public function inject_categories( $categories ) { + if ( ! is_array( $categories ) ) { + $categories = array(); + } + + $categories = $this->strip_categories( $categories ); + + foreach ( $this->build_categories() as $cat ) { + $categories[] = $cat; + } + + return $categories; + } + + /** + * Remove SLASHED-prefixed categories from a categories array. + * + * @param mixed $categories Value of bricks_global_classes_categories option. + * @return array + */ + public function strip_categories( $categories ) { + return $this->strip_prefixed( $categories ); + } + + /** + * Shared "strip every entry whose id starts with our prefix" helper. + * + * @param mixed $entries Possibly malformed list of `{id,...}` entries. + * @return array + */ + private function strip_prefixed( $entries ) { + if ( ! is_array( $entries ) ) { + return array(); + } + + $kept = array(); + foreach ( $entries as $entry ) { + if ( is_array( $entry ) + && isset( $entry['id'] ) + && is_string( $entry['id'] ) + && 0 === strpos( $entry['id'], self::ID_PREFIX ) + ) { + continue; + } + $kept[] = $entry; + } + + return $kept; + } + + /** + * Build SLASHED class entries from the inventory. + * + * Each entry follows the Bricks-native shape: + * { id, name, settings: { locked: true }, category } + * + * - `id` is a stable slashed-* slug so strip_classes() can find it + * reliably across read passes; Bricks accepts any unique string. + * - `name` is the actual class name users will apply (e.g. "sf-stack"). + * - `settings.locked` puts the entry in the Class Manager's Locked + * filter so framework classes aren't accidentally edited. + * - `category` references one of our stable category ids. + * + * @return array> + */ + public function build_classes() { + $entries = array(); + + foreach ( Slashed_Bricks_Inventory::get_sf_classes() as $name ) { + $entries[] = array( + 'id' => self::ID_PREFIX . sanitize_key( $name ), + 'name' => $name, + 'settings' => array( 'locked' => true ), + 'category' => self::CATEGORY_LAYOUT, + ); + } + + foreach ( Slashed_Bricks_Inventory::get_is_classes() as $name ) { + $entries[] = array( + 'id' => self::ID_PREFIX . sanitize_key( $name ), + 'name' => $name, + 'settings' => array( 'locked' => true ), + 'category' => self::CATEGORY_STATE, + ); + } + + /** + * Filter the SLASHED class entries before injection. + * + * @param array $entries Class entries. + */ + return apply_filters( 'slashed_bricks/registered_classes', $entries ); + } + + /** + * Build SLASHED class category entries. + * + * @return array> + */ + public function build_categories() { + return array( + array( + 'id' => self::CATEGORY_LAYOUT, + 'name' => __( 'SLASHED Layout', 'slashed-bricks' ), + ), + array( + 'id' => self::CATEGORY_STATE, + 'name' => __( 'SLASHED State', 'slashed-bricks' ), + ), + ); + } } diff --git a/SLASHED-for-WP/integrations/bricks/includes/class-enqueue.php b/SLASHED-for-WP/integrations/bricks/includes/class-enqueue.php index 4156fc75..23782b2f 100644 --- a/SLASHED-for-WP/integrations/bricks/includes/class-enqueue.php +++ b/SLASHED-for-WP/integrations/bricks/includes/class-enqueue.php @@ -6,7 +6,7 @@ */ if ( ! defined( 'ABSPATH' ) ) { - exit; + exit; } /** @@ -17,53 +17,53 @@ */ class Slashed_Bricks_Enqueue { - public function __construct() { - add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_frontend_styles' ) ); - add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_editor_styles' ) ); - } + public function __construct() { + add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_frontend_styles' ) ); + add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_editor_styles' ) ); + } - /** - * Add Bricks-specific inline CSS on the frontend and canvas iframe. - * - * `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; - } + /** + * Add Bricks-specific inline CSS on the frontend and canvas iframe. + * + * `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; + } - // Bridge Bricks' dark mode toggle (data-brx-theme attribute) to SLASHED's theme system. - wp_add_inline_style( - 'slashed-framework', - '@layer slashed.themes{[data-brx-theme="light"]{color-scheme:light;--sf-is-dark:0}[data-brx-theme="dark"]{color-scheme:dark;--sf-is-dark:1}}' - ); - } + // Bridge Bricks' dark mode toggle (data-brx-theme attribute) to SLASHED's theme system. + wp_add_inline_style( + 'slashed-framework', + '@layer slashed.themes{[data-brx-theme="light"]{color-scheme:light;--sf-is-dark:0}[data-brx-theme="dark"]{color-scheme:dark;--sf-is-dark:1}}' + ); + } - /** - * Enqueue editor-specific styles in the Bricks admin panel. - * - * Only loads on Bricks builder pages for panel styling. - */ - public function enqueue_editor_styles() { - if ( ! function_exists( 'bricks_is_builder_main' ) ) { - return; - } + /** + * Enqueue editor-specific styles in the Bricks admin panel. + * + * Only loads on Bricks builder pages for panel styling. + */ + public function enqueue_editor_styles() { + if ( ! function_exists( 'bricks_is_builder_main' ) ) { + return; + } - if ( ! bricks_is_builder_main() ) { - return; - } + if ( ! bricks_is_builder_main() ) { + return; + } - $editor_css = SLASHED_BRICKS_URL . 'assets/editor.css'; + $editor_css = SLASHED_BRICKS_URL . 'assets/editor.css'; - wp_enqueue_style( - 'slashed-bricks-editor', - $editor_css, - array(), - SLASHED_BRICKS_VERSION - ); - } + wp_enqueue_style( + 'slashed-bricks-editor', + $editor_css, + array(), + SLASHED_BRICKS_VERSION + ); + } } diff --git a/SLASHED-for-WP/integrations/bricks/includes/class-rebemer-rest.php b/SLASHED-for-WP/integrations/bricks/includes/class-rebemer-rest.php index 2b2a81ad..22957fb7 100644 --- a/SLASHED-for-WP/integrations/bricks/includes/class-rebemer-rest.php +++ b/SLASHED-for-WP/integrations/bricks/includes/class-rebemer-rest.php @@ -125,7 +125,7 @@ public function get_unused_classes() { if ( ! is_array( $cls ) || empty( $cls['id'] ) ) { continue; } - $processed_classes++; + ++$processed_classes; $id = (string) $cls['id']; $count = isset( $reference_counts['counts'][ $id ] ) ? (int) $reference_counts['counts'][ $id ] @@ -218,8 +218,8 @@ private function count_class_references( $classes ) { // with reproducible content rather than whatever order MySQL // happened to return rows in. $rows = $wpdb->get_col( + // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- $placeholders is a list of literal %s built from a constant key list; the values are bound through prepare(). $wpdb->prepare( - // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared "SELECT meta_value FROM {$wpdb->postmeta} WHERE meta_key IN ($placeholders) AND meta_value != '' @@ -227,6 +227,7 @@ private function count_class_references( $classes ) { LIMIT %d", array_merge( self::BRICKS_CONTENT_META_KEYS, array( $cap + 1 ) ) ) + // phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared ); if ( ! is_array( $rows ) ) { @@ -279,7 +280,7 @@ private function collect_class_ids_recursive( $tree, &$counts ) { if ( is_array( $ids ) ) { foreach ( $ids as $cid ) { if ( is_string( $cid ) && isset( $counts[ $cid ] ) ) { - $counts[ $cid ]++; + ++$counts[ $cid ]; } } } diff --git a/SLASHED-for-WP/integrations/bricks/includes/class-variables.php b/SLASHED-for-WP/integrations/bricks/includes/class-variables.php index d32854ea..d54e8518 100644 --- a/SLASHED-for-WP/integrations/bricks/includes/class-variables.php +++ b/SLASHED-for-WP/integrations/bricks/includes/class-variables.php @@ -7,7 +7,7 @@ */ if ( ! defined( 'ABSPATH' ) ) { - exit; + exit; } /** @@ -49,258 +49,258 @@ */ class Slashed_Bricks_Variables { - /** - * Prefix used on every variable id this integration injects. - * Used to identify our entries when stripping on save. - */ - const ID_PREFIX = 'slashed-'; - - /** - * Prefix used on every category id this integration injects. - */ - const CAT_PREFIX = 'slashed-cat-'; - - /** - * Constructor. Register option filters and code editor hook. - */ - public function __construct() { - // Inject SLASHED variables when Bricks reads the option. - add_filter( 'option_bricks_global_variables', array( $this, 'inject_variables' ), 20 ); - add_filter( 'default_option_bricks_global_variables', array( $this, 'inject_variables' ), 20 ); - - // Strip SLASHED variables before they are persisted back to the DB. - add_filter( 'pre_update_option_bricks_global_variables', array( $this, 'strip_variables' ), 10, 1 ); - - // Same managed/virtual pattern for variable categories. - add_filter( 'option_bricks_global_variables_categories', array( $this, 'inject_categories' ), 20 ); - add_filter( 'default_option_bricks_global_variables_categories', array( $this, 'inject_categories' ), 20 ); - add_filter( 'pre_update_option_bricks_global_variables_categories', array( $this, 'strip_categories' ), 10, 1 ); - - // Code editor autocomplete (Bricks 1.9.2+): lists the original - // --sf-* names so authors typing custom CSS see the framework's - // native namespace directly. - add_filter( 'bricks/code/get_code_signatures', array( $this, 'register_code_signatures' ) ); - } - - // --------------------------------------------------------------- - // Variable Manager: inject / strip. - // --------------------------------------------------------------- - - /** - * Inject SLASHED variables into the Bricks global variables list. - * - * Idempotent: any existing SLASHED-prefixed entries are removed first - * so multiple read passes don't create duplicates. - * - * @param mixed $variables Existing value of bricks_global_variables option. - * @return array - */ - public function inject_variables( $variables ) { - if ( ! is_array( $variables ) ) { - $variables = array(); - } - - $variables = $this->strip_variables( $variables ); - - foreach ( $this->build_variables() as $entry ) { - $variables[] = $entry; - } - - return $variables; - } - - /** - * Remove SLASHED-prefixed entries from a global variables array. - * - * Always returns a clean array, even when the option is malformed. - * - * @param mixed $variables Value of bricks_global_variables option. - * @return array - */ - public function strip_variables( $variables ) { - return $this->strip_prefixed( $variables, self::ID_PREFIX ); - } - - /** - * Inject SLASHED variable category entries. - * - * @param mixed $categories Existing value of bricks_global_variables_categories option. - * @return array - */ - public function inject_categories( $categories ) { - if ( ! is_array( $categories ) ) { - $categories = array(); - } - - $categories = $this->strip_categories( $categories ); - - foreach ( $this->build_categories() as $cat ) { - $categories[] = $cat; - } - - return $categories; - } - - /** - * Remove SLASHED-prefixed categories from a categories array. - * - * @param mixed $categories Value of bricks_global_variables_categories option. - * @return array - */ - public function strip_categories( $categories ) { - return $this->strip_prefixed( $categories, self::CAT_PREFIX ); - } - - /** - * Shared "strip every entry whose id starts with the given prefix" helper. - * - * @param mixed $entries Possibly malformed list of `{id,...}` entries. - * @param string $prefix Prefix to match against. - * @return array - */ - private function strip_prefixed( $entries, $prefix ) { - if ( ! is_array( $entries ) ) { - return array(); - } - - $kept = array(); - foreach ( $entries as $entry ) { - if ( is_array( $entry ) - && isset( $entry['id'] ) - && is_string( $entry['id'] ) - && 0 === strpos( $entry['id'], $prefix ) - ) { - continue; - } - $kept[] = $entry; - } - - return array_values( $kept ); - } - - // --------------------------------------------------------------- - // Variable Manager: build entries. - // --------------------------------------------------------------- - - /** - * Build SLASHED variable entries from the inventory. - * - * Each entry follows the Bricks-native variable shape: - * { id, name, value, category } - * - * - `id` is a stable slashed-* slug so strip_variables() can find it. - * - `name` is the native property name WITHOUT the `--` prefix (Bricks - * adds `--` automatically), e.g. `sf-color-primary`. - * - `value` is empty string - Bricks skips empty values in :root output, - * so the framework remains the single source of truth. - * - `category` references one of our stable category ids. - * - * @return array> - */ - public function build_variables() { - $entries = array(); - - foreach ( $this->get_variables() as $category => $vars ) { - $cat_id = self::CAT_PREFIX . sanitize_key( $category ); - - foreach ( $vars as $var ) { - // Strip leading '--' to get the native name Bricks expects. - $native_name = ltrim( $var, '-' ); - - $entries[] = array( - 'id' => self::ID_PREFIX . $native_name, - 'name' => $native_name, - 'value' => '', - 'category' => $cat_id, - ); - } - } - - /** - * Filter the SLASHED variable entries before injection. - * - * @param array $entries Variable entries. - */ - return apply_filters( 'slashed_bricks/registered_variables', $entries ); - } - - /** - * Build SLASHED variable category entries. - * - * @return array> - */ - public function build_categories() { - $categories = array(); - - foreach ( $this->get_variables() as $category => $vars ) { - if ( empty( $vars ) ) { - continue; - } - - $categories[] = array( - 'id' => self::CAT_PREFIX . sanitize_key( $category ), - 'name' => 'SLASHED ' . $category, - ); - } - - return $categories; - } - - // --------------------------------------------------------------- - // Shared variable source. - // --------------------------------------------------------------- - - /** - * Get all SLASHED CSS variables grouped by category. - * - * @return array Map of category => variable names. - */ - public function get_variables() { - $variables = Slashed_Bricks_Inventory::get_variables_by_category(); - - /** - * Filter the registered CSS variables. - * - * @param array $variables Map of category => variable names. - */ - return apply_filters( 'slashed_bricks/variables', $variables ); - } - - // --------------------------------------------------------------- - // Code editor autocomplete. - // --------------------------------------------------------------- - - /** - * Register variables for the Bricks code editor autocomplete. - * - * Uses the original --sf-* names so authors writing CSS see the - * framework's native namespace directly. - * - * @param array $signatures Existing code signatures. - * @return array Modified code signatures. - */ - public function register_code_signatures( $signatures ) { - if ( ! is_array( $signatures ) ) { - $signatures = array(); - } - - $css_vars = array(); - foreach ( $this->get_variables() as $category => $vars ) { - foreach ( $vars as $var ) { - $css_vars[] = array( - 'label' => $var, - 'detail' => 'SLASHED ' . $category, - 'type' => 'variable', - ); - } - } - - if ( ! isset( $signatures['css'] ) || ! is_array( $signatures['css'] ) ) { - $signatures['css'] = array(); - } - - $signatures['css']['slashed_variables'] = $css_vars; - - return $signatures; - } + /** + * Prefix used on every variable id this integration injects. + * Used to identify our entries when stripping on save. + */ + const ID_PREFIX = 'slashed-'; + + /** + * Prefix used on every category id this integration injects. + */ + const CAT_PREFIX = 'slashed-cat-'; + + /** + * Constructor. Register option filters and code editor hook. + */ + public function __construct() { + // Inject SLASHED variables when Bricks reads the option. + add_filter( 'option_bricks_global_variables', array( $this, 'inject_variables' ), 20 ); + add_filter( 'default_option_bricks_global_variables', array( $this, 'inject_variables' ), 20 ); + + // Strip SLASHED variables before they are persisted back to the DB. + add_filter( 'pre_update_option_bricks_global_variables', array( $this, 'strip_variables' ), 10, 1 ); + + // Same managed/virtual pattern for variable categories. + add_filter( 'option_bricks_global_variables_categories', array( $this, 'inject_categories' ), 20 ); + add_filter( 'default_option_bricks_global_variables_categories', array( $this, 'inject_categories' ), 20 ); + add_filter( 'pre_update_option_bricks_global_variables_categories', array( $this, 'strip_categories' ), 10, 1 ); + + // Code editor autocomplete (Bricks 1.9.2+): lists the original + // --sf-* names so authors typing custom CSS see the framework's + // native namespace directly. + add_filter( 'bricks/code/get_code_signatures', array( $this, 'register_code_signatures' ) ); + } + + // --------------------------------------------------------------- + // Variable Manager: inject / strip. + // --------------------------------------------------------------- + + /** + * Inject SLASHED variables into the Bricks global variables list. + * + * Idempotent: any existing SLASHED-prefixed entries are removed first + * so multiple read passes don't create duplicates. + * + * @param mixed $variables Existing value of bricks_global_variables option. + * @return array + */ + public function inject_variables( $variables ) { + if ( ! is_array( $variables ) ) { + $variables = array(); + } + + $variables = $this->strip_variables( $variables ); + + foreach ( $this->build_variables() as $entry ) { + $variables[] = $entry; + } + + return $variables; + } + + /** + * Remove SLASHED-prefixed entries from a global variables array. + * + * Always returns a clean array, even when the option is malformed. + * + * @param mixed $variables Value of bricks_global_variables option. + * @return array + */ + public function strip_variables( $variables ) { + return $this->strip_prefixed( $variables, self::ID_PREFIX ); + } + + /** + * Inject SLASHED variable category entries. + * + * @param mixed $categories Existing value of bricks_global_variables_categories option. + * @return array + */ + public function inject_categories( $categories ) { + if ( ! is_array( $categories ) ) { + $categories = array(); + } + + $categories = $this->strip_categories( $categories ); + + foreach ( $this->build_categories() as $cat ) { + $categories[] = $cat; + } + + return $categories; + } + + /** + * Remove SLASHED-prefixed categories from a categories array. + * + * @param mixed $categories Value of bricks_global_variables_categories option. + * @return array + */ + public function strip_categories( $categories ) { + return $this->strip_prefixed( $categories, self::CAT_PREFIX ); + } + + /** + * Shared "strip every entry whose id starts with the given prefix" helper. + * + * @param mixed $entries Possibly malformed list of `{id,...}` entries. + * @param string $prefix Prefix to match against. + * @return array + */ + private function strip_prefixed( $entries, $prefix ) { + if ( ! is_array( $entries ) ) { + return array(); + } + + $kept = array(); + foreach ( $entries as $entry ) { + if ( is_array( $entry ) + && isset( $entry['id'] ) + && is_string( $entry['id'] ) + && 0 === strpos( $entry['id'], $prefix ) + ) { + continue; + } + $kept[] = $entry; + } + + return $kept; + } + + // --------------------------------------------------------------- + // Variable Manager: build entries. + // --------------------------------------------------------------- + + /** + * Build SLASHED variable entries from the inventory. + * + * Each entry follows the Bricks-native variable shape: + * { id, name, value, category } + * + * - `id` is a stable slashed-* slug so strip_variables() can find it. + * - `name` is the native property name WITHOUT the `--` prefix (Bricks + * adds `--` automatically), e.g. `sf-color-primary`. + * - `value` is empty string - Bricks skips empty values in :root output, + * so the framework remains the single source of truth. + * - `category` references one of our stable category ids. + * + * @return array> + */ + public function build_variables() { + $entries = array(); + + foreach ( $this->get_variables() as $category => $vars ) { + $cat_id = self::CAT_PREFIX . sanitize_key( $category ); + + foreach ( $vars as $var ) { + // Strip leading '--' to get the native name Bricks expects. + $native_name = ltrim( $var, '-' ); + + $entries[] = array( + 'id' => self::ID_PREFIX . $native_name, + 'name' => $native_name, + 'value' => '', + 'category' => $cat_id, + ); + } + } + + /** + * Filter the SLASHED variable entries before injection. + * + * @param array $entries Variable entries. + */ + return apply_filters( 'slashed_bricks/registered_variables', $entries ); + } + + /** + * Build SLASHED variable category entries. + * + * @return array> + */ + public function build_categories() { + $categories = array(); + + foreach ( $this->get_variables() as $category => $vars ) { + if ( empty( $vars ) ) { + continue; + } + + $categories[] = array( + 'id' => self::CAT_PREFIX . sanitize_key( $category ), + 'name' => 'SLASHED ' . $category, + ); + } + + return $categories; + } + + // --------------------------------------------------------------- + // Shared variable source. + // --------------------------------------------------------------- + + /** + * Get all SLASHED CSS variables grouped by category. + * + * @return array Map of category => variable names. + */ + public function get_variables() { + $variables = Slashed_Bricks_Inventory::get_variables_by_category(); + + /** + * Filter the registered CSS variables. + * + * @param array $variables Map of category => variable names. + */ + return apply_filters( 'slashed_bricks/variables', $variables ); + } + + // --------------------------------------------------------------- + // Code editor autocomplete. + // --------------------------------------------------------------- + + /** + * Register variables for the Bricks code editor autocomplete. + * + * Uses the original --sf-* names so authors writing CSS see the + * framework's native namespace directly. + * + * @param array $signatures Existing code signatures. + * @return array Modified code signatures. + */ + public function register_code_signatures( $signatures ) { + if ( ! is_array( $signatures ) ) { + $signatures = array(); + } + + $css_vars = array(); + foreach ( $this->get_variables() as $category => $vars ) { + foreach ( $vars as $var ) { + $css_vars[] = array( + 'label' => $var, + 'detail' => 'SLASHED ' . $category, + 'type' => 'variable', + ); + } + } + + if ( ! isset( $signatures['css'] ) || ! is_array( $signatures['css'] ) ) { + $signatures['css'] = array(); + } + + $signatures['css']['slashed_variables'] = $css_vars; + + return $signatures; + } } diff --git a/SLASHED-for-WP/integrations/bricks/slashed-bricks.php b/SLASHED-for-WP/integrations/bricks/slashed-bricks.php index ebfafd66..dbece9a0 100644 --- a/SLASHED-for-WP/integrations/bricks/slashed-bricks.php +++ b/SLASHED-for-WP/integrations/bricks/slashed-bricks.php @@ -13,7 +13,7 @@ */ if ( ! defined( 'ABSPATH' ) ) { - exit; + exit; } /** @@ -25,10 +25,10 @@ * the standalone Bricks plugin and the unified SLASHED plugin are active. */ if ( ! defined( 'SLASHED_BRICKS_VERSION' ) ) { - define( 'SLASHED_BRICKS_VERSION', '0.0.1' ); - define( 'SLASHED_BRICKS_PATH', plugin_dir_path( __FILE__ ) ); - define( 'SLASHED_BRICKS_URL', plugin_dir_url( __FILE__ ) ); - define( 'SLASHED_BRICKS_CSS_REF', 'v0.5.23' ); + define( 'SLASHED_BRICKS_VERSION', '0.0.1' ); + define( 'SLASHED_BRICKS_PATH', plugin_dir_path( __FILE__ ) ); + define( 'SLASHED_BRICKS_URL', plugin_dir_url( __FILE__ ) ); + define( 'SLASHED_BRICKS_CSS_REF', 'v0.5.23' ); } /** @@ -37,24 +37,27 @@ * everything from the shared includes directory two levels up. */ if ( ! defined( 'SLASHED_VERSION' ) ) { - add_action( 'init', function () { - load_plugin_textdomain( 'slashed-bricks', false, dirname( plugin_basename( __FILE__ ) ) . '/languages' ); - } ); + add_action( + 'init', + function () { + load_plugin_textdomain( 'slashed-bricks', false, dirname( plugin_basename( __FILE__ ) ) . '/languages' ); + } + ); } if ( ! class_exists( 'Slashed_Token_Store' ) ) { - $_slashed_shared = SLASHED_BRICKS_PATH . '../../includes/'; - require_once $_slashed_shared . 'class-settings.php'; - require_once $_slashed_shared . 'class-css-loader.php'; - require_once $_slashed_shared . 'class-core-enqueue.php'; - require_once $_slashed_shared . 'class-token-store.php'; - require_once $_slashed_shared . 'class-token-sanitizer.php'; - require_once $_slashed_shared . 'class-token-defaults.php'; - require_once $_slashed_shared . 'class-tab-registry.php'; - require_once $_slashed_shared . 'class-css-generator.php'; - require_once $_slashed_shared . 'class-rest-controller.php'; - require_once $_slashed_shared . 'class-token-page.php'; - unset( $_slashed_shared ); + $slashed_shared = SLASHED_BRICKS_PATH . '../../includes/'; + require_once $slashed_shared . 'class-settings.php'; + require_once $slashed_shared . 'class-css-loader.php'; + require_once $slashed_shared . 'class-core-enqueue.php'; + require_once $slashed_shared . 'class-token-store.php'; + require_once $slashed_shared . 'class-token-sanitizer.php'; + require_once $slashed_shared . 'class-token-defaults.php'; + require_once $slashed_shared . 'class-tab-registry.php'; + require_once $slashed_shared . 'class-css-generator.php'; + require_once $slashed_shared . 'class-rest-controller.php'; + require_once $slashed_shared . 'class-token-page.php'; + unset( $slashed_shared ); } /** @@ -66,15 +69,15 @@ * @return string One of 'essential', 'optimal', 'full'. */ function slashed_bricks_get_css_bundle() { - if ( class_exists( 'Slashed_CSS_Loader' ) ) { - return Slashed_CSS_Loader::get_bundle(); - } - $settings = Slashed_Token_Store::get_plugin_settings(); - $bundle = isset( $settings['css_bundle'] ) ? (string) $settings['css_bundle'] : 'optimal'; - if ( ! in_array( $bundle, Slashed_Token_Store::ALLOWED_CSS_BUNDLES, true ) ) { - $bundle = 'optimal'; - } - return $bundle; + if ( class_exists( 'Slashed_CSS_Loader' ) ) { + return Slashed_CSS_Loader::get_bundle(); + } + $settings = Slashed_Token_Store::get_plugin_settings(); + $bundle = isset( $settings['css_bundle'] ) ? (string) $settings['css_bundle'] : 'optimal'; + if ( ! in_array( $bundle, Slashed_Token_Store::ALLOWED_CSS_BUNDLES, true ) ) { + $bundle = 'optimal'; + } + return $bundle; } /** @@ -90,28 +93,28 @@ function slashed_bricks_get_css_bundle() { * @return string URL to the CSS bundle. */ function slashed_bricks_get_css_url() { - if ( class_exists( 'Slashed_CSS_Loader' ) ) { - return apply_filters( 'slashed_bricks/css_bundle_url', Slashed_CSS_Loader::get_url() ); - } - - // Standalone fallback. - $bundle = slashed_bricks_get_css_bundle(); - $filename = 'slashed.' . $bundle . '.css'; - $default_url = sprintf( - 'https://github.com/codeslash-dev/SLASHED/releases/download/%s/%s', - rawurlencode( SLASHED_BRICKS_CSS_REF ), - $filename - ); - - // Check plugin root dist/ first (two levels up: integrations/bricks/ → plugin root). - $plugin_dist = SLASHED_BRICKS_PATH . '../../dist/' . $filename; - if ( file_exists( $plugin_dist ) ) { - $default_url = SLASHED_BRICKS_URL . '../../dist/' . $filename; - } elseif ( file_exists( SLASHED_BRICKS_PATH . 'dist/' . $filename ) ) { - $default_url = SLASHED_BRICKS_URL . 'dist/' . $filename; - } - - return apply_filters( 'slashed_bricks/css_bundle_url', $default_url ); + if ( class_exists( 'Slashed_CSS_Loader' ) ) { + return apply_filters( 'slashed_bricks/css_bundle_url', Slashed_CSS_Loader::get_url() ); + } + + // Standalone fallback. + $bundle = slashed_bricks_get_css_bundle(); + $filename = 'slashed.' . $bundle . '.css'; + $default_url = sprintf( + 'https://github.com/codeslash-dev/SLASHED/releases/download/%s/%s', + rawurlencode( SLASHED_BRICKS_CSS_REF ), + $filename + ); + + // Check plugin root dist/ first (two levels up: integrations/bricks/ → plugin root). + $plugin_dist = SLASHED_BRICKS_PATH . '../../dist/' . $filename; + if ( file_exists( $plugin_dist ) ) { + $default_url = SLASHED_BRICKS_URL . '../../dist/' . $filename; + } elseif ( file_exists( SLASHED_BRICKS_PATH . 'dist/' . $filename ) ) { + $default_url = SLASHED_BRICKS_URL . 'dist/' . $filename; + } + + return apply_filters( 'slashed_bricks/css_bundle_url', $default_url ); } /** @@ -125,22 +128,22 @@ function slashed_bricks_get_css_url() { * @return string */ function slashed_bricks_get_bricks_version() { - if ( defined( 'BRICKS_VERSION' ) ) { - return (string) BRICKS_VERSION; - } + if ( defined( 'BRICKS_VERSION' ) ) { + return (string) BRICKS_VERSION; + } - $theme = wp_get_theme(); + $theme = wp_get_theme(); - if ( 'bricks' === strtolower( $theme->get_template() ) ) { - $parent = $theme->parent(); - return $parent ? (string) $parent->get( 'Version' ) : (string) $theme->get( 'Version' ); - } + if ( 'bricks' === strtolower( $theme->get_template() ) ) { + $parent = $theme->parent(); + return $parent ? (string) $parent->get( 'Version' ) : (string) $theme->get( 'Version' ); + } - if ( 'bricks' === strtolower( $theme->get( 'Name' ) ) ) { - return (string) $theme->get( 'Version' ); - } + if ( 'bricks' === strtolower( $theme->get( 'Name' ) ) ) { + return (string) $theme->get( 'Version' ); + } - return ''; + return ''; } /** @@ -149,13 +152,13 @@ function slashed_bricks_get_bricks_version() { * @return bool */ function slashed_bricks_is_bricks_active() { - $version = slashed_bricks_get_bricks_version(); + $version = slashed_bricks_get_bricks_version(); - if ( '' === $version ) { - return false; - } + if ( '' === $version ) { + return false; + } - return version_compare( $version, '1.9.2', '>=' ); + return version_compare( $version, '1.9.2', '>=' ); } // Token admin page (Slashed_Token_Page) and the main REST controller @@ -166,14 +169,21 @@ function slashed_bricks_is_bricks_active() { // in unified mode — CSS delivery, token REST API, admin page, override injection. new Slashed_Core_Enqueue(); - add_action( 'rest_api_init', function () { - ( new Slashed_REST_Controller() )->register_routes(); - } ); + add_action( + 'rest_api_init', + function () { + ( new Slashed_REST_Controller() )->register_routes(); + } + ); if ( is_admin() ) { - add_action( 'plugins_loaded', function () { - new Slashed_Token_Page(); - }, 20 ); + add_action( + 'plugins_loaded', + function () { + new Slashed_Token_Page(); + }, + 20 + ); } if ( ! function_exists( 'slashed_inject_token_overrides' ) ) { @@ -199,13 +209,13 @@ function slashed_inject_token_overrides() { * Only Bricks-specific endpoints (reBEMer, fonts) are registered here. */ function slashed_bricks_rest_routes_init() { - // Slashed_REST_Controller (token CRUD) is registered globally by slashed.php. - // Register only the Bricks-specific endpoints here. - require_once SLASHED_BRICKS_PATH . 'includes/class-rebemer-rest.php'; - require_once SLASHED_BRICKS_PATH . 'includes/class-fonts-rest.php'; + // Slashed_REST_Controller (token CRUD) is registered globally by slashed.php. + // Register only the Bricks-specific endpoints here. + require_once SLASHED_BRICKS_PATH . 'includes/class-rebemer-rest.php'; + require_once SLASHED_BRICKS_PATH . 'includes/class-fonts-rest.php'; - ( new Slashed_Bricks_ReBEMer_REST() )->register_routes(); - ( new Slashed_Bricks_Fonts_REST() )->register_routes(); + ( new Slashed_Bricks_ReBEMer_REST() )->register_routes(); + ( new Slashed_Bricks_Fonts_REST() )->register_routes(); } add_action( 'rest_api_init', 'slashed_bricks_rest_routes_init' ); @@ -219,9 +229,9 @@ function slashed_bricks_rest_routes_init() { * other has already run. Idempotent via require_once. */ function slashed_bricks_require_data_classes() { - require_once SLASHED_BRICKS_PATH . 'includes/class-css-parser.php'; - require_once SLASHED_BRICKS_PATH . 'includes/class-color-resolver.php'; - require_once SLASHED_BRICKS_PATH . 'includes/class-inventory.php'; + require_once SLASHED_BRICKS_PATH . 'includes/class-css-parser.php'; + require_once SLASHED_BRICKS_PATH . 'includes/class-color-resolver.php'; + require_once SLASHED_BRICKS_PATH . 'includes/class-inventory.php'; } /** @@ -237,29 +247,29 @@ function slashed_bricks_require_data_classes() { * simply never fire, which is harmless. */ function slashed_bricks_data_init() { - // Bail early on non-Bricks sites to avoid loading classes needlessly. - if ( 'bricks' !== strtolower( (string) get_option( 'template', '' ) ) ) { - return; - } - - slashed_bricks_require_data_classes(); - require_once SLASHED_BRICKS_PATH . 'includes/class-variables.php'; - require_once SLASHED_BRICKS_PATH . 'includes/class-classes.php'; - - new Slashed_Bricks_Variables(); - new Slashed_Bricks_Classes(); - - // Invalidate the Bricks Font-Manager CPT cache on every custom-font save. - // Registered here (plugins_loaded, all request types) rather than from REST - // route registration so the cache is busted on normal admin saves too, not - // only during REST requests. The collector + transient live in the - // always-loaded Slashed_Token_Page. - if ( class_exists( 'Slashed_Token_Page' ) ) { - add_action( - 'save_post_' . Slashed_Token_Page::get_bricks_fonts_post_type(), - array( 'Slashed_Token_Page', 'flush_bricks_fonts_cache' ) - ); - } + // Bail early on non-Bricks sites to avoid loading classes needlessly. + if ( 'bricks' !== strtolower( (string) get_option( 'template', '' ) ) ) { + return; + } + + slashed_bricks_require_data_classes(); + require_once SLASHED_BRICKS_PATH . 'includes/class-variables.php'; + require_once SLASHED_BRICKS_PATH . 'includes/class-classes.php'; + + new Slashed_Bricks_Variables(); + new Slashed_Bricks_Classes(); + + // Invalidate the Bricks Font-Manager CPT cache on every custom-font save. + // Registered here (plugins_loaded, all request types) rather than from REST + // route registration so the cache is busted on normal admin saves too, not + // only during REST requests. The collector + transient live in the + // always-loaded Slashed_Token_Page. + if ( class_exists( 'Slashed_Token_Page' ) ) { + add_action( + 'save_post_' . Slashed_Token_Page::get_bricks_fonts_post_type(), + array( 'Slashed_Token_Page', 'flush_bricks_fonts_cache' ) + ); + } } add_action( 'plugins_loaded', 'slashed_bricks_data_init', 20 ); @@ -270,15 +280,15 @@ function slashed_bricks_data_init() { * Data managers (variables, classes, colors) are already initialized above. */ function slashed_bricks_init() { - if ( ! slashed_bricks_is_bricks_active() ) { - add_action( 'admin_notices', 'slashed_bricks_missing_bricks_notice' ); - return; - } + if ( ! slashed_bricks_is_bricks_active() ) { + add_action( 'admin_notices', 'slashed_bricks_missing_bricks_notice' ); + return; + } - slashed_bricks_require_data_classes(); - require_once SLASHED_BRICKS_PATH . 'includes/class-enqueue.php'; + slashed_bricks_require_data_classes(); + require_once SLASHED_BRICKS_PATH . 'includes/class-enqueue.php'; - new Slashed_Bricks_Enqueue(); + new Slashed_Bricks_Enqueue(); } add_action( 'after_setup_theme', 'slashed_bricks_init' ); @@ -294,12 +304,12 @@ function slashed_bricks_init() { * notice from slashed_bricks_init() already covers that case. */ function slashed_bricks_rebemer_init() { - if ( ! slashed_bricks_is_bricks_active() ) { - return; - } + if ( ! slashed_bricks_is_bricks_active() ) { + return; + } - require_once SLASHED_BRICKS_PATH . 'includes/class-rebemer-enqueue.php'; - new Slashed_Bricks_ReBEMer_Enqueue(); + require_once SLASHED_BRICKS_PATH . 'includes/class-rebemer-enqueue.php'; + new Slashed_Bricks_ReBEMer_Enqueue(); } add_action( 'after_setup_theme', 'slashed_bricks_rebemer_init', 20 ); @@ -307,13 +317,13 @@ function slashed_bricks_rebemer_init() { * Display admin notice when Bricks Builder is not active. */ function slashed_bricks_missing_bricks_notice() { - ?> -
-

- SLASHED for Bricks requires Bricks Builder to be installed and active. -

-
- +
+

+ SLASHED for Bricks requires Bricks Builder to be installed and active. +

+
+ color_variables(); // Bucket every token by family + kind. - $families = array(); // family => kind => [ [order, var] ] - $semantic = array(); // [ [key, var] ] + $families = array(); // Keyed by family, then kind; holds order/var/info tuples. + $semantic = array(); // Holds key/var tuples for semantic tokens. foreach ( $vars as $var ) { $info = $this->classify_color( $var ); @@ -246,7 +256,7 @@ static function ( $a, $b ) { // Semantic tokens: keep the inventory's natural (sorted) order. foreach ( $semantic as $item ) { - $info = array( + $info = array( 'family' => 'semantic', 'kind' => 'semantic', 'key' => $item[0], @@ -316,17 +326,32 @@ private function classify_color( $var ) { $suffix = ( false === $dash ) ? '' : substr( $key, $dash + 1 ); if ( '' === $suffix ) { - return array( 'family' => $family, 'kind' => 'base', 'key' => $key, 'order' => -1 ); + return array( + 'family' => $family, + 'kind' => 'base', + 'key' => $key, + 'order' => -1, + ); } // The `-light` source duplicates the resolved base swatch — skip. if ( 'light' === $suffix ) { return null; } if ( preg_match( '/^[0-9]+$/', $suffix ) ) { - return array( 'family' => $family, 'kind' => 'scale', 'key' => $key, 'order' => (int) $suffix ); + return array( + 'family' => $family, + 'kind' => 'scale', + 'key' => $key, + 'order' => (int) $suffix, + ); } if ( preg_match( '/^a[0-9]+$/', $suffix ) ) { - return array( 'family' => $family, 'kind' => 'alpha', 'key' => $key, 'order' => (int) substr( $suffix, 1 ) ); + return array( + 'family' => $family, + 'kind' => 'alpha', + 'key' => $key, + 'order' => (int) substr( $suffix, 1 ), + ); } $alias_idx = array_search( $suffix, self::ALIAS_ORDER, true ); return array( @@ -381,7 +406,15 @@ private function color_label( $info ) { private function humanize( $key ) { $key = str_replace( '--', '-', $key ); $parts = preg_split( '/-+/', $key ); - $parts = array_map( 'ucfirst', array_filter( $parts, 'strlen' ) ); + $parts = array_map( + 'ucfirst', + array_filter( + $parts, + static function ( $part ) { + return '' !== $part; + } + ) + ); return implode( ' ', $parts ); } diff --git a/SLASHED-for-WP/integrations/gutenberg/slashed-gutenberg.php b/SLASHED-for-WP/integrations/gutenberg/slashed-gutenberg.php index d05eecd8..0d1ac93c 100644 --- a/SLASHED-for-WP/integrations/gutenberg/slashed-gutenberg.php +++ b/SLASHED-for-WP/integrations/gutenberg/slashed-gutenberg.php @@ -25,10 +25,10 @@ * plugin they are not yet set and are defined here as usual. */ if ( ! defined( 'SLASHED_GUTENBERG_VERSION' ) ) { - define( 'SLASHED_GUTENBERG_VERSION', '0.0.1' ); - define( 'SLASHED_GUTENBERG_PATH', plugin_dir_path( __FILE__ ) ); - define( 'SLASHED_GUTENBERG_URL', plugin_dir_url( __FILE__ ) ); - define( 'SLASHED_GUTENBERG_CSS_REF', 'v0.5.23' ); + define( 'SLASHED_GUTENBERG_VERSION', '0.0.1' ); + define( 'SLASHED_GUTENBERG_PATH', plugin_dir_path( __FILE__ ) ); + define( 'SLASHED_GUTENBERG_URL', plugin_dir_url( __FILE__ ) ); + define( 'SLASHED_GUTENBERG_CSS_REF', 'v0.5.23' ); } define( 'SLASHED_GUTENBERG_ALLOWED_BUNDLES', array( 'essential', 'optimal', 'full' ) ); @@ -51,17 +51,17 @@ * multiple integrations together. */ if ( ! class_exists( 'Slashed_Token_Store' ) ) { - $_slashed_shared = SLASHED_GUTENBERG_PATH . '../../includes/'; - require_once $_slashed_shared . 'class-settings.php'; - require_once $_slashed_shared . 'class-css-loader.php'; - require_once $_slashed_shared . 'class-token-store.php'; - require_once $_slashed_shared . 'class-token-sanitizer.php'; - require_once $_slashed_shared . 'class-token-defaults.php'; - require_once $_slashed_shared . 'class-tab-registry.php'; - require_once $_slashed_shared . 'class-css-generator.php'; - require_once $_slashed_shared . 'class-rest-controller.php'; - require_once $_slashed_shared . 'class-token-page.php'; - unset( $_slashed_shared ); + $slashed_shared = SLASHED_GUTENBERG_PATH . '../../includes/'; + require_once $slashed_shared . 'class-settings.php'; + require_once $slashed_shared . 'class-css-loader.php'; + require_once $slashed_shared . 'class-token-store.php'; + require_once $slashed_shared . 'class-token-sanitizer.php'; + require_once $slashed_shared . 'class-token-defaults.php'; + require_once $slashed_shared . 'class-tab-registry.php'; + require_once $slashed_shared . 'class-css-generator.php'; + require_once $slashed_shared . 'class-rest-controller.php'; + require_once $slashed_shared . 'class-token-page.php'; + unset( $slashed_shared ); } /** @@ -122,9 +122,12 @@ function slashed_gutenberg_get_css_url() { } if ( ! defined( 'SLASHED_VERSION' ) ) { - add_action( 'init', function () { - load_plugin_textdomain( 'slashed-gutenberg', false, dirname( plugin_basename( __FILE__ ) ) . '/languages' ); - } ); + add_action( + 'init', + function () { + load_plugin_textdomain( 'slashed-gutenberg', false, dirname( plugin_basename( __FILE__ ) ) . '/languages' ); + } + ); } /** @@ -138,14 +141,21 @@ function slashed_gutenberg_get_css_url() { * mode, so Slashed_Core_Enqueue is not instantiated here. */ if ( ! defined( 'SLASHED_VERSION' ) ) { - add_action( 'rest_api_init', function () { - ( new Slashed_REST_Controller() )->register_routes(); - } ); + add_action( + 'rest_api_init', + function () { + ( new Slashed_REST_Controller() )->register_routes(); + } + ); if ( is_admin() ) { - add_action( 'plugins_loaded', function () { - new Slashed_Token_Page(); - }, 20 ); + add_action( + 'plugins_loaded', + function () { + new Slashed_Token_Page(); + }, + 20 + ); } // Shared with the Bricks standalone bootstrap via the !function_exists guard, diff --git a/SLASHED-for-WP/slashed.php b/SLASHED-for-WP/slashed.php index e747b747..c092253f 100644 --- a/SLASHED-for-WP/slashed.php +++ b/SLASHED-for-WP/slashed.php @@ -18,9 +18,9 @@ // ─── Canonical constants ────────────────────────────────────────────────────── -define( 'SLASHED_VERSION', '0.0.1' ); -define( 'SLASHED_PATH', plugin_dir_path( __FILE__ ) ); -define( 'SLASHED_URL', plugin_dir_url( __FILE__ ) ); +define( 'SLASHED_VERSION', '0.0.1' ); +define( 'SLASHED_PATH', plugin_dir_path( __FILE__ ) ); +define( 'SLASHED_URL', plugin_dir_url( __FILE__ ) ); /** * Framework version this plugin ships with / tracks by default. @@ -29,11 +29,14 @@ * artifacts (GitHub Release assets per version; the `dist` branch for * "latest") — see Slashed_CSS_Loader and Slashed_Framework_Updater. */ -define( 'SLASHED_CSS_REF', 'v0.5.23' ); +define( 'SLASHED_CSS_REF', 'v0.5.23' ); -add_action( 'init', function () { - load_plugin_textdomain( 'slashed', false, dirname( plugin_basename( __FILE__ ) ) . '/languages' ); -} ); +add_action( + 'init', + function () { + load_plugin_textdomain( 'slashed', false, dirname( plugin_basename( __FILE__ ) ) . '/languages' ); + } +); // ─── Shared infrastructure ──────────────────────────────────────────────────── @@ -60,9 +63,12 @@ require_once SLASHED_PATH . 'includes/class-rest-controller.php'; // Token REST routes live under slashed/v1, independent of any builder. -add_action( 'rest_api_init', function () { - ( new Slashed_REST_Controller() )->register_routes(); -} ); +add_action( + 'rest_api_init', + function () { + ( new Slashed_REST_Controller() )->register_routes(); + } +); // Inject token override CSS after whichever integration enqueued slashed-framework. function slashed_inject_token_overrides() { @@ -80,12 +86,15 @@ function slashed_inject_token_overrides() { if ( is_admin() ) { require_once SLASHED_PATH . 'includes/class-admin.php'; require_once SLASHED_PATH . 'includes/class-hooks-page.php'; - add_action( 'plugins_loaded', function () { - new Slashed_Admin(); - new Slashed_Token_Page(); - new Slashed_Framework_Updater(); - new Slashed_Hooks_Page(); - } ); + add_action( + 'plugins_loaded', + function () { + new Slashed_Admin(); + new Slashed_Token_Page(); + new Slashed_Framework_Updater(); + new Slashed_Hooks_Page(); + } + ); } // ─── Integration bootstraps ─────────────────────────────────────────────────── @@ -105,19 +114,27 @@ function slashed_inject_token_overrides() { // ─── Activation / deactivation ─────────────────────────────────────────────── -register_deactivation_hook( __FILE__, function () { - // Clear every scheduled instance of the Bricks version-check cron, not just - // the next one — guards against an orphaned event being left behind if the - // Bricks integration was toggled off while an instance was still scheduled. - wp_clear_scheduled_hook( 'slashed_bricks_version_check' ); -} ); +register_deactivation_hook( + __FILE__, + function () { + // Clear every scheduled instance of the Bricks version-check cron, not just + // the next one — guards against an orphaned event being left behind if the + // Bricks integration was toggled off while an instance was still scheduled. + wp_clear_scheduled_hook( 'slashed_bricks_version_check' ); + } +); // When the Bricks integration is toggled OFF via settings (not just deactivation), // clear the cron immediately so it does not remain scheduled with no handler. -add_action( 'update_option_slashed_settings', function ( $old_value, $new_value ) { - $was_on = ! empty( $old_value['integrations']['bricks'] ); - $is_on = ! empty( $new_value['integrations']['bricks'] ); - if ( $was_on && ! $is_on ) { - wp_clear_scheduled_hook( 'slashed_bricks_version_check' ); - } -}, 10, 2 ); +add_action( + 'update_option_slashed_settings', + function ( $old_value, $new_value ) { + $was_on = ! empty( $old_value['integrations']['bricks'] ); + $is_on = ! empty( $new_value['integrations']['bricks'] ); + if ( $was_on && ! $is_on ) { + wp_clear_scheduled_hook( 'slashed_bricks_version_check' ); + } + }, + 10, + 2 +); diff --git a/composer.json b/composer.json new file mode 100644 index 00000000..99ea1a7b --- /dev/null +++ b/composer.json @@ -0,0 +1,28 @@ +{ + "name": "codeslash-dev/slashed-for-wp", + "description": "Dev tooling (static analysis + coding standards) for the SLASHED for WordPress plugin.", + "type": "wordpress-plugin", + "license": "MIT", + "require": { + "php": ">=7.4" + }, + "require-dev": { + "squizlabs/php_codesniffer": "^3.13", + "wp-coding-standards/wpcs": "^3.2", + "phpcompatibility/phpcompatibility-wp": "^2.1", + "dealerdirect/phpcodesniffer-composer-installer": "^1.1", + "phpstan/phpstan": "^2.1", + "szepeviktor/phpstan-wordpress": "^2.0", + "php-stubs/wordpress-stubs": "^6.7" + }, + "scripts": { + "phpcs": "phpcs", + "phpcbf": "phpcbf", + "phpstan": "phpstan analyse --memory-limit=1G" + }, + "config": { + "allow-plugins": { + "dealerdirect/phpcodesniffer-composer-installer": true + } + } +} diff --git a/composer.lock b/composer.lock new file mode 100644 index 00000000..7f4ca961 --- /dev/null +++ b/composer.lock @@ -0,0 +1,829 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "491c47c75ac08466a470741523a2e394", + "packages": [], + "packages-dev": [ + { + "name": "dealerdirect/phpcodesniffer-composer-installer", + "version": "v1.2.1", + "source": { + "type": "git", + "url": "https://github.com/PHPCSStandards/composer-installer.git", + "reference": "963f0c67bffde0eac41b56be71ac0e8ba132f0bd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHPCSStandards/composer-installer/zipball/963f0c67bffde0eac41b56be71ac0e8ba132f0bd", + "reference": "963f0c67bffde0eac41b56be71ac0e8ba132f0bd", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^2.2", + "php": ">=5.4", + "squizlabs/php_codesniffer": "^3.1.0 || ^4.0" + }, + "require-dev": { + "composer/composer": "^2.2", + "ext-json": "*", + "ext-zip": "*", + "php-parallel-lint/php-parallel-lint": "^1.4.0", + "phpcompatibility/php-compatibility": "^9.0 || ^10.0.0@dev", + "yoast/phpunit-polyfills": "^1.0" + }, + "type": "composer-plugin", + "extra": { + "class": "PHPCSStandards\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin" + }, + "autoload": { + "psr-4": { + "PHPCSStandards\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Franck Nijhof", + "email": "opensource@frenck.dev", + "homepage": "https://frenck.dev", + "role": "Open source developer" + }, + { + "name": "Contributors", + "homepage": "https://github.com/PHPCSStandards/composer-installer/graphs/contributors" + } + ], + "description": "PHP_CodeSniffer Standards Composer Installer Plugin", + "keywords": [ + "PHPCodeSniffer", + "PHP_CodeSniffer", + "code quality", + "codesniffer", + "composer", + "installer", + "phpcbf", + "phpcs", + "plugin", + "qa", + "quality", + "standard", + "standards", + "style guide", + "stylecheck", + "tests" + ], + "support": { + "issues": "https://github.com/PHPCSStandards/composer-installer/issues", + "security": "https://github.com/PHPCSStandards/composer-installer/security/policy", + "source": "https://github.com/PHPCSStandards/composer-installer" + }, + "funding": [ + { + "url": "https://github.com/PHPCSStandards", + "type": "github" + }, + { + "url": "https://github.com/jrfnl", + "type": "github" + }, + { + "url": "https://opencollective.com/php_codesniffer", + "type": "open_collective" + }, + { + "url": "https://thanks.dev/u/gh/phpcsstandards", + "type": "thanks_dev" + } + ], + "time": "2026-05-06T08:26:05+00:00" + }, + { + "name": "php-stubs/wordpress-stubs", + "version": "v6.9.4", + "source": { + "type": "git", + "url": "https://github.com/php-stubs/wordpress-stubs.git", + "reference": "90a9412826b9944f93b10bf41d795b5fe68abcd5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-stubs/wordpress-stubs/zipball/90a9412826b9944f93b10bf41d795b5fe68abcd5", + "reference": "90a9412826b9944f93b10bf41d795b5fe68abcd5", + "shasum": "" + }, + "conflict": { + "phpdocumentor/reflection-docblock": "5.6.1" + }, + "require-dev": { + "dealerdirect/phpcodesniffer-composer-installer": "^1.0", + "nikic/php-parser": "^5.5", + "php": "^7.4 || ^8.0", + "php-stubs/generator": "^0.8.6", + "phpdocumentor/reflection-docblock": "^6.0", + "phpstan/phpstan": "^2.1", + "phpunit/phpunit": "^9.5", + "symfony/polyfill-php80": "*", + "szepeviktor/phpcs-psr-12-neutron-hybrid-ruleset": "^1.1.1", + "wp-coding-standards/wpcs": "3.1.0 as 2.3.0" + }, + "suggest": { + "paragonie/sodium_compat": "Pure PHP implementation of libsodium", + "symfony/polyfill-php80": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "szepeviktor/phpstan-wordpress": "WordPress extensions for PHPStan" + }, + "type": "library", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "WordPress function and class declaration stubs for static analysis.", + "homepage": "https://github.com/php-stubs/wordpress-stubs", + "keywords": [ + "PHPStan", + "static analysis", + "wordpress" + ], + "support": { + "issues": "https://github.com/php-stubs/wordpress-stubs/issues", + "source": "https://github.com/php-stubs/wordpress-stubs/tree/v6.9.4" + }, + "time": "2026-05-01T20:36:01+00:00" + }, + { + "name": "phpcompatibility/php-compatibility", + "version": "9.3.5", + "source": { + "type": "git", + "url": "https://github.com/PHPCompatibility/PHPCompatibility.git", + "reference": "9fb324479acf6f39452e0655d2429cc0d3914243" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHPCompatibility/PHPCompatibility/zipball/9fb324479acf6f39452e0655d2429cc0d3914243", + "reference": "9fb324479acf6f39452e0655d2429cc0d3914243", + "shasum": "" + }, + "require": { + "php": ">=5.3", + "squizlabs/php_codesniffer": "^2.3 || ^3.0.2" + }, + "conflict": { + "squizlabs/php_codesniffer": "2.6.2" + }, + "require-dev": { + "phpunit/phpunit": "~4.5 || ^5.0 || ^6.0 || ^7.0" + }, + "suggest": { + "dealerdirect/phpcodesniffer-composer-installer": "^0.5 || This Composer plugin will sort out the PHPCS 'installed_paths' automatically.", + "roave/security-advisories": "dev-master || Helps prevent installing dependencies with known security issues." + }, + "type": "phpcodesniffer-standard", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-3.0-or-later" + ], + "authors": [ + { + "name": "Wim Godden", + "homepage": "https://github.com/wimg", + "role": "lead" + }, + { + "name": "Juliette Reinders Folmer", + "homepage": "https://github.com/jrfnl", + "role": "lead" + }, + { + "name": "Contributors", + "homepage": "https://github.com/PHPCompatibility/PHPCompatibility/graphs/contributors" + } + ], + "description": "A set of sniffs for PHP_CodeSniffer that checks for PHP cross-version compatibility.", + "homepage": "http://techblog.wimgodden.be/tag/codesniffer/", + "keywords": [ + "compatibility", + "phpcs", + "standards" + ], + "support": { + "issues": "https://github.com/PHPCompatibility/PHPCompatibility/issues", + "source": "https://github.com/PHPCompatibility/PHPCompatibility" + }, + "time": "2019-12-27T09:44:58+00:00" + }, + { + "name": "phpcompatibility/phpcompatibility-paragonie", + "version": "1.3.4", + "source": { + "type": "git", + "url": "https://github.com/PHPCompatibility/PHPCompatibilityParagonie.git", + "reference": "244d7b04fc4bc2117c15f5abe23eb933b5f02bbf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHPCompatibility/PHPCompatibilityParagonie/zipball/244d7b04fc4bc2117c15f5abe23eb933b5f02bbf", + "reference": "244d7b04fc4bc2117c15f5abe23eb933b5f02bbf", + "shasum": "" + }, + "require": { + "phpcompatibility/php-compatibility": "^9.0" + }, + "require-dev": { + "dealerdirect/phpcodesniffer-composer-installer": "^1.0", + "paragonie/random_compat": "dev-master", + "paragonie/sodium_compat": "dev-master" + }, + "suggest": { + "dealerdirect/phpcodesniffer-composer-installer": "^1.0 || This Composer plugin will sort out the PHP_CodeSniffer 'installed_paths' automatically.", + "roave/security-advisories": "dev-master || Helps prevent installing dependencies with known security issues." + }, + "type": "phpcodesniffer-standard", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-3.0-or-later" + ], + "authors": [ + { + "name": "Wim Godden", + "role": "lead" + }, + { + "name": "Juliette Reinders Folmer", + "role": "lead" + } + ], + "description": "A set of rulesets for PHP_CodeSniffer to check for PHP cross-version compatibility issues in projects, while accounting for polyfills provided by the Paragonie polyfill libraries.", + "homepage": "http://phpcompatibility.com/", + "keywords": [ + "compatibility", + "paragonie", + "phpcs", + "polyfill", + "standards", + "static analysis" + ], + "support": { + "issues": "https://github.com/PHPCompatibility/PHPCompatibilityParagonie/issues", + "security": "https://github.com/PHPCompatibility/PHPCompatibilityParagonie/security/policy", + "source": "https://github.com/PHPCompatibility/PHPCompatibilityParagonie" + }, + "funding": [ + { + "url": "https://github.com/PHPCompatibility", + "type": "github" + }, + { + "url": "https://github.com/jrfnl", + "type": "github" + }, + { + "url": "https://opencollective.com/php_codesniffer", + "type": "open_collective" + }, + { + "url": "https://thanks.dev/u/gh/phpcompatibility", + "type": "thanks_dev" + } + ], + "time": "2025-09-19T17:43:28+00:00" + }, + { + "name": "phpcompatibility/phpcompatibility-wp", + "version": "2.1.8", + "source": { + "type": "git", + "url": "https://github.com/PHPCompatibility/PHPCompatibilityWP.git", + "reference": "7c8d18b4d90dac9e86b0869a608fa09158e168fa" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHPCompatibility/PHPCompatibilityWP/zipball/7c8d18b4d90dac9e86b0869a608fa09158e168fa", + "reference": "7c8d18b4d90dac9e86b0869a608fa09158e168fa", + "shasum": "" + }, + "require": { + "phpcompatibility/php-compatibility": "^9.0", + "phpcompatibility/phpcompatibility-paragonie": "^1.0", + "squizlabs/php_codesniffer": "^3.3" + }, + "require-dev": { + "dealerdirect/phpcodesniffer-composer-installer": "^1.0" + }, + "suggest": { + "dealerdirect/phpcodesniffer-composer-installer": "^1.0 || This Composer plugin will sort out the PHP_CodeSniffer 'installed_paths' automatically.", + "roave/security-advisories": "dev-master || Helps prevent installing dependencies with known security issues." + }, + "type": "phpcodesniffer-standard", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-3.0-or-later" + ], + "authors": [ + { + "name": "Wim Godden", + "role": "lead" + }, + { + "name": "Juliette Reinders Folmer", + "role": "lead" + } + ], + "description": "A ruleset for PHP_CodeSniffer to check for PHP cross-version compatibility issues in projects, while accounting for polyfills provided by WordPress.", + "homepage": "http://phpcompatibility.com/", + "keywords": [ + "compatibility", + "phpcs", + "standards", + "static analysis", + "wordpress" + ], + "support": { + "issues": "https://github.com/PHPCompatibility/PHPCompatibilityWP/issues", + "security": "https://github.com/PHPCompatibility/PHPCompatibilityWP/security/policy", + "source": "https://github.com/PHPCompatibility/PHPCompatibilityWP" + }, + "funding": [ + { + "url": "https://github.com/PHPCompatibility", + "type": "github" + }, + { + "url": "https://github.com/jrfnl", + "type": "github" + }, + { + "url": "https://opencollective.com/php_codesniffer", + "type": "open_collective" + }, + { + "url": "https://thanks.dev/u/gh/phpcompatibility", + "type": "thanks_dev" + } + ], + "time": "2025-10-18T00:05:59+00:00" + }, + { + "name": "phpcsstandards/phpcsextra", + "version": "1.5.0", + "source": { + "type": "git", + "url": "https://github.com/PHPCSStandards/PHPCSExtra.git", + "reference": "b598aa890815b8df16363271b659d73280129101" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHPCSStandards/PHPCSExtra/zipball/b598aa890815b8df16363271b659d73280129101", + "reference": "b598aa890815b8df16363271b659d73280129101", + "shasum": "" + }, + "require": { + "php": ">=5.4", + "phpcsstandards/phpcsutils": "^1.2.0", + "squizlabs/php_codesniffer": "^3.13.5 || ^4.0.1" + }, + "require-dev": { + "php-parallel-lint/php-console-highlighter": "^1.0", + "php-parallel-lint/php-parallel-lint": "^1.4.0", + "phpcsstandards/phpcsdevcs": "^1.2.0", + "phpcsstandards/phpcsdevtools": "^1.2.1", + "phpunit/phpunit": "^4.5 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.3.4" + }, + "type": "phpcodesniffer-standard", + "extra": { + "branch-alias": { + "dev-stable": "1.x-dev", + "dev-develop": "1.x-dev" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-3.0-or-later" + ], + "authors": [ + { + "name": "Juliette Reinders Folmer", + "homepage": "https://github.com/jrfnl", + "role": "lead" + }, + { + "name": "Contributors", + "homepage": "https://github.com/PHPCSStandards/PHPCSExtra/graphs/contributors" + } + ], + "description": "A collection of sniffs and standards for use with PHP_CodeSniffer.", + "keywords": [ + "PHP_CodeSniffer", + "phpcbf", + "phpcodesniffer-standard", + "phpcs", + "standards", + "static analysis" + ], + "support": { + "issues": "https://github.com/PHPCSStandards/PHPCSExtra/issues", + "security": "https://github.com/PHPCSStandards/PHPCSExtra/security/policy", + "source": "https://github.com/PHPCSStandards/PHPCSExtra" + }, + "funding": [ + { + "url": "https://github.com/PHPCSStandards", + "type": "github" + }, + { + "url": "https://github.com/jrfnl", + "type": "github" + }, + { + "url": "https://opencollective.com/php_codesniffer", + "type": "open_collective" + }, + { + "url": "https://thanks.dev/u/gh/phpcsstandards", + "type": "thanks_dev" + } + ], + "time": "2025-11-12T23:06:57+00:00" + }, + { + "name": "phpcsstandards/phpcsutils", + "version": "1.2.2", + "source": { + "type": "git", + "url": "https://github.com/PHPCSStandards/PHPCSUtils.git", + "reference": "c216317e96c8b3f5932808f9b0f1f7a14e3bbf55" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHPCSStandards/PHPCSUtils/zipball/c216317e96c8b3f5932808f9b0f1f7a14e3bbf55", + "reference": "c216317e96c8b3f5932808f9b0f1f7a14e3bbf55", + "shasum": "" + }, + "require": { + "dealerdirect/phpcodesniffer-composer-installer": "^0.4.1 || ^0.5 || ^0.6.2 || ^0.7 || ^1.0", + "php": ">=5.4", + "squizlabs/php_codesniffer": "^3.13.5 || ^4.0.1" + }, + "require-dev": { + "ext-filter": "*", + "php-parallel-lint/php-console-highlighter": "^1.0", + "php-parallel-lint/php-parallel-lint": "^1.4.0", + "phpcsstandards/phpcsdevcs": "^1.2.0", + "yoast/phpunit-polyfills": "^1.1.0 || ^2.0.0 || ^3.0.0" + }, + "type": "phpcodesniffer-standard", + "extra": { + "branch-alias": { + "dev-stable": "1.x-dev", + "dev-develop": "1.x-dev" + } + }, + "autoload": { + "classmap": [ + "PHPCSUtils/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-3.0-or-later" + ], + "authors": [ + { + "name": "Juliette Reinders Folmer", + "homepage": "https://github.com/jrfnl", + "role": "lead" + }, + { + "name": "Contributors", + "homepage": "https://github.com/PHPCSStandards/PHPCSUtils/graphs/contributors" + } + ], + "description": "A suite of utility functions for use with PHP_CodeSniffer", + "homepage": "https://phpcsutils.com/", + "keywords": [ + "PHP_CodeSniffer", + "phpcbf", + "phpcodesniffer-standard", + "phpcs", + "phpcs3", + "phpcs4", + "standards", + "static analysis", + "tokens", + "utility" + ], + "support": { + "docs": "https://phpcsutils.com/", + "issues": "https://github.com/PHPCSStandards/PHPCSUtils/issues", + "security": "https://github.com/PHPCSStandards/PHPCSUtils/security/policy", + "source": "https://github.com/PHPCSStandards/PHPCSUtils" + }, + "funding": [ + { + "url": "https://github.com/PHPCSStandards", + "type": "github" + }, + { + "url": "https://github.com/jrfnl", + "type": "github" + }, + { + "url": "https://opencollective.com/php_codesniffer", + "type": "open_collective" + }, + { + "url": "https://thanks.dev/u/gh/phpcsstandards", + "type": "thanks_dev" + } + ], + "time": "2025-12-08T14:27:58+00:00" + }, + { + "name": "phpstan/phpstan", + "version": "2.2.2", + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/e5cc34d491a90e79c216d824f60fe21fd4d93bd6", + "reference": "e5cc34d491a90e79c216d824f60fe21fd4d93bd6", + "shasum": "" + }, + "require": { + "php": "^7.4|^8.0" + }, + "conflict": { + "phpstan/phpstan-shim": "*" + }, + "bin": [ + "phpstan", + "phpstan.phar" + ], + "type": "library", + "autoload": { + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ondřej Mirtes" + }, + { + "name": "Markus Staab" + }, + { + "name": "Vincent Langlet" + } + ], + "description": "PHPStan - PHP Static Analysis Tool", + "keywords": [ + "dev", + "static analysis" + ], + "support": { + "docs": "https://phpstan.org/user-guide/getting-started", + "forum": "https://github.com/phpstan/phpstan/discussions", + "issues": "https://github.com/phpstan/phpstan/issues", + "security": "https://github.com/phpstan/phpstan/security/policy", + "source": "https://github.com/phpstan/phpstan-src" + }, + "funding": [ + { + "url": "https://github.com/ondrejmirtes", + "type": "github" + }, + { + "url": "https://github.com/phpstan", + "type": "github" + } + ], + "time": "2026-06-05T09:00:01+00:00" + }, + { + "name": "squizlabs/php_codesniffer", + "version": "3.13.5", + "source": { + "type": "git", + "url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git", + "reference": "0ca86845ce43291e8f5692c7356fccf3bcf02bf4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/0ca86845ce43291e8f5692c7356fccf3bcf02bf4", + "reference": "0ca86845ce43291e8f5692c7356fccf3bcf02bf4", + "shasum": "" + }, + "require": { + "ext-simplexml": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": ">=5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.3.4" + }, + "bin": [ + "bin/phpcbf", + "bin/phpcs" + ], + "type": "library", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Greg Sherwood", + "role": "Former lead" + }, + { + "name": "Juliette Reinders Folmer", + "role": "Current lead" + }, + { + "name": "Contributors", + "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer/graphs/contributors" + } + ], + "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", + "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer", + "keywords": [ + "phpcs", + "standards", + "static analysis" + ], + "support": { + "issues": "https://github.com/PHPCSStandards/PHP_CodeSniffer/issues", + "security": "https://github.com/PHPCSStandards/PHP_CodeSniffer/security/policy", + "source": "https://github.com/PHPCSStandards/PHP_CodeSniffer", + "wiki": "https://github.com/PHPCSStandards/PHP_CodeSniffer/wiki" + }, + "funding": [ + { + "url": "https://github.com/PHPCSStandards", + "type": "github" + }, + { + "url": "https://github.com/jrfnl", + "type": "github" + }, + { + "url": "https://opencollective.com/php_codesniffer", + "type": "open_collective" + }, + { + "url": "https://thanks.dev/u/gh/phpcsstandards", + "type": "thanks_dev" + } + ], + "time": "2025-11-04T16:30:35+00:00" + }, + { + "name": "szepeviktor/phpstan-wordpress", + "version": "v2.0.3", + "source": { + "type": "git", + "url": "https://github.com/szepeviktor/phpstan-wordpress.git", + "reference": "aa722f037b2d034828cd6c55ebe9e5c74961927e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/szepeviktor/phpstan-wordpress/zipball/aa722f037b2d034828cd6c55ebe9e5c74961927e", + "reference": "aa722f037b2d034828cd6c55ebe9e5c74961927e", + "shasum": "" + }, + "require": { + "php": "^7.4 || ^8.0", + "php-stubs/wordpress-stubs": "^6.6.2", + "phpstan/phpstan": "^2.0" + }, + "require-dev": { + "composer/composer": "^2.1.14", + "composer/semver": "^3.4", + "dealerdirect/phpcodesniffer-composer-installer": "^1.0", + "php-parallel-lint/php-parallel-lint": "^1.1", + "phpstan/phpstan-strict-rules": "^2.0", + "phpunit/phpunit": "^9.0", + "szepeviktor/phpcs-psr-12-neutron-hybrid-ruleset": "^1.0", + "wp-coding-standards/wpcs": "3.1.0 as 2.3.0" + }, + "suggest": { + "swissspidy/phpstan-no-private": "Detect usage of internal core functions, classes and methods" + }, + "type": "phpstan-extension", + "extra": { + "phpstan": { + "includes": [ + "extension.neon" + ] + } + }, + "autoload": { + "psr-4": { + "SzepeViktor\\PHPStan\\WordPress\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "WordPress extensions for PHPStan", + "keywords": [ + "PHPStan", + "code analyse", + "code analysis", + "static analysis", + "wordpress" + ], + "support": { + "issues": "https://github.com/szepeviktor/phpstan-wordpress/issues", + "source": "https://github.com/szepeviktor/phpstan-wordpress/tree/v2.0.3" + }, + "time": "2025-09-14T02:58:22+00:00" + }, + { + "name": "wp-coding-standards/wpcs", + "version": "3.3.0", + "source": { + "type": "git", + "url": "https://github.com/WordPress/WordPress-Coding-Standards.git", + "reference": "7795ec6fa05663d716a549d0b44e47ffc8b0d4a6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/WordPress/WordPress-Coding-Standards/zipball/7795ec6fa05663d716a549d0b44e47ffc8b0d4a6", + "reference": "7795ec6fa05663d716a549d0b44e47ffc8b0d4a6", + "shasum": "" + }, + "require": { + "ext-filter": "*", + "ext-libxml": "*", + "ext-tokenizer": "*", + "ext-xmlreader": "*", + "php": ">=7.2", + "phpcsstandards/phpcsextra": "^1.5.0", + "phpcsstandards/phpcsutils": "^1.1.0", + "squizlabs/php_codesniffer": "^3.13.4" + }, + "require-dev": { + "php-parallel-lint/php-console-highlighter": "^1.0.0", + "php-parallel-lint/php-parallel-lint": "^1.4.0", + "phpcompatibility/php-compatibility": "^10.0.0@dev", + "phpcsstandards/phpcsdevtools": "^1.2.0", + "phpunit/phpunit": "^8.0 || ^9.0" + }, + "suggest": { + "ext-iconv": "For improved results", + "ext-mbstring": "For improved results" + }, + "type": "phpcodesniffer-standard", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Contributors", + "homepage": "https://github.com/WordPress/WordPress-Coding-Standards/graphs/contributors" + } + ], + "description": "PHP_CodeSniffer rules (sniffs) to enforce WordPress coding conventions", + "keywords": [ + "phpcs", + "standards", + "static analysis", + "wordpress" + ], + "support": { + "issues": "https://github.com/WordPress/WordPress-Coding-Standards/issues", + "source": "https://github.com/WordPress/WordPress-Coding-Standards", + "wiki": "https://github.com/WordPress/WordPress-Coding-Standards/wiki" + }, + "funding": [ + { + "url": "https://opencollective.com/php_codesniffer", + "type": "custom" + } + ], + "time": "2025-11-25T12:08:04+00:00" + } + ], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": {}, + "prefer-stable": false, + "prefer-lowest": false, + "platform": { + "php": ">=7.4" + }, + "platform-dev": {}, + "plugin-api-version": "2.9.0" +} diff --git a/phpcs.xml.dist b/phpcs.xml.dist new file mode 100644 index 00000000..db7b2d2c --- /dev/null +++ b/phpcs.xml.dist @@ -0,0 +1,93 @@ + + + WordPress coding standards for the SLASHED for WordPress plugin. + + + SLASHED-for-WP + + + */dist/* + */data/* + */vendor/* + */node_modules/* + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + 0 + + + + + 0 + + + + + diff --git a/phpstan-bootstrap.php b/phpstan-bootstrap.php new file mode 100644 index 00000000..bc28f402 --- /dev/null +++ b/phpstan-bootstrap.php @@ -0,0 +1,28 @@ +