README.md 14 KB

QDR — Studiou WC Order Print Statuses

WordPress plugin that extends WooCommerce with a dedicated workflow for managing print orders sent to third-party print providers. It adds custom order statuses, tracking fields, CSV export, protocol-based CSV imports, and search/filter capabilities tailored to a print fulfillment pipeline.

  • Plugin slug / text domain: studiou-wc-ord-print-statuses
  • Current version: 1.4.0
  • Author: Dalibor Votruba — quadarax.com
  • License: GPL v2 or later

Requirements

Component Minimum Tested up to
WordPress 5.8 6.9.4
WooCommerce 3.0 10.7.0
PHP 7.2

Compatible with WooCommerce High-Performance Order Storage (HPOS) — the plugin declares custom_order_tables compatibility and queries the HPOS wc_orders table directly.


Installation

  1. Copy the studiou-wc-ord-print-statuses folder into wp-content/plugins/.
  2. Make sure WooCommerce is installed and active.
  3. Activate the plugin from Plugins in the WordPress admin.

No additional setup is required — custom statuses, fields, columns, and bulk actions are registered on activation.


Features

1. Custom order statuses

Two new statuses are inserted in the WooCommerce status pipeline, right after processing:

Slug Label Purpose
wc-to-print Prepare to Printing Order is queued and exported to the print shop.
wc-in-print In Printing Print shop has accepted the order.

Status transitions automatically stamp the related metadata field (to_print_date / in_print_date) with the current server time.

2. Print Information fields on the order edit page

A new Print Information panel is added to the order details screen with four editable fields:

  • Prepare To Print Date (to_print_date)
  • In Print Date (in_print_date)
  • External Order Number (external_ref_ord_no)
  • External Order Date (external_ref_ord_date) — populated by InPrint protocol imports.
  • External Order Delivered (external_ref_ord_delivered)

3. Bulk actions on the Orders list

Available in the Bulk actions dropdown on WooCommerce → Orders:

  • Prepare to Printing Export — runs the print-shop export SQL across the selected orders, streams the result as a CSV download, and moves every selected order to wc-to-print.
  • Set Status to Prepare to Printing — moves selected orders to wc-to-print and stamps to_print_date.
  • Set Status to In Printing — moves selected orders to wc-in-print and stamps in_print_date.

4. Extra columns in the Orders list

Three columns are appended after Total:

  • To Print Date
  • In Print Date
  • External Order Number

5. Search by External Order Number

The standard WooCommerce Search orders input also matches the external_ref_ord_no meta value — no separate input is required. Works under both legacy CPT storage and HPOS (woocommerce_shop_order_search_fields and woocommerce_order_table_search_query_meta_keys filters).

6. Protocol imports

A WooCommerce → Import Protocols submenu exposes two CSV upload forms:

  • Import InPrint Protocol — for every row in the file, the matching order is set to wc-in-print and the external reference number / date are saved.
  • Import Delivered Protocol — for every row in the file, the matching order is set to wc-completed and the delivery timestamp is recorded.

Both importers require the manage_woocommerce capability and are protected by WordPress nonces.


CSV formats

Export — Prepare to Printing

Generated file: prepare_to_printing_export.csv (UTF-8 with BOM — opens correctly in Excel on Windows).

Columns (in order):

order_no, prod_cat, prod_name, prod_var, prod_var_type, prod_img_url, qty, email
  • prod_var_type is sourced from the variation's attribute_pa_format postmeta, resolved against the wp_terms table.
  • prod_cat is a comma-separated list (deduplicated) when a product belongs to multiple product_cat terms — the row itself is not duplicated.
  • The file is generated before any status change. If the underlying SQL returns no rows the file is not produced and statuses are still advanced (per spec), with an admin notice surfacing the situation.

Headers are normalised on read: column names are lowercased and internal whitespace is collapsed to underscore. Both the original spec casing (Order No, ExternalOrder, ExternalOrderDate) and the documented lowercase form (order_no, externalorder, externalorderdate) work. Rows are also deduplicated by order_no before processing.

Import — InPrint Protocol

Required headers (any of the accepted casings):

order_no, externalorder, externalorderdate

Effect per row: order → status wc-in-print, sets in_print_date (now), external_ref_ord_no, external_ref_ord_date (parsed from the CSV). Orders in a terminal status (completed, cancelled, refunded, failed) are skipped with a per-row error notice.

Import — Delivered Protocol

Required header:

order_no

Effect per row: order → status wc-completed, sets external_ref_ord_delivered (now).


Architecture

The plugin follows a manager-based pattern. The main bootstrapper (studiou-wc-ord-print-statuses.php) wires up specialised classes, each owning one slice of behaviour:

Class File Responsibility
Order_Status_Manager includes/class-order-status-manager.php Register custom statuses, handle transitions.
Order_Fields_Manager includes/class-order-fields-manager.php Render and persist Print Information fields.
Bulk_Actions_Manager includes/class-bulk-actions-manager.php Register and dispatch bulk actions.
Custom_Columns_Manager includes/class-custom-columns-manager.php Inject extra columns into the Orders list.
Import_Manager includes/class-import-manager.php Admin UI + handlers for protocol CSV imports.
Order_Search_Manager includes/class-order-search-manager.php Extend order search to external reference no.
Studiou_DB_Manager includes/class-db-manager.php All SQL and protocol-processing logic.
UtilsLog includes/utils-log.php Lightweight logging helper (uses WP_DEBUG).

The export query in Studiou_DB_Manager::get_orders_for_printing() joins wc_orders, wc_order_product_lookup, posts (products + variations), postmeta (variation attribute + thumbnail), terms, term_taxonomy, and term_relationships to assemble the print-shop payload in a single round-trip.


Internationalization

  • Text domain: studiou-wc-ord-print-statuses
  • Translation files: languages/
  • Bundled locales: Czech (cs_CZ) — see docs/translations.txt for the EN→CS reference list.

Use the standard WordPress functions (__(), _e(), _x(), _n_noop()) for any new strings.


Logging & user notices

  • UtilsLog::log($message) writes to the WordPress error log when WP_DEBUG is enabled (guarded as defined('WP_DEBUG') && WP_DEBUG — works for both boolean and integer truthy values). With WP_DEBUG_LOG on, log output ends up in wp-content/debug.log.
  • UtilsLog::message($message, $type) queues a dismissible WordPress admin notice (info / success / warning / error) for the current user. Notices are stored in a per-user transient (60-second TTL) so they survive the redirect that follows bulk actions and imports. Used to report success counts, skipped orders, malformed CSV rows, etc.

Project layout

studiou-wc-ord-print-statuses/
├── studiou-wc-ord-print-statuses.php   # Plugin bootstrap (header + main class)
├── includes/
│   ├── class-db-manager.php
│   ├── class-order-status-manager.php
│   ├── class-order-fields-manager.php
│   ├── class-order-search-manager.php
│   ├── class-bulk-actions-manager.php
│   ├── class-custom-columns-manager.php
│   ├── class-import-manager.php
│   └── utils-log.php
├── languages/                          # .po / .mo translation files
├── docs/                               # Project documentation (see below)
├── README.md                           # This file
└── CLAUDE.md                           # Guidance for Claude Code sessions

Documentation

Reference documents live under docs/:

Project-internal guidance for AI-assisted development is documented in CLAUDE.md.


Changelog

1.4.0 — 2026-05-12

  • Tested with: WordPress 6.9.4, WooCommerce 10.7.0 (HPOS enabled).

Resolution of every finding catalogued in docs/revise-1.3.2.md. Highlights:

  • Fixed: Search by External Order Number is now functional. The meta-key mismatch is resolved (external_ref_ord_no consistently, no _ prefix), and the integration uses WooCommerce's own search filters (woocommerce_shop_order_search_fields for legacy CPT and woocommerce_order_table_search_query_meta_keys for HPOS). No separate UI input — typing the external order number into the standard Search orders box finds the order.
  • Fixed: Order_Status_Manager::handle_status_transitions() now writes timestamps via wc_get_order()->update_meta_data() instead of update_post_meta(). Print-date stamps are no longer silently lost under HPOS for non-bulk status transitions.
  • Fixed: CSV imports now deduplicate rows by order_no (per the original spec) and accept both the spec's title-case headers and the lowercase form documented in the README.
  • Fixed: "Prepare to Printing Export" is now atomic — the CSV is generated in memory before any status change. Order status is advanced after a successful CSV build. If the export query returns no rows the user is notified.
  • Fixed: Export CSV is now UTF-8 with BOM (charset=utf-8 header + leading \xEF\xBB\xBF). Czech diacritics render correctly in Excel on Windows.
  • Fixed: Export SQL no longer multiplies rows when a product belongs to multiple product_cat terms — categories are concatenated via GROUP_CONCAT(DISTINCT …) inside a GROUP BY per line item.
  • Fixed: Export SQL now goes through $wpdb->prepare() with %d placeholders rather than relying on intval() for safety.
  • Fixed: Late woocommerce_payment_complete events no longer demote orders already in to-print or in-print back to processing. The guard extends to all print statuses plus completed.
  • Fixed: Bulk actions guard with current_user_can('edit_shop_orders'). Imports keep their existing manage_woocommerce guard.
  • Fixed: Bulk actions and protocol imports skip orders in terminal statuses (completed, cancelled, refunded, failed) instead of silently reactivating them.
  • Fixed: UtilsLog::log() guard is now defined('WP_DEBUG') && WP_DEBUG (previously true === WP_DEBUG, which failed when WP_DEBUG was defined as integer 1).
  • Fixed: UtilsLog::message() is now implemented as a per-user transient that renders via the admin_notices hook. Bulk actions and imports now produce visible user feedback after the redirect.
  • Fixed: parse_csv() no longer truncates rows at 1000 bytes (passes 0 to fgetcsv), validates that the header row is non-empty, normalises header casing, and skips rows whose column count diverges from the header.
  • Fixed: Import handlers verify $_FILES[...]['error'] and is_uploaded_file() server-side instead of relying solely on the client-side accept=".csv" attribute.
  • Fixed: external_ref_ord_date is parsed via strtotime() and stored in MySQL datetime format; if parsing fails the raw value is retained.
  • Added: external_ref_ord_date is now rendered in the Print Information panel on the order edit screen.
  • Added: STUDIOU_WC_OPS_VERSION and STUDIOU_WC_OPS_FILE constants for code-side version references.
  • Changed: Translation loader and plugin bootstrap now have explicit plugins_loaded priorities (5 and 10) so translations are guaranteed to load before any manager instantiates.
  • Removed: // visualized leftover comments and the dead-code commented body of UtilsLog::message().
  • Docs: README architecture/install/usage updated, CLAUDE.md updated, docs/translations.txt extended with the strings that were missing.

Translations: the .po file ships new strings; the .mo file must be rebuilt (e.g. via wp i18n make-mo languages/ or Poedit) before the new Czech wording is visible. This release does not regenerate the binary.

1.3.2 — 2025-10-18

  • Fixed: prod_var_type column was empty in prepare_to_printing_export.csv. Variation attribute is now resolved through postmeta.attribute_pa_format joined against wp_terms.name.
  • Fixed: HPOS incompatibility warning. Plugin now explicitly declares custom_order_tables compatibility.
  • Tested: WordPress 6.8.3, WooCommerce 10.2.2 with HPOS enabled.

1.3.1

  • Previous stable release.

Support

For bug reports, feature requests or commercial support, contact quadarax.com.


License

Released under the GNU General Public License v2.0 or later — see https://www.gnu.org/licenses/gpl-2.0.html.