rest_url( 'wp-ai-workflows/v1' ),
'nonce' => wp_create_nonce( 'wp_rest' ),
'siteUrl' => get_site_url(),
'assetsUrl' => plugins_url( 'assets', WP_AI_WORKFLOWS_PLUGIN_DIR . 'wp-ai-workflows.php' ),
'isChat' => true,
// WooCommerce presence + its own AJAX add-to-cart endpoint, so the
// widget's product cards can add to the cart using Woo's session
// (no custom cart mutation on our side).
'wooActive' => class_exists( 'WooCommerce' ),
'wcAjaxUrl' => class_exists( 'WC_AJAX' ) ? WC_AJAX::get_endpoint( 'add_to_cart' ) : '',
// Gates the visitor-facing widget's diagnostic logger
// (frontend/src/utils/debug.js). FALSE by default - visitors must
// see essentially nothing in the console. Set WP_AI_WORKFLOWS_DEBUG
// to true in wp-config.php to surface debug.log()/debug.warn().
'debug' => defined( 'WP_AI_WORKFLOWS_DEBUG' ) && WP_AI_WORKFLOWS_DEBUG,
)
);
}
public function enqueue_assets() {
if ( ! $this->script_loaded ) {
// Intentionally NOT enqueuing the 'wp-ai-workflows-app' stylesheet here.
// The chat widget renders inside a Shadow DOM (frontend/src/index.js
// injects chat.css directly into the shadow root), so it does not need,
// and must not load, the full React app stylesheet (antd + global
// resets) on public pages. Loading it globally clobbers the active
// theme's layout/typography for every visitor. The script is still
// needed to boot the widget bundle.
wp_enqueue_script( 'wp-ai-workflows-app' );
$this->script_loaded = true;
}
}
public function render_shortcode( $atts ) {
$atts = shortcode_atts(
array(
'id' => '',
'theme' => '',
'position' => '',
'show_citations' => '',
'show_powered_by' => '',
'include_page_context' => '',
),
$atts,
'wp_ai_workflow_chat'
);
if ( empty( $atts['id'] ) ) {
return '
Error: Workflow ID is required
';
}
// Clean the ID to get base workflow ID
$workflow_id = preg_replace( '/-[\w\d]+$/', '', $atts['id'] );
$config = $this->get_chat_config( $workflow_id );
if ( is_wp_error( $config ) ) {
return '