StitchPress

Home / Docs / Developers

Developers

StitchPress is extended through WordPress actions and filters. Every hook name starts with stp_. Where a setting and a filter cover the same value, the settings screen hooks that filter at the default priority (10). Hook the same filter at priority 11 or higher and your value wins over the setting.

Hooks and filters

Arguments are listed in order. "Action" means do_action, everything else is a filter.

Extension points

Hook Arguments Use
stp_settings_schema $schema Add options: name => type, default, label, description, section, choices, sanitize. An entry with a section gets a field on the settings screen. Read with STP_Settings::get().
stp_settings_sections $sections Add settings sections: id => title, description, priority.
stp_admin_menu (action) $parent, $cap Add a screen under the StitchPress menu with add_submenu_page( $parent, ... ).
stp_admin_submenus $entries Declarative alternative: a list of slug, title, menu_title, capability, callback.
stp_rest_routes $routes, $namespace Add REST routes under stitchpress/v1 (see below).
stp_rest_init (action) $namespace After StitchPress routes are registered.
stp_email_classes $emails Add WC_Email classes: id => instance or class name.
stp_email_templates $templates Email template map: id => html and plain paths relative to templates/.
stp_module_dirs $dirs Folders scanned for StitchPress modules.
stp_modules_loaded (action) $classes After every module's register() ran.
stp_event (action) $name, $context Every StitchPress domain event (see Events).
stp_log_debug_enabled $on Force debug logging on or off.

Templates and methods

Hook Arguments Use
stp_decoration_methods $methods The method registry. Add a method (label, palette label, colors per element, accepted artwork, pricing dimensions, setup fee unit, sheet fields, estimators) without editing core.
stp_resolve_template_for_product $resolved, $product_id The template a product resolves to. Return null to disable decoration on a product.
stp_template_category_terms $terms, $parent_id Reorder or filter the categories consulted during resolution.
stp_template_config $config, $template_id A decoded template config on read.
stp_template_default_config $config The skeleton for new templates.
stp_template_saved (action) $template_id, $config After a template is stored.
stp_template_config_invalid (action) $template_id, $reason A stored config could not be decoded.
stp_pricing_models_for_method $models, $method_key, $definition Pricing models a method may use.
stp_setup_fee_units $units Accepted setup-fee counting units.
stp_palettes_options $options Palettes offered in the template editor.

Pricing and setup fees

Hook Arguments Use
stp_price_for_item $amount, $item, $spec, $config, $qty Price of one placement, before tiers.
stp_price_for_spec $amount, $spec, $config, $qty Final per-unit decoration charge. A change adds an "Adjustment" row to the breakdown.
stp_pricing_breakdown $lines, $spec, $config, $qty Breakdown rows (label, amount). Change totals through stp_price_for_spec so rows still add up.
stp_pricing_model_lines $lines, $model, $items, $block, $spec, $config, $qty Price a custom pricing model.
stp_pricing_config_for_record $config, $spec, $product_id, $live_config The config a design is priced against (default: the template it was captured on).
stp_pricing_boot_data $out, $config Pricing data sent to the designer.
stp_pricing_cart_item_priced (action) $cart_item_key, $surcharge, $base, $spec, $cart After a cart line is repriced.
stp_pricing_missing_config (action) $method, $spec, $config A design's method has no pricing block; it is priced at 0.
stp_pricing_unknown_model (action) $model, $method, $spec A stored pricing model has no implementation.
stp_pricing_template_drift (action) $spec_template_id, $live_id, $product_id, $spec The product now resolves to a different template than the design's.
stp_pricing_template_unresolved (action) $product_id, $spec_template_id, $spec The design's template is gone; priced from the product's current one.
stp_pricing_error (action) $e, $context Pricing caught an exception (the cart never fatals).
stp_setup_fee_item_signatures $signatures, $unit, $item What counts as one setup unit for an item.
stp_setup_fee_units_count $count, $method_key, $signatures, $cart Setup units charged per method.
stp_setup_fee_waived $waived, $method_key, $decorated_subtotal, $fee, $cart Whether the setup fee is waived.
stp_setup_fee_amount $amount, $method_key, $count, $fee, $cart The setup fee amount.
stp_setup_fee_label $label, $method_key, $unit, $count The fee line label.
stp_setup_fee_taxable $taxable, $method_key, $cart Whether the fee is taxable (default: store tax setting).
stp_setup_fee_tax_class $tax_class, $method_key, $cart Tax class for the fee.
stp_setup_fee_conflict (action) $method_key, $winner, $loser, $cart Two templates in one cart set different fees; the higher wins.
stp_underbase_charges_screen $charges, $method_key Whether a definite underbase is billed as an extra screen.

Designer and cart

Hook Arguments Use
stp_capture_usable_config $usable, $resolved What the designer may offer on a product. Return null to hide it.
stp_capture_boot_data $boot, $usable, $product The data handed to the designer script.
stp_capture_launcher_label $label, $product The launcher button text (default "Design yours"; the Launcher button label setting overrides it).
stp_capture_display $display, $usable, $modes inline (a card in the product page, the default when visual placement is on) or modal (a popup).
stp_capture_launcher_blocks $blocks Block names the launcher is injected into on block themes.
stp_inline_boot $inline Print the boot module inline (default) or as a file.
stp_capture_modes_for_method $modes, $method_key, $definition Text and artwork modes per method.
stp_capture_colors_required $required, $mode, $cardinality, $definition Whether an element must carry a color.
stp_capture_popular_tier $tier, $entries, $palette_id Palette tier shown before "More colors". Return '' to show the first 24 colors instead.
stp_capture_record $record, $raw, $usable A validated design record, before the save-path check.
stp_capture_item_summary $summary, $item One-line summary of a placement in the cart and order.
stp_capture_show_price_row $show, $record Hard off switch for the cart price rows.
stp_capture_price_breakdown $mode, $record Cart detail: rows, total or off.
stp_capture_show_edit_link $show, $cart_item, $cart_item_key Whether a cart line offers "Edit design".
stp_capture_edit_link_label $label, $cart_item The edit link text.
stp_capture_ajax_success $payload, $cart_item_key, $cart_item AJAX add-to-cart success payload.
stp_capture_ajax_error $payload, $code AJAX add-to-cart error payload.
stp_capture_cart_line_rejected (action) $cart_item_key, $error_code, $product_id A cart line was removed because its design failed validation.
stp_capture_cart_line_replaced (action) $old_key, $new_key, $product_id A re-edited cart line replaced the old one.
stp_capture_spec_write_failed (action) $item, $code A design record could not be saved onto an order line.
stp_capture_estimate_failed (action) $e, $item, $record No estimate could be produced for an order line.
stp_capture_variation_template_ignored (action) $variation_id, $variation_template_id, $parent_template_id A variation-level template was ignored.
stp_save_design_rate_limit, stp_save_design_global_limit, stp_save_design_max_bytes $value Limits for guest "Save design": per client per hour (30), shop-wide per hour (600), bytes (64 KB).

Uploads and artwork

Hook Arguments Use
stp_artwork_max_bytes $max Artwork size limit (default 10 MB).
stp_artwork_rate_limit $limit Uploads per client per hour (default 20).
stp_artwork_client_ip $ip The client IP the upload and Save design limits count against (default REMOTE_ADDR).
stp_artwork_uploaded (action) $rel, $result After an artwork file is stored.
stp_artwork_gc_max_age $seconds Age before unreferenced artwork is deleted (default 30 days).
stp_artwork_gc_delete $delete, $path, $basename Last chance to keep a file the cleanup is about to delete.

Palettes and fonts

Hook Arguments Use
stp_palette_boot_entries $entries, $palette_id Palette entries sent to the designer.
stp_palette_imported (action) $palette_id, $imported, $skipped After a CSV import.
stp_palette_deleted (action) $palette_id After a palette is deleted.
stp_font_max_bytes $max Font size limit (default 5 MB).
stp_font_faces_css $css, $fonts, $font_ids The @font-face CSS StitchPress prints.
stp_fonts_changed (action) none A font was added, deleted, reordered or toggled.

Production estimates

Hook Use
stp_estimates_enabled Estimates on or off.
stp_estimate_customer_visible Whether the estimate is written onto the order and emails.
stp_estimate_for_record The finished estimate record ($estimate, $spec, $config, $qty, $product_id) before it is stored.
stp_estimate_meta_description The one-line customer-visible summary.
stp_estimate_warning_text A rendered warning ($text, $key, $data, $method).
stp_estimate_underbase The underbase conclusion for a line.
stp_estimates_boot_data Estimator data sent to the designer.
stp_estimate_error (action) The estimator caught an exception.
stp_estimate_band_pct, stp_emb_density, stp_emb_stitches_per_char, stp_emb_min_text_height, stp_emb_max_area, stp_emb_artwork_coverage, stp_emb_detail_tones, stp_artwork_min_dpi, stp_sp_max_colors, stp_underbase_mode, stp_underbase_attribute, stp_underbase_dark_terms, stp_tier_nudge, stp_tier_nudge_within The constants behind the settings of the same names.
stp_estimate_advance_ratio, stp_estimate_cap_ratio, stp_estimate_height_exponent, stp_estimate_alpha_cut, stp_estimate_white_cut, stp_estimate_max_analysis_pixels Text-measurement and artwork-analysis constants.

Previews

Hook Use
stp_preview_enabled Turn cart preview pictures off ($enabled, $record).
stp_preview_format webp or png.
stp_preview_width Width in pixels.
stp_preview_max_decode_pixels Pixel ceiling for one render.
stp_preview_gc_max_age Age before unused previews are deleted.

Proofs

Hook Arguments Use
stp_proofs_hold_order $hold, $order Kill switch for the production gate.
stp_proofs_gate_statuses $statuses, $order Statuses whose arrival puts an order on the gate (default processing, on-hold, completed).
stp_proofs_terminal_statuses $statuses, $order Statuses in which the proof workflow does nothing.
stp_proof_token_ttl_days $days Link lifetime after upload (default 60).
stp_proof_max_bytes $max Proof file size limit (default 20 MB).
stp_proof_client_ip $ip The client IP recorded on decisions and counted by the decision limit.
stp_proof_email_subject, stp_proof_email_body see Emails The Proof ready email.
stp_proof_confirm_customer $send, $order, $decision, $round Whether to send the customer confirmation.
stp_proof_confirm_subject, stp_proof_confirm_body The customer confirmation.
stp_proof_notify_admin_on_approve $notify, $order Whether to email the shop on approval.
stp_proof_admin_email $email, $order Shop notice recipient.
stp_proof_admin_notification $mail, $order, $round, $decision Shop notice: to, subject, body.
stp_proof_contact, stp_proof_logo Contact line and logo on the proof page.
stp_proof_round_added (action) $order, $number A round was uploaded.
stp_proof_sent (action) $order, $number, $email A round was emailed.
stp_proof_approved (action) $order, $round, $data A round was approved.
stp_proof_changes_requested (action) $order, $round, $data The customer asked for changes.
stp_proof_hold_released (action) $order, $reason The gate was canceled without an approval.

Job Jacket and production queue

Hook Use
stp_sheet_render_order The rendered Job Jacket for an order ($html, $order).
stp_sheet_render_item One line item's section ($html, $item, $spec).
stp_sheet_css The Job Jacket stylesheet.
stp_sheet_field_labels Production field labels.
stp_sheet_estimate_warning_labels Operator wording for estimate warnings.
stp_sheet_item_proof_banner The per-item proof banner.
stp_sheet_proof_width Width of the proof picture.
stp_sheet_inline_image_exts Artwork types shown inline.
stp_sheet_arc_preview_max_chars Longest text the arc preview draws.
stp_production_field_choices Fixed choices on the Confirm production values form.
stp_queue_statuses Statuses the production queue covers.
stp_queue_scan_limit How many recent decorated orders the queue inspects.
stp_queue_proof_state The queue's proof cell.

Skins

Hook Arguments Use
stp_skin_url $url, $key URL of the skin file to load; empty string loads none. See Skins.
stp_skin_choices $choices Skins listed on the settings screen.

The full map, including names reserved for upcoming features, is includes/hooks.php in the plugin source.

Hooks added in 1.0.0: stp_settings_export_keys, stp_status_checks, stp_wizard_steps, stp_bulk_assign_done, stp_production_statuses, stp_production_status_changed, stp_webhook_topics, stp_reorder_record, stp_export_columns, stp_variation_view_image, stp_design_saved, stp_privacy_data, stp_retention_days, stp_license_status, stp_demo_created. Arguments are documented in includes/hooks.php.

Events

STP_Log::event( $name, $context ) fires the stp_event action with an event name and a context array of IDs and states, never customer text. Listen to it for webhooks, integrations or your own logging:

add_action( 'stp_event', function ( $name, $context ) {
    if ( 'proof.approved' === $name ) {
        // $context['order_id'], $context['round']
    }
}, 10, 2 );

Event names are listed in includes/hooks.php (design.ordered, proof.sent, proof.approved, proof.changes_requested, production.status_changed, design.saved, upload.rejected, settings.imported, privacy.erased, license.changed). In this build the proof workflow fires its own actions (stp_proof_sent, stp_proof_approved, stp_proof_changes_requested); use those until the events are wired.

REST API

All StitchPress routes live under one namespace, stitchpress/v1. Routes are added through the stp_rest_routes filter, not by calling register_rest_route() directly:

add_filter( 'stp_rest_routes', function ( $routes ) {
    $routes[] = array(
        'route' => '/orders/(?P<id>\d+)/designs',
        'args'  => array(
            'methods'             => 'GET',
            'callback'            => 'my_designs_callback',
            'permission_callback' => function () {
                return current_user_can( 'manage_woocommerce' );
            },
        ),
    );
    return $routes;
} );

args may be one endpoint array or a list of them, as WordPress accepts. A route without a permission_callback is refused and logged as an error, so a forgotten capability check cannot ship. A public route must say so explicitly with '__return_true' and do its own nonce and rate-limit checks.

StitchPress's own routes need manage_woocommerce (an application password or a WooCommerce REST API key of a user who has it; 401 or 403 otherwise):

  • GET /orders: decorated orders, newest first. Arguments status, production_status, after (date-time), page, per_page (up to 100). The X-WP-Total and X-WP-TotalPages headers count every matching order. Decorated orders are found by reading orders newest first, at most 10,000 for one page (filter stp_rest_orders_scan_limit); when that limit stops a page before it is full, the response has the header X-STP-Truncated: true. Narrow the request with after or status and ask again.
  • GET /orders/<id>: the order document (lines with their design records, proof state, production status and history).
  • GET /orders/<id>/designs: the design record of each decorated line, keyed by line id.
  • GET /orders/<id>/sheet: the production sheet HTML.
  • POST /orders/<id>/production: set the production status (status).

Webhooks

Three WooCommerce webhook topics: stitchpress.design_ordered (a decorated order is paid, once per order), stitchpress.proof_approved and stitchpress.production_status. Add them under WooCommerce > Settings > Advanced > Webhooks like any WooCommerce webhook; the secret, the X-WC-Webhook-Signature header (base64 of HMAC-SHA256 of the body with the secret) and the delivery log are WooCommerce's.

The body is the document GET /stitchpress/v1/orders/<id> returns, plus three fields:

  • event: the topic.
  • event_id: a UUID (v4) for this event. It is the same on every retry of the event, so store it and skip a body whose event_id you have already processed. WooCommerce's X-WC-Webhook-Delivery-ID header changes on every attempt and is not a de-duplication key.
  • occurred_at: when the event happened, in UTC (2026-10-07T14:03:00Z), not when this attempt was sent.

Retries. WooCommerce sends each delivery once. When one of these topics gets a connection error or a status outside 200 to 299, StitchPress sends it again after 1, 5 and 30 minutes (filter stp_webhook_retry_delays), then logs that it gave up.

WooCommerce disables a failing webhook. Every failed attempt, retries included, adds one to the webhook's failure count; a success (status 200 to 302) resets it to zero. When a delivery fails while the count is already above 5 (filter woocommerce_max_webhook_delivery_failures), WooCommerce sets the webhook to Disabled. One event that fails every attempt counts 4 failures, so two such events in a row disable the webhook, and StitchPress does not retry for a disabled webhook. Re-enabling it in the settings does not reset the count, so the next failure disables it again until one delivery succeeds. Keep your endpoint answering 2xx quickly and do the work after replying.

Logging

StitchPress logs through WooCommerce's logger with the source stitchpress. Read the logs under WooCommerce > Status > Logs and pick a stitchpress file (or source).

  • Errors and warnings are always written.
  • Debug lines are written only when Debug log is on (StitchPress settings > Advanced) or when stp_log_debug_enabled returns true. Leave it off unless support asks for it.
  • Anything that looks like an email address is masked as [email] before a line is written.

From your own code:

STP_Log::warning( 'Something to look at', array( 'order_id' => 123 ) );

STP_Log has debug(), info(), warning(), error() and event(). Pass IDs and states in the context array, not customer text.

Template overrides

StitchPress renders its storefront, proof page and Job Jacket markup in PHP, not from template files, so there is nothing to copy into your theme in this build. Change output with the filters above (stp_sheet_render_item, stp_sheet_css, stp_proof_email_body and so on) and the look of the designer with a skin.

The override folder is reserved: templates that StitchPress renders through STP_Email_Registry::render() are looked up first in wp-content/themes/<your-theme>/stitchpress/, then in the plugin's templates/ folder, the same way WooCommerce template overrides work.

Email templates ship under templates/emails/ as an HTML and a plain-text file per email; copy one to <your-theme>/stitchpress/emails/ with the same file name to override it.

Product setup

Products that arrive by import, REST or a feed plugin are set up at the end of the request (see Set up a product for decoration).

  • do_action( 'stp_setup_product', $product_id ) queues a product from your own importer.
  • stp_setup_should_run (filter, bool $run, int $product_id, string $source) skips products.
  • stp_setup_result (filter, array $report, WC_Product $product, array $args) changes what is written, or returns a WP_Error to stop.
  • stp_setup_done (action, int $product_id, array $report) runs after each setup.
  • STP_Product_Setup::run( $product_id, array( 'dry' => true ) ) returns the report without writing.
  • REST: GET and POST stitchpress/v1/products/<id>/setup (dry, force), for users who can manage WooCommerce and edit that product.

Product meta: _stp_decorate (yes or no), _stp_product_views (view key to attachment ID), _stp_setup (the last report).

Adding a module

Code that ships inside StitchPress is organised as modules: a file includes/admin/, includes/commerce/ or includes/release/ named class-stp-<name>.php, defining STP_<Name> with a public static function register(). StitchPress loads every module on plugins_loaded after its core has started. This is for StitchPress itself; for site-specific changes, use the hooks above from your theme or a small plugin.

Source: the plugin's docs/site/developers.md, rendered for StitchPress 1.0.0-rc4. Found an error? Tell support.