feat: Initial Claude skills for websimple-devops
This commit is contained in:
70
references/websimple-gitea.md
Normal file
70
references/websimple-gitea.md
Normal file
@@ -0,0 +1,70 @@
|
||||
# Websimple Gitea
|
||||
|
||||
Use this skill for Websimple Gitea repository conventions and read-only metadata lookup workflows.
|
||||
|
||||
## Base URL
|
||||
|
||||
Websimple Gitea is hosted at:
|
||||
|
||||
- `https://gitea.websimple.com`
|
||||
|
||||
|
||||
## Authentication
|
||||
|
||||
Authenticated Gitea API reads use the `WEBSIMPLE_GITEA_API_TOKEN` environment variable. The bundled `scripts/gitea.sh` wrapper reads this value automatically. Assume the base URL is constant at `https://gitea.websimple.com`.
|
||||
|
||||
If `WEBSIMPLE_GITEA_API_TOKEN` is not set in the user's environment, ask them to export it before proceeding. Never print or echo the token's value back in chat. Use it only for read-only Gitea API requests.
|
||||
|
||||
## Available operations
|
||||
|
||||
The skill bundles a `scripts/gitea.sh` wrapper that exposes three read-only operations. The path is relative to the skill root, so resolve it from the skill directory (typically something like `<skill-root>/scripts/gitea.sh`).
|
||||
|
||||
Each operation prints a JSON envelope to stdout and exits non-zero on failure (with an error message on stderr).
|
||||
|
||||
- `gitea.sh repos-list [--org <org>]` — list repositories for an organization. Default org is `wp-sites`. Maps to `GET /orgs/{org}/repos`.
|
||||
- `gitea.sh vars-list <owner> <repo>` — list Actions variables for a repository. Maps to `GET /repos/{owner}/{repo}/actions/variables`.
|
||||
- `gitea.sh var-get <owner> <repo> <variable-name>` — get one Actions variable. Maps to `GET /repos/{owner}/{repo}/actions/variables/{variablename}`.
|
||||
|
||||
Example usage:
|
||||
|
||||
```bash
|
||||
bash "${SKILL_ROOT}/scripts/gitea.sh" var-get wp-sites example WP_SITE_URL
|
||||
```
|
||||
|
||||
Pipe through `jq` if a specific field is needed:
|
||||
|
||||
```bash
|
||||
bash "${SKILL_ROOT}/scripts/gitea.sh" var-get wp-sites example WP_SITE_URL | jq -r '.variable.data'
|
||||
```
|
||||
|
||||
If the wrapper exits non-zero, surface its stderr message to the user rather than retrying blindly; common causes are a missing/expired token or a typo in owner/repo/variable name.
|
||||
|
||||
## WordPress repositories
|
||||
|
||||
Websimple WordPress site repositories live under the `wp-sites` organization.
|
||||
|
||||
For WordPress project slug `${slug}`:
|
||||
|
||||
- Repository URL: `https://gitea.websimple.com/wp-sites/${slug}`
|
||||
|
||||
## Actions variables
|
||||
|
||||
Use Gitea Actions variables as the source of truth for project deployment and remote environment metadata.
|
||||
|
||||
For WordPress projects, expect these deployment values, usually from repository Actions variables:
|
||||
|
||||
- `WP_SITE_URL`: production WordPress site URL, including protocol, matching the WordPress `siteurl` option concept.
|
||||
- `REMOTE_HOST`: SSH host for the remote environment.
|
||||
- `REMOTE_PORT`: SSH port for the remote environment.
|
||||
- `REMOTE_USER`: SSH user for the remote environment.
|
||||
- `REMOTE_PATH`: WordPress project path on the remote host.
|
||||
|
||||
`wp-sites` repositories may rely on organization/repository fallback variables or secrets for `REMOTE_*` deployment values. If a per-repository `REMOTE_HOST`, `REMOTE_PORT`, `REMOTE_USER`, or `REMOTE_PATH` variable is missing, check the relevant fallback variable/secret source before treating the repository metadata as incomplete.
|
||||
|
||||
Prefer reading Gitea deployment metadata before using SSH. SSH lookups are fallback-only when required metadata is missing after repository values and fallback variables/secrets are considered.
|
||||
|
||||
## Safety
|
||||
|
||||
Treat Gitea metadata reads as read-only. Do not modify repositories, variables, secrets, workflows, branches, tags, issues, releases, or pull requests unless a future workflow explicitly adds an approval path.
|
||||
|
||||
Do not expose tokens or secrets. If authentication is needed beyond `WEBSIMPLE_GITEA_API_TOKEN`, ask the user to set the appropriate environment variable rather than printing or storing secrets inline.
|
||||
50
references/websimple-stack.md
Normal file
50
references/websimple-stack.md
Normal file
@@ -0,0 +1,50 @@
|
||||
# websimple-stack
|
||||
|
||||
Use this skill for host environment, Docker Compose, Traefik routing, and shared tooling concerns surrounding the Websimple local development environment.
|
||||
|
||||
The Websimple local development Docker stack is maintained in Gitea:
|
||||
|
||||
- https://gitea.websimple.com/docker/websimple-stack
|
||||
|
||||
## Config values used here
|
||||
|
||||
These environment variables drive stack-level operations:
|
||||
|
||||
- `WEBSIMPLE_STACK_PATH`: local path to the `websimple-stack` Docker project checkout.
|
||||
- `WEBSIMPLE_STACK_PROTOCOL`: protocol used by local Traefik routing, `http` or `https`.
|
||||
- `WEBSIMPLE_STACK_DOMAIN`: local domain suffix used by Traefik labels.
|
||||
|
||||
Do not hard-code these values in commands or examples. Read them from the environment. If any are missing when needed, ask the user to export them before proceeding rather than guessing.
|
||||
|
||||
## Environment expectations
|
||||
|
||||
The plugin assumes it is running on a developer machine configured for the Websimple local development stack.
|
||||
|
||||
### Stack and routing
|
||||
|
||||
- The `websimple-stack` Docker Compose project is configured and running locally.
|
||||
- A wildcard `*.${WEBSIMPLE_STACK_DOMAIN}` resolves to the local IP.
|
||||
- Traefik serves local stack services at `${WEBSIMPLE_STACK_PROTOCOL}://*.${WEBSIMPLE_STACK_DOMAIN}` using that wildcard domain routing.
|
||||
|
||||
### Required host executables
|
||||
|
||||
The following executables are expected to be available in the host `$PATH`:
|
||||
|
||||
- `mysql`
|
||||
- `node`
|
||||
- `pnpm`
|
||||
- `php`
|
||||
- `composer`
|
||||
- `wp`
|
||||
|
||||
### MySQL access
|
||||
|
||||
- MySQL credentials are stored in `~/.my.cnf`.
|
||||
- The `mysql` client should connect without prompting for a password.
|
||||
- `/etc/hosts` contains an entry resolving `mysql`, so the DB host resolves the same way on the host as it does inside containers.
|
||||
|
||||
### WP-CLI defaults
|
||||
|
||||
- WP-CLI defaults are configured in `~/.wp-cli/config.yml`.
|
||||
- DB host, user, and password defaults are already set there.
|
||||
- `wp core config` workflows should only need to specify the database name.
|
||||
271
references/wp-acf.md
Normal file
271
references/wp-acf.md
Normal file
@@ -0,0 +1,271 @@
|
||||
# WP ACF
|
||||
|
||||
Use this skill for Websimple WordPress projects that use Advanced Custom Fields.
|
||||
|
||||
Use `references/wp-theme-dev.md` for general PHP/theme structure, `references/wp-code-style.md` for PHPCS/PHPCBF, `references/wp-browser.md` for visual checks, and `references/wp-xdebug.md` for runtime debugging.
|
||||
|
||||
## Core principles
|
||||
|
||||
- Keep ACF configuration predictable, portable, and version-controlled.
|
||||
- Prefer clear field names that map naturally to template usage.
|
||||
- Keep field registration/ACF hooks under `includes/vendors/acf.php` or the existing ACF vendor/module file.
|
||||
- Keep rendering logic in templates and reusable data helpers under `includes/` when needed.
|
||||
- Avoid changing field keys, field names, return formats, or option names casually; these may affect stored content.
|
||||
|
||||
## Local JSON
|
||||
|
||||
ACF field group JSON definitions should live under the active theme's `acf-json/` directory.
|
||||
|
||||
- Keep ACF JSON files version-controlled.
|
||||
- Preserve the project's existing JSON directory if one exists.
|
||||
- For greenfield projects, use `acf-json/` at the theme root.
|
||||
- Ensure the `acf-json/` directory exists and is writable by WordPress.
|
||||
- Do not delete or regenerate ACF JSON files without checking the diff.
|
||||
|
||||
When local JSON is enabled, saving a field group, post type, taxonomy, or options page in wp-admin automatically creates or updates its JSON file. Do not tell the user to manually re-export JSON after normal dashboard saves; instead, remind them to review and commit the changed JSON file.
|
||||
|
||||
There is no expected per-field-group `json_sync` flag in Websimple conventions. ACF local JSON is controlled by ACF's global JSON setting and save/load paths. ACF defaults local JSON on and uses the active theme's `acf-json/` folder unless customized.
|
||||
|
||||
If PHP hooks customize ACF JSON paths, keep them in the ACF vendor/module file, e.g. `includes/vendors/acf.php`.
|
||||
|
||||
## Field group keys and filenames
|
||||
|
||||
For greenfield field groups, use deterministic field group keys instead of ACF's auto-generated group keys.
|
||||
|
||||
The field group key should match the JSON filename and describe what the group targets:
|
||||
|
||||
```text
|
||||
acf-json/group_post_project.json
|
||||
key: group_post_project
|
||||
```
|
||||
|
||||
Examples:
|
||||
|
||||
```text
|
||||
group_post_project # fields for the project custom post type
|
||||
group_page_home # fields for the home page/template
|
||||
group_options_site # site options fields
|
||||
group_taxonomy_sector # fields for the sector taxonomy
|
||||
```
|
||||
|
||||
ACF field keys inside the group may remain auto-generated. The deterministic-key convention applies primarily to field groups so JSON files stay organized and easy to find.
|
||||
|
||||
For existing projects with auto-generated field group keys, preserve them unless the user explicitly approves a cleanup/migration. Do not rename existing field group keys casually because synced JSON, database references, and editor workflows may depend on them.
|
||||
|
||||
## Synchronizing ACF JSON
|
||||
|
||||
For ACF 6.8+ with WP-CLI available, prefer the built-in ACF JSON CLI commands.
|
||||
|
||||
Safe inspection:
|
||||
|
||||
```bash
|
||||
wp acf json status
|
||||
wp acf json sync --dry-run
|
||||
```
|
||||
|
||||
Apply pending local JSON changes to the database:
|
||||
|
||||
```bash
|
||||
wp acf json sync
|
||||
```
|
||||
|
||||
Useful scoped variants:
|
||||
|
||||
```bash
|
||||
wp acf json sync --type=field-group
|
||||
wp acf json sync --key=group_post_project
|
||||
```
|
||||
|
||||
Notes:
|
||||
|
||||
- `wp acf json sync` modifies the database; run `--dry-run` first, especially outside local development.
|
||||
- The command syncs pending local JSON changes for ACF item types such as field groups, post types, taxonomies, and options pages.
|
||||
- If no items are pending, expect an “already in sync” style result.
|
||||
- Do not use a guessed `--all` flag; current ACF CLI sync defaults to all supported item types unless scoped with `--type` or `--key`.
|
||||
|
||||
If the project uses an older ACF/ACF PRO version without these commands:
|
||||
|
||||
1. Check the installed ACF version and whether an update is safe for the project.
|
||||
2. If updating is low-risk and explicitly approved, update ACF/ACF PRO first, then use the CLI workflow.
|
||||
3. Otherwise, use `references/wp-browser.md` to navigate wp-admin and sync from the ACF field group/admin screen.
|
||||
|
||||
For production or staging, ask before updating plugins or syncing database-backed ACF changes.
|
||||
|
||||
## Field group organization
|
||||
|
||||
Use field groups that reflect editorial concepts and template needs.
|
||||
|
||||
Common grouping patterns:
|
||||
|
||||
- page/template-specific fields;
|
||||
- reusable section/component fields;
|
||||
- site options;
|
||||
- post type-specific metadata;
|
||||
- taxonomy/user/menu-item metadata when needed.
|
||||
|
||||
Avoid dumping unrelated fields into a single large group. Prefer labels and instructions that make sense to editors.
|
||||
|
||||
## Field naming
|
||||
|
||||
Use stable, descriptive, snake_case field names.
|
||||
|
||||
Good examples:
|
||||
|
||||
```text
|
||||
hero_title
|
||||
hero_text
|
||||
hero_image
|
||||
cta_link
|
||||
featured_posts
|
||||
background_color
|
||||
```
|
||||
|
||||
Avoid vague names like `title_2`, `content_block`, or `misc` unless the existing project convention requires it.
|
||||
|
||||
Do not rename existing field names unless the user accepts the content migration risk.
|
||||
|
||||
## Return formats
|
||||
|
||||
Respect existing return formats. Changing them can break templates.
|
||||
|
||||
Common preferences:
|
||||
|
||||
- image fields: use the format already expected by the theme; arrays are useful when templates need alt/title/sizes;
|
||||
- link fields: arrays are usually practical for URL/title/target;
|
||||
- post object / relationship fields: know whether the field returns IDs or objects before using it;
|
||||
- true/false fields: handle empty/false explicitly.
|
||||
|
||||
When uncertain, inspect the field group JSON or runtime value before changing template code.
|
||||
|
||||
## Template usage
|
||||
|
||||
Prefer `get_field()` when the value needs escaping, conditionals, fallback handling, or reuse.
|
||||
|
||||
```php
|
||||
<?php $title = get_field( 'hero_title' ); ?>
|
||||
|
||||
<?php if ( $title ) : ?>
|
||||
<h1><?= esc_html( $title ); ?></h1>
|
||||
<?php endif; ?>
|
||||
```
|
||||
|
||||
Use compact output tags with escaping, following `references/wp-theme-dev.md`:
|
||||
|
||||
```php
|
||||
<?= esc_html( get_field( 'eyebrow' ) ); ?>
|
||||
<?= wp_kses_post( get_field( 'intro' ) ); ?>
|
||||
```
|
||||
|
||||
Avoid `the_field()` for dynamic frontend output unless the value is known safe for the exact context. Prefer explicit escaping with `get_field()`.
|
||||
|
||||
For image arrays:
|
||||
|
||||
```php
|
||||
<?php $image = get_field( 'hero_image' ); ?>
|
||||
|
||||
<?php if ( $image ) : ?>
|
||||
<img
|
||||
src="<?= esc_url( $image['url'] ); ?>"
|
||||
alt="<?= esc_attr( $image['alt'] ?? '' ); ?>"
|
||||
>
|
||||
<?php endif; ?>
|
||||
```
|
||||
|
||||
For link arrays:
|
||||
|
||||
```php
|
||||
<?php $link = get_field( 'cta_link' ); ?>
|
||||
|
||||
<?php if ( $link ) : ?>
|
||||
<a href="<?= esc_url( $link['url'] ); ?>" target="<?= esc_attr( $link['target'] ?: '_self' ); ?>">
|
||||
<?= esc_html( $link['title'] ); ?>
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
```
|
||||
|
||||
## Options pages
|
||||
|
||||
Keep ACF options-page registration in the ACF vendor/module file.
|
||||
|
||||
Use options pages for true site-wide settings, not content that belongs to a page, post, taxonomy, or theme template.
|
||||
|
||||
When reading option fields, make the option scope explicit:
|
||||
|
||||
```php
|
||||
<?php $phone = get_field( 'phone_number', 'option' ); ?>
|
||||
```
|
||||
|
||||
## Flexible content and repeaters
|
||||
|
||||
Keep flexible content layouts readable and component-oriented.
|
||||
|
||||
- Use layout names that map to template partials or sections.
|
||||
- Keep layout fields scoped to what the layout renders.
|
||||
- Avoid deeply nested repeaters/flexible fields unless there is a strong editorial reason.
|
||||
- For complex flexible content rendering, prefer dispatching to template parts instead of one giant template file.
|
||||
|
||||
The dispatch pattern depends on the theme. **Check whether the theme is a Kaliroots child theme first** (see `references/wp-kaliroots.md`) — Kaliroots has its own template lookup helpers and overriding them with generic WP dispatch fragments the resolution path.
|
||||
|
||||
For a **generic (non-Kaliroots) WordPress theme**:
|
||||
|
||||
```php
|
||||
<?php if ( have_rows( 'sections' ) ) : ?>
|
||||
<?php while ( have_rows( 'sections' ) ) : the_row(); ?>
|
||||
<?php get_template_part( 'templates/content/sections/' . get_row_layout() ); ?>
|
||||
<?php endwhile; ?>
|
||||
<?php endif; ?>
|
||||
```
|
||||
|
||||
For a **Kaliroots child theme**, dispatch through the Kaliroots section helper so child/parent override resolution works correctly:
|
||||
|
||||
```php
|
||||
<?php if ( have_rows( 'sections' ) ) : ?>
|
||||
<?php while ( have_rows( 'sections' ) ) : the_row(); ?>
|
||||
<?= kaliroots_section_template( get_row_layout() ); ?>
|
||||
<?php endwhile; ?>
|
||||
<?php endif; ?>
|
||||
```
|
||||
|
||||
In a Kaliroots project, the section partial then lives at `templates/content/sections/{layout-name}.php` and is located via Kaliroots' lookup pipeline — see `references/wp-kaliroots.md` for the helper set and naming rules.
|
||||
|
||||
Verify that the target partial exists before introducing either dispatch into an existing theme. If the project already uses a different established pattern, follow that — don't reorganize.
|
||||
|
||||
Inside the layout partial, use `get_sub_field()` (not `get_field()`) to read layout sub-fields, and escape at output:
|
||||
|
||||
```php
|
||||
<?php
|
||||
$heading = get_sub_field( 'heading' );
|
||||
$image = get_sub_field( 'image' );
|
||||
?>
|
||||
<?php if ( $heading ) : ?>
|
||||
<h2><?= esc_html( $heading ); ?></h2>
|
||||
<?php endif; ?>
|
||||
```
|
||||
|
||||
## Relationship and post object fields
|
||||
|
||||
Before using relationship/post object fields, confirm whether they return IDs or post objects.
|
||||
|
||||
- If using objects, restore global post state after setup.
|
||||
- If using IDs, use explicit IDs with WordPress APIs.
|
||||
- Avoid expensive relationship queries inside repeated templates when values can be prepared once.
|
||||
|
||||
## Refactoring workflow
|
||||
|
||||
1. Inspect the active theme, ACF plugin availability, existing ACF JSON path, and ACF-related include files.
|
||||
2. Inspect existing field group JSON before changing field names, keys, return formats, or locations.
|
||||
3. Keep PHP hooks/registration in the existing ACF module, usually `includes/vendors/acf.php`.
|
||||
4. Keep template output escaped explicitly with `get_field()` where practical.
|
||||
5. Make small, reversible changes.
|
||||
6. After wp-admin field group edits, inspect the automatically updated `acf-json/` diff.
|
||||
7. Run PHP lint/style checks via `references/wp-code-style.md` when PHP files changed.
|
||||
8. Smoke-test affected frontend/admin behavior with `references/wp-browser.md` when relevant.
|
||||
9. Inspect the diff, especially ACF JSON changes.
|
||||
|
||||
## Safety
|
||||
|
||||
- Do not rename existing field names or change return formats without calling out content/template impact.
|
||||
- Do not delete ACF JSON files without explicit approval.
|
||||
- Do not expose secrets from options pages or database values.
|
||||
- Do not assume `the_field()` output is safe; escape based on context.
|
||||
- Preserve the project's existing ACF structure when it is coherent.
|
||||
155
references/wp-assets.md
Normal file
155
references/wp-assets.md
Normal file
@@ -0,0 +1,155 @@
|
||||
# WP Assets
|
||||
|
||||
Use this skill for Websimple WordPress theme asset source, build, and enqueue conventions.
|
||||
|
||||
Use `references/wp-theme-dev.md` for general PHP/theme structure, `references/wp-code-style.md` for PHP linting, and `references/wp-browser.md` for visual smoke tests.
|
||||
|
||||
## Core principles
|
||||
|
||||
- Keep build-time source assets under `src/`.
|
||||
- Do not edit compiled/generated assets unless the user explicitly asks and there is no source available.
|
||||
- Detect the project's actual pipeline before changing files.
|
||||
- Preserve the existing asset toolchain unless the user asks for migration.
|
||||
- Keep PHP enqueue integration aligned with the build output and manifest strategy.
|
||||
|
||||
## Source structure
|
||||
|
||||
Theme source assets should live under `src/` with clear subdirectories for frontend concerns.
|
||||
|
||||
Common structure:
|
||||
|
||||
```text
|
||||
src/
|
||||
styles/ # CSS/SCSS source
|
||||
scripts/ # JavaScript/TypeScript entrypoints and modules
|
||||
components/ # Vue/React or shared frontend components
|
||||
images/ # source images/icons when processed by the build
|
||||
fonts/ # source fonts when processed by the build
|
||||
```
|
||||
|
||||
Follow the existing project structure first. Do not reorganize assets broadly without approval.
|
||||
|
||||
## Detect the pipeline
|
||||
|
||||
Before editing assets, inspect the theme root for signals:
|
||||
|
||||
```text
|
||||
package.json
|
||||
vite.config.*
|
||||
webpack.config.*
|
||||
webpack.mix.js
|
||||
postcss.config.*
|
||||
tailwind.config.*
|
||||
tsconfig.json
|
||||
src/
|
||||
assets/
|
||||
dist/
|
||||
```
|
||||
|
||||
Use `package.json` scripts as the source of truth for build/dev commands.
|
||||
|
||||
Common signals:
|
||||
|
||||
- Vite: `vite.config.ts`, scripts like `dev`, `build`, `preview`.
|
||||
- Legacy webpack/Mix: `webpack.config.js`, `webpack.mix.js`, scripts using `webpack`, `mix`, or older build tooling.
|
||||
- Plain scripts/styles: source under `src/` with minimal bundler config.
|
||||
|
||||
If signals conflict, report the ambiguity before changing build config.
|
||||
|
||||
## Build output
|
||||
|
||||
Treat build output as generated unless the project clearly uses checked-in compiled assets.
|
||||
|
||||
Common output directories:
|
||||
|
||||
```text
|
||||
assets/
|
||||
dist/
|
||||
```
|
||||
|
||||
Compiled/generated assets should normally be excluded from Git. For new or modernized projects, prefer ignoring generated build output and committing only source/config files.
|
||||
|
||||
Legacy projects may already commit compiled assets. Do not remove those generated files or change `.gitignore` behavior without approval. For those projects, keep the committed-build convention and make sure to run the build before committing so generated assets stay in sync with source changes.
|
||||
|
||||
Do not edit minified files, hashed files, generated manifests, compiled CSS/JS, source maps, or copied vendor assets directly when source files exist.
|
||||
|
||||
If compiled assets are committed in the project, update them by running the project build instead of manual edits.
|
||||
|
||||
## Vite conventions
|
||||
|
||||
For Vite-based themes:
|
||||
|
||||
- inspect `vite.config.*` before adding entrypoints;
|
||||
- keep entrypoints under `src/`;
|
||||
- preserve existing manifest/output settings;
|
||||
- use the manifest when PHP enqueue code relies on hashed filenames;
|
||||
- run the project build after changing source assets when verification requires compiled output.
|
||||
|
||||
Do not rewrite Vite config or migrate legacy projects to Vite unless explicitly requested.
|
||||
|
||||
## Legacy webpack conventions
|
||||
|
||||
For legacy webpack/Mix themes:
|
||||
|
||||
- inspect `webpack.config.*` or `webpack.mix.js` first;
|
||||
- preserve existing entrypoint names and output paths;
|
||||
- avoid modernizing syntax or build tooling as part of unrelated changes;
|
||||
- run the existing build script when compiled assets must be refreshed.
|
||||
|
||||
Do not convert webpack/Mix to Vite without an explicit migration request.
|
||||
|
||||
## Enqueue integration
|
||||
|
||||
Asset enqueue logic usually belongs under theme PHP includes, often `includes/core/assets.php` or the existing project equivalent.
|
||||
|
||||
Before changing enqueue code:
|
||||
|
||||
1. Identify the build output path.
|
||||
2. Identify whether filenames are stable or hashed.
|
||||
3. Identify whether the theme uses a manifest.
|
||||
4. Preserve existing handles, dependencies, script type/module settings, and localization/global variables unless changing them is required.
|
||||
|
||||
For stable filenames, filemtime-based cache busting is acceptable when already used by the project:
|
||||
|
||||
```php
|
||||
wp_enqueue_style(
|
||||
'example-theme',
|
||||
get_stylesheet_directory_uri() . '/dist/css/theme.css',
|
||||
[],
|
||||
filemtime( get_stylesheet_directory() . '/dist/css/theme.css' )
|
||||
);
|
||||
```
|
||||
|
||||
For hashed filenames, read from the manifest rather than hardcoding generated names.
|
||||
|
||||
## Vue and React source
|
||||
|
||||
Vue/React source should still live under `src/`, typically under `src/components/` or an existing frontend app directory.
|
||||
|
||||
Keep this skill focused on source placement and build integration. For component architecture, state management, app mounting, or framework-specific conventions, use dedicated future `wp-vue` or `wp-react` guidance.
|
||||
|
||||
## Styling conventions
|
||||
|
||||
- Keep styles under `src/styles/` or the existing style source directory.
|
||||
- Preserve the project's CSS methodology and naming conventions.
|
||||
- Avoid broad restyling when the user asked for a targeted fix.
|
||||
- Prefer source-level changes over compiled CSS edits.
|
||||
|
||||
## Workflow
|
||||
|
||||
1. Inspect theme root, `package.json`, build config, source directories, output directories, and enqueue PHP.
|
||||
2. Determine whether the project uses Vite, webpack/Mix, or another pipeline.
|
||||
3. Edit source files under `src/` or the established source directory.
|
||||
4. Do not touch generated output manually.
|
||||
5. Run the smallest relevant check: build, typecheck, lint, or targeted frontend smoke test.
|
||||
6. If compiled assets are committed, run the build before committing and inspect generated diffs.
|
||||
7. Use `references/wp-browser.md` to verify visible frontend changes.
|
||||
8. Report changed source files, generated files, and any build/verification blockers.
|
||||
|
||||
## Safety
|
||||
|
||||
- Do not run package installs or major upgrades without approval.
|
||||
- Do not migrate build tools without explicit request.
|
||||
- Do not edit compiled/minified/generated assets directly when source exists.
|
||||
- Do not remove legacy build config just because a newer tool would be nicer.
|
||||
- Watch for large generated diffs and call them out before committing.
|
||||
77
references/wp-browser.md
Normal file
77
references/wp-browser.md
Normal file
@@ -0,0 +1,77 @@
|
||||
# WP Browser
|
||||
|
||||
Use this skill for WordPress tasks that require a real browser instead of WP-CLI or file inspection. Prefer `references/wp-project.md` first when you need to resolve a project slug, local URL, production URL, repo, or paths.
|
||||
|
||||
## Safety and scope
|
||||
|
||||
- Treat local sites as safe to inspect and operate, but still avoid destructive admin actions unless explicitly requested.
|
||||
- Ask before changing production content, settings, users, plugins, themes, orders, forms, menus, options, or publishing state.
|
||||
- Prefer read-only checks on remote/production sites: navigate, inspect, screenshot, verify text/layout, check console/network symptoms.
|
||||
- Do not submit public forms, checkout flows, newsletter signups, contact forms, or anything that sends email/external effects unless explicitly requested.
|
||||
- If login is required, use existing browser session/cookies when available. Ask for credentials only if no usable session exists.
|
||||
|
||||
## Choosing the URL
|
||||
|
||||
Resolve the target URL from the request:
|
||||
|
||||
- If the user gives a full URL, use it directly.
|
||||
- If the user gives a project slug, use `references/wp-project.md` conventions to derive the local site URL: `${WEBSIMPLE_STACK_PROTOCOL}://${slug}.${WEBSIMPLE_STACK_DOMAIN}`.
|
||||
- If the user says production/remote, prefer `WP_SITE_URL` from Gitea repository Actions variables via `references/websimple-gitea.md` conventions/tools when available.
|
||||
- If the request is ambiguous between local and production, default to local and state that assumption briefly.
|
||||
|
||||
## Browser environment prerequisite
|
||||
|
||||
Websimple local dev sites may resolve to private network IPs, for example a `*.${WEBSIMPLE_STACK_DOMAIN}` hostname resolving to an IPv6 ULA address like `fd00::/8`. Some browser/MCP harnesses are SSRF-guarded and block private-network targets by default.
|
||||
|
||||
If browser navigation to a local Websimple site fails with a policy-related error (e.g. "navigation blocked by policy"), the browser harness likely needs an allowlist entry for the local Websimple domain plus private-network opt-in. The shape of that configuration depends on the harness in use (Playwright MCP, OpenClaw, etc.), but conceptually:
|
||||
|
||||
- Allow `*.${WEBSIMPLE_STACK_DOMAIN}` (and `${WEBSIMPLE_STACK_DOMAIN}` itself) on the hostname allowlist.
|
||||
- Permit private-network destinations.
|
||||
|
||||
Resolve `${WEBSIMPLE_STACK_DOMAIN}` from the environment; do not hard-code a specific local domain. Prefer an allowlisted form over globally allowing private-network access. Restart/reload the browser harness after changing its SSRF policy.
|
||||
|
||||
## Browser workflow
|
||||
|
||||
1. Open or reuse a browser tab for the target site.
|
||||
2. Take a snapshot before interacting; use semantic/ARIA refs where possible.
|
||||
3. Navigate like a user: click links/buttons, fill inputs, use menus, and wait for reliable UI state instead of arbitrary delays.
|
||||
4. Check the page result with at least one concrete signal: visible text, URL, status page, screenshot, console messages, or DOM state.
|
||||
5. Report concise evidence: URL checked, action performed, result, and any blockers.
|
||||
|
||||
For multi-step browser flows, login checks, stale refs, or tab recovery, follow the general `browser-automation` skill’s browser-control practices.
|
||||
|
||||
## WordPress admin
|
||||
|
||||
Common admin URLs:
|
||||
|
||||
- Dashboard: `/wp-admin/`
|
||||
- Login: `/wp-login.php`
|
||||
- Plugins: `/wp-admin/plugins.php`
|
||||
- Themes: `/wp-admin/themes.php`
|
||||
- Customizer: `/wp-admin/customize.php`
|
||||
- Menus: `/wp-admin/nav-menus.php`
|
||||
- Pages: `/wp-admin/edit.php?post_type=page`
|
||||
- Posts: `/wp-admin/edit.php`
|
||||
- Site Health: `/wp-admin/site-health.php`
|
||||
|
||||
When checking admin screens:
|
||||
|
||||
- Confirm whether the session is authenticated by looking for the admin bar, dashboard, or login form.
|
||||
- Avoid saving forms unless requested.
|
||||
- For settings screens, inspect current values and controls before editing.
|
||||
- For editor screens, avoid autosave-risky content edits unless explicitly requested.
|
||||
- If normal browser `fill` does not populate the WordPress login fields, use a narrow DOM fallback to set `#user_login` and `#user_pass`, dispatch `input` events, then submit. Do not echo credentials back to the user.
|
||||
|
||||
## Frontend checks
|
||||
|
||||
For frontend verification:
|
||||
|
||||
- Check desktop first unless the user asks for mobile/responsive.
|
||||
- Capture a screenshot when visual appearance matters.
|
||||
- Inspect console errors when behavior looks broken or JavaScript-heavy.
|
||||
- Verify canonical symptoms with user-visible evidence, not assumptions from source code alone.
|
||||
|
||||
## Cookies and debugging hooks
|
||||
|
||||
- For Xdebug-specific browser requests, use `references/wp-xdebug.md`.
|
||||
- If needed manually, set or include the `XDEBUG_SESSION=vscode` cookie only for local debugging flows and mention that it may route PHP through `wp-php-xdebug`.
|
||||
62
references/wp-code-style.md
Normal file
62
references/wp-code-style.md
Normal file
@@ -0,0 +1,62 @@
|
||||
# WP Code Style
|
||||
|
||||
Use this skill for PHP source formatting and coding-standard checks in Websimple WordPress projects.
|
||||
|
||||
## Shared tooling model
|
||||
|
||||
Websimple WordPress projects should rely on shared/global Websimple PHPCS tooling, not per-project Composer installs.
|
||||
|
||||
Project repos should keep only project-specific lint scope in `phpcs.xml`. The PHPCS binary, PHPCBF binary, and `WebsimpleWP` ruleset should come from global Composer tooling.
|
||||
|
||||
Expected global setup, only when explicitly asked to install or repair tooling:
|
||||
|
||||
```bash
|
||||
composer global config allow-plugins.dealerdirect/phpcodesniffer-composer-installer true
|
||||
composer global require squizlabs/php_codesniffer lewebsimple/wp-phpcs-ruleset
|
||||
```
|
||||
|
||||
If global Composer binaries are not on `PATH`, locate them with:
|
||||
|
||||
```bash
|
||||
composer global config bin-dir --absolute --quiet
|
||||
```
|
||||
|
||||
When cleaning an existing project, remove per-project Composer ownership of PHP_CodeSniffer and Websimple coding-standard tooling:
|
||||
|
||||
- remove `squizlabs/php_codesniffer` from `require-dev` when present;
|
||||
- remove `lewebsimple/wp-phpcs-ruleset` from `require-dev` when present;
|
||||
- remove `lint` / `lintfix` Composer scripts when they only wrap project-local PHPCS/PHPCBF, such as `vendor/bin/phpcs` or `vendor/bin/phpcbf`.
|
||||
|
||||
Preserve unrelated Composer dependencies and scripts. If a script does more than run PHPCS/PHPCBF, ask before removing or rewriting it.
|
||||
|
||||
## Required phpcs.xml
|
||||
|
||||
Make sure `phpcs.xml` exists at the project root and only includes `wp-content/mu-plugins/` plus the active/current theme directory:
|
||||
|
||||
```xml
|
||||
<?xml version="1.0"?>
|
||||
<ruleset name="wp-code-style">
|
||||
<rule ref="WebsimpleWP"/>
|
||||
<file>wp-content/mu-plugins/</file>
|
||||
<file>wp-content/themes/${theme}/</file>
|
||||
</ruleset>
|
||||
```
|
||||
|
||||
Resolve `${theme}` from the active child/current theme or from the user’s target. Do not lint all themes, WordPress core, vendor, uploads, cache, generated assets, or unrelated directories.
|
||||
|
||||
## Workflow
|
||||
|
||||
1. Inspect `composer.json`, `composer.lock`, and any existing `phpcs.xml` / `phpcs.xml.dist`.
|
||||
2. Resolve the target theme with WP-CLI or source inspection.
|
||||
3. Remove project-local PHPCS/ruleset Composer dependencies and simple `lint` / `lintfix` scripts when present.
|
||||
4. Ensure `phpcs.xml` is present and scoped correctly.
|
||||
5. Run lint with global `phpcs` from the shell, not `vendor/bin/phpcs`.
|
||||
6. Use global `phpcbf` only when the user requested formatting or the fix is clearly safe.
|
||||
7. Re-run lint after fixes and inspect the diff before claiming success.
|
||||
|
||||
## Safety
|
||||
|
||||
- Do not run PHPCBF across broad paths unless the `phpcs.xml` scope is correct.
|
||||
- Do not modify vendor, WordPress core, uploads, caches, or compiled assets.
|
||||
- If PHPCBF changes files, summarize changed files and remaining PHPCS issues.
|
||||
- Do not remove Composer scripts that contain extra behavior beyond straightforward PHPCS/PHPCBF wrappers without asking first.
|
||||
134
references/wp-composer.md
Normal file
134
references/wp-composer.md
Normal file
@@ -0,0 +1,134 @@
|
||||
# WP Composer
|
||||
|
||||
Use this skill for Composer-based dependency management in Websimple WordPress projects.
|
||||
|
||||
## Context
|
||||
|
||||
Websimple manages WordPress plugins and themes with PHP Composer.
|
||||
|
||||
Private Websimple Composer packages are served by Satis at:
|
||||
|
||||
- `https://satis.ledevsimple.ca`
|
||||
|
||||
For WordPress project conventions such as slug, local path, local URL, database name, and repository URL, use `references/wp-project.md`. For host tooling assumptions, including the `composer` executable being available in `$PATH`, use `references/websimple-stack.md`.
|
||||
|
||||
## Operating guidance
|
||||
|
||||
- Work from the local project root containing `composer.json`.
|
||||
- Prefer read-only inspection commands before making dependency changes.
|
||||
- Inspect `composer.json` and `composer.lock` directly when answering dependency questions.
|
||||
- Use Composer commands through the host `composer` executable unless a task explicitly requires container context.
|
||||
- Treat dependency changes as project code changes: inspect the resulting `composer.json` and `composer.lock`, then run a small verification command.
|
||||
- Ensure `wp-config.php` loads Composer vendor libraries when a project uses Composer.
|
||||
- Composer-managed WordPress plugins/themes should be ignored by Git. Some projects also have project-specific plugins/themes committed with the WordPress project; do not delete or overwrite source-controlled plugins/themes when repairing Composer-managed dependencies.
|
||||
|
||||
## Common read-only checks
|
||||
|
||||
Use these before changing dependencies:
|
||||
|
||||
```bash
|
||||
composer validate --no-check-all
|
||||
composer show
|
||||
composer show vendor/package
|
||||
composer outdated --direct
|
||||
composer why vendor/package
|
||||
composer why-not vendor/package:^1.2
|
||||
```
|
||||
|
||||
Use `composer validate --no-check-all` by default because existing Websimple WordPress projects may intentionally use `"*"` version constraints for WordPress plugins/themes, and plain `composer validate` complains about unbound constraints.
|
||||
|
||||
## Package repositories
|
||||
|
||||
Composer projects should have Composer repository entries for both Satis (private repository) and WPackagist (official WordPress package repository).
|
||||
|
||||
The `repositories` section of `composer.json` should include:
|
||||
|
||||
```json
|
||||
{
|
||||
"repositories": [
|
||||
{
|
||||
"type": "composer",
|
||||
"url": "https://satis.ledevsimple.ca"
|
||||
},
|
||||
{
|
||||
"type": "composer",
|
||||
"url": "https://wpackagist.org"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Do not assume every project already has these repositories configured. Check `composer.json` first.
|
||||
|
||||
Repository priority order matters: check Websimple Satis first, then WPackagist. Private Websimple packages should win over public package sources when names overlap.
|
||||
|
||||
## Dependency changes
|
||||
|
||||
When asked to add, update, or remove a WordPress plugin/theme package:
|
||||
|
||||
1. Confirm the target project path using `references/wp-project.md` conventions.
|
||||
2. Inspect `composer.json` and `composer.lock`.
|
||||
3. Verify package resolution priority before adding or updating packages: Websimple Satis first, then WPackagist.
|
||||
4. Run the smallest Composer command that performs the requested change.
|
||||
5. Inspect the diff for `composer.json` and `composer.lock`.
|
||||
6. Run `composer validate --no-check-all` after the change.
|
||||
|
||||
Examples:
|
||||
|
||||
```bash
|
||||
composer require vendor/package:^1.2
|
||||
composer update vendor/package --with-dependencies
|
||||
composer remove vendor/package
|
||||
composer validate --no-check-all
|
||||
```
|
||||
|
||||
Ask before running broad updates such as `composer update` without package names.
|
||||
|
||||
## WordPress Composer autoload
|
||||
|
||||
When a WordPress project uses Composer, ensure `wp-config.php` contains this Composer autoloader guard so WordPress can load Composer-managed vendor libraries:
|
||||
|
||||
```php
|
||||
if ( file_exists( __DIR__ . '/vendor/autoload.php' ) ) {
|
||||
require_once __DIR__ . '/vendor/autoload.php';
|
||||
}
|
||||
```
|
||||
|
||||
Add it only if missing, and avoid duplicating equivalent autoload logic.
|
||||
|
||||
Place the guard near the top of `wp-config.php`, after the opening `<?php` and any file header/comments, before WordPress settings/constants and before this line:
|
||||
|
||||
```php
|
||||
require_once ABSPATH . 'wp-settings.php';
|
||||
```
|
||||
|
||||
This keeps Composer classes available to project configuration and WordPress bootstrap code.
|
||||
|
||||
## Plugins/themes integrity check
|
||||
|
||||
Composer-based WordPress projects can drift when a plugin/theme installed under `wp-content/plugins` or `wp-content/themes` no longer matches the version/source recorded in `composer.lock` (for example after a WordPress dashboard update, manual file edits, interrupted install, or broken vendor state).
|
||||
|
||||
When diagnosing plugin/theme drift:
|
||||
|
||||
1. Inspect `composer.lock` to identify packages installed into `wp-content/plugins/*` and `wp-content/themes/*`.
|
||||
2. Check Git status before touching files so source-controlled project-specific plugins/themes are preserved.
|
||||
3. Treat Git-ignored Composer-managed plugin/theme directories as disposable install artifacts.
|
||||
4. Prefer read-only checks first, such as `composer install --dry-run` when useful, `composer show --locked`, and direct inspection of installed package metadata when available.
|
||||
5. If integrity is uncertain, prefer a clean reinstall of Composer-managed plugins/themes from repositories rather than trying to patch files in place.
|
||||
|
||||
Safe repair pattern:
|
||||
|
||||
```bash
|
||||
composer install --no-interaction --prefer-dist
|
||||
```
|
||||
|
||||
If a fresh install is required, remove only Composer-managed, Git-ignored plugin/theme directories and reinstall from `composer.lock`. Do not remove project-specific plugin/theme directories that are tracked by Git.
|
||||
|
||||
Before deleting any plugin/theme directory, verify both:
|
||||
|
||||
```bash
|
||||
git check-ignore -q wp-content/plugins/example-plugin
|
||||
git ls-files --error-unmatch wp-content/plugins/example-plugin >/dev/null 2>&1
|
||||
```
|
||||
|
||||
Only a path that is ignored and not tracked should be considered disposable. Ask before deleting directories, even when they appear disposable.
|
||||
249
references/wp-kaliroots.md
Normal file
249
references/wp-kaliroots.md
Normal file
@@ -0,0 +1,249 @@
|
||||
# WP Kaliroots
|
||||
|
||||
Use this skill when a Websimple WordPress site uses the `kaliroots` parent theme or when behavior may come from Kaliroots parent-theme code.
|
||||
|
||||
Kaliroots source of truth: `https://gitea.websimple.com/wp-themes/kaliroots`.
|
||||
|
||||
Use `references/wp-theme-dev.md` for general theme PHP conventions that do not conflict with Kaliroots. Use `references/wp-browser.md` for frontend checks and `references/wp-xdebug.md` when parent/child template resolution or hooks are unclear.
|
||||
|
||||
## Core rule
|
||||
|
||||
For Kaliroots child themes, do not apply generic WordPress template organization blindly. Kaliroots has its own wrapper and template lookup system.
|
||||
|
||||
Prefer child-theme overrides and additions. Treat parent theme changes as higher-risk because they can affect many sites.
|
||||
|
||||
## Confirm Kaliroots usage
|
||||
|
||||
Before applying Kaliroots conventions, confirm the active theme relationship:
|
||||
|
||||
```bash
|
||||
wp theme list --status=active
|
||||
wp theme get $(wp option get stylesheet) --field=template
|
||||
```
|
||||
|
||||
Or inspect the child theme `style.css` for a parent declaration like:
|
||||
|
||||
```css
|
||||
Template: kaliroots
|
||||
```
|
||||
|
||||
Inspect the child theme first, then inspect the parent theme only when inherited behavior or helper functions matter.
|
||||
|
||||
## Parent theme structure
|
||||
|
||||
Kaliroots parent uses a compact structure:
|
||||
|
||||
```text
|
||||
functions.php
|
||||
includes/
|
||||
core/
|
||||
purgecss.php
|
||||
theme-setup.php
|
||||
theme-wrapper.php
|
||||
helpers/
|
||||
assets.php
|
||||
attachment.php
|
||||
datetime.php
|
||||
html.php
|
||||
input.php
|
||||
mail.php
|
||||
media.php
|
||||
menu.php
|
||||
meta.php
|
||||
mutex.php
|
||||
query.php
|
||||
shortcodes.php
|
||||
social.php
|
||||
taxonomy.php
|
||||
template.php
|
||||
user.php
|
||||
utilities.php
|
||||
wpfs.php
|
||||
vendors/
|
||||
acf.php
|
||||
gutenberg.php
|
||||
wpbakery.php
|
||||
templates/
|
||||
html/
|
||||
head.php
|
||||
mail.php
|
||||
wrap.php
|
||||
content/
|
||||
main.php
|
||||
```
|
||||
|
||||
The parent `functions.php` is a loader for `includes/core`, `includes/helpers`, and `includes/vendors`.
|
||||
|
||||
Child themes may add their own `includes/`, `templates/`, and asset sources. Preserve existing child-theme conventions unless the user asks for cleanup.
|
||||
|
||||
## Template wrapper model
|
||||
|
||||
Kaliroots wraps base WordPress templates through the `template_include` filter.
|
||||
|
||||
The parent wrapper flow is:
|
||||
|
||||
1. `template_include` calls `kaliroots_wrap_base_template()`.
|
||||
2. The wrapper locates `templates/html/wrap-{base}.php` through `kaliroots_locate_template()`.
|
||||
3. `{base}` is expanded by `kaliroots_base_placeholders()` using WordPress conditional context.
|
||||
4. `locate_template()` gives child themes priority over parent templates.
|
||||
|
||||
Parent default wrapper:
|
||||
|
||||
```php
|
||||
<!DOCTYPE html>
|
||||
<html <?php language_attributes(); ?>>
|
||||
<?= kaliroots_html_template( 'head' ); ?>
|
||||
<body class="<?= join( ' ', get_body_class() ) ?>">
|
||||
<div id="app">
|
||||
<main>
|
||||
<?= kaliroots_generic_template( '{base}' ) ?>
|
||||
</main>
|
||||
</div>
|
||||
<?php wp_footer(); ?>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
When changing page layout in a Kaliroots child theme, prefer overriding or adding wrapper/content templates in the child theme instead of replacing standard WordPress top-level templates without checking how Kaliroots resolves them.
|
||||
|
||||
## Template helper functions
|
||||
|
||||
Kaliroots provides template helper functions in `includes/helpers/template.php`.
|
||||
|
||||
Common helpers:
|
||||
|
||||
```php
|
||||
kaliroots_generic_template( $template_path, $vars = [], $args = [] );
|
||||
kaliroots_html_template( $template_name, $vars = [], $args = [] );
|
||||
kaliroots_site_template( $template_name, $vars = [], $args = [] );
|
||||
kaliroots_content_template( $template_name, $vars = [], $args = [] );
|
||||
kaliroots_loop_template( $template_name, $vars = [], $args = [] );
|
||||
kaliroots_section_template( $template_name, $vars = [], $args = [] );
|
||||
kaliroots_shortcode_template( $template_name, $vars = [], $args = [] );
|
||||
kaliroots_widget_template( $template_name, $vars = [], $args = [] );
|
||||
```
|
||||
|
||||
These helpers locate templates through the Kaliroots lookup pipeline, inject `$vars` using `set_query_var()`, buffer template output, and can optionally cache rendered output.
|
||||
|
||||
Example:
|
||||
|
||||
```php
|
||||
<?= kaliroots_content_template( 'hero', [ 'post_id' => get_the_ID() ] ); ?>
|
||||
```
|
||||
|
||||
Inside the located template, read injected values with `get_query_var()` when needed:
|
||||
|
||||
```php
|
||||
<?php $post_id = get_query_var( 'post_id' ); ?>
|
||||
```
|
||||
|
||||
## Template naming and lookup
|
||||
|
||||
Kaliroots lookup supports placeholders:
|
||||
|
||||
- `{base}`: expanded using the current WordPress conditional/template context.
|
||||
- `{post_type}`: expanded using `get_post_type()` when available.
|
||||
|
||||
Examples:
|
||||
|
||||
```php
|
||||
kaliroots_html_template( 'head' );
|
||||
// looks for templates/html/head-{base}.php, then falls back through base placeholder variants.
|
||||
|
||||
kaliroots_content_template( 'main' );
|
||||
// looks for templates/content/main-{base}.php variants.
|
||||
|
||||
kaliroots_loop_template( 'default' );
|
||||
// looks for templates/content/loops/default-{post_type}.php, then fallback variants.
|
||||
```
|
||||
|
||||
When adding child-theme templates, prefer Kaliroots-compatible paths and names:
|
||||
|
||||
```text
|
||||
templates/html/wrap-front-page.php
|
||||
templates/html/wrap.php
|
||||
templates/content/main-front-page.php
|
||||
templates/content/main-single-project.php
|
||||
templates/content/loops/default-project.php
|
||||
```
|
||||
|
||||
Inspect the actual child theme before adding a new path; some projects may already have established naming.
|
||||
|
||||
## Extending template resolution
|
||||
|
||||
Kaliroots exposes filters for template lookup.
|
||||
|
||||
Use these only when adding a reusable lookup convention is clearer than adding explicit templates:
|
||||
|
||||
```php
|
||||
add_filter( 'kaliroots_locate_templates', 'example_kaliroots_locate_templates' );
|
||||
function example_kaliroots_locate_templates( array $templates ): array {
|
||||
$templates[] = 'templates/content/custom-fallback';
|
||||
|
||||
return $templates;
|
||||
}
|
||||
```
|
||||
|
||||
```php
|
||||
add_filter( 'kaliroots_base_placeholders', 'example_kaliroots_base_placeholders' );
|
||||
function example_kaliroots_base_placeholders( array $templates ): array {
|
||||
if ( is_post_type_archive( 'project' ) ) {
|
||||
array_unshift( $templates, 'archive-project-featured' );
|
||||
}
|
||||
|
||||
return $templates;
|
||||
}
|
||||
```
|
||||
|
||||
Keep these filters rare and well-named; they affect template resolution globally.
|
||||
|
||||
## Helpers and inherited behavior
|
||||
|
||||
Before reimplementing helper logic in a child theme, inspect Kaliroots helpers under `includes/helpers/`.
|
||||
|
||||
Useful parent helpers include:
|
||||
|
||||
- asset registration with filemtime cache busting;
|
||||
- template loading and pagination;
|
||||
- menu/media/meta/query helpers;
|
||||
- HTML cleaning helpers;
|
||||
- shortcode and utility helpers.
|
||||
|
||||
Do not assume helper behavior from memory. Inspect the parent helper before using or overriding it.
|
||||
|
||||
## Parent vs child changes
|
||||
|
||||
Default to child-theme changes:
|
||||
|
||||
- child template override;
|
||||
- child `includes/` function/hook;
|
||||
- child asset/source change;
|
||||
- child-specific filter/action.
|
||||
|
||||
Only edit Kaliroots parent when the user explicitly asks to change shared parent behavior or the bug truly belongs in the parent.
|
||||
|
||||
Before parent edits, report blast radius:
|
||||
|
||||
- which projects/sites may inherit the change;
|
||||
- whether a child override is safer;
|
||||
- how behavior will be verified.
|
||||
|
||||
## Refactoring workflow
|
||||
|
||||
1. Confirm active child theme and Kaliroots parent.
|
||||
2. Inspect child theme overrides first.
|
||||
3. Inspect relevant Kaliroots parent files: usually `includes/core/theme-wrapper.php` and `includes/helpers/template.php`.
|
||||
4. Choose child override vs parent change deliberately.
|
||||
5. Keep changes small and reversible.
|
||||
6. Run PHP lint/style checks via `references/wp-code-style.md` when PHP files changed.
|
||||
7. Use `references/wp-browser.md` for frontend smoke checks.
|
||||
8. Use `references/wp-xdebug.md` if template resolution/hook flow is unclear.
|
||||
9. Inspect the diff before claiming success.
|
||||
|
||||
## Safety
|
||||
|
||||
- Do not apply generic `references/wp-theme-dev.md` template structure when Kaliroots lookup rules apply.
|
||||
- Do not edit parent Kaliroots casually; prefer child overrides.
|
||||
- Do not mass-reorganize child templates without approval.
|
||||
- Do not touch core, vendor, uploads, caches, or compiled assets.
|
||||
- Preserve existing project conventions when they are coherent.
|
||||
214
references/wp-local-site.md
Normal file
214
references/wp-local-site.md
Normal file
@@ -0,0 +1,214 @@
|
||||
# WP Local Site
|
||||
|
||||
Use this skill for local WordPress site lifecycle operations. For project naming and derived values, use `references/wp-project.md`. For stack/host environment assumptions, use `references/websimple-stack.md`. For Composer-managed plugins/themes, use `references/wp-composer.md`.
|
||||
|
||||
## Derived values
|
||||
|
||||
For project slug `${slug}`, use `references/wp-project.md` conventions:
|
||||
|
||||
- Local project path: `${WP_LOCAL_ROOT_PATH}/${slug}`
|
||||
- Local database name: `wp_${slug}`
|
||||
- Local site URL: `${WEBSIMPLE_STACK_PROTOCOL}://${slug}.${WEBSIMPLE_STACK_DOMAIN}`
|
||||
- Default local DB table prefix: `wp_`, unless the production/source instance uses a different prefix
|
||||
- Repository URL: `https://gitea.websimple.com/wp-sites/${slug}`
|
||||
|
||||
Resolve project values with `references/wp-project.md`; do not hard-code local paths, protocol, or domain.
|
||||
|
||||
## Safety
|
||||
|
||||
- Prefer read-only checks before creating, deleting, or resetting anything.
|
||||
- Ask before destructive actions such as dropping a database, deleting a project directory, or overwriting local files.
|
||||
- Use recoverable deletion where practical. If shelling out, prefer moving to the user's trash over permanent removal.
|
||||
- Never delete source-controlled project-specific plugins/themes as part of Composer repair; use the `references/wp-composer.md` integrity guidance.
|
||||
- Treat remote hosts as read-only unless a future approved workflow says otherwise.
|
||||
|
||||
## Create local site skeleton
|
||||
|
||||
A local site creation workflow should generally:
|
||||
|
||||
1. Resolve `${slug}` and derived values with `references/wp-project.md`.
|
||||
2. Verify `${WP_LOCAL_ROOT_PATH}` exists.
|
||||
3. Verify `${WP_LOCAL_ROOT_PATH}/${slug}` does not already exist, or ask how to proceed.
|
||||
4. Clone or create the project directory from `https://gitea.websimple.com/wp-sites/${slug}`.
|
||||
5. Create the local database `wp_${slug}` using host `mysql` credentials from `~/.my.cnf`.
|
||||
6. Determine the DB table prefix: use `wp_` by default, or the production/source prefix when provisioning from an existing site.
|
||||
7. Run `wp core config` with only the database name and table prefix when WP-CLI defaults provide DB host/user/password.
|
||||
8. Run Composer install if the project uses Composer.
|
||||
9. Either run `wp core install` for a fresh local site or synchronize/import from an existing remote site.
|
||||
10. Verify local URL and WP-CLI access.
|
||||
|
||||
Example database creation command:
|
||||
|
||||
```bash
|
||||
mysql -e 'CREATE DATABASE `wp_example` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;'
|
||||
```
|
||||
|
||||
Use the real derived DB name; quote identifiers safely.
|
||||
|
||||
## WP core config
|
||||
|
||||
The host should have WP-CLI defaults in `~/.wp-cli/config.yml` for DB host, user, and password. Local provisioning should normally only specify the DB name:
|
||||
|
||||
```bash
|
||||
wp core config --dbname="wp_${slug}" --dbprefix="wp_"
|
||||
```
|
||||
|
||||
Run from the local project path. Do not duplicate DB host/user/password flags unless defaults are missing or the user explicitly asks.
|
||||
|
||||
Use `wp_` as the default table prefix for new local sites. When provisioning from production/staging, detect and preserve the source table prefix if it differs from `wp_`; the imported database and local `wp-config.php` prefix must agree.
|
||||
|
||||
## WP core install
|
||||
|
||||
Use `wp core install` only when creating a fresh local site without importing an existing database. Do not run it before a remote DB import because the import will replace the local tables anyway.
|
||||
|
||||
Example for a new local site:
|
||||
|
||||
```bash
|
||||
wp core install \
|
||||
--url="${WEBSIMPLE_STACK_PROTOCOL}://${slug}.${WEBSIMPLE_STACK_DOMAIN}" \
|
||||
--title="${slug}" \
|
||||
--skip-email
|
||||
```
|
||||
|
||||
`~/.wp-cli/config.yml` contains default admin user, email, and password values, so do not pass `--admin_user`, `--admin_email`, or `--admin_password` unless the user asks for custom values. Avoid inventing real production credentials.
|
||||
|
||||
## Standard admin user
|
||||
|
||||
Local sites should have the standard admin user from `~/.wp-cli/config.yml`. After installing or importing a site, check whether that user exists. If missing, create it using the configured default admin values.
|
||||
|
||||
Do not hard-code admin credentials in commands. Do not echo the password in chat or log summaries. Refer to credentials by variable name only.
|
||||
|
||||
The exact YAML shape varies by user setup. Inspect the file before constructing any command, so the keys you read match the keys that actually exist:
|
||||
|
||||
```bash
|
||||
# Inspect — show keys only, not the password value
|
||||
grep -E '^[[:space:]]*(user_login|user_email|user_pass|role)' ~/.wp-cli/config.yml \
|
||||
| sed 's/\(user_pass:\).*/\1 <redacted>/'
|
||||
```
|
||||
|
||||
Two common shapes:
|
||||
|
||||
```yaml
|
||||
# Shape A — defaults nested under `user create:`
|
||||
user create:
|
||||
user_login: someuser
|
||||
user_email: someone@example.com
|
||||
user_pass: <set>
|
||||
role: administrator
|
||||
```
|
||||
|
||||
```yaml
|
||||
# Shape B — flat top-level keys consumed by custom commands
|
||||
admin_user: someuser
|
||||
admin_email: someone@example.com
|
||||
admin_password: <set>
|
||||
```
|
||||
|
||||
If the file uses Shape A, WP-CLI will already apply the defaults when `wp user create` runs without explicit flags. If it uses Shape B, the values have to be passed explicitly.
|
||||
|
||||
When `yq` is available, prefer it over hand-parsing:
|
||||
|
||||
```bash
|
||||
ADMIN_USER="$(yq '.["user create"].user_login // .admin_user' ~/.wp-cli/config.yml)"
|
||||
ADMIN_EMAIL="$(yq '.["user create"].user_email // .admin_email' ~/.wp-cli/config.yml)"
|
||||
# Keep ADMIN_PASSWORD only in the subshell that needs it; do not export or print it.
|
||||
```
|
||||
|
||||
If `yq` is not available and the YAML doesn't match a known shape, ask the user for the admin login and email rather than guessing — and have them provide the password via stdin (`read -s`) instead of an argument that would land in shell history.
|
||||
|
||||
Typical flow:
|
||||
|
||||
1. Inspect `~/.wp-cli/config.yml` and identify the admin user/email key names actually used.
|
||||
2. Check whether that user exists locally.
|
||||
3. Create the user only if missing.
|
||||
4. Grant the administrator role if needed.
|
||||
|
||||
```bash
|
||||
# Step 2–4 — assuming ADMIN_USER, ADMIN_EMAIL, ADMIN_PASSWORD are set in the current shell
|
||||
if ! wp user get "$ADMIN_USER" >/dev/null 2>&1; then
|
||||
wp user create "$ADMIN_USER" "$ADMIN_EMAIL" \
|
||||
--role=administrator \
|
||||
--user_pass="$ADMIN_PASSWORD"
|
||||
fi
|
||||
wp user set-role "$ADMIN_USER" administrator
|
||||
```
|
||||
|
||||
If `wp user create` works without the explicit `--user_pass` flag (Shape A in use), prefer that form so the password never appears on the command line.
|
||||
|
||||
## Synchronize from remote site
|
||||
|
||||
Synchronizing from a remote site means pulling production/staging state into the local site. Keep remote actions read-only: export/read/copy from remote is okay; writing to or mutating remote is not.
|
||||
|
||||
Typical flow:
|
||||
|
||||
1. Resolve local metadata with `references/wp-project.md` and remote metadata with `references/websimple-gitea.md` Actions variables, especially `WP_SITE_URL`.
|
||||
2. Confirm source remote URL/host and destination local path/database.
|
||||
3. Create/reset the local database only after confirmation.
|
||||
4. Detect the remote/source DB table prefix before export/import. Use `wp_` only if the source also uses `wp_` or the source prefix is unknown and no imported DB is involved.
|
||||
5. Export the remote database in a read-only way, preferably streaming to local instead of leaving files on the remote host.
|
||||
6. Import into local DB.
|
||||
7. Ensure local `wp-config.php` uses the same table prefix as the imported DB.
|
||||
8. Search-replace remote URLs to the derived local URL.
|
||||
9. Pull uploads/media from remote unless specified otherwise.
|
||||
10. Verify `siteurl` and `home` locally.
|
||||
|
||||
Preferred DB sync path: stream a compressed remote DB dump over SSH into the local MySQL client. Use this when both remote WP-CLI and local `mysql` are available:
|
||||
|
||||
```bash
|
||||
ssh "$REMOTE_SSH" 'cd "$REMOTE_PATH" && wp db export - --skip-plugins --skip-themes --single-transaction --quick --lock-tables=false | gzip -c' \
|
||||
| gunzip \
|
||||
| mysql "$LOCAL_DB_NAME"
|
||||
```
|
||||
|
||||
After DB import, run URL replacement locally:
|
||||
|
||||
```bash
|
||||
wp search-replace "$REMOTE_SITE_URL" "${WEBSIMPLE_STACK_PROTOCOL}://${slug}.${WEBSIMPLE_STACK_DOMAIN}" --all-tables --skip-columns=guid
|
||||
wp option get siteurl
|
||||
wp option get home
|
||||
```
|
||||
|
||||
Do not run `wp search-replace` on the remote site during local synchronization.
|
||||
|
||||
Preferred uploads sync path: use `rsync` over SSH and include `--delete` so local `wp-content/uploads/` matches remote exactly, unless the user asks to preserve extra local files. Websimple SSH usually requires an explicit port, so include the SSH transport option when needed:
|
||||
|
||||
```bash
|
||||
rsync -az --delete -e "ssh -p $REMOTE_SSH_PORT" "$REMOTE_SSH:$REMOTE_PATH/wp-content/uploads/" "wp-content/uploads/"
|
||||
```
|
||||
|
||||
If the SSH host alias already encodes the port in `~/.ssh/config`, the `-e "ssh -p ..."` option may be omitted. If remote uploads path differs, inspect the project before syncing. Be explicit when `--delete` will remove local-only upload files.
|
||||
|
||||
## Provision from existing project
|
||||
|
||||
When provisioning from an existing local or remote project:
|
||||
|
||||
1. Resolve local and remote metadata using `references/wp-project.md` and `references/websimple-gitea.md`.
|
||||
2. Confirm the source and destination clearly.
|
||||
3. Keep remote actions read-only.
|
||||
4. Import database/content only after confirming the target local DB and path.
|
||||
5. After import, replace remote URLs with the derived local site URL.
|
||||
6. Run small verification checks, such as `wp option get siteurl` and `wp option get home`.
|
||||
|
||||
## Delete/reset local site
|
||||
|
||||
A local delete/reset workflow may include:
|
||||
|
||||
- local project directory `${WP_LOCAL_ROOT_PATH}/${slug}`
|
||||
- local database `wp_${slug}`
|
||||
- generated/cache artifacts
|
||||
|
||||
Before deleting:
|
||||
|
||||
1. Show the resolved path, DB name, and local URL.
|
||||
2. Check whether the path exists and whether it has uncommitted Git changes.
|
||||
3. Ask for confirmation.
|
||||
4. Prefer backup/trash for files where practical.
|
||||
5. Drop the local DB only after explicit confirmation.
|
||||
|
||||
Example DB drop command after confirmation:
|
||||
|
||||
```bash
|
||||
mysql -e 'DROP DATABASE `wp_example`;'
|
||||
```
|
||||
|
||||
Use the real derived DB name; quote identifiers safely.
|
||||
199
references/wp-lovable.md
Normal file
199
references/wp-lovable.md
Normal file
@@ -0,0 +1,199 @@
|
||||
# WP Lovable
|
||||
|
||||
Use this skill when turning a Lovable export into a Websimple WordPress project, especially when the output should become a normal WordPress marketing site rather than a detached static React app.
|
||||
|
||||
Use related references as needed:
|
||||
|
||||
- `references/wp-project.md` and `references/wp-local-site.md` for resolving, creating, provisioning, or checking local WordPress sites.
|
||||
- `references/websimple-stack.md` for local stack protocol/domain configuration and Traefik SSL routing.
|
||||
- `references/wp-kaliroots.md` for Kaliroots child-theme structure and template wrapper decisions.
|
||||
- `references/wp-theme-dev.md` for general theme PHP organization.
|
||||
- `references/wp-assets.md` for frontend source, Vite/Tailwind, build output, and enqueue integration.
|
||||
- `references/wp-acf.md` for editable content models, local JSON, options pages, and section data.
|
||||
- `references/wp-browser.md` for frontend/wp-admin smoke tests and visual checks.
|
||||
|
||||
## Core Approach
|
||||
|
||||
Keep WordPress as the application shell and source of truth. Treat the Lovable project as frontend source material to port into the active theme, not as a static app to drop into WordPress unchanged.
|
||||
|
||||
For new Websimple WordPress projects, start from the `wp-boilerplate` template unless the user or project context says otherwise:
|
||||
|
||||
```text
|
||||
https://gitea.websimple.com/templates/wp-boilerplate
|
||||
```
|
||||
|
||||
Prefer this shape for a Websimple WordPress conversion:
|
||||
|
||||
```text
|
||||
wp-content/themes/{child-theme}/
|
||||
acf-json/
|
||||
includes/
|
||||
core/
|
||||
assets.php
|
||||
theme-setup.php
|
||||
vendors/
|
||||
acf.php
|
||||
gravityforms.php
|
||||
templates/
|
||||
src/
|
||||
components/
|
||||
hooks/
|
||||
lib/
|
||||
pages/
|
||||
main.tsx
|
||||
index.css
|
||||
dist/
|
||||
package.json
|
||||
vite.config.ts
|
||||
tailwind.config.*
|
||||
postcss.config.*
|
||||
```
|
||||
|
||||
Adapt the paths to the existing theme. Do not reorganize established projects broadly without approval.
|
||||
|
||||
## First Pass
|
||||
|
||||
Before editing, inspect both sides:
|
||||
|
||||
1. Identify the Lovable source project, its framework, routes, components, CSS/Tailwind setup, static assets, forms, and data assumptions.
|
||||
2. Identify the WordPress site, active theme, parent theme, template wrappers, ACF setup, menus, SEO plugin, forms plugin, and asset pipeline.
|
||||
3. Check git status in the WordPress project and avoid touching unrelated dirty files.
|
||||
4. Decide which Lovable pieces are presentation components and which are actually content, navigation, SEO, media, forms, or settings that belong in WordPress.
|
||||
|
||||
Use `rg --files`, `package.json`, `vite.config.*`, `tailwind.config.*`, `src/`, `includes/`, `templates/`, and `acf-json/` as the main inspection points.
|
||||
|
||||
## Porting Rules
|
||||
|
||||
Port reusable React/Tailwind UI into the child theme `src/`. Keep TypeScript path aliases, component names, and Tailwind conventions only when they still make sense inside the theme.
|
||||
|
||||
Move editable site concerns into WordPress:
|
||||
|
||||
- page and section content into pages, ACF fields, flexible content, or options pages;
|
||||
- navigation into WordPress menus;
|
||||
- images and downloadable media into the media library or ACF media fields;
|
||||
- SEO title, canonical, OpenGraph/Twitter, schema, and indexing behavior into the SEO plugin and WordPress-rendered document head;
|
||||
- contact forms into Gravity Forms or the existing WordPress form plugin;
|
||||
- global settings such as phone, address, social links, CTAs, and layout toggles into ACF options when they are truly site-wide.
|
||||
|
||||
React should render serialized WordPress data with safe fallbacks. It should not become the CMS.
|
||||
|
||||
## Routing And SEO
|
||||
|
||||
Avoid pure React Router SPA behavior for normal WordPress marketing pages.
|
||||
|
||||
Prefer WordPress-rendered URLs and document navigation so SEO plugins can output correct per-page titles, canonical URLs, OpenGraph/Twitter tags, JSON-LD, breadcrumbs, and indexing controls.
|
||||
|
||||
Use React routing only when the requested result is an actual app-like interface where client-side routing is intentional. For standard pages, replace internal SPA links with normal document links and let WordPress resolve the route.
|
||||
|
||||
## Bundler Pattern
|
||||
|
||||
For modern Lovable migrations, Vite in the child theme is usually the cleanest fit:
|
||||
|
||||
- keep the app entry at `src/main.tsx` or the existing theme entrypoint;
|
||||
- keep Tailwind/PostCSS config in the theme root;
|
||||
- use an alias such as `@` to point at `src` only if the source already uses it or it improves the port;
|
||||
- output production assets to `dist/`;
|
||||
- generate `dist/.vite/manifest.json`;
|
||||
- set production `base` to `/wp-content/themes/{child-theme}/dist/` when assets are served from the theme;
|
||||
- have PHP enqueue code read the manifest rather than hardcoding hashed filenames;
|
||||
- mark Vite client and app scripts as `type="module"` when needed.
|
||||
|
||||
For local development, bind Vite to the local WordPress host on a fixed port and expose CORS headers so the WordPress page can load the dev server assets.
|
||||
|
||||
Mirror Mooncake's local SSL pattern when the Websimple stack uses HTTPS:
|
||||
|
||||
```ts
|
||||
import basicSsl from "@vitejs/plugin-basic-ssl";
|
||||
import { homedir } from "os";
|
||||
import { resolve } from "path";
|
||||
|
||||
const isHttps = process.env.LOCAL_PROTOCOL === "https";
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [
|
||||
...(isHttps ? [basicSsl({ certDir: resolve(homedir(), ".local/share/certs") })] : []),
|
||||
],
|
||||
server: {
|
||||
host: `${resolve(__dirname, "../../..").split("/").pop()}.${process.env.TLD || "ledevsimple.ca"}`,
|
||||
port: 3001,
|
||||
strictPort: true,
|
||||
headers: { "Access-Control-Allow-Origin": "*" },
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
Resolve `LOCAL_PROTOCOL` and `TLD` from the local stack configuration whenever possible:
|
||||
|
||||
- `LOCAL_PROTOCOL` should match `$WEBSIMPLE_STACK_PROTOCOL`, usually `https` when Traefik serves local sites with TLS.
|
||||
- `TLD` should match `$WEBSIMPLE_STACK_DOMAIN`, for example `ledevsimple.ca`.
|
||||
- Prefer package scripts, shell environment, or generated local env files that pass those values through to Vite.
|
||||
- If the stack protocol cannot be discovered, inspect `references/websimple-stack.md` config and the current local site URL before choosing `http` or `https`.
|
||||
|
||||
Do not let leftover `dist/.vite/manifest.json` silently force production mode if the local workflow expects the dev server. Prefer an explicit local/dev switch, an environment constant, or a detection strategy that matches the project's generated-output policy.
|
||||
|
||||
## PHP Integration
|
||||
|
||||
Keep PHP integration small and explicit:
|
||||
|
||||
- enqueue assets from `includes/core/assets.php` or the existing asset module;
|
||||
- localize or inline only the WordPress data React needs to render;
|
||||
- keep data preparation in helpers/includes when it becomes non-trivial;
|
||||
- keep template files responsible for mounting the frontend and providing page context;
|
||||
- keep ACF and vendor integrations in the existing vendor/module files.
|
||||
|
||||
For Kaliroots child themes, use Kaliroots wrapper and template conventions instead of inventing top-level WordPress templates.
|
||||
|
||||
## Forms
|
||||
|
||||
Do not rebuild normal WordPress forms in React just because the Lovable export included form markup.
|
||||
|
||||
Prefer a WordPress-native form flow:
|
||||
|
||||
1. Add an ACF field for a form selector or section configuration.
|
||||
2. Render the selected Gravity Form or existing form plugin output in PHP or through a focused React wrapper fed by WordPress data.
|
||||
3. Style the generated form in theme source CSS.
|
||||
4. Verify submit behavior, validation, notifications, spam protection, and accessibility in the browser.
|
||||
|
||||
Only build a custom React form when the project specifically needs custom app behavior and the backend handling is clear.
|
||||
|
||||
## What To Avoid
|
||||
|
||||
- Do not drop the Lovable export into WordPress as a static page dump.
|
||||
- Do not make WordPress serve a one-route SPA for normal marketing content.
|
||||
- Do not hard-code editor-controlled content, layout settings, form IDs, media, menus, or SEO metadata in React.
|
||||
- Do not edit compiled `dist/` assets manually when source exists.
|
||||
- Do not migrate build tools, package managers, or theme architecture as a side effect unless the user approved that scope.
|
||||
- Do not assume Lovable's placeholder copy, mock data, or generated routes are production information.
|
||||
- Do not use manifest existence alone as the only dev/prod signal if generated output may be checked in or left over locally.
|
||||
|
||||
## Verification
|
||||
|
||||
Use the smallest checks that cover the migration risk:
|
||||
|
||||
```bash
|
||||
pnpm build
|
||||
find wp-content/themes/{child-theme} -name '*.php' -print0 | xargs -0 -n1 php -l
|
||||
```
|
||||
|
||||
Then smoke-test representative URLs in the browser:
|
||||
|
||||
- home page;
|
||||
- at least one inner page;
|
||||
- contact/form page;
|
||||
- mobile viewport;
|
||||
- browser console;
|
||||
- SEO/head output for title, canonical, OpenGraph/Twitter, JSON-LD, and no accidental SPA-only metadata.
|
||||
|
||||
Report changed source files, generated files, existing dirty files left untouched, and any checks that could not run.
|
||||
|
||||
## Reference Pattern
|
||||
|
||||
The first known conversion following this pattern was:
|
||||
|
||||
```text
|
||||
Lovable source: https://github.com/Moonthewhite/chemineeschaleurs
|
||||
WordPress site: https://gitea.websimple.com/wp-sites/chemineeschaleurs
|
||||
Child theme: wp-content/themes/cheminees
|
||||
```
|
||||
|
||||
That project used a Kaliroots child theme, React/Tailwind source under `src/`, Vite output under `dist/`, ACF local JSON under `acf-json/`, PHP enqueueing under `includes/core/assets.php`, WordPress/ACF-owned section layout settings, and Gravity Forms for the contact form.
|
||||
56
references/wp-project.md
Normal file
56
references/wp-project.md
Normal file
@@ -0,0 +1,56 @@
|
||||
# WP Project
|
||||
|
||||
Use this reference for WordPress-specific Websimple project conventions. For host environment, Docker, Traefik, protocol, or domain assumptions, see `websimple-stack.md`.
|
||||
|
||||
## Config values used here
|
||||
|
||||
These environment variables drive WordPress project value derivation:
|
||||
|
||||
- `WP_LOCAL_ROOT_PATH`: shared local WordPress root path served by `wp-apache2`.
|
||||
- `WEBSIMPLE_STACK_PROTOCOL`: stack-level protocol used to build local WordPress URLs.
|
||||
- `WEBSIMPLE_STACK_DOMAIN`: stack-level domain suffix used to build local WordPress URLs.
|
||||
|
||||
Read these from the environment. Do not hard-code them in commands or examples; if any are missing when needed, ask the user to export them before proceeding.
|
||||
|
||||
## Slug
|
||||
|
||||
A Websimple WordPress project is identified by a unique slug derived from its production domain.
|
||||
|
||||
Example:
|
||||
|
||||
- `www.example.com` → `example`
|
||||
|
||||
## Local WordPress site
|
||||
|
||||
For a WordPress project `${slug}`:
|
||||
|
||||
- Local project path: `${WP_LOCAL_ROOT_PATH}/${slug}`. In the current websimple-stack this normally maps to `${DOCKER_DATA}/wp/sites/${slug}` on the host and `/var/www/html/${slug}` in containers.
|
||||
- Local database name: `wp_${slug}`
|
||||
- Local site URL: `${WEBSIMPLE_STACK_PROTOCOL}://${slug}.${WEBSIMPLE_STACK_DOMAIN}`
|
||||
- Git repository URL: `https://gitea.websimple.com/wp-sites/${slug}`
|
||||
|
||||
## Remote WordPress site
|
||||
|
||||
Use the corresponding Gitea repository Actions variables as the source of truth for the remote production environment:
|
||||
|
||||
- `WP_SITE_URL`: production site URL source of truth, including protocol.
|
||||
- `REMOTE_HOST`
|
||||
- `REMOTE_PORT`
|
||||
- `REMOTE_USER`
|
||||
- `REMOTE_PATH`
|
||||
|
||||
`wp-sites` repositories may rely on organization/repository fallback variables or secrets for `REMOTE_*` deployment values. If a per-repository `REMOTE_HOST`, `REMOTE_PORT`, `REMOTE_USER`, or `REMOTE_PATH` variable is missing, check the relevant fallback variable/secret source before treating the project metadata as incomplete or attempting to infer SSH values from the public site URL.
|
||||
|
||||
Prefer `WP_SITE_URL` for the production site URL. Reading it from repository variables is cheaper and avoids unnecessary remote SSH work. `WP_SITE_URL` must include the protocol, for example `https://www.example.com`.
|
||||
|
||||
Normally, the local user has SSH access to `${REMOTE_USER}@${REMOTE_HOST}` on `${REMOTE_PORT}` after repository values and fallback variables/secrets are resolved.
|
||||
|
||||
Only perform read-only actions on the remote host. Do not modify files, run updates, change options, write database data, deploy code, or execute destructive commands unless a future workflow explicitly adds a reviewed approval path.
|
||||
|
||||
If `WP_SITE_URL` is missing, determine the production site URL from the remote WordPress environment by running WP-CLI read-only from `${REMOTE_PATH}`:
|
||||
|
||||
```bash
|
||||
ssh -p "${REMOTE_PORT}" "${REMOTE_USER}@${REMOTE_HOST}" 'cd "${REMOTE_PATH}" && wp option get siteurl'
|
||||
```
|
||||
|
||||
Treat that `siteurl` value as the fallback production site URL. It should include the protocol.
|
||||
228
references/wp-theme-dev.md
Normal file
228
references/wp-theme-dev.md
Normal file
@@ -0,0 +1,228 @@
|
||||
# WP Theme Dev
|
||||
|
||||
Use this skill for general Websimple WordPress theme PHP development conventions.
|
||||
|
||||
Do not use this skill for PHPCS tooling setup or formatting commands; use `references/wp-code-style.md`. Use `references/wp-browser.md` for visual/frontend checks and `references/wp-xdebug.md` for runtime PHP debugging.
|
||||
|
||||
## Scope boundaries
|
||||
|
||||
This skill covers:
|
||||
|
||||
- theme PHP file/folder organization;
|
||||
- `functions.php` organization;
|
||||
- actions and filters;
|
||||
- function naming and namespacing/prefixing;
|
||||
- template conventions for regular WordPress themes;
|
||||
- comments/docblocks style;
|
||||
- escaping, sanitization, translation, and preferred output syntax;
|
||||
- safe PHP/theme refactoring workflow.
|
||||
|
||||
Defer specialized areas to dedicated skills when they apply:
|
||||
|
||||
- Kaliroots child themes: use/refine the `references/wp-kaliroots.md` conventions instead of this skill's template guidance.
|
||||
- PHPCS/PHPCBF/tooling: use `references/wp-code-style.md`.
|
||||
- ACF architecture/conventions: use `references/wp-acf.md`.
|
||||
- Asset pipeline details, bundler config, and build commands: use `references/wp-assets.md`.
|
||||
- Vue/React/headless conventions beyond source placement: use dedicated skills when available.
|
||||
|
||||
## Theme structure
|
||||
|
||||
Prefer small, discoverable theme files over large catch-all files.
|
||||
|
||||
- Keep all PHP logic under `includes/`, grouped by category.
|
||||
- Keep `functions.php` as a categorized bootstrap/loader for `includes/` files.
|
||||
- Use category directories such as `includes/admin/`, `includes/core/`, `includes/cpt/`, `includes/taxonomies/`, `includes/forms/`, `includes/roles/`, `includes/schemas/`, `includes/sections/`, `includes/shortcodes/`, `includes/vendors/`, `includes/widgets/`, and `includes/woocommerce/` as applicable.
|
||||
- Keep helpers/utilities separate from hook callback registration when practical.
|
||||
- Use `src/` for CSS/SCSS, JavaScript, TypeScript, Vue, React, and similar source assets that are compiled or bundled.
|
||||
- Preserve the existing project structure unless the user asks for reorganization.
|
||||
- Do not introduce a new architecture into an established theme without approval.
|
||||
|
||||
Preferred `functions.php` pattern: keep it as a categorized loader for files under `includes/`.
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
// Administration
|
||||
require_once __DIR__ . '/includes/admin/attachment.php';
|
||||
require_once __DIR__ . '/includes/admin/user.php';
|
||||
|
||||
// Core
|
||||
require_once __DIR__ . '/includes/core/assets.php';
|
||||
require_once __DIR__ . '/includes/core/helpers.php';
|
||||
require_once __DIR__ . '/includes/core/theme-setup.php';
|
||||
|
||||
// Custom Post Types
|
||||
require_once __DIR__ . '/includes/cpt/project.php';
|
||||
|
||||
// Custom Taxonomies
|
||||
require_once __DIR__ . '/includes/taxonomies/project-category.php';
|
||||
|
||||
// Roles
|
||||
require_once __DIR__ . '/includes/roles/editor.php';
|
||||
|
||||
// Shortcodes
|
||||
require_once __DIR__ . '/includes/shortcodes/alert.php';
|
||||
|
||||
// Vendors
|
||||
require_once __DIR__ . '/includes/vendors/acf.php';
|
||||
require_once __DIR__ . '/includes/vendors/gravityforms.php';
|
||||
require_once __DIR__ . '/includes/vendors/polylang.php';
|
||||
require_once __DIR__ . '/includes/vendors/tinymce.php';
|
||||
|
||||
// Widgets
|
||||
require_once __DIR__ . '/includes/widgets/contact-info.php';
|
||||
|
||||
// WooCommerce
|
||||
require_once __DIR__ . '/includes/woocommerce/cart.php';
|
||||
require_once __DIR__ . '/includes/woocommerce/checkout.php';
|
||||
require_once __DIR__ . '/includes/woocommerce/product.php';
|
||||
```
|
||||
|
||||
Keep empty category headers when they make the intended structure clearer or match the project convention.
|
||||
|
||||
Avoid modifying WordPress core, vendor directories, uploads, caches, compiled assets, or unrelated themes.
|
||||
|
||||
## Templates and template parts
|
||||
|
||||
For themes that are child themes of Kaliroots, do not apply generic template conventions. Refer to `references/wp-kaliroots.md` instead.
|
||||
|
||||
For regular WordPress themes, templates should live under `templates/` and be grouped by rendering purpose:
|
||||
|
||||
```text
|
||||
templates/
|
||||
html/ # outer high-level templates
|
||||
site/ # global site header/footer and site-wide layout parts
|
||||
content/ # content-related templates
|
||||
loops/ # loop wrappers and loop item templates
|
||||
emails/ # outgoing email templates
|
||||
```
|
||||
|
||||
Each template group may have a `partials/` subdirectory for smaller local partials.
|
||||
|
||||
Use `templates/content/loops/` for loop templates. Prefer paired names where the outer loop and item template share a base name:
|
||||
|
||||
```text
|
||||
templates/content/loops/events.php
|
||||
templates/content/loops/events-item.php
|
||||
templates/content/loops/posts.php
|
||||
templates/content/loops/posts-item.php
|
||||
```
|
||||
|
||||
Additional conventions:
|
||||
|
||||
- Use WordPress template hierarchy intentionally.
|
||||
- Keep template files readable and focused on rendering.
|
||||
- Use template parts for repeated markup or meaningful sections.
|
||||
- Prefer clear names that describe the rendered section or component.
|
||||
- Keep heavy data preparation, custom queries, and complex conditionals out of templates when a helper or setup function would make the template clearer.
|
||||
- Keep markup/output close to templates and reusable data/logic close to `includes/` helpers/modules.
|
||||
|
||||
Do not mass-reorganize template files without explicit approval.
|
||||
|
||||
## Actions and filters
|
||||
|
||||
Register hooks in predictable locations, following the theme's existing organization.
|
||||
|
||||
- Prefer named callbacks over anonymous closures when the callback is reused, non-trivial, or likely to need debugging.
|
||||
- Use clear project/theme-prefixed or namespaced callback names.
|
||||
- Keep callback names tied to the hook purpose.
|
||||
- Avoid hidden side effects in filters unless intentional and documented by context.
|
||||
- Preserve important priorities and accepted-argument counts.
|
||||
- Document or call out non-obvious hook ordering dependencies.
|
||||
|
||||
Example pattern:
|
||||
|
||||
```php
|
||||
// Enqueue theme assets.
|
||||
add_action( 'wp_enqueue_scripts', 'example_enqueue_assets' );
|
||||
function example_enqueue_assets(): void {
|
||||
wp_enqueue_style(
|
||||
'example-theme',
|
||||
get_stylesheet_directory_uri() . '/dist/css/theme.css',
|
||||
[],
|
||||
wp_get_theme()->get( 'Version' )
|
||||
);
|
||||
}
|
||||
|
||||
// Add a body class on the front page.
|
||||
add_filter( 'body_class', 'example_add_body_classes' );
|
||||
function example_add_body_classes( array $classes ): array {
|
||||
if ( is_front_page() ) {
|
||||
$classes[] = 'is-front-page';
|
||||
}
|
||||
|
||||
return $classes;
|
||||
}
|
||||
```
|
||||
|
||||
When refactoring hooks, verify behavior with the smallest meaningful check: WP-CLI, browser smoke test, or Xdebug when needed.
|
||||
|
||||
## Function naming
|
||||
|
||||
Follow the existing theme convention first. When adding new global functions, avoid generic names.
|
||||
|
||||
Prefer one of:
|
||||
|
||||
- a theme/project prefix, e.g. `example_get_hero_title()`;
|
||||
- a namespace if the theme already uses namespaces;
|
||||
- a class/static method only when the theme already uses that style or it genuinely improves organization.
|
||||
|
||||
Keep helper names descriptive. Separate hook callbacks from pure/data helpers when it improves readability.
|
||||
|
||||
## Comments and docblocks
|
||||
|
||||
Keep the project's existing commenting style coherent.
|
||||
|
||||
Comments may be explicit and simple, including human-readable descriptions of what a function does. Do not remove comments just because they restate the function name if that style is consistent in the project.
|
||||
|
||||
Use comments/docblocks to improve scanability and clarify intent, inputs, outputs, side effects, or hook context when useful. Avoid stale, misleading, or decorative comments.
|
||||
|
||||
## Escaping, sanitization, translation, and output syntax
|
||||
|
||||
Escape dynamic values at output time unless WordPress or the data source has already produced safe markup for that exact context.
|
||||
|
||||
Common choices:
|
||||
|
||||
- `esc_html()` for plain text;
|
||||
- `esc_attr()` for attribute values;
|
||||
- `esc_url()` for URLs;
|
||||
- `wp_kses_post()` for trusted post-like HTML;
|
||||
- `wp_json_encode()` for JSON output.
|
||||
|
||||
Sanitize input before saving or using it in queries. Use WordPress translation helpers for user-facing theme strings when appropriate.
|
||||
|
||||
Prefer compact PHP output tags for template output:
|
||||
|
||||
```php
|
||||
<?= esc_html( $title ); ?>
|
||||
<?= esc_url( $url ); ?>
|
||||
<?= wp_kses_post( $content ); ?>
|
||||
```
|
||||
|
||||
Do not rewrite existing `<?php echo ...; ?>` output solely for style unless the user asked for cleanup or the surrounding file is already being touched.
|
||||
|
||||
## Data and query conventions
|
||||
|
||||
- Use core WordPress APIs where possible.
|
||||
- Reset post data after custom `WP_Query` loops.
|
||||
- Avoid relying on surprising global state.
|
||||
- Avoid expensive queries inside repeated template parts.
|
||||
- Add caching only when justified by a concrete performance issue.
|
||||
|
||||
## Refactoring workflow
|
||||
|
||||
1. Inspect the theme structure, active child/parent theme relationship, and existing conventions.
|
||||
2. If the theme is a Kaliroots child theme, defer template decisions to Kaliroots-specific conventions.
|
||||
3. Make small coherent changes that preserve behavior unless the user requested redesign.
|
||||
4. Avoid mixing formatting-only and behavior changes.
|
||||
5. Run lint/style checks via `references/wp-code-style.md` when PHP files changed.
|
||||
6. Use `references/wp-browser.md` for frontend smoke checks when templates/output changed.
|
||||
7. Use `references/wp-xdebug.md` when runtime behavior is unclear.
|
||||
8. Inspect the diff before claiming success.
|
||||
|
||||
## Safety
|
||||
|
||||
- Do not mass-reorganize a theme without explicit approval.
|
||||
- Do not touch core, vendor, uploads, caches, compiled assets, or unrelated themes.
|
||||
- Do not silently force conventions when the existing project clearly uses a different coherent pattern; call out the tradeoff.
|
||||
- Keep changes reversible and scoped to the user's request.
|
||||
140
references/wp-xdebug.md
Normal file
140
references/wp-xdebug.md
Normal file
@@ -0,0 +1,140 @@
|
||||
# WP Xdebug
|
||||
|
||||
Use this skill when the agent should debug local Websimple WordPress PHP execution autonomously. Prefer `references/wp-project.md` first when you need to resolve the site slug, local URL, or project path. Use `references/wp-browser.md` only when browser interaction is needed to understand or reproduce the behavior.
|
||||
|
||||
The expected path is autonomous debugging with `koriym/xdebug-mcp`; do not require the user to have VS Code open or listening for Xdebug connections.
|
||||
|
||||
## Scope and safety
|
||||
|
||||
- Use Xdebug only for local Websimple development sites unless the user explicitly confirms otherwise.
|
||||
- Do not install tools, enable/reconfigure Xdebug, restart services, or modify project files unless requested.
|
||||
- Avoid sending public/production form submissions or external-effect requests while debugging.
|
||||
- Prefer deterministic local reproductions: PHP script, WP-CLI command, PHPUnit command, safe curl/API request, or a minimal reproducer.
|
||||
- If autonomous runtime debugging cannot be performed because `xdebug-mcp` or Xdebug is missing, report that as a blocker and suggest the smallest next setup step.
|
||||
|
||||
## Required autonomous debugger
|
||||
|
||||
Use `koriym/xdebug-mcp` to provide Xdebug-backed tools with structured JSON output for AI analysis:
|
||||
|
||||
- `xtrace`: trace execution flow.
|
||||
- `xstep`: stop at breakpoints and inspect variables.
|
||||
- `xprofile`: collect performance profiling data.
|
||||
- `xcoverage`: collect coverage data.
|
||||
- `xback`: capture call stack/backtrace at a breakpoint.
|
||||
- `xcompare`: compare variable states across runs; CLI-only.
|
||||
|
||||
Check availability before relying on it:
|
||||
|
||||
```bash
|
||||
command -v xtrace xstep xprofile xcoverage xback
|
||||
```
|
||||
|
||||
If Composer global binaries are not on `PATH`, locate them with:
|
||||
|
||||
```bash
|
||||
composer global config bin-dir --absolute --quiet
|
||||
```
|
||||
|
||||
Installation, only when explicitly requested:
|
||||
|
||||
```bash
|
||||
composer global require koriym/xdebug-mcp
|
||||
```
|
||||
|
||||
## Preconditions
|
||||
|
||||
Before triggering a debug run, confirm or infer:
|
||||
|
||||
- The target is local code/site, normally `${WEBSIMPLE_STACK_PROTOCOL}://${slug}.${WEBSIMPLE_STACK_DOMAIN}` and `${WP_LOCAL_ROOT_PATH}/${slug}`.
|
||||
- Xdebug 3.x is installed for the PHP runtime used by the debug command.
|
||||
- `xdebug-mcp` CLI tools are available, or MCP exposes the equivalent tools.
|
||||
- The reproduction command actually executes the PHP code being investigated.
|
||||
|
||||
For Websimple WordPress, remember that the served document root inside the PHP container is normally `/var/www/html`; map that mentally to the local WordPress project root when interpreting file paths.
|
||||
|
||||
## Autonomous workflow
|
||||
|
||||
1. Resolve the project slug, local URL, and local path with `references/wp-project.md` conventions.
|
||||
2. Identify the code path and the safest reproduction strategy:
|
||||
- WP-CLI command when WordPress bootstrap/state is needed.
|
||||
- PHP script or small throwaway reproducer for isolated functions/classes.
|
||||
- PHPUnit or project test command when a test exists.
|
||||
- curl/API request only when it safely and actually triggers the PHP code under debug.
|
||||
- Browser only to discover state, cookies, nonces, or the user flow; then reduce to a deterministic command when possible.
|
||||
3. Pick the xdebug-mcp tool:
|
||||
- Need execution path? Use `xtrace`.
|
||||
- Need variable state at a line? Use `xstep --break='file.php:line'`.
|
||||
- Need caller chain? Use `xback --break='file.php:line'`.
|
||||
- Need slowness data? Use `xprofile --json`.
|
||||
- Need coverage? Use `xcoverage`.
|
||||
4. Run the smallest safe command that captures runtime data.
|
||||
5. Analyze the JSON output and inspect source files as needed.
|
||||
6. Iterate with narrower breakpoints/traces until the cause is clear.
|
||||
7. Report evidence: command shape, breakpoint/trace target, observed runtime data, conclusion, and any blockers.
|
||||
|
||||
## Example commands
|
||||
|
||||
Script or isolated command:
|
||||
|
||||
```bash
|
||||
xtrace -- php path/to/script.php
|
||||
xstep --break='path/to/file.php:42' -- php path/to/script.php
|
||||
xback --break='path/to/file.php:42' -- php path/to/script.php
|
||||
xprofile --json -- php path/to/script.php
|
||||
```
|
||||
|
||||
WP-CLI reproduction from the local WordPress root. When using the `/usr/local/bin/wp` PHAR, invoke it explicitly through PHP so `xdebug-mcp` can determine the target script:
|
||||
|
||||
```bash
|
||||
cd "${WP_LOCAL_ROOT_PATH}/${slug}"
|
||||
xtrace -- php /usr/local/bin/wp --path="${WP_LOCAL_ROOT_PATH}/${slug}" eval '/* minimal safe reproduction */'
|
||||
xstep --break='wp-content/themes/theme/file.php:42' -- php /usr/local/bin/wp --path="${WP_LOCAL_ROOT_PATH}/${slug}" eval '/* minimal safe reproduction */'
|
||||
xback --break='wp-content/themes/theme/file.php:42' -- php /usr/local/bin/wp --path="${WP_LOCAL_ROOT_PATH}/${slug}" eval '/* minimal safe reproduction */'
|
||||
```
|
||||
|
||||
Test reproduction:
|
||||
|
||||
```bash
|
||||
xtrace -- vendor/bin/phpunit --filter 'RelevantTest'
|
||||
xcoverage -- vendor/bin/phpunit --filter 'RelevantTest'
|
||||
```
|
||||
|
||||
Containerized reproduction, if the PHP code must run inside the Websimple stack, should use the actual service names after inspection. Standard PHP is `wp-php`; browser-triggered Xdebug requests are routed to `wp-php-xdebug` when the `XDEBUG_SESSION=vscode` cookie is present.
|
||||
|
||||
```bash
|
||||
xtrace -- docker compose exec -T wp-php php /var/www/html/${slug}/path/to/script.php
|
||||
xstep --break='/var/www/html/${slug}/wp-content/themes/theme/file.php:42' -- docker compose exec -T wp-php php /var/www/html/${slug}/path/to/script.php
|
||||
```
|
||||
|
||||
Only use command forms that match the actual Websimple stack project layout after inspecting the project/stack.
|
||||
|
||||
## Browser and HTTP flows
|
||||
|
||||
For browser-only bugs:
|
||||
|
||||
- Use `references/wp-browser.md` to reproduce the UI and inspect the request details.
|
||||
- Avoid relying on a human IDE listener.
|
||||
- Prefer converting the observed request into a safe deterministic command: WP-CLI, script, test, or curl with required cookies/nonces.
|
||||
- Be careful: wrapping `curl` with `xtrace` only debugs PHP if the Xdebug capture is attached to the PHP runtime handling the request. If the PHP executes in Apache/FPM separately, use a supported xdebug-mcp/container strategy or reduce the behavior to WP-CLI/script instead.
|
||||
|
||||
Do not use Xdebug triggers on production/remote URLs.
|
||||
|
||||
## Common WordPress targets
|
||||
|
||||
- Frontend template load: theme template, `template_redirect`, query hooks, block rendering.
|
||||
- wp-admin page: menu page callbacks, list tables, metaboxes, save handlers.
|
||||
- REST API: route callback and permission callback.
|
||||
- admin-ajax: `wp_ajax_*` / `wp_ajax_nopriv_*` handlers.
|
||||
- Forms: validation/submission hooks, but do not submit externally-effectful forms unless explicitly requested.
|
||||
- Cron-like handlers: only trigger explicitly requested local code paths; do not run destructive jobs by accident.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
If no runtime data appears:
|
||||
|
||||
- Confirm `xtrace`/`xstep`/`xback` is installed and on `PATH`.
|
||||
- Confirm the command after `--` actually runs PHP and reaches the code path.
|
||||
- Confirm Xdebug 3.x is installed for that PHP binary/container.
|
||||
- Confirm paths in breakpoints match the runtime paths shown in traces, often `/var/www/html/...` inside containers.
|
||||
- Confirm the request/command is local, not production.
|
||||
- If browser navigation is blocked by policy, use `references/wp-browser.md`’s browser SSRF prerequisite for `${WEBSIMPLE_STACK_DOMAIN}` local sites.
|
||||
Reference in New Issue
Block a user