Controller API¶
Restart_Registry_Controller
(plugin/includes/class-restart-registry-controller.php) is the single façade
through which all registry and item operations flow. The shortcode and AJAX
handlers in Restart_Registry_Public only ever touch this class — never the
Lambda or post-meta directly.
The controller has two collaborators, both injectable via the constructor:
public function __construct(
?Restart_Registry_Lambda_Client $lambda = null,
?Restart_Registry_Affiliate_Converter $affiliate_converter = null
) { /* ... */ }
This is the seam the integration test suite uses to swap in LambdaClientFake.
Registry read¶
get_registry(int $registry_id)¶
Loads a registry by WP post ID. Returns the registry array
(post_to_registry-shaped, with items populated from the Lambda) or a
WP_Error('not_found', ...) if the post is missing or not a restart-registry.
get_registry_by_share_key(string $key)¶
Looks up by either the numeric post ID (the canonical share key) or the post
slug. Used by the ?registry=<key> URL param flow. Returns the same shape as
get_registry() or a WP_Error('not_found', ...).
get_user_registry(int $user_id): ?array¶
The first registry owned by $user_id, or null if they have none. Searches
across publish, private, and draft statuses. Used by [restart_registry]
to find the logged-in user's manage page.
Registry write¶
create_registry(int $user_id, string $title, string $description = '', bool $is_public = false)¶
Creates a restart-registry CPT post for the user. Returns:
['id' => int, 'share_key' => int] // share_key === id
Returns WP_Error('registry_exists', ...) if the user already has one
(enforced single-registry-per-user). Initializes the four post-meta keys to
empty defaults.
update_registry(int $registry_id, array $data): bool¶
Updates fields. Accepted keys:
| Key | Effect |
|---|---|
title |
wp_update_post(post_title = ...) (sanitized) |
description |
wp_update_post(post_content = ...) (textarea-sanitized) |
is_public |
Sets post_status to publish (true) or private (false) |
event_type |
Sets restart_event_type post meta |
event_date |
Sets restart_event_date post meta |
Always returns true.
delete_registry(int $registry_id): bool¶
Deletes the WP post and every Lambda item linked via restart_item_ids
(best-effort). Forces deletion (skips trash). Returns the result of
wp_delete_post.
Items¶
get_registry_items(int $registry_id): array¶
Reads restart_item_ids and fans out to Lambda_Client::get_items(). Order
is preserved from the meta array. IDs that 404 in the Lambda are silently
skipped (the controller treats them as deleted).
get_item(int $item_id)¶
Pass-through to Lambda_Client::get_item().
add_item(int $registry_id, array $data)¶
Required keys: name, url. Optional: description, price, quantity,
image_url.
Steps:
- Run the URL through
Affiliate_Converter::convert_url()— setsretailer,affiliate_url,affiliate_statuson the Lambda payload when applicable. - Truncate the name to 100 chars on a smart separator (
truncate_name()tries-,|,:, en/em-dashes, then,, then a word boundary). - POST to the Lambda.
- Append the new item ID to
restart_item_idspost meta.
Returns:
['id' => int, 'is_affiliate' => bool, 'retailer' => string, 'html_item' => array]
Or a WP_Error if the Lambda call fails.
update_item(int $item_id, array $data)¶
Accepted keys: name, url, description, price, quantity (mapped to
quantity_needed), image_url. Empty update payload returns
WP_Error('no_data', ...).
delete_item(int $item_id, int $registry_id): bool¶
Deletes from Lambda and removes the ID from restart_item_ids.
mark_item_purchased(int $item_id, int $quantity = 1, string $purchaser_name = '', string $purchaser_email = '', string $purchaser_note = '', bool $is_anonymous = false)¶
Increments quantity_purchased on the Lambda item, then sends an email
notification to the registry owner via send_purchase_notification().
- Returns
WP_Error('not_found', ...)if the item is missing. - Returns
WP_Error('quantity_exceeded', ...)if the request would pushquantity_purchasedabovequantity_needed. - Honors the owner's
restart_notify_on_purchaseuser meta — if set to'0', the email is skipped.
The notification email is plain text and includes the purchaser name (or
"Someone" for anonymous), the item name, an optional note from the purchaser,
and a link back to the registry. From: uses the restart_registry_email_from
and restart_registry_email_name options when set.
Invites¶
send_invite(int $registry_id, string $invitee)¶
Adds $invitee (a username or an email) to restart_invitees. Returns
WP_Error('already_invited', ...) if it is already there. If $invitee
parses as an email, sends an invite email via wp_mail.
Returns:
['invite_id' => int] // index into the invitees array
get_registry_invites(int $registry_id): array¶
Returns the invitees as [['id' => 0, 'email' => '...'], ['id' => 1, 'email' =>
'...'], ...] for easy iteration in templates.
Access control¶
can_view_registry(int $registry_id, ?int $user_id = null): bool¶
True when any of:
- The registry's post status is
publish(public). $user_idis the post author.$user_idhas themanage_restart_registrycapability (admins).$user_id's email oruser_loginappears inrestart_invitees.
False when the post does not exist or is not a restart-registry CPT.
can_edit_registry(int $registry_id, int $user_id): bool¶
True when $user_id is the post author or has
manage_restart_registry. There is no invitee-level edit access.
Private helpers worth knowing¶
truncate_name(string $name): string¶
Caps an item name at 100 chars, preferring a clean break on common
product-name separators (-, |, :, –, —, ,) before falling
back to a word-boundary cut. Used in add_item() and update_item().
This is what keeps Amazon-style "Brand X 12-piece Premium Knife Set with Wooden Block, Stainless Steel ..." titles from overflowing the UI.
send_purchase_notification(array $item, string $purchaser_name, string $purchaser_note): void¶
Internal — invoked from mark_item_purchased(). Composes the email body and
sends with wp_mail.