init_hooks();
}
public function init_hooks() {
add_action( 'admin_enqueue_scripts', array( $this, 'apply_whitelabel_styles' ), 99 );
add_action( 'admin_enqueue_scripts', array( $this, 'apply_custom_branding' ), 100 );
add_filter( 'wp_ai_workflows_email_template', array( $this, 'customize_email_template' ), 10, 2 );
add_filter( 'wp_ai_workflows_email_subject', array( $this, 'customize_email_subject' ), 10, 1 );
add_action( 'wp_enqueue_scripts', array( $this, 'maybe_replace_logo' ), 999 );
}
/**
* Get whitelabel settings.
*
* NOTE: access control lives in the REST layer
* (WP_AI_Workflows_Platform_Client::whitelabel_management_gate() enforces
* connected + Business tier + org owner with a live management session). The
* retired SLM "agency license" check has been removed - there is no license path
* to white-labeling anymore.
*/
public function get_whitelabel_settings() {
$settings = get_option(
'wp_ai_workflows_whitelabel_settings',
array(
'enable_whitelabel' => false,
'logo_url' => '',
'header_text' => 'AI Workflow Automation',
'primary_color' => '#1890ff',
'menu_bg_color' => '#001529',
'menu_text_color' => '#ffffff',
'custom_email_subject' => 'New Task Awaiting Your Input',
'custom_email_template' => '',
)
);
return $settings;
}
/**
* Update whitelabel settings
*/
public function update_whitelabel_settings( $request ) {
// Access control is enforced by the REST layer (whitelabel_management_gate:
// connected + Business tier + org owner with a live management session).
$params = $request->get_params();
$settings = array(
'enable_whitelabel' => isset( $params['enable_whitelabel'] ) ? (bool) $params['enable_whitelabel'] : false,
'logo_url' => isset( $params['logo_url'] ) ? sanitize_url( $params['logo_url'] ) : '',
'header_text' => isset( $params['header_text'] ) ? sanitize_text_field( $params['header_text'] ) : 'AI Workflow Automation',
'primary_color' => isset( $params['primary_color'] ) ? sanitize_text_field( $params['primary_color'] ) : '#1890ff',
'menu_bg_color' => isset( $params['menu_bg_color'] ) ? sanitize_text_field( $params['menu_bg_color'] ) : '#001529',
'menu_text_color' => isset( $params['menu_text_color'] ) ? sanitize_text_field( $params['menu_text_color'] ) : '#ffffff',
'custom_email_subject' => isset( $params['custom_email_subject'] ) ? sanitize_text_field( $params['custom_email_subject'] ) : 'New Task Awaiting Your Input',
'custom_email_template' => isset( $params['custom_email_template'] ) ? wp_kses_post( $params['custom_email_template'] ) : '',
);
update_option( 'wp_ai_workflows_whitelabel_settings', $settings );
add_action(
'admin_footer',
function () use ( $settings ) {
$header_data = array(
'enabled' => ! empty( $settings['enable_whitelabel'] ) ? '1' : '0',
'headerText' => $settings['header_text'],
'logoUrl' => $settings['logo_url'],
'primaryColor' => $settings['primary_color'],
'menuBgColor' => $settings['menu_bg_color'],
'menuTextColor' => $settings['menu_text_color'],
);
echo '';
}
);
return array(
'success' => true,
'message' => 'Whitelabel settings updated successfully',
);
}
/**
* Handle logo upload
*/
public function handle_logo_upload( $request ) {
// Access control is enforced by the REST layer (whitelabel_management_gate).
if ( ! function_exists( 'wp_handle_upload' ) ) {
require_once ABSPATH . 'wp-admin/includes/file.php';
}
$files = $request->get_file_params();
if ( empty( $files['logo'] ) ) {
return new WP_REST_Response(
array(
'success' => false,
'message' => 'No logo file uploaded',
),
400
);
}
$uploaded_file = $files['logo'];
$allowed_types = array( 'image/png', 'image/jpeg', 'image/jpg', 'image/gif', 'image/svg+xml' );
if ( ! in_array( $uploaded_file['type'], $allowed_types ) ) {
return new WP_REST_Response(
array(
'success' => false,
'message' => 'Invalid file type. Allowed types: PNG, JPEG, GIF, SVG',
),
400
);
}
$upload_overrides = array(
'test_form' => false,
'test_size' => true,
'test_upload' => true,
);
$movefile = wp_handle_upload( $uploaded_file, $upload_overrides );
if ( $movefile && ! isset( $movefile['error'] ) ) {
$settings = get_option( 'wp_ai_workflows_whitelabel_settings', array() );
$settings['logo_url'] = $movefile['url'];
update_option( 'wp_ai_workflows_whitelabel_settings', $settings );
return array(
'success' => true,
'message' => 'Logo uploaded successfully',
'data' => array(
'url' => $movefile['url'],
),
);
} else {
return array(
'success' => false,
'message' => $movefile['error'],
);
}
}
/**
* Apply whitelabel styles to admin
*/
public function apply_whitelabel_styles( $hook ) {
if ( strpos( $hook, 'wp-ai-workflows' ) === false ) {
return;
}
$settings = get_option( 'wp_ai_workflows_whitelabel_settings', array() );
if ( empty( $settings ) || empty( $settings['enable_whitelabel'] ) ) {
return;
}
$custom_css = $this->generate_custom_css( $settings );
wp_add_inline_style( 'wp-ai-workflows-admin-styles', $custom_css );
}
/**
* Apply custom branding (logo and header text)
*/
public function apply_custom_branding( $hook ) {
if ( strpos( $hook, 'wp-ai-workflows' ) === false ) {
return;
}
$settings = get_option( 'wp_ai_workflows_whitelabel_settings', array() );
if ( empty( $settings ) || empty( $settings['enable_whitelabel'] ) ) {
add_action(
'admin_head',
function () {
echo '';
}
);
return;
}
$header_data = array(
'enabled' => '1', // Use string "1" to match expected format
'headerText' => isset( $settings['header_text'] ) ? $settings['header_text'] : 'AI Workflow Automation',
'logoUrl' => isset( $settings['logo_url'] ) ? $settings['logo_url'] : '',
'primaryColor' => isset( $settings['primary_color'] ) ? $settings['primary_color'] : '#1890ff',
'menuBgColor' => isset( $settings['menu_bg_color'] ) ? $settings['menu_bg_color'] : '#001529',
'menuTextColor' => isset( $settings['menu_text_color'] ) ? $settings['menu_text_color'] : '#ffffff',
);
add_action(
'admin_head',
function () use ( $header_data ) {
echo '';
}
);
add_action(
'admin_footer',
function () {
echo '';
}
);
}
/**
* Generate custom CSS from settings
*/
private function generate_custom_css( $settings ) {
$css = '';
// Use both selector patterns to be safe
$selectors = array( '.wp-ai-workflows-wrapper', '#wp-ai-workflows-root' );
foreach ( $selectors as $selector ) {
if ( ! empty( $settings['primary_color'] ) ) {
$css .= "{$selector} .ant-btn-primary { background-color: " . esc_attr( $settings['primary_color'] ) . " !important; }\n";
$css .= "{$selector} .ant-btn-primary:hover { background-color: " . esc_attr( $settings['primary_color'] ) . " !important; filter: brightness(1.1); }\n";
$css .= "{$selector} a { color: " . esc_attr( $settings['primary_color'] ) . " !important; }\n";
$css .= "{$selector} .ant-menu-item-selected { color: " . esc_attr( $settings['primary_color'] ) . " !important; }\n";
$css .= "{$selector} .ant-switch-checked { background-color: " . esc_attr( $settings['primary_color'] ) . " !important; }\n";
}
if ( ! empty( $settings['menu_bg_color'] ) ) {
$css .= "{$selector} .ant-layout-header, {$selector} .ant-menu.ant-menu-dark { background-color: " . esc_attr( $settings['menu_bg_color'] ) . " !important; }\n";
}
if ( ! empty( $settings['menu_text_color'] ) ) {
$css .= "{$selector} .ant-menu.ant-menu-dark .ant-menu-item, {$selector} .ant-menu.ant-menu-dark .ant-menu-item > a { color: " . esc_attr( $settings['menu_text_color'] ) . " !important; }\n";
}
}
$css .= "#wp-ai-workflows-root .logo-container {
min-width: 180px !important;
max-width: 520px !important;
width: 30% !important;
height: 32px !important;
margin-top: 2px !important;
margin-left: auto !important;
margin-right: 50 !important;
flex-shrink: 0 !important;
position: relative !important;
overflow: hidden !important;
display: flex !important;
justify-content: flex-end !important;
align-items: center !important;
text-align: right !important;
z-index: 100 !important;
}\n";
$css .= "#wp-ai-workflows-root .logo-container img {
height: 100% !important;
width: auto !important;
max-height: 32px !important;
object-fit: contain !important;
display: block !important;
margin-left: auto !important;
}\n";
return $css;
}
/**
* Customize email template for task notifications
*/
public function customize_email_template( $template, $task ) {
$settings = get_option( 'wp_ai_workflows_whitelabel_settings', array() );
if ( empty( $settings ) || empty( $settings['enable_whitelabel'] ) || empty( $settings['custom_email_template'] ) ) {
return $template;
}
$custom_template = $settings['custom_email_template'];
$logo_url = ! empty( $settings['logo_url'] ) ? $settings['logo_url'] : get_site_icon_url( 96 );
if ( empty( $logo_url ) ) {
$logo_url = admin_url( 'images/wordpress-logo.png' );
}
$site_name = get_bloginfo( 'name' );
$admin_url = admin_url( 'admin.php?page=wp-ai-workflows-tasks' );
$content_display = 'No content provided';
if ( isset( $task['content'] ) && ! is_null( $task['content'] ) ) {
if ( is_string( $task['content'] ) ) {
$content_display = $task['content'];
} elseif ( is_array( $task['content'] ) || is_object( $task['content'] ) ) {
$content_display = print_r( $task['content'], true );
}
}
$instructions = '';
if ( ! empty( $task['instructions'] ) ) {
$instructions = $task['instructions'];
if ( is_string( $instructions ) ) {
$decoded = json_decode( $instructions, true );
if ( json_last_error() === JSON_ERROR_NONE ) {
$instructions = $decoded;
}
}
if ( is_array( $instructions ) || is_object( $instructions ) ) {
$instructions = print_r( $instructions, true );
}
}
$placeholders = array(
'{{site_name}}' => $site_name,
'{{task_id}}' => $task['id'],
'{{workflow_name}}' => $task['workflow_name'],
'{{input_type}}' => $task['input_type'],
'{{content}}' => $content_display,
'{{instructions}}' => $instructions,
'{{admin_url}}' => $admin_url,
'{{site_icon_url}}' => $logo_url,
);
foreach ( $placeholders as $placeholder => $value ) {
$custom_template = str_replace( $placeholder, $value, $custom_template );
}
return $custom_template;
}
/**
* Customize email subject for task notifications
*/
public function customize_email_subject( $subject ) {
$settings = get_option( 'wp_ai_workflows_whitelabel_settings', array() );
if ( empty( $settings ) || empty( $settings['enable_whitelabel'] ) || empty( $settings['custom_email_subject'] ) ) {
return $subject;
}
return $settings['custom_email_subject'];
}
/**
* Apply logo replacement on frontend
*/
public function maybe_replace_logo() {
global $post;
if ( ! is_object( $post ) || ! has_shortcode( $post->post_content, 'wp_ai_workflow_chat' ) ) {
return;
}
$settings = get_option( 'wp_ai_workflows_whitelabel_settings', array() );
if ( empty( $settings ) || empty( $settings['enable_whitelabel'] ) ) {
return;
}
$css = '';
if ( ! empty( $settings['logo_url'] ) ) {
$logo_url = esc_url( $settings['logo_url'] );
$css .= ".wp-ai-workflows-chat-widget .chat-header-logo { background-image: url({$logo_url}) !important; background-size: contain; background-position: center; background-repeat: no-repeat; }";
}
if ( ! empty( $settings['primary_color'] ) ) {
$primary_color = esc_attr( $settings['primary_color'] );
$css .= ".wp-ai-workflows-chat-widget .chat-primary-button, .wp-ai-workflows-chat-widget .chat-send-button { background-color: {$primary_color} !important; }";
$css .= ".wp-ai-workflows-chat-widget .chat-widget-header { background-color: {$primary_color} !important; }";
}
if ( ! empty( $css ) ) {
wp_add_inline_style( 'wp-ai-workflows-chat-styles', $css );
}
}
/**
* Import whitelabel settings from uploaded JSON file
*/
public function import_whitelabel_settings( $request ) {
// Access control is enforced by the REST layer (whitelabel_management_gate).
$files = $request->get_file_params();
if ( empty( $files['settings_file'] ) ) {
return array(
'success' => false,
'message' => 'No file uploaded',
);
}
$file = $files['settings_file'];
if ( $file['error'] !== UPLOAD_ERR_OK ) {
return array(
'success' => false,
'message' => 'Upload failed: ' . $this->get_upload_error_message( $file['error'] ),
);
}
$content = file_get_contents( $file['tmp_name'] );
$settings = json_decode( $content, true );
if ( json_last_error() !== JSON_ERROR_NONE ) {
return array(
'success' => false,
'message' => 'Invalid JSON file: ' . json_last_error_msg(),
);
}
$required_fields = array( 'enable_whitelabel', 'primary_color', 'menu_bg_color', 'menu_text_color' );
foreach ( $required_fields as $field ) {
if ( ! isset( $settings[ $field ] ) ) {
return array(
'success' => false,
'message' => "Missing required field: {$field}",
);
}
}
$sanitized_settings = array(
'enable_whitelabel' => (bool) $settings['enable_whitelabel'],
'logo_url' => isset( $settings['logo_url'] ) ? sanitize_url( $settings['logo_url'] ) : '',
'header_text' => isset( $settings['header_text'] ) ? sanitize_text_field( $settings['header_text'] ) : 'AI Workflow Automation',
'primary_color' => sanitize_text_field( $settings['primary_color'] ),
'menu_bg_color' => sanitize_text_field( $settings['menu_bg_color'] ),
'menu_text_color' => sanitize_text_field( $settings['menu_text_color'] ),
'custom_email_subject' => isset( $settings['custom_email_subject'] ) ? sanitize_text_field( $settings['custom_email_subject'] ) : 'New Task Awaiting Your Input',
'custom_email_template' => isset( $settings['custom_email_template'] ) ? wp_kses_post( $settings['custom_email_template'] ) : '',
);
update_option( 'wp_ai_workflows_whitelabel_settings', $sanitized_settings );
add_action(
'admin_footer',
function () use ( $sanitized_settings ) {
$header_data = array(
'enabled' => ! empty( $sanitized_settings['enable_whitelabel'] ) ? '1' : '0',
'headerText' => $sanitized_settings['header_text'],
'logoUrl' => $sanitized_settings['logo_url'],
'primaryColor' => $sanitized_settings['primary_color'],
'menuBgColor' => $sanitized_settings['menu_bg_color'],
'menuTextColor' => $sanitized_settings['menu_text_color'],
);
echo '';
}
);
return array(
'success' => true,
'message' => 'Settings imported successfully',
'settings' => $sanitized_settings,
);
}
/**
* Get upload error message
*/
private function get_upload_error_message( $error_code ) {
switch ( $error_code ) {
case UPLOAD_ERR_INI_SIZE:
return 'The uploaded file exceeds the upload_max_filesize directive in php.ini';
case UPLOAD_ERR_FORM_SIZE:
return 'The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form';
case UPLOAD_ERR_PARTIAL:
return 'The uploaded file was only partially uploaded';
case UPLOAD_ERR_NO_FILE:
return 'No file was uploaded';
case UPLOAD_ERR_NO_TMP_DIR:
return 'Missing a temporary folder';
case UPLOAD_ERR_CANT_WRITE:
return 'Failed to write file to disk';
case UPLOAD_ERR_EXTENSION:
return 'A PHP extension stopped the file upload';
default:
return 'Unknown upload error';
}
}
}