git clone https://github.com/ateeducacion/wp-decker.git
cd wp-decker
composer install
make upWordPress: http://localhost:8888
Credentials: admin / password
| Command | Description |
|---|---|
make up |
Start the development environment |
make down |
Stop it |
make test |
Run PHPUnit tests |
make lint |
PHP_CodeSniffer |
make fix |
Auto-fix coding standards |
make check |
Full check (lint + tests + plugin-check) |
make pot |
Regenerate translation template |
make package VERSION=x.y.z |
Build a release ZIP |
make help |
List all targets |
- WordPress Coding Standards
- English for code, comments and identifiers
- Spanish for user-facing strings
- Every new/changed string must update the
.pot/.po/.moin the same commit (make check-untranslated)
See AGENTS.md and CONVENTIONS.md for detailed agent and project conventions.
Skills are folders of instructions an AI coding agent loads on demand. They live
under .agents/skills/ (Copilot, Codex, Cursor) and .claude/skills/
(Claude Code). Grok Build reads Claude Code skills automatically. Install and
refresh them with the GitHub CLI:
gh skill add WordPress/agent-skills wp-performance --agent github-copilot
gh skill add WordPress/agent-skills wp-performance --agent claude-code
gh skill update --allgh skill add is an alias of gh skill install. Each host gets its own copy;
older Claude Code entries remain as symlinks into .agents/skills/. Do not
convert one layout into the other by hand.
| Skill | Read it before |
|---|---|
wp-plugin-development |
Touching hooks, activation/uninstall, the Settings API, options, cron or release packaging |
wp-rest-api |
Adding or debugging routes: register_rest_route, permission_callback, schema/args, register_meta, show_in_rest |
wp-plugin-directory-guidelines |
Editing readme.txt, license headers or plugin naming — what make check-plugin enforces |
blueprint |
Editing blueprint.json or the Playground preview |
wp-performance |
Profiling or improving backend performance |
wp-project-triage |
Inspecting what kind of WordPress repo this is before changing tooling |
wp-plugin-security |
Writing or reviewing code that handles input, output, AJAX/REST, capabilities or files |
security-audit |
Hunting vulnerabilities and validating findings |
The WordPress ones come from WordPress/agent-skills
(GPL-2.0-or-later); wp-plugin-security from
fernandotellado/ai-skills;
security-audit from
cloudflare/security-audit-skill.
All of them are vendored verbatim. Do not reformat or patch them locally —
gh skill update is how they stay current.
Nothing under .agents/, .claude/, AGENTS.md or CLAUDE.md reaches the
release ZIP; .gitattributes marks it export-ignore.
do_action( 'decker_task_created', $task_id );
do_action( 'decker_task_updated', $task_id );
do_action( 'decker_stack_transition', $task_id, $source_stack, $target_stack );
do_action( 'decker_task_completed', $task_id, $target_stack );
do_action( 'decker_user_assigned', $task_id, $user_id );apply_filters( 'decker_save_task_send_response', true );The hooks above, plus Decker_Task_Writer::create_or_update_task( array $args ), are
what integrations should build on. Everything else — class names, method names, which
class registers which callback — is internal and gets reorganised as classes grow.
Most public methods on these classes are public only because WordPress needs to call them as hook callbacks. Calling them directly, or unhooking them by name, is not supported.
Symbols that have moved, so an integration that referenced the old location can find the new one. None of these changed behaviour; only their owner changed.
| Was | Is now |
|---|---|
Decker_Boards::add_color_field() / edit_color_field() / save_color_meta() |
Decker_Board_Term_Fields (extends Decker_Term_Color_Field) |
Decker_Labels::add_color_field() / edit_color_field() / save_color_meta() |
Decker_Term_Color_Field |
Decker_Kb::track_last_editor() / get_last_editor() / get_latest_revision_id() / get_revision_admin_url() |
Decker_Kb_Revisions |
Decker_Events::add_meta_boxes() / display_users_meta_box() / render_event_details_meta_box() |
Decker_Event_Meta_Box |
Decker_Events::hide_visibility_options() / add_custom_columns() / render_custom_columns() |
Decker_Event_Admin_Screen |
Decker_Admin_Settings::*_render() (16 field renderers) / section callbacks |
Decker_Admin_Settings_Fields (single public render() dispatcher) |
Decker_Admin_Settings private validators |
Decker_Admin_Settings_Validator::validate() |
Decker_Notification_Handler::add_notification_to_user() / remove_notification_from_user() |
Decker_Notification_Store |
Decker_Notification_Handler::MAX_NOTIFICATIONS (public constant) |
Decker_Notification_Store::MAX_NOTIFICATIONS |
Decker_Notification_Handler::heartbeat_received() / modify_heartbeat_settings() / ajax_*() |
Decker_Notification_Ajax |
Decker_Events meta-saving pipeline (bodies; process_and_save_meta() / save_event_meta() stay as public delegators) |
Decker_Event_Meta_Saver |
Decker_Email_To_Post attachment pipeline (upload_attachment() and helpers) |
Decker_Email_Attachment_Uploader |
Decker_Email_To_Post board directive resolution |
Decker_Email_Board_Resolver |
Decker_Demo_Data task/comment seeding and randomness helpers |
Decker_Demo_Tasks, Decker_Demo_Randomizer |
Decker_Calendar::handle_ical_request() / add_ical_endpoint() and access checks |
Decker_Calendar_Ical_Feed |
Decker_Calendar::get_cached_ical() / flush_cache_*() |
Decker_Calendar_Cache |
Decker_Kb::save_article() and the write path |
Decker_Kb_Article_Writer |
Decker_Kb::reorder_articles() and sibling renumbering |
Decker_Kb_Reorder |
TaskManager "for today" query bodies (public entry points stay as delegators) |
Decker_Task_Today_Query, Decker_Task_Date_Relations |
Decker_Tasks::clone_task() and its private readers |
Decker_Task_Clone |
Decker_Tasks::merge_tasks() and the merge pipeline |
Decker_Task_Merge |
Decker_Tasks lock REST routes + refresh_task_lock_heartbeat() |
Decker_Tasks_Rest_Locks |
Decker_Tasks today REST routes (handle_task_today(), mark/unmark relations) |
Decker_Tasks_Rest_Today |
Decker_Tasks field-op REST routes + REST insert guards |
Decker_Tasks_Rest_Ops |
Decker_Tasks::search_tasks() / clone + merge REST transport |
Decker_Tasks_Rest_Tools |
Decker_Tasks::make_permission_callback() / lock_error_response() |
Decker_Tasks_Rest_Support (public statics) |
Decker_Tasks order/stack engine (update_task_stack_and_order(), handle_fix_order(), reorder_tasks_in_stack(), get_new_task_order()) |
Decker_Task_Order |
Decker_Tasks order hook reactions (post-data filter, board/stack term changes) |
Decker_Task_Order_Hooks |
Decker_Tasks edit-screen meta boxes (add_meta_boxes() and the eight display/render methods) |
Decker_Task_Meta_Boxes |
Decker_Tasks admin list table (columns, sorting, taxonomy/status filters, row actions) |
Decker_Task_Admin_List |
Decker_Tasks edit-screen chrome (visibility/menu-order/permalink hiding, publish box title, Gutenberg disable, Add New removal) |
Decker_Task_Admin_Chrome |
Decker_Public::enqueue_scripts() body |
Decker_Public_Assets |
Decker_Tasks::save_meta() and the private meta-save pipeline |
Decker_Task_Meta_Saver |
Decker_Tasks::handle_save_decker_task() + lock guards |
Decker_Task_Ajax_Save (no delegator — direct callers must retarget) |
Decker_Tasks $_POST readers |
Decker_Task_Request_Reader |
Decker_Tasks::add_user_date_relation() / remove_user_date_relation() |
Decker_Task_Today_Manager::mark_for_today() / unmark_for_today() |
Decker_Tasks::create_or_update_task() and the write pipeline |
Decker_Task_Writer::create_or_update_task( array $args ) — signature changed, no delegator |
Task::render_task_card() and the card display helpers (get_card_background_style(), get_due_css_class(), render_card_board_name(), render_card_comments_counter(), render_card_labels_counter(), render_people_avatars(), get_relative_time(), get_formatted_date(), pastelize_color()) |
Decker_Task_Card_Renderer — pastelize_color() became a public static (parameter-pure); get_relative_time() / get_formatted_date() stay public instance methods |
Task::render_task_menu() and the menu-item builders (get_menu_task_url(), get_admin_menu_items(), get_owner_menu_items(), get_archive_menu_item(), get_assignment_menu_items(), print_menu_dropdown()) |
Decker_Task_Menu_Renderer |
Task::get_people_users() / get_people_names() / get_user_history_with_objects() |
Decker_Task_People_View |
Note that unhooking one of these by name fails silently rather than fatally:
// No longer matches anything; the field still renders.
remove_action( 'decker_board_add_form_fields', array( $boards, 'add_color_field' ) );To suppress a field, unhook the current owner, or filter the markup it produces.
Tests live under /tests/ and use factories.
Run with make test.
- Create a feature branch.
- Make your changes following the coding standards and translation rules.
- Run
make check. - Open a Pull Request.