Skip to main content

Overview

Versions prior to 1.0.0-beta used hardcoded PHP template files for the CEP and Certificates forms. Starting with 1.0.0-beta, both flows are driven by a JSON field schema stored either in the WooCommerce product’s _utb_form_config post meta or in the certificate record’s form_config_json column. The migration converts the legacy templates to this format.
Do not remove CertificadosFlow.php or CEPFlow.php during or after migration. Both files contain the AJAX handlers (ajax_calculate_discount, utb_cert_price, etc.) and OAuth integration logic that the frontend depends on, regardless of whether the form fields are driven by JSON or hardcoded PHP.

Database migration

The plugin tracks its schema version in the WordPress option utb_pb_db_version. On every plugins_loaded event, Plugin::init() compares this value against the required version (3.0.1):
$current_db_version = get_option('utb_pb_db_version', '0.0.0');
if (version_compare($current_db_version, '3.0.1', '<')) {
    \UTB_PB_DB_Schema::install_tables();
    update_option('utb_pb_db_version', '3.0.1');
}
This means the database schema upgrades automatically on the first page load after a plugin update, even if the update was performed by uploading a ZIP file without triggering the activation hook. After upgrading, confirm the option was updated:
wp option get utb_pb_db_version
Expected output: 3.0.1

Migrating from hardcoded PHP templates to JSON-driven flows

1

Identify the product IDs for each environment

The migration script references WooCommerce product IDs directly. These IDs differ between staging and production.
# List products associated with each flow
wp post list --post_type=product --fields=ID,post_title

# Alternatively, query flow assignments
wp option get utb_pb_flow_assignments
Note the product IDs for the CEP product and the Certificates product in each environment.
2

Run the migration script

wp eval-file migrate-flows.php
The script reads the existing hardcoded field structure from each flow’s get_default_config() method and writes it as JSON to the _utb_form_config post meta on the corresponding product. After this step, FormConfigManager::get_config() will serve the JSON schema instead of falling back to the hardcoded default.
3

Verify the JSON was saved

# Replace 42 with the actual product ID
wp post meta get 42 _utb_form_config
The output should be a JSON array containing the field definitions matching get_default_config().
4

Customize via the Form Builder (optional)

Go to UTB Builder → Form Builder and select the migrated product. You can now drag, reorder, and configure fields through the visual interface. Changes are saved back to _utb_form_config.

Post-migration testing checklist

Run this checklist on every environment after migration:

Wizard steps and conditional fields

  • All form sections render in the correct order.
  • Conditional fields (e.g., utb_qty hidden until a quantity-enabled certificate is selected) show and hide correctly when expected.
  • Required field markers (*) appear on all required fields.

Pricing

  • CEP: Selecting a program displays the correct price below the selector. Price disappears and reappears correctly on change (no CSS animation block).
  • CEP: Entering a valid document number and names triggers the discount check. The discount banner renders with the correct percentage and final price.
  • Certificates: Changing certificate, format, or level updates the price display in real time.
  • Certificates: Price for a certificate without explicit level assignments resolves correctly for both Pregrado and Posgrado.

Server-side validation

  • Submitting the CEP form with mismatched names and document returns the identity mismatch error.
  • Submitting the Certificates form without accepting policies is blocked.
  • Submitting with a certificate that does not match the applicant type (e.g., student certificate for an egresado role) is blocked.

Order metadata

  • After checkout, inspect the order in WooCommerce → Orders → (order).
  • All _utb_cep_* or _utb_cert_* meta keys are visible with correct values.
  • The _utb_cep_descuento_porcentaje and _utb_cep_rol_aplicado keys are populated when a discount was applied.
  • The _utb_cert_price_total key reflects price_unit × qty.

Webhooks

  • Complete a test order and verify a row was created in wp_utb_webhook_logs.
  • The webhook log entry shows status success (or failed with retry count if the endpoint was unreachable).

Identifying product IDs across environments

Because WordPress auto-increments post IDs, the same product will have different IDs in staging and production. Use one of these approaches to keep the migration script environment-agnostic: By post title:
wp post list --post_type=product --post_status=publish \
  --fields=ID,post_title | grep "CEP"
By flow assignment:
wp eval 'print_r(get_option("utb_pb_flow_assignments"));'
This prints an array of product_id => flow_id pairs that shows every product already linked to a flow. By post meta:
wp post list --post_type=product \
  --meta_key=_utb_flow_id --meta_value=utb_cep_programs \
  --fields=ID,post_title

Build docs developers (and LLMs) love