Integrate with Elementor's Angie - #705
Conversation
|
Test on Playground |
✅ Code Coverage Report
🎉 Great job maintaining/improving code coverage! 📊 File-level Coverage Changes (4 files)🆕 New Files
📈 Coverage Improved
ℹ️ About this report
|
|
Notes from the recent commits:
We should be careful when defining schema, docs are not that clear and a small mistake can cause Progress Planner MCP server (or tools) not to be registered. |
🔍 WordPress Plugin Check Report
📊 Report
|
| 📍 Line | 🔖 Check | 💬 Message |
|---|---|---|
232 |
WordPressVIPMinimum.Performance.WPQueryParams.PostNotIn_post__not_in | Using exclusionary parameters, like post__not_in, in calls to get_posts() should be done with caution, see https://docs.wpvip.com/databases/optimize-queries/using-post__not_in/ for more information. |
377 |
WordPressVIPMinimum.Performance.WPQueryParams.PostNotIn_post__not_in | Using exclusionary parameters, like post__not_in, in calls to get_posts() should be done with caution, see https://docs.wpvip.com/databases/optimize-queries/using-post__not_in/ for more information. |
381 |
WordPressVIPMinimum.Performance.WPQueryParams.PostNotIn_post__not_in | Using exclusionary parameters, like post__not_in, in calls to get_posts() should be done with caution, see https://docs.wpvip.com/databases/optimize-queries/using-post__not_in/ for more information. |
388 |
WordPressVIPMinimum.Performance.WPQueryParams.PostNotIn_post__not_in | Using exclusionary parameters, like post__not_in, in calls to get_posts() should be done with caution, see https://docs.wpvip.com/databases/optimize-queries/using-post__not_in/ for more information. |
📁 classes/suggested-tasks/data-collector/class-unpublished-content.php (1 warning)
| 📍 Line | 🔖 Check | 💬 Message |
|---|---|---|
103 |
WordPressVIPMinimum.Performance.WPQueryParams.PostNotIn_post__not_in | Using exclusionary parameters, like post__not_in, in calls to get_posts() should be done with caution, see https://docs.wpvip.com/databases/optimize-queries/using-post__not_in/ for more information. |
📁 classes/suggested-tasks/data-collector/class-yoast-orphaned-content.php (1 warning)
| 📍 Line | 🔖 Check | 💬 Message |
|---|---|---|
111 |
PluginCheck.Security.DirectDB.UnescapedDBParameter | Unescaped parameter $query used in $wpdb->get_row()\n$query assigned unsafely at line 98. |
📁 classes/suggested-tasks/data-collector/class-terms-without-description.php (1 warning)
| 📍 Line | 🔖 Check | 💬 Message |
|---|---|---|
108 |
PluginCheck.Security.DirectDB.UnescapedDBParameter | Unescaped parameter $query used in $wpdb->get_results()\n$query assigned unsafely at line 106. |
📁 classes/suggested-tasks/data-collector/class-terms-without-posts.php (1 warning)
| 📍 Line | 🔖 Check | 💬 Message |
|---|---|---|
120 |
PluginCheck.Security.DirectDB.UnescapedDBParameter | Unescaped parameter $query used in $wpdb->get_results()\n$query assigned unsafely at line 118. |
📁 classes/activities/class-query.php (2 warnings)
| 📍 Line | 🔖 Check | 💬 Message |
|---|---|---|
71 |
PluginCheck.Security.DirectDB.UnescapedDBParameter | Unescaped parameter $table_name used in $wpdb->query()\n$table_name assigned unsafely at line 58. |
163 |
PluginCheck.Security.DirectDB.UnescapedDBParameter | Unescaped parameter $where_args used in $wpdb->get_results()\n$where_args assigned unsafely at line 153. |
🤖 Generated by WordPress Plugin Check Action • Learn more about Plugin Check
Three test files conflicted (add/add): both branches had written tests for select-locale, select-timezone and core-blogdescription. Resolved by taking develop's versions. That is not the obvious choice -- this branch's versions were larger and better designed (they complete a task by setting the real option, where develop's fake it by inserting a Suggested_Task activity, which is what produces the "Column 'type' cannot be null" noise in the test output). But they target complete_task() on the task providers, which develop removed in the onboarding rework (39a2e0d). All 17 errored. The same removal broke the feature itself, not just its tests: Angie_API::complete_task() called $task_provider->complete_task(), a fatal on every Angie task completion. Ported to the replacement contract. The providers now apply settings through handle_interactive_task_submit(), which reads $_POST and terminates with wp_send_json_*(). A REST callback has to return a response, so that method cannot be called from one. The update is performed in Angie_API::update_task_setting() instead, which reuses the provider's option whitelist (and its filter) rather than bypassing it -- this endpoint can only write options the interactive tasks could already write, which the old complete_task() path did not enforce. get_angie_tasks_map() consequently maps task IDs to option names (WPLANG, timezone_string) rather than the old per-task argument names. Timezone handling mirrors Select_Timezone: a UTC+/- value is stored as a numeric gmt_offset, a named zone as a timezone_string, never both. Adds 6 tests for the new path: the whitelist rejecting an off-list option, a whitelisted option being written, non-scalar and empty values rejected before anything is written, and the two timezone formats plus an unrecognised one. Verified by mutation -- removing the whitelist, the scalar guard, the empty guard or the timezone branch each fail tests. Note the named-timezone test does not assert gmt_offset is emptied: WordPress core recomputes it from timezone_string, so it reads back as that zone's offset rather than the '' written here.
A local vendor symlink used to run the test suite in a worktree was swept
into the merge commit by git add -A, which broke the Build plugin step
("Broken symlink at /vendor").
Angie 1.1.12 collects MCP-capable plugins through the angie_mcp_plugins filter and passes the result to its app as window.angieConfig.plugins. Progress Planner was not in that list, so the MCP server script this integration enqueues registered into nothing -- confirmed against a live install, where the filter returned only ["elementor_pro"]. Add the filter, matching how Angie's own Elementor module registers. This is unverified beyond the PHP layer. Angie's app is fetched at runtime from editor-static-bucket.elementor.com, so whether it does anything with a third-party key cannot be determined from this codebase; every other entry in that list is published by Elementor. The app also only enqueues on Angie's own admin screens and behind a consent gate and an account, none of which are reachable from WP-CLI. Needs a manual pass with a real Angie account to confirm.
get_tasks_by_status() returned only the three recommendations Angie can complete itself and silently dropped the rest, so asking Angie to list tasks on a site with 19 open recommendations reported two -- and on a site where none of those three happened to be open, it reported none at all. The endpoint answers "what are my tasks", so it now returns all of them and marks each with can_complete. This does not widen what Angie can change: complete_task() enforces the same map, and can_complete simply tells Angie which ones it can act on. complete_task() previously fell through to $task->celebrate() for any task ID that was not in the map, marking the recommendation done without touching the site it described -- the user would be told their site had been changed when nothing had. It now returns task_not_completable and leaves the recommendation open. Two existing tests asserted the old filtering (one asserted a count of 0 with two tasks present, which is the reported behaviour) and have been rewritten. Adds a test that a task Angie cannot handle is refused and stays open. Verified against a live Angie 1.1.12 install: the endpoint returned 0 tasks before this change on a site with 16 open recommendations, and 19 with 2 completable after.
Tested against a live Angie 1.1.12 installNotes from bringing this branch up to date, since a couple of things here are easy to miss. It works now, but it needed a registration changeAngie 1.1.12 discovers MCP-capable plugins through the Added in 21ac0b8, matching how Angie's own Elementor module registers. After that, Angie discovers the tools and calls them: the composer shows a Progress Planner badge and the task list renders with action buttons. The "you have no active tasks" bug
On a live site that meant: None of those 16 happened to be one of the three, so Angie reported "You currently have no active tasks in Progress Planner" on a site with 16 open recommendations. Even once two of the three existed, it listed 2 of 19 with no indication the rest were hidden. Fixed in 8789e42: every recommendation is listed, each carrying a A second bug found while fixing that one
It now returns The provider API had moved out from under this branchWorth flagging for anyone picking this up: develop's onboarding rework (39a2e0d) removed The replacement ( Also: three test files ( Still open
|
Notes: porting to the Abilities API (Path B)Recording the design discussion so it isn't lost. Nothing here is implemented — this is what a port would involve if we continue the Angie integration. Why bother, when the current approach worksThe integration works today (see previous comment): Angie discovers the MCP server via The argument for moving is that completion should go through plugin code, not around it. For a side-effect-free task like the tagline, Framing the simple tasks as a canary for the integration is the right instinct. It only works if the completion demonstrably routes through our code. What already exists on this branchWorth stating, because analysis done against
So the "we need a REST equivalent of the AJAX handler" step is already done. What's missing is only the ability registration layer. What a port would addFollowing Angie's own pattern (
Both routes already exist and are tested, so this is a registration layer over them rather than new endpoint work. The payoff is that abilities are consumer-agnostic: they'd serve Angie and any other MCP client, and would let us delete the ~500-line TS source and its ~12k committed Where to register itProgress Planner registering its own, guarded by Blocker for local workAngie's Checked on this install:
So this can't be developed or tested locally as-is. Needs either an Angie build with its Composer deps, or Separate bug worth fixing regardless
$updated = \update_option( $setting, $value );
if ( ! $updated ) {
\wp_send_json_error( [ 'message' => … 'Failed to update setting.' ] );
}
The REST route on this branch doesn't inherit it (it doesn't check the return value), but the two should agree on what "success" means — worth fixing on |
This PR implements https://github.com/ProgressPlanner/progress-planner-pro/issues/182 (still WIP of course)
Technically implementation is described in README.md, so I will focus more on testing initial implementation and what needs to be done in the future.
When Progress Planner MCP server is registered Angie becomes aware of it and it is smart when you ask her about it, for example queries like "List me all (completed) Progress Planner tasks" work without the a problem.
Tasks like "Can you complete 'Set site tagline' Progress Planner task for me? I would like to set tagline to 'Thank you!'" work fine most of the time.
Good example is "Can you complete the "Set site timezone" Progress Planner task? I would like to set the timezone to Amsterdam" as well. It is smart enough to pass Europe/Amsterdam to our API callback so the
timezone_stringwp_optionis correctly set.Completing the "Set site locale" didnt work for me, what Angie did was that it set the site locale (by setting the
wp_optiondirectly) and then tried to mark PP task as completed through our API endpoint. That is the thing which we need to be careful when testing, as PP plugin codebase will mark task as completed if the condition is satisfied, but it doesnt mean that it was completed through the Angie integration itself. More on that below.Also my tries to tell it to complete the "Set the site icon" task to the icon which I have uploaded failed, it didn't even add icon to the Media library
Angie runs in an iframe and the WP Dashboard on the right doesn't update without refreshing it. Mentioning it since it will look a bit weird if Angie says that she changed site locale but change is not visible right away. This can be especially be weird if we trigger confetti (yes, it should be possible to do some kind of celebration at least) but in order to do so we need to make sure that tasks are completed through our integration (not by setting
wp_optionsdirectly).That can probably be improved by providing better context to Angie here.
When testing be aware that you have (only) 900 tokens per day on a free plan.
One technical note, code is placed in this way so our autoloader works (at first I placed it in
./third-party/angie, but autoloader requires classes only from classes directory) so we will probably move it to a better place.