119 Commits
Author SHA1 Message Date
John Smith 914088ff92 feat(abilities): enhance schema compat, user meta, e-commerce meta, and creator pipeline
- fix(schema-compat): prefer 'string' in non-null scalar unions to fix SanitizeSchemaUnionItemsTypeTest
- fix(content): define featured_image output properties and return resilient empty object structure for posts without thumbnails
- feat(content): add get_allowed_protected_meta() with WooCommerce and paywall whitelist
- feat(user): add sanitized meta support to create-user, update-user, and get-user with privilege escalation guard
- feat(database): support 'query' argument alias in emcp-tools/query
- feat(woo): expand create/update-product with author/vendor ownership, virtual/downloadable, prices, categories, tags, and meta; add list-vendors
- test: add 14 new automated unit tests across User, Content, Woo, and Database suites
2026-09-12 17:59:29 -04:00
John Smith 80ca8741d5 feat(ads): add ad monetization ability engine, exoclick api integration, skills, and tests 2026-09-05 11:23:24 -04:00
John Smith bf93cc08bf feat(comic): add featured_image and featured_image_url with attachment fallback to comic read ops 2026-09-04 19:11:49 -04:00
John Smith 5c4606fc77 emcp-tooling 2026-09-03 19:06:59 -04:00
John SmithandClaude 7d899d8a78 feat(migrate): paired targets, scoped sync, push/sync admin, url-search-replace tool
- EMCP_Tools_Migration_Engine: shared transfer engine — the four private
  helpers that lived in the migrate abilities moved here verbatim
  (push_packets/finalize/poll_job) plus push_archive orchestration.
- EMCP_Tools_Migrate_Targets: {prefix}emcp_migrate_targets store, encrypted
  secrets (never returned), single-use pairing-code redemption. Connector is
  now 1.2.0: adds /pair/issue, open /pair/exchange (HTTPS-gated), /verify, a
  settings page that issues codes, and advertises scope-restore.
- EMCP_Tools_Sync_Engine + Packager scope opts: full/selective .emcp sync
  archives (db all|none|tables[], file_roots all|none|roots[]) with additive
  scope+kind manifest keys (absent scope = full; format_version stays 2).
- Scope-aware restore on both sides: search-replace gated on a real DB import
  and restricted to archived tables; connector no longer errors on DB-less
  (files-only) archives.
- MCP surface: migrate-site gains optional target_id (raw remote_url+secret
  back-compat kept); sync-to-live is now the documented scoped push; new
  url-search-replace tool carries the old local search-replace body
  (disabled-by-default via DEFAULTS_VERSION 37, drift-guard + catalog wired).
- Admin: Backup & Migrate tab split into Archives | Push to Site | Sync with
  paired-target add/delete/verify + blocking push/sync handlers; adds
  assets/js/migrate.js and pro-manifest entry.
- Tests: migrate/packager assert suite extended (scope normalization, root
  traversal guards, scoped archive manifests, files-only has no DB dump).

Co-Authored-By: Claude <[email protected]>
2026-09-03 11:57:20 -04:00
John SmithandClaude d6a93ceb5b fix(migrate): address CodeRabbit findings on the backup/migrate/restore flow
Code-review findings verified against the current code; only still-valid issues
fixed, minimal churn, no .emcp-format or push-protocol changes.

- migrate-site: schema now accepts direction "pull" so the explicit
  unsupported error is reachable (matches the docs); a restore is reported as
  success only when the destination job state is "done" — pending/unknown/
  queued return a WP_Error carrying the job details.
- search-replace engine: walk_table() with before_cap=0 no longer sets
  partial (no before-image capture is not truncation).
- connector: hashless archives (no database_sha256) now import instead of
  failing integrity; import statement errors stay under db stats (non-fatal)
  so a partial import still gets the URL rewrite, while stream/hash failures
  remain fatal and drive the job state; destination URL is captured before the
  import replaces wp_options; rewrite_rows/search_replace report partial when
  the per-table cap is hit so a run can never silently claim done.
- restore engine: destination URL captured before import; hash-mismatch abort
  no longer double-closes/cleans (the finally block owns cleanup); DB stream
  extraction requires a successful stream_copy_to_stream and closes handles on
  every failure path.
- packager: list_archives() no longer hashes every archive (full read per row
  on a plain listing); create_archive validates addFile/addFromString/close and
  removes a partial archive on failure; default filenames gain a random suffix
  and the backups dir gets .htaccess/index.html web-denial guards.
- search-replace wrapper guards on the engine class existing.
- migrate module: drains output buffers before streaming binary downloads.
- tests: extended harness with a walk_table before_cap=0 case (9 suites green).

Co-Authored-By: Claude <[email protected]>
2026-09-03 02:02:54 -04:00
John SmithandClaude 448e46ff18 feat(migrate): real backup/restore/sync engine + HMAC connector, AI Chat hygiene
The fork's Pro merge left Backup/Restore/Migrate/Sync as placeholders (4 naive
files): no restore path, migrate-site was a canned-success stub, sync-to-live
touched only wp_options, and the connector exposed only a /status route. This
makes the story real at a bounded scope and fixes the wiring/doc drift found in
a feature-parity review against upstream Pro.

- search-replace engine: byte-accurate serialized fixer (length-delta, never
  unserializes), JSON escaped+unescaped URL pair replace (_elementor_data), and
  a site-wide table walker; legacy EMCP_Tools_Search_Replace now delegates.
- backups: streamed DB export (bounded chunks, explicit-column INSERTs), richer
  .emcp manifest (format version, site_url, php/wp/db, DB sha256 + row stats),
  opt-in include_files bundling of uploads/plugins/themes.
- restore: hardened statement-aware importer (skips transaction-control
  directives, ';'-in-string safe); new Restore_Engine (hash-verified -> import
  -> URL rewrite -> traversal-guarded file placement); admin Restore/Download/
  Delete + restore-history panel (nonce + manage_options, admin-only).
- migrate-site: real push to a standalone HMAC connector (2 MB signed packets ->
  assemble -> verify -> self-contained restore -> pollable job). confirm:true
  required; direction "pull" returns unsupported.
- sync-to-live: real site-wide serialized-safe URL search-replace across
  options/posts/postmeta/comments/term+usermeta + prefixed tables, ledger-
  recorded for History rollback.
- remove 3 never-registered ghost tools (list-syncable-changes,
  sync-content-item, discard-sync-change) from catalog/slugs/seeding.
- AI Chat: canonical module id 'ai-chat' (admin toggle now works, legacy
  ai_chat read-back), /emcp/v1/chat route gated on module state, default on.
- docs: correct README/readme.txt over-claims (WooCommerce op list, addon slugs,
  atomic wording, SEO/forms counts), tidy pro-manifest.txt; bump 3.16.0.

Tests: extended tests/test-migrate-packager.php (8 suites, all passing) covering
byte-accurate SR, export/import round trip, directive-skip, quote-safe split,
and packager create/read/list/delete.

Co-Authored-By: Claude <[email protected]>
2026-09-03 01:09:03 -04:00
John SmithandClaude 9610fc76ad fix(comic): expose per-operation argument schema on the comic dispatchers
LobeHub (and other) agents kept failing to call emcp-tools/comic-write
because its "scheme" was invisible: the static schema exposed only an
unconstrained operation string plus an opaque free-form arguments object,
and comic-write uniquely marked operation as REQUIRED, so the documented
"call with no operation to list the catalog" discovery call was blocked at
the schema level. The hand-maintained runtime catalog had also drifted from
the executors, omitting status (which defaults to publish), date, author,
taxonomies, content_warning, and comic_html_above/below — exactly the facts
agents were guessing at.

- comic-write no longer requires operation, so the empty-op discovery call
  is legal; both tools' operation property now carries an enum of the real
  operation names.
- Add op_schema() to the read and write operations classes as the single
  source of truth (typed JSON Schema + a realistic example per op). The
  discovery catalog is generated from it — each entry keeps the flat
  arguments hints and gains typed schema + example — so the docs can never
  drift from the executors again.
- Tool descriptions now state the discovery flow and the create-comic
  contract (status defaults to "publish", date backdating, image flow,
  author).
- Clarify in both emcp-comic-easel SKILL.md files that imported strips must
  always pass "status": "draft" explicitly, since the tool's own default is
  publish.
- Tests: new schema-exposure suite (no required operation, enum == spec
  keys, catalog schema+example, status default/fields exposed, and a parity
  guard pinning every executor field to the spec). All 8 suites pass.

Co-Authored-By: Claude <[email protected]>
2026-09-02 15:45:19 -04:00
John SmithandClaude 147365bafa fix(sandbox): complete EMCP_Tools_Block_Store API to stop the page=emcp-tools-widgets fatal
The Sandbox admin page fatals on shad-base.com with
"Call to undefined method EMCP_Tools_Block_Store::user_has_access()"
(views/sandbox/overview.php:41). The store loads eagerly so class_exists()
passes, but the class shipped by the unlocked port (9176dd7) was never given
the API its own views call — pagination commit b7cfe45 updated blocks.php and
the widget/snippet stores but not the block store.

Add the missing consumer-facing methods, mirroring the widget store and the
EMCP_Tools_Sandbox_Store base:
- user_has_access()   (overview.php:41, blocks.php:21, admin AJAX guards)
- summary()           admin-table row: block_id/block_name, publish->active
- list_blocks()       overview card counts
- list_blocks_page()  blocks.php table via EMCP_Tools_Sandbox_List_Query
- get_asset()         block.json/render.php code viewer (whitelisted)
- create_block()      fixes latent fatal in apply_bundle() (bundle import)
- uninstall_cleanup() uninstaller.php:77

Harden create()/update()/compile() with a class_exists guard on the deferred
EMCP_Tools_Block_Generator (matches class-widget-store.php:372).

New tests/test-sandbox-blocks.php: 7 suites — method presence, user_has_access
gate, summary mapping, overview.php render smoke (the previously-fatal file),
get_asset whitelist round-trip, apply_bundle->create_block draft import, and
list_blocks_page shape. All pass; migrate/comic/skills suites still green.

Co-Authored-By: Claude <[email protected]>
2026-09-02 14:34:34 -04:00
John Smith a2149de1fe feat(skills): add complete Agent Skills bundle including Comic Easel, performance, security, and 10 vertical packs 2026-09-02 14:05:02 -04:00
John Smith fadea0060c fix(migrate): load EMCP_Tools_Packager and migrate engine classes to prevent fatal error 2026-09-02 13:58:33 -04:00
John Smith f73557df79 test(comic): add date preservation test for ISO 8601 twitter timestamps 2026-09-02 13:49:04 -04:00
John Smith 290ead0e64 feat(comic-easel): add Comic Easel MCP integration with multi-image strips and source tracking 2026-09-02 13:04:43 -04:00
Mian Shahzad Raza 853fdecf05 release: prepare 3.14.2 2026-09-02 11:35:42 +05:00
Mian Shahzad Raza 2472df86a0 feat(atomic): add global variables and harden style writes 2026-08-30 00:25:35 +05:00
Mian Shahzad RazaandClaude Opus 4.8 e3a3602047 fix(blocks): fail loudly instead of silently dropping a block on a bad position path
Block_Tree::insert() no-ops when an index path does not resolve and returns the
tree unchanged, so every block pack saved the unchanged post and still reported
success — the block was lost and the agent believed it landed. Found live while
building a 29-block Kadence page: three nested infoboxes vanished with 'ok' for
each. New Block_Tree::position_is_valid() (append/prepend always valid;
inside/before/after require a path that resolves via at()), enforced in the
Kadence (add-block + insert-pattern), Spectra, GenerateBlocks and Blocksy add
paths with an invalid_position WP_Error. Core Gutenberg already guarded this.

Note for callers: position.path indexes the SEPARATOR-STRIPPED tree (what
get-post-blocks returns), not raw parse_blocks output, which counts whitespace
entries — that mismatch is exactly what produced the lost blocks.

Tests: BlockTreePositionTest (5) incl. the silent-noop behaviour the guard exists
to prevent. Suites: pro 2070, public 155.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-08-16 23:30:38 +05:00
Mian Shahzad RazaandClaude Opus 4.8 48bac2b821 fix(oauth): serve the .well-known discovery doc on subdirectory installs (3.12.2)
On a WordPress site under a subpath (e.g. example.com/gpt-build/), the RFC 9728
protected-resource metadata request arrives as /gpt-build/.well-known/oauth-protected-resource,
but EMCP_Tools_OAuth_Metadata::request_path() matched the raw URI against the
site-root-relative /.well-known/... paths, so it never matched and the request
404'd — even though the WWW-Authenticate header advertises that exact subfolder URL.
OAuth discovery (ChatGPT, Claude, any RFC 9728 client) dead-ended and no tools
appeared. Strip the home-URL path prefix before matching (no-op on root installs).
Tests: OAuthMetadataSubdirTest (public suite 150).

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-08-16 23:30:38 +05:00
Mian Shahzad RazaandClaude Opus 4.8 5748f005b0 fix(#111,#112): container-experiment guard + atomic dynamic-prop save fallback
#111 (part 2): on installs with Elementor's Flexbox Container experiment OFF, the
'container' element type is unregistered, so add-container/build-page stored pages
that render empty (Elements_Manager skips the uninstantiable element). Add
EMCP_Tools_Atomic_Props::is_container_supported() (authoritative element-type check),
refuse add-container/build-page up front with an actionable container_unsupported
error, and surface supports_container + a warning + recommended_mode='unsupported'
from detect-elementor-version.

#112: Document::save() THROWS Elementor's atomic settings/styles validation on an
editor-authored {$$type:'dynamic'} paragraph whose tag the CLI/REST atomic
dynamic-tags registry can't resolve, and because save() validates the whole tree it
blocked EVERY edit to the document. Route a validation-rejection throw into the
existing raw meta-write fallback (the tree is already coerce_tree'd, so what remains
is data the editor itself persists) via EMCP_Tools_Data::is_atomic_validation_rejection();
genuine fatals still hard-fail.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-08-13 12:57:45 +05:00
Mian Shahzad RazaandClaude Opus 4.8 a63ed73c93 fix(#111): invalidate Elementor 4.2 element cache on data writes
MCP-created pages rendered empty on Elementor 4.2.x: create-page writes empty
[] data, an intermediate render caches an empty _elementor_element_cache, and
the plugin's raw update_post_meta() write path never invalidated it (Elementor
only clears it in Document::save(), which the CLI/proxy fallback bypasses). On a
persistent object cache (WP Engine) the stale empty entry survives every content
write, so the page serves the cached empty render forever.

Add EMCP_Tools_Data::init() — an added/updated_post_meta hook that clears
_elementor_element_cache whenever _elementor_data changes, from ANY write path —
plus an explicit clear in the save fallback. Also fixes delayed visibility of
edits to existing pages. Root-caused + fix live-verified on Elementor 4.2.2.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-08-11 22:06:26 +05:00
Mian Shahzad RazaandClaude Opus 4.8 b5303c1c11 fix(connect): make Server URL override authoritative for OAuth resource+token
resource()/base_url() (token/register/revoke) now route through the shared
rest_endpoint() helper too, so an admin override (or a host where rest_url
differs) yields a fully consistent OAuth discovery document — issuer, authorize,
resource, and token all on one reachable host. HTTP-verified against the live
well-known endpoints. +2 tests.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-08-11 21:51:59 +05:00
Mian Shahzad RazaandClaude Opus 4.8 6c4201519b feat(connect): reachable public base URL for bundle + OAuth (staging fix)
On hosts that pin the Site Address to a not-yet-live domain (e.g. Hostinger
staging), home_url() is unreachable while rest_url() answers on the real host.
The .mcpb bundle WP_URL and the OAuth issuer/authorization_endpoint used
home_url(), so they shipped/advertised an unreachable URL — the bundle couldn't
connect, OAuth discovery 404'd, and mcp-remote dropped pursuing the dead issuer.

Add EMCP_Tools_Site_Context::public_base_url() (rest_url-derived default, admin
override option, emcp_tools_public_base_url filter) + mcp_endpoint(), and route
the bundle, OAuth issuer + authorize endpoint, the Connection-tab endpoint, and
the JS config vars through it. Add an editable Server URL field on the
Connection tab. Live-verified across a simulated rest/home split; +7 tests.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-08-11 21:39:50 +05:00
Mian Shahzad RazaandClaude Opus 4.8 7fdf1399b2 refactor(redirects): wrap the Redirect Manager as a toggleable module
New EMCP_Tools_Redirect_Module (free, on by default) owns the store+handler boot
and gates — via static is_enabled() — the ability group in the registrar, the
Redirects admin tab, and the delete/rename suggest-only wiring, so the whole
feature can be switched off from the Modules tab. Same pattern as EMCP Themer.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-08-11 07:17:59 +05:00
Mian Shahzad RazaandClaude Opus 4.8 102a323656 feat(redirects): suggest-only redirects on delete-post + slug change
Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-08-11 04:59:46 +05:00
Mian Shahzad RazaandClaude Opus 4.8 70a4dc6353 feat(redirects): find-broken-links read-only scan
Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-08-11 04:58:02 +05:00
Mian Shahzad RazaandClaude Opus 4.8 6f400028d1 feat(redirects): CRUD MCP tools + registration + bootstrap wiring
Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-08-11 04:55:42 +05:00
Mian Shahzad RazaandClaude Opus 4.8 cf1b5aadd9 feat(redirects): redirect store — table, path normalize, CRUD, loop guard
Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-08-11 04:50:04 +05:00
Mian Shahzad RazaandClaude Opus 4.8 165b09caf1 perf(mcp): no-store/LiteSpeed cache headers + reliability guidance (Issue 1)
Bug report Issue 1 (intermittent 'connector isn't responding' on shared
LiteSpeed): send Cache-Control: no-store + X-LiteSpeed-Cache-Control: no-cache
+ X-Accel-Buffering: no on the MCP route so LiteSpeed/QUIC never caches or
buffers MCP responses. Adds a readme FAQ (cache-exclusion + PHP limits + MCP
Log) and an opt-in EMCP_TOOLS_PROFILE_REGISTRATION timing seam. The registrar
was confirmed already lazy/cheap, so this targets the transport layer.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-08-01 05:13:37 +05:00
Mian Shahzad RazaandClaude Opus 4.8 68a945884c feat(mcp): request log + MCP Log admin tab (Issue 5)
Bug report Issue 5: the client only sees generic error strings with no
server-side diagnostics. Records each MCP request (tool, status, duration,
request id) to a capped option via rest_pre/post_dispatch on the MCP route,
surfaced on a new 'MCP Log' admin tab. The underlying error is stored only
when WP_DEBUG is on. 3 unit tests.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-08-01 04:51:53 +05:00
Mian Shahzad RazaandClaude Opus 4.8 483b444661 feat(mcp): host-mismatch guard returns explicit 421 for stale-domain connectors
Bug report Issue 2: a connector left pointed at an old domain still loaded
tools/list (GET follows the 301) but every tool execution failed opaquely.
A rest_pre_dispatch filter scoped to /mcp/emcp-tools-server now returns a
421 with the correct endpoint URL when the Host header no longer matches
home_url(), so the connector breaks visibly. Fail-open on missing Host.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-08-01 04:28:35 +05:00
Mian Shahzad Raza 0ce420601b style(copy): remove em dashes from plugin copy, fix mcpb display name
Sweeps shipped copy clean of em dashes: readme.txt, README.md,
CHANGELOG.md, the bundled sample prompts, and user-facing PHP strings
(tool descriptions, admin labels). PHP was swept on non-comment lines
only, so developer docblocks and inline comments are untouched.
Internal dev docs (CLAUDE.md, docs/) were deliberately left alone.

Replacements are contextual: colons for label/definition patterns,
commas for asides, en dashes for numeric ranges.

The .mcpb bundle display_name now reads "EMCP Tools - <host>" with a
plain hyphen; its test is updated to match. Fixing CHANGELOG.md also
clears the em dashes from the website's generated changelog on the
next site build, since that file is its source.

Verified: php -l clean on every touched file, pro suite 1559 pass,
public suite 102 pass. Bumps the pro submodule for the Pro-side sweep.
2026-07-21 08:03:19 +05:00
Mian Shahzad Raza fefcf1bbc0 feat(forms): Contact Form 7 adapter (free) — forms/fields/mail/messages/settings, live-verified 2026-07-18 21:45:31 +05:00
Mrshahidali420 1d217e3dbd feat: Meta Box custom-fields abilities (metabox-read / metabox-write) 2026-07-16 20:30:08 +05:00
786e8347d7 Merge PR #87: unique .mcpb manifest name per site (fixes #86) into 3.3.0
@Mrshahidali420's fix for the Claude Desktop bundle collision (each site's
.mcpb now installs side by side). Resolved CHANGELOG (folded into 3.3.0
Fixed); source + test applied clean. Public suite 70 green.

Co-Authored-By: Mrshahidali420 <[email protected]>
Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-12 21:46:21 +05:00
Mrshahidali420 cdd49dbdec fix(mcpb): unique manifest name per site so bundles don't overwrite
Claude Desktop keys installed extensions by the manifest `name`, but every
generated .mcpb bundle used a fixed `emcp-tools`, so installing a second
site's bundle silently replaced the first. Derive a per-site slug from the
host (emcp-tools-<host-slug>), with a self-contained PHPUnit test.

Fixes #86.
2026-07-12 12:19:34 +00:00
Mrshahidali420 7a8d2ad2bb feat(nav-menu): menu-read/menu-write dispatchers + [emcp_menu] shortcode
Adds WordPress nav-menu management as two dispatcher tools (menu-read /
menu-write, 13 operations) mirroring the ACF pattern, an [emcp_menu] shortcode
for live menus in custom HTML headers, and a self-contained PHPUnit test.
Wired always-on in the registrar + bootstrap; CHANGELOG under Unreleased.
2026-07-11 17:54:30 +00:00
82f1f59145 feat(acf): ACF/ACF PRO integration as 2 dispatcher tools (#76)
Lands the ACF domain from #76 (by @DeibyRo), reworked to a consolidated
2-tool surface and a new admin home.

Surface: instead of 15 individual MCP abilities, the domain registers TWO
dispatcher tools — emcp-tools/acf-read and emcp-tools/acf-write — that expose
15 operations (8 read, 7 write). Each takes { operation, arguments }; calling
with no operation returns a discovery catalog listing that side's operations.
dispatch() gates each call by ACF-6.1+ availability (CPT/tax ops) then the
operation's own capability check — no privilege escalation.

Gating: read-vs-write is at the TOOL level — acf-read and acf-write are the
two toggles (acf-read on, acf-write off by default), enabled/disabled by the
standard filter_disabled_tools mechanism like any other tool. No per-operation
toggles. Seeded by the v14 defaults step (DEFAULTS_VERSION 13 -> 14), which
adds emcp-tools/acf-write to the disabled set and strips any pre-release
per-operation ACF slugs.

Admin: new "Plugins" sub-tab on the Tools screen; the ACF section shows the
two dispatcher toggles, each listing the operations it covers.

Everything else from #76 is preserved: CPT/taxonomy authoring as data via
acf_import_* (no executable PHP), full Pro field support
(repeater/flexible/gallery/group/clone), name->key write resolution, immutable
slugs, no delete operations.

Tests: tests/ harness reworked to the dispatcher model (49 tests — routing,
catalog, permission delegation + the 15 executors). pro/tests
ToolCatalogPlatformTest updated for the Plugins tab. Full suite 928 green;
live-verified end-to-end against ACF 6.8.5, including over the real MCP stdio
transport (acf-read exposed, acf-write hidden while off). Versioned 3.2.1.

Co-Authored-By: DeibyRo <[email protected]>
Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-11 17:18:23 +05:00
deibyRoandClaude Fable 5 1ab1713c16 Tests: ACF CPT/taxonomy coverage + 6.1 API stubs
Fixture-driven stubs for acf_get_acf_post_types/taxonomies,
acf_import_post_type/taxonomy, acf_get/update_internal_post_type, plus
post_type_exists/taxonomy_exists. 14 new cases: full 15-tool
registration, read/write annotations, key generation on create,
duplicate/reserved/overlong slug rejection, immutable slug on update,
taxonomy object_type requirement, list filtering, and manage_options
gating. 43 tests / 150 assertions green.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-10 12:28:45 -05:00
deibyRoandClaude Fable 5 aa8280beba Tests: standalone public tests/ harness with WP+ACF stubs; ACF abilities coverage
The root phpunit.xml points at the private pro/tests submodule that
outside contributors cannot fetch, so tests/ is a self-contained
harness (fixture-driven WordPress + ACF stubs) runnable with plain
PHPUnit: vendor/bin/phpunit -c tests/phpunit.xml. 29 tests covering
registration, permissions, target validation, name-to-key resolution,
flexible layout validation, the Pro gate, value normalization, and the
field-group authoring guardrails. Un-ignores /tests/ so the public
suite is committable.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-10 11:37:45 -05:00
Mian Shahzad RazaandClaude Fable 5 84b85ccaf8 feat: split Pro tier into private emcp-pro submodule (pro/)
Move all Pro-tier code + tests/ + tools/ out of this public repo into the
private msrbuilds/emcp-pro repo, mounted as a git submodule at pro/. No Pro
source ships in any free artifact.

- EMCP_Tools_Pro_Loader: dual-root conditional loader (plugin root in the
  premium build where pro/* is overlaid; pro/ in a dev checkout). Free plugin
  runs with pro/ absent — every Pro require/instantiation guarded.
- Bootstrap, widget-store, uninstaller guarded; admin AI-Chat/Skills tabs fall
  back to an upsell CTA when pro/ is absent.
- pro-manifest.txt is the authoritative Pro-path list; verify-release-zip.sh
  hard-fails if any Pro path leaks into the free zip.
- Free build (pro/ absent) = 115 abilities, no fatal; Pro present = 134
  (identical to pre-split). PHPUnit 604 pass / 1 pre-existing skip.

Squashed from feature/ai-chat to avoid publishing in-place Pro history.
Docs: CLAUDE.md (Repository topology, Release, Freemius policy).

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-02 04:29:15 +05:00
Mian Shahzad RazaandClaude Opus 4.8 6e960f84f6 fix(connect): MCPB args use ${__dirname} so node resolves server/index.js
Claude Desktop does not cd into the extracted bundle directory before
running `node`, so the relative path `server/index.js` resolved against
the wrong CWD → "Cannot find module" → instant "Server disconnected".
Prefix the entry-point with the MCPB ${__dirname} substitution variable
(the bundle's install path), matching the canonical DXT/MCPB pattern.

Verified: generated server/index.js passes `node --check` and boots
cleanly (prints startup logs, exits 0) with credentials embedded and the
correct /mcp/emcp-tools-server route.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-06-30 05:47:58 +05:00
Mian Shahzad RazaandClaude Sonnet 4.6 2a4e89af47 fix(connect): MCPB bundles self-contained CJS server/index.js (no spawn, no npx, no proxy.mjs)
Convert bin/mcp-proxy.mjs ESM→CJS on the fly and embed it directly in
server/index.js with credentials prepended. Single file, no subprocess,
no PATH resolution needed — just the Node.js binary Claude Desktop already
has. Fixes build-in-Node.js mode where server/index.js exited immediately
and fixes the npm-package old-route issue by using the local proxy source.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <[email protected]>
2026-06-30 04:04:26 +05:00
Mian Shahzad RazaandClaude Sonnet 4.6 8db6673fa7 fix(connect): bundle proxy.mjs in MCPB — no npx/network/PATH needed
Replace npx-based launch with bundling bin/mcp-proxy.mjs directly inside
the .mcpb as server/proxy.mjs. server/index.js runs it via process.execPath
(the same Node binary Claude Desktop already uses), so the extension works
with Claude Desktop's built-in Node.js without needing npx or system PATH.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <[email protected]>
2026-06-30 03:46:19 +05:00
Mian Shahzad RazaandClaude Sonnet 4.6 7b2e378fef feat(admin): exclude Elementor tools from stats counts when Elementor inactive
Co-Authored-By: Claude Sonnet 4.6 (1M context) <[email protected]>
2026-06-30 01:13:55 +05:00
Mian Shahzad Raza 5846e52b7b test(deps): harden did_action stub + add tearDown to bootstrap gate test 2026-06-30 01:01:45 +05:00
Mian Shahzad RazaandClaude Sonnet 4.6 171aba1075 feat(deps): add EMCP_Tools_Bootstrap::elementor_active() gate
Adds a single source-of-truth static method for the optional-Elementor
gate, a did_action() test stub, the Bootstrap autoload entry, the
Bootstrap test suite registration in phpunit.xml, and 2 passing tests.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <[email protected]>
2026-06-30 00:56:33 +05:00
Mian Shahzad Raza edabed0e0f fix(security): cut malware false positives (self-exclude plugin dir+sandbox, skip benign PHP guards, drop noisy backtick rule) 2026-06-27 22:49:24 +05:00
Mian Shahzad Raza 74040a43f0 test(security): harness stubs for live audit methods 2026-06-27 22:38:40 +05:00
Mian Shahzad Raza 015ad248c0 feat(security): register scan-security ability 2026-06-27 22:22:16 +05:00
Mian Shahzad Raza 7a665214f0 feat(security): scanner orchestrator (checks/score/group) 2026-06-27 22:12:21 +05:00
Mian Shahzad RazaandClaude Opus 4.8 e2275944e3 feat(security): outdated/abandoned software audit
Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-27 22:07:50 +05:00