agentsclimarketplace

Wp sage

Skill ComeOnOliver/skillshub/skills/alessioarzenton/claude-code-wp-toolkit/wp-sage

🧠 The right skill, one API call. AI agent skills registry with token-efficient skill resolution. 5,000+ skills from 500+ top repos.

Install
npx -y skills add ComeOnOliver/skillshub --skill wp-sage

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

What its author says it does

Copied from the file, not written here

Conventions for WordPress Bedrock + Sage + Acorn + Blade + Tailwind CSS 4 + Vite projects. Always-active rules.

SKILL.md

12.0 KB, as published. Nobody here has run it

WP-Sage Stack β€” Bedrock + Sage + Acorn

Stack

  • WordPress 6.x + Bedrock
  • PHP 8.2+ (recommended 8.4)
  • Theme: Sage + Acorn ^5.0 β€” Laravel Blade templating
  • CSS: Tailwind CSS 4 (CSS-first config via @theme, prefix {{PREFIX}})
  • Bundler: Vite (NOT Bud) β€” laravel-vite-plugin + @roots/vite-plugin
  • Custom Fields: ACF Pro + ACF Composer (log1x/acf-composer)
  • Post Types/Taxonomies: Acorn Post Types (roots/acorn-post-types) + Extended CPTs (johnbillion/extended-cpts)

Typical project structure

{{THEME_DIR}}/
β”œβ”€β”€ app/
β”‚   β”œβ”€β”€ Blocks/              # ACF Composer blocks
β”‚   β”œβ”€β”€ Fields/              # ACF Composer field groups
β”‚   β”œβ”€β”€ Options/             # ACF Composer option pages
β”‚   β”œβ”€β”€ Providers/ThemeServiceProvider.php
β”‚   β”œβ”€β”€ View/Composers/      # View composers (App, Header, Footer, etc.)
β”‚   β”œβ”€β”€ setup.php            # Theme setup (features, nav menus)
β”‚   β”œβ”€β”€ filters.php
β”‚   └── import.php           # Helper functions
β”œβ”€β”€ config/
β”‚   β”œβ”€β”€ acf.php              # ACF Composer configuration
β”‚   └── post-types.php       # Post types and taxonomies registration
β”œβ”€β”€ resources/
β”‚   β”œβ”€β”€ views/
β”‚   β”‚   β”œβ”€β”€ layouts/app.blade.php
β”‚   β”‚   β”œβ”€β”€ components/      # Composite Blade components
β”‚   β”‚   β”œβ”€β”€ blocks/          # ACF/Gutenberg block templates
β”‚   β”‚   β”œβ”€β”€ sections/        # Header, footer
β”‚   β”‚   β”œβ”€β”€ partials/        # Content partials, cards
β”‚   β”‚   β”œβ”€β”€ common/          # Reusable utilities
β”‚   β”‚   └── forms/           # Form templates
β”‚   β”œβ”€β”€ css/
β”‚   β”‚   β”œβ”€β”€ app.css          # CSS entry point
β”‚   β”‚   β”œβ”€β”€ common/          # theme.css, custom-properties.css, semantic-color.css, base.css
β”‚   β”‚   └── components/      # Atomic design: atoms/ molecules/ organisms/ design-system/
β”‚   β”œβ”€β”€ js/
β”‚   β”œβ”€β”€ images/ and fonts/
└── vite.config.js

Prefix {{PREFIX}} β€” MANDATORY

TypeFormatExample
Tailwind utilities{{PREFIX}}:{utility}{{PREFIX}}:flex, {{PREFIX}}:p-4, {{PREFIX}}:md:grid
CSS components{{PREFIX}}-{name}.{{PREFIX}}-button, .{{PREFIX}}-card, .{{PREFIX}}-container
Semantic utilities{{PREFIX}}-{cat}-{var}{{PREFIX}}-content-01, {{PREFIX}}-background-primary

CSS import: @import 'tailwindcss' prefix({{PREFIX}});

Approach

  • Utility-first: don't create custom CSS classes when TW4 utilities suffice
  • Use @theme variables β€” never hardcode colors, spacing, or fonts
  • Mobile-first: base styles = mobile, then {{PREFIX}}:md:, {{PREFIX}}:lg:, {{PREFIX}}:xl:

Naming

TypeConvention
Blade fileskebab-case (page-header-simple.blade.php)
PHP classesPascalCase
Helper functionssnake_case
Blade variablescamelCase

Code Style

  • PHP: PSR-12 + Laravel Pint (pint.json)
  • JS/CSS/HTML: Prettier (120 chars, single quotes, trailing comma ES5)
  • Blade: blade-formatter (.bladeformatterrc)
  • Tailwind: prettier-plugin-tailwindcss for class sorting

Blade & View Composers

  • Blade components are used with @include(), not <x-component>
  • View Composers extend Roots\Acorn\View\Composer
  • Composer method with() returns an array of data for the view
  • Automatic registration via ThemeServiceProvider

Post Types and Taxonomies (roots/acorn-post-types)

Post types and taxonomies are defined in config/post-types.php and automatically registered via roots/acorn-post-types using John Billion's Extended CPTs library.

config/post-types.php structure:

return [
    'post_types' => [
        'cpt_name' => [
            'names' => [
                'singular' => 'Singular',
                'plural' => 'Plural',
                'slug' => 'cpt-name',
            ],
            'labels' => [...],  // Full WP labels
            'menu_icon' => 'dashicons-admin-post',
            'supports' => ['title', 'editor', 'thumbnail', 'custom-fields'],
            'hierarchical' => false,
            'has_archive' => true,
            'show_in_rest' => true,
            'public' => true,
            'publicly_queryable' => true,
            'exclude_from_search' => false,
        ],
    ],
    'taxonomies' => [
        'tax_name' => [
            'post_types' => ['post', 'page', 'cpt_name'],
            'names' => [
                'singular' => 'Singular',
                'plural' => 'Plural',
            ],
            'labels' => [...],
            'hierarchical' => true,
            'show_in_rest' => true,
        ],
    ],
];

Loading config in ThemeServiceProvider:

public function register()
{
    parent::register();

    $configPath = get_theme_file_path('config/post-types.php');
    if (is_file($configPath)) {
        $this->app->make('config')->set('post-types', require $configPath);
    }
}

Best practices:

  • Always use Extended CPTs features (admin cols, filters, etc.)
  • hierarchical: true for page-like post types
  • show_in_rest: true for Gutenberg
  • exclude_from_search: true only for internal CPTs
  • Slugs always in English, labels localized

ACF Composer β€” Field Groups

ACF field groups are defined as PHP classes in app/Fields/ extending Log1x\AcfComposer\Field.

Example app/Fields/ExampleFields.php:

<?php

namespace App\Fields;

use Log1x\AcfComposer\Builder;
use Log1x\AcfComposer\Field;

class ExampleFields extends Field
{
    public function fields(): array
    {
        $fields = Builder::make('example_fields');

        $fields
            ->setLocation()
                ->where('post_type', 'post');

        $fields
            ->addTab(__('General', '{{TEXT_DOMAIN}}'), [
                'placement' => 'top',
            ])
            ->addText('title', [
                'label' => __('Title', '{{TEXT_DOMAIN}}'),
                'instructions' => __('Enter a title', '{{TEXT_DOMAIN}}'),
                'required' => 1,
            ])
            ->addTextarea('description', [
                'label' => __('Description', '{{TEXT_DOMAIN}}'),
                'maxlength' => 300,
            ])
            ->addImage('image', [
                'label' => __('Image', '{{TEXT_DOMAIN}}'),
                'return_format' => 'array',
                'preview_size' => 'medium',
            ])
            ->addRepeater('items', [
                'label' => __('Items', '{{TEXT_DOMAIN}}'),
                'layout' => 'table',
                'button_label' => __('Add Item', '{{TEXT_DOMAIN}}'),
            ])
                ->addText('name')
                ->addTextarea('description')
                ->endRepeater();

        return $fields->build();
    }
}

Location rules:

$fields
    ->setLocation()
        ->where('post_type', 'post')
        ->or('post_type', 'page')
        ->or('page_template', 'template-custom.blade.php');

Useful commands:

wp acorn acf:make field FieldName      # Generate field group
wp acorn acf:cache                     # Cache fields (prod)
wp acorn acorn ide:helpers             # PHPDoc autocomplete

ACF Composer β€” Gutenberg Blocks

Blocks are defined in app/Blocks/ extending Log1x\AcfComposer\Block.

Example app/Blocks/ExampleBlock.php:

<?php

namespace App\Blocks;

use Log1x\AcfComposer\Block;
use Log1x\AcfComposer\Builder;

class ExampleBlock extends Block
{
    public $name = 'Example Block';
    public $description = 'Block description';
    public $category = 'theme';  // or 'common', 'formatting', etc.
    public $icon = 'admin-post';  // dashicon
    public $keywords = ['example', 'test'];
    public $post_types = ['page', 'post'];  // Restrict to specific CPTs

    // Supported alignments
    public $supports = [
        'align' => ['wide', 'full'],
        'mode' => false,  // Disable edit/preview toggle
        'jsx' => true,
    ];

    public function fields(): array
    {
        $fields = Builder::make('example_block');

        $fields
            ->addText('title', [
                'label' => __('Title', '{{TEXT_DOMAIN}}'),
            ])
            ->addWysiwyg('content', [
                'label' => __('Content', '{{TEXT_DOMAIN}}'),
            ]);

        return $fields->build();
    }

    // Data passed to the Blade template
    public function with(): array
    {
        return [
            'title' => $this->title,
            'content' => $this->content,
            'classes' => $this->classes,  // Automatic CSS classes
        ];
    }
}

Template resources/views/blocks/example-block/example-block.blade.php:

<div {!! $attributes !!}>
  <h2>{{ $title }}</h2>
  <div>{!! $content !!}</div>
</div>

$attributes helper: automatically generates class, id, data- attributes.

Commands:

wp acorn acf:make block BlockName      # Generate block + template

ACF Composer β€” Option Pages

Option pages for theme/site settings in app/Options/.

Example app/Options/ThemeSettings.php:

<?php

namespace App\Options;

use Log1x\AcfComposer\Builder;
use Log1x\AcfComposer\Options as Field;

class ThemeSettings extends Field
{
    public $name = 'Theme Settings';
    public $title = 'Settings | Theme';
    public $menu_slug = 'theme-settings';
    public $parent = 'options-general.php';  // Under "Settings"
    public $capability = 'manage_options';
    public $position = 30;
    public $redirect = false;

    public function fields(): array
    {
        $fields = Builder::make('theme_settings');

        $fields
            ->addTab(__('General', '{{TEXT_DOMAIN}}'))
            ->addText('site_phone', [
                'label' => __('Phone', '{{TEXT_DOMAIN}}'),
            ])
            ->addText('site_email', [
                'label' => __('Email', '{{TEXT_DOMAIN}}'),
            ]);

        return $fields->build();
    }
}

Retrieving options:

$phone = get_field('site_phone', 'option');

Commands:

wp acorn acf:make options OptionsName  # Generate option page

Vite Aliases

@scripts β†’ js, @styles β†’ css, @fonts β†’ fonts, @images β†’ images

What NOT to do

  • Don't forget the {{PREFIX}}: prefix on Tailwind utilities β€” it's mandatory
  • Don't use @apply in CSS β€” prefer utilities in markup
  • Don't hardcode colors, spacing, fonts β€” use @theme variables
  • Don't regenerate existing components β€” check {{COMPONENTS_CATALOG}}
  • Don't use bud.config.js β€” the bundler is Vite
  • Don't modify vite.config.js without confirmation
  • Don't generate JavaScript unless requested
  • Don't use <a role="button"> or clickable <div> β€” use native elements
  • Don't remove outline on :focus without a visible alternative
  • Don't omit aria-hidden="true" focusable="false" on decorative SVGs
  • Don't add alt text to decorative images β€” use alt=""
  • Don't use fixed heading levels in reusable components β€” make them parametric
  • Don't register post types/taxonomies with register_post_type() β€” use config/post-types.php
  • Don't create ACF field groups via JSON β€” use ACF Composer (app/Fields/)
  • Don't register blocks with register_block_type() β€” use ACF Composer (app/Blocks/)
  • Don't use get_field() directly in templates β€” pass data via with() in the Block/Composer

Nunjucks β†’ Blade Migration (if applicable)

If the project migrates from a Nunjucks design system:

  • .njk β†’ .blade.php in resources/views/components/{atoms|molecules|organisms}/
  • .js β†’ resources/js/{atoms|molecules|organisms}/
  • .css β†’ stay in resources/css/components/ (unchanged)
  • .config.yml β†’ View Composer or @include() parameters

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.