Two custom tables, per-site (not centralised — the atomic claim UPDATE joins against the posts table, and post IDs are only unique within a single site's own posts table on Multisite): {$wpdb->prefix}lh_tasks_status and, as of 1.8.0, {$wpdb->prefix}lh_tasks_dependencies. Everything else lives in WordPress's own posts, postmeta, terms/term_relationships/term_taxonomy tables (or their per-site equivalents on Multisite).
lh_tasks-task_post
draft / pending / lh_tasks-active / private / future / trash. lh_tasks-active (added 1.6.0, replaces publish for this CPT) is required for a task to be claimable via claim_next_task(), and is registered public => false — front-end read access is gated per-task via map_meta_cap, not blanket-public. create_task() defaults to lh_tasks-active; pass draft or pending for a task that shouldn't be visible/claimable until reviewed.
{$wpdb->prefix}lh_tasks_status table)Status key (namespace lh_tasks-) | Label | Notes |
|---|---|---|
new_task | New | Initial state; claimable (subject to post_status = lh_tasks-active) |
claim_task | Claimed | Set atomically by claim_next_task(); renew_task() (the renew-claim heartbeat) keeps a task in this status while pushing claimed_at forward |
prog_task | In Progress | For workers that separate "claimed" from "started"; not set automatically |
pend_task | Pending | Manual/human-workflow use. Also set automatically (1.8.0) when a task waiting in New loses a blocked_by prerequisite to Cancelled, the trash or deletion |
revw_task | Awaiting review | Open (1.23.0, #150480). Set when someone other than the task's author marks an assigned task done. The author or staff then accepts it (Resolved) or sends it back with a note (New, still assigned to the doer). Never claimable, and mark as done is refused while a task is in it. |
fail_task | Failed | Set automatically when retries are exhausted, with the claim released (1.18.0; was block_task, "Blocked", renamed so it is not confused with a task held back by a blocked_by prerequisite, which stays New and is skipped by claims). Open, for a person to triage; edit-task with status New and reset_retries requeues it with its full retries |
res_task | Resolved | Set by complete_task(); terminal |
clos_task | Closed | Manual final closure after resolution; terminal |
cncl_task | Cancelled | Terminal |
defr_task | Deferred | Parked for later — deliberately worth doing eventually, not urgent now. Not in return_open_statuses() (won't dilute the dashboard widget/default list) and not terminal (promotable back to New later via reassign_task()) |
Status key naming (e.g. pend_task not pending_task) is unchanged from when these were post_status values constrained to 20 characters — the table column isn't constrained the same way, but there was no reason to rename and break continuity with existing data/consumers. The one exception is block_task, renamed to fail_task in 1.18.0 because the old name was actively misleading.
Table columns (as of 1.6.0, table version 2.0): post_id (PK), status, claim_token, assigned_to (BIGINT UNSIGNED NULL — hard requirement), assignee (BIGINT UNSIGNED NULL — current claim holder), claimed_at, retry_count, max_retries, created_at, updated_at.
Table version 2.1 (1.18.0) changes data, not columns: migrate_2_0_to_2_1(), run once per site from maybe_create_table() on init, moves block_task rows to fail_task, and repairs two keys that edit-task stored before 1.17.1 validated statuses: can_task to cncl_task and resolved to res_task. These are plain row updates, so no progress-log entries are written and no status actions fire. The version is in the lh_tasks_status_table_version option.
{$wpdb->prefix}lh_tasks_dependencies table, 1.8.0)One row per "task waits on blocker" edge, and the only store of blocked_by (it replaced the _lh_tasks-blocked_by post meta, which was migrated and deleted). Columns: task_id, blocker_id (primary key together), created_at; indexed on blocker_id. Version option lh_tasks_dependencies_schema_version. Rows for a permanently deleted task are removed in either column.
lh_tasks_queue — non-hierarchical, non-public. Routing/lane, e.g. email-triage. Admin column shown on the Tasks list screen.lh_tasks_task_type — non-hierarchical, non-public. Classification of the kind of work, e.g. github_triage. Distinct from queue: a queue can carry more than one task type and vice versa. Admin column shown on the Tasks list screen.lh_tasks_priority (1.15.0) — a locked set of four terms (low, normal, high, urgent), ranked by term meta order (10, 20, 30, 40). Each task carries one. Version option lh_tasks_priority_schema_version. See Architecture notes._lh_tasks-)| Meta key | Type | Description |
|---|---|---|
payload | JSON string | Machine-actionable spec for agent tasks: the ability to run and its params |
result | JSON string | Output on completion (since 1.23.0 the completion note, for a task marked done by a person), or an error object on a retryable failure. A stale error is cleared when the task is later completed |
due_date | MySQL datetime | Optional |
source_plugin | string | Slug of the plugin that created this task, e.g. lh-crm |
source_post_id | int | ID of the originating post in the source plugin |
skip_review | int (1) | Set when the task was created with requires_review false: the assignee's done resolves it without a review step. 1.23.0 |
progress_log | array of objects | Appended to by reassign_task(), update_task(), add_note(), complete_assigned_task(), review_task(), LH_Tasks_dependencies_class::flag_dependents(), LH_Tasks_follow_up_class, renew_task() (only when a note is given), and edit_task(). Each entry: timestamp, event (reassigned, heartbeat, admin_override, prerequisite_dropped, note (1.10.0), marked_done (1.11.0, when the assigned member marks it done from their profile, with their note if they gave one), follow_up and follow_up_escalated (1.16.0, written by the daily follow-up with actor 0, and never counted as activity), submitted_for_review, review_accepted and review_sent_back (1.23.0, the review step, each with to_status), or updated, which also records fields and, if the task was claimed, claimed_by), from_status/to_status (reassigned, admin_override and prerequisite_dropped only), from_assignee/to_assigned_to (reassign only), retries_reset_from (admin_override with reset_retries, 1.18.0: the retry count before it was reset), via (1.23.0: mcp when a completion or review came through an ability rather than the task page), actor (WP user ID), note |
follow_up | array | Where an assigned task is in the follow-up cycle, including when the last follow-up was sent (at); activity after that time starts the cycle again. 1.16.0 |
claim_started | Unix timestamp | When the current claim was made, set on lh_tasks_task_claimed; the start of the maximum lease for automatic renewal. 1.17.0 |
ability_calls | int | Count of write ability calls made with this task (succeeded or failed, not refused). 1.17.0 |
last_ability | array | The last such call: ability, time_gmt, success, renewed. 1.17.0 |
assignee, assigned_to, claim_token, claimed_at, retry_count, and max_retries live in the status table, not postmeta — see above. The follow-up's BuddyPress notifications carry two notification meta keys, lh_tasks_blog_id and lh_tasks_link, recording the task's site and link (1.16.0).