diff --git a/SKILLS.md b/SKILLS.md new file mode 100644 index 0000000..aac1b91 --- /dev/null +++ b/SKILLS.md @@ -0,0 +1,302 @@ +# Advanced MCP Plugin by AskTam — Tool Skills Reference + +> Auto-generated from the live tool registry on 2026-10-16. +> Plugin: `colorlink/advanced-mcp-plugin` · GPL-2.0-or-later · namespace `AskTamMCP\`. +> Total tools: **267**. Of these, **60** are net-new merge additions (batches b1–b12); the rest are the core/baseline set. + +## How tools are defined +Each tool: `name`, `scope` (read|write), a JSON input schema, and a static handler `Class::method(array $args): array`. Handlers throw `\RuntimeException` on error. Empty PHP arrays are cast to `new \stdClass()` so they serialize as `{}` not `[]`. + +## Architecture / adding tools +Add a batch = drop one file `includes/Extensions/BatchN.php` that registers on the `asktam_mcp_register_tools` hook. The main file glob-auto-discovers `Batch*.php` (priority 20, `class_exists` + try/catch per batch), so no core edits are needed and a broken batch cannot fatal the plugin. Guard families for absent plugins with `defined()` / `class_exists()` / theme checks so they stay inert where the dependency is missing and auto-activate where present. + +--- + +## Net-new merge additions (b1–b12) + +### b1 — Elementor structure (net-new gaps) +Guard: `defined('ELEMENTOR_VERSION')`. Fills gaps the base Elementor set missed. Writes to `_elementor_data`; CSS is regenerated on save. + +**`elementor_add_section`** +Add a classic Elementor section (legacy row layout). Optional parent_id nests it; settings accepts gap, content_width, background_color, padding, etc. +Args: `post_id:integer` **(req)**, `parent_id:string`, `position:integer`, `settings:object` + +**`elementor_add_column`** +Add a column inside a section. size is the column width in percent (1-100, default 100). +Args: `post_id:integer` **(req)**, `section_id:string` **(req)**, `size:integer`, `position:integer`, `settings:object` + +**`elementor_set_global_font`** +Add or update a typography entry in the Elementor global font palette (system_typography). +Args: `id:string`, `title:string` **(req)**, `font_family:string` **(req)**, `font_weight:string` + +**`elementor_delete_global_color`** +Remove a colour from the Elementor global palette by its id. +Args: `id:string` **(req)** + +**`elementor_delete_template`** +Delete a saved Elementor library template permanently. +Args: `template_id:integer` **(req)** + +### b2 — SEO (extended) + text extraction +Guard: `none (SEO plugin auto-detected)`. seo_* auto-detect Yoast / RankMath / SEOPress and map each one's meta keys. On a site with no SEO plugin they report plugin=none (not an error). extract_page_text walks post content + Elementor data. + +**`seo_detect`** +Detect which SEO plugin is active (Yoast, RankMath, SEOPress, AIOSEO) and whether extended meta read/write is supported. +Args: _(no args)_ + +**`seo_get_extended`** +Get extended SEO meta for a post: title, description, canonical, OG title/description/image, Twitter title, robots. Supports Yoast, RankMath, SEOPress. +Args: `post_id:integer` **(req)** + +**`seo_update_extended`** +Update extended SEO meta on a post. Only supplied fields change. Supports Yoast, RankMath, SEOPress. +Args: `post_id:integer` **(req)**, `title:string`, `description:string`, `canonical:string`, `og_title:string`, `og_description:string`, `og_image:string`, `twitter_title:string`, `noindex:boolean`, `nofollow:boolean` + +**`seo_bulk_audit`** +Scan posts/pages for missing SEO title or meta description. Returns the offenders. +Args: `post_types:array`, `per_page:integer` + +**`extract_page_text`** +Extract all human-readable text from a page: title, excerpt, post content, and every Elementor text node (with element_id + field) — for translation, audit, or rewriting. +Args: `post_id:integer` **(req)** + +### b3 — Accessibility audit (read-only) +Guard: `none`. WCAG 2.1 relative-luminance math (verified #777/#fff = 4.48:1). Walks post content via DOMDocument + Elementor data. All read-only. + +**`a11y_contrast_check`** +Compute the WCAG 2.1 contrast ratio between two hex colours and report AA/AAA pass for normal and large text. +Args: `foreground:string` **(req)**, `background:string` **(req)** + +**`a11y_audit_page`** +Accessibility audit of one page: images missing alt text, heading-order skips, and empty links/buttons. Scans post content and Elementor data. +Args: `post_id:integer` **(req)** + +**`a11y_heading_outline`** +Return the ordered heading outline (level + text) of a page and flag skipped heading levels. +Args: `post_id:integer` **(req)** + +**`a11y_images_missing_alt`** +List media-library image attachments that have no alt text. +Args: `per_page:integer` + +**`a11y_audit_site`** +Run the page accessibility audit across published pages/posts and return per-page issue counts. +Args: `post_types:array`, `per_page:integer` + +### b4 — WPML translation audit +Guard: `defined('ICL_SITEPRESS_VERSION')`. Uses the WPML filter API (apply_filters wpml_*). Inert unless WPML is active. + +**`wpml_list_languages`** +List all WPML languages: code, name, native name, active flag, and which is the default. +Args: _(no args)_ + +**`wpml_get_post_language`** +Get the WPML language code of a post. +Args: `post_id:integer` **(req)** + +**`wpml_get_translations`** +Get the full translation group of a post: for each language, the translated post id, title, status, and whether it exists. +Args: `post_id:integer` **(req)** + +**`wpml_missing_translations`** +List the WPML languages a post is NOT yet translated into. +Args: `post_id:integer` **(req)** + +**`wpml_audit`** +Audit published posts/pages for missing translations across all active WPML languages. Returns per-language missing counts and the offenders. +Args: `post_types:array`, `per_page:integer` + +### b5 — Media & content utilities +Guard: `none`. Alt-text writers + link/image hygiene. bulk_set_alt_from_title derives alt from attachment title; find_broken_internal_links checks same-host links only. + +**`set_image_alt`** +Set (or clear) the alt text of a media-library image attachment. +Args: `attachment_id:integer` **(req)**, `alt:string` **(req)** + +**`bulk_set_alt_from_title`** +Backfill alt text for image attachments from their title (or a humanized filename). By default only fills images that have no alt; set overwrite=true to replace existing alts. +Args: `per_page:integer`, `overwrite:boolean` + +**`find_broken_internal_links`** +Scan published posts/pages for internal links whose target slug does not resolve to a post/page (candidate broken links). Heuristic: term/archive URLs may appear as false positives. +Args: `post_types:array`, `per_page:integer` + +**`list_large_images`** +List media-library images whose file size exceeds a threshold (KB), largest first. +Args: `min_kb:integer`, `per_page:integer` + +**`duplicate_title_finder`** +Find published posts/pages that share an identical title. +Args: `post_types:array`, `per_page:integer` + +### b6 — Gutenberg blocks +Guard: `none`. insert_blocks/create_reusable_block build block markup server-side. render_shortcode runs do_shortcode. list_block_types enumerates the registered block registry. + +**`list_block_types`** +List registered Gutenberg block types (name, title, category). Optional category filter. +Args: `category:string`, `per_page:integer` + +**`insert_blocks`** +Insert Gutenberg blocks into a post from a simple spec. Each block: {type, content, level?, items?, url?, alt?, id?}. Types: paragraph, heading, list, image, quote, html. mode=append (default) or replace. +Args: `post_id:integer` **(req)**, `blocks:array` **(req)**, `mode:string(append|replace)` + +**`create_reusable_block`** +Create a reusable block (wp_block) from a block spec or raw block markup. +Args: `title:string` **(req)**, `blocks:array`, `markup:string` + +**`list_reusable_blocks`** +List reusable blocks (wp_block posts). +Args: `per_page:integer` + +**`render_shortcode`** +Render a shortcode string to HTML via do_shortcode, optionally in the context of a post. +Args: `shortcode:string` **(req)**, `post_id:integer` + +### b7 — WPBakery (js_composer) +Guard: `defined('WPB_VC_VERSION')`. Elements enumerated via WPBMap::getAllShortCodes(). Inert on sites without WPBakery (verified GUARD_OK on mainwp). FUNCTIONAL TEST STILL PENDING on a js_composer site. + +**`wpbakery_detect`** — _(guarded off where WPBakery absent — not in the live mainwp registry; activates on js_composer sites)_ + +**`wpbakery_list_elements`** — _(guarded off where WPBakery absent)_ + +**`wpbakery_get_content`** — _(guarded off where WPBakery absent)_ + +**`wpbakery_add_element`** — _(guarded off where WPBakery absent)_ + +**`wpbakery_replace_text`** — _(guarded off where WPBakery absent)_ + +### b8 — Remote-data presets +Guard: `none (outbound HTTP)`. wp_remote_get + transient cache (prefix amp_rd_). API keys are passed per-call and NEVER stored. remote_weather=OpenWeather, remote_place_reviews=Google Places. + +**`remote_fetch_json`** +Fetch a JSON URL (GET) with transient caching. Optional dot-path (e.g. "data.0.name") extracts part of the response. cache_minutes default 15. +Args: `url:string` **(req)**, `cache_minutes:integer`, `path:string`, `headers:object` + +**`remote_weather`** +Current weather from OpenWeather. Provide api_key and either city or lat+lon. units=metric (default) or imperial. Cached 30 min. +Args: `api_key:string` **(req)**, `city:string`, `lat:number`, `lon:number`, `units:string(metric|imperial)` + +**`remote_place_reviews`** +Google Place rating + reviews via Places Details API. Provide api_key and place_id. Cached 60 min. +Args: `api_key:string` **(req)**, `place_id:string` **(req)** + +**`remote_list_cache`** +List cached remote-data entries (key + size). +Args: _(no args)_ + +**`remote_clear_cache`** +Clear cached remote-data. Provide key to clear one, or omit to clear all remote-data cache. +Args: `key:string` + +### b9 — Backup / export (Elementor) +Guard: `defined('ELEMENTOR_VERSION')`. export/import round-trips `_elementor_data` as JSON; import uses wp_slash(wp_json_encode(...)) and regenerates element IDs to avoid collisions. + +**`export_elementor_page`** +Export a page's Elementor data: parsed elements, page settings, and template. Use as a backup or to clone into another page. +Args: `post_id:integer` **(req)** + +**`import_elementor_page`** +Import Elementor data into a target post. Provide elementor_data (JSON string or array). regenerate_ids=true gives every element a fresh id. +Args: `post_id:integer` **(req)**, `elementor_data:Array` **(req)**, `regenerate_ids:boolean` + +**`export_global_styles`** +Export the active Elementor kit's global styles (colors, typography, and other page settings). +Args: _(no args)_ + +**`import_global_styles`** +Write global styles into the active Elementor kit. merge=true (default) merges into existing settings; false replaces them. +Args: `settings:object` **(req)**, `merge:boolean` + +**`duplicate_elementor_page`** +Duplicate a page including its Elementor data into a new post (default draft). +Args: `source_id:integer` **(req)**, `title:string`, `status:string` + +### b10 — Memory layer (KV store) +Guard: `none`. Option-backed by default; ttl_minutes>0 switches to a transient. Keys sanitized to [a-z0-9_-] and prefixed ampmem_. Values are strings — JSON-encode structured data yourself. memory_append maintains a newline list. + +**`memory_set`** +Store a string value under a key. Optional ttl_minutes makes it expire (otherwise it persists). For structured data, pass JSON text as value. +Args: `key:string` **(req)**, `value:string` **(req)**, `ttl_minutes:integer` + +**`memory_get`** +Retrieve a stored value by key. +Args: `key:string` **(req)** + +**`memory_list`** +List stored memory keys, optionally filtered by prefix. +Args: `prefix:string` + +**`memory_delete`** +Delete a stored value by key. +Args: `key:string` **(req)** + +**`memory_append`** +Append an item to a newline-delimited list stored at key (created if absent). +Args: `key:string` **(req)**, `item:string` **(req)** + +### b11 — Motion / GSAP +Guard: `defined('ELEMENTOR_VERSION')`. Entrance animations (_animation/_animation_delay) + scroll motion-fx (translateY parallax / opacity). motion_apply_preset staggers delay across top-level elements. Recursive element walk by id. + +**`motion_list_presets`** +List available entrance animations, scroll motion-FX effects, and named preset bundles. +Args: _(no args)_ + +**`motion_set_entrance`** +Set an Elementor entrance animation (and optional delay in ms) on one element by its id within a post. +Args: `post_id:integer` **(req)**, `element_id:string` **(req)**, `animation:string` **(req)**, `delay_ms:integer` + +**`motion_set_scroll_fx`** +Apply a scroll motion-FX (translateY parallax or opacity fade) to one Elementor element by id. +Args: `post_id:integer` **(req)**, `element_id:string` **(req)**, `effect:string(translateY|opacity)` **(req)**, `speed:integer` + +**`motion_apply_preset`** +Apply a named motion preset bundle to all top-level elements of an Elementor post (staggered). +Args: `post_id:integer` **(req)**, `preset:string` **(req)** + +**`motion_clear`** +Remove entrance animation and scroll motion-FX settings from one element (or all top-level elements if element_id omitted). +Args: `post_id:integer` **(req)**, `element_id:string` + +### b12 — Woodmart theme helpers +Guard: `active theme = Woodmart`. Writes to the xts-woodmart-options store. set_option is JSON-aware and auto-backs-up the prior value into amp_wd_backup; restore_option reverts or removes. Fully functional on mainwp (Woodmart 8.4.1). + +**`woodmart_detect`** +Report whether the Woodmart theme is active and its version. +Args: _(no args)_ + +**`woodmart_get_option`** +Read one Woodmart theme option by key. +Args: `key:string` **(req)** + +**`woodmart_list_options`** +List Woodmart theme option keys (and value types), optionally filtered by prefix. +Args: `prefix:string` + +**`woodmart_set_option`** +Set one Woodmart theme option. value is parsed as JSON when valid (so arrays/booleans/numbers work), otherwise stored as a string. The prior value is auto-backed-up for woodmart_restore_option. +Args: `key:string` **(req)**, `value:string` **(req)** + +**`woodmart_restore_option`** +Restore one Woodmart option to the value saved before the last woodmart_set_option (or remove it if there was none). +Args: `key:string` **(req)** + +--- + +## Core / baseline tools + +The pre-existing plugin tools (Elementor base set, core WordPress CRUD, WooCommerce, media, menus, users, options, SEO base, etc.). Full definitions are the live registry; this section is a grouped index by name prefix. Regenerate the full listing any time with the dump + generator scripts noted at the foot of this file. + +Counts by prefix (267 total = 212 core + 55 net-new live; b7's 5 WPBakery tools are guarded off on mainwp): +`activate` 1 · `add` 1 · `ai` 1 · `approve` 1 · `cli` 2 · `count` 3 · `create` 6 · `deactivate` 1 · `delete` 11 · `elementor` 56 · `email` 3 · `fs` 5 · `generate` 2 · `get` 31 · `list` 13 · `pexels` 2 · `read` 1 · `reorder` 1 · `run` 1 · `search` 1 · `send` 1 · `set` 2 · `spam` 1 · `sql` 3 · `switch` 1 · `theme` 7 · `transient` 5 · `trash` 1 · `update` 13 · `upload` 1 · `wc` 27 · `widget` 5 · `wp` 1 · `write` 1 + +(The net-new families above — a11y, seo, wpml, memory, motion, remote, woodmart, plus the b1/b5/b6/b9 additions — are documented in full in the section above.) + +--- + +## Regenerating this file +Against the live registry on the target container: +1. `/tmp/dev_dump_defs.php` — bootstraps wp-load, calls `new \AskTamMCP\MCP\Registry()->getToolDefinitions()`, writes `amp_defs.json`. +2. `/tmp/dev_gen_skills.js` — formats that JSON into this grouped reference. +Re-run both whenever a batch is added so the count and listings stay in sync. + +_End of reference._