| Server IP : 121.121.20.254 / Your IP : 216.73.216.202 Web Server : Microsoft-IIS/10.0 System : Windows NT WEB-SERVER 10.0 build 20348 (Windows Server 2022) AMD64 User : IUSR ( 0) PHP Version : 8.3.28 Disable Function : NONE MySQL : ON | cURL : ON | WGET : OFF | Perl : OFF | Python : OFF | Sudo : OFF | Pkexec : OFF Directory : C:/inetpub/wwwroot/AIWEBSTATION/wp-content/plugins/ai-engine-pro/premium/ |
Upload File : |
<?php
define( 'MWAI_FORMS_FRONT_PARAMS', [ 'id', 'label', 'type', 'name', 'options', 'copyButton', 'localMemory',
'required', 'placeholder', 'default', 'maxlength', 'rows', 'outputElement', 'accept', 'customAccept', 'multiple',
'conditionField', 'conditionValue', 'conditions', 'logic' ] );
define( 'MWAI_FORMS_SERVER_PARAMS', [ 'model', 'temperature', 'maxTokens', 'prompt', 'message',
'envId', 'scope', 'resolution', 'message', 'assistantId', 'chatbotId', 'scope',
'embeddingsIndex', 'embeddingsEnv', 'embeddingsEnvId', 'embeddingsNamespace', 'mcpServers'
] );
class MeowPro_MWAI_Forms {
private $core = null;
private $namespace = 'mwai-ui/v1';
public function __construct() {
global $mwai_core;
$this->core = $mwai_core;
add_action( 'rest_api_init', [ $this, 'rest_api_init' ] );
if ( MeowKit_MWAI_Helpers::is_asynchronous_request() ) {
return;
}
add_action( 'wp_enqueue_scripts', [ $this, 'register_scripts' ] );
add_action( 'wp_enqueue_scripts', [ $this, 'check_and_enqueue_container_assets' ], 20 );
add_shortcode( 'mwai-form-field', [ $this, 'shortcode_mwai_form_field' ] );
add_shortcode( 'mwai-form-upload', [ $this, 'shortcode_mwai_form_upload' ] );
add_shortcode( 'mwai-form-submit', [ $this, 'shortcode_mwai_form_submit' ] );
add_shortcode( 'mwai-form-reset', [ $this, 'shortcode_mwai_form_reset' ] );
add_shortcode( 'mwai-form-output', [ $this, 'shortcode_mwai_form_output' ] );
add_shortcode( 'mwai-form-conditional', [ $this, 'shortcode_mwai_form_conditional' ] );
}
public function register_scripts() {
$physical_file = trailingslashit( MWAI_PATH ) . 'premium/forms.js';
$cache_buster = file_exists( $physical_file ) ? filemtime( $physical_file ) : MWAI_VERSION;
wp_register_script(
'mwai_forms',
trailingslashit( MWAI_URL ) . 'premium/forms.js',
[ 'wp-element' ],
$cache_buster,
false
);
}
public function enqueue_scripts( $themeId = null ) {
wp_enqueue_script( 'mwai_forms' );
if ( $themeId ) {
$this->core->enqueue_theme( $themeId );
}
}
public function check_and_enqueue_container_assets() {
global $post;
if ( !$post ) {
return;
}
// Flatten the post's content by resolving synced patterns / reusable blocks
// (wp:block refs) so we can find form shortcodes/containers that live inside
// a pattern. Without this, strpos/preg_match on $post->post_content misses
// anything nested in a reusable block.
$content = self::flatten_block_refs( $post->post_content );
// Check if the content has our form container data attribute
if ( strpos( $content, 'data-mwai-form-container' ) !== false ) {
// Check if any form fields are present which would trigger forms.js enqueue
$has_form_fields = strpos( $content, 'mwai-form-field-container' ) !== false
|| strpos( $content, 'mwai-form-submit-container' ) !== false
|| strpos( $content, 'mwai-form-upload-container' ) !== false
|| strpos( $content, 'mwai-form-output-container' ) !== false
|| strpos( $content, 'mwai-form-reset-container' ) !== false
|| strpos( $content, 'mwai-form-conditional-container' ) !== false;
// If there are form fields, forms.js will be enqueued by their shortcodes
// We just need to handle theme CSS for containers without other form elements
if ( !$has_form_fields ) {
if ( preg_match( '/data-theme="([^"]+)"/', $content, $matches ) ) {
$theme = $matches[1];
if ( $theme && $theme !== 'none' ) {
$this->core->enqueue_theme( strtolower( $theme ) );
}
}
}
}
// Also handle the case where a Forms post is embedded via the [mwai_form id="..."] shortcode.
// We proactively fetch the referenced form post here so we can enqueue the
// theme CSS early enough (during wp_enqueue_scripts).
if ( strpos( $content, '[mwai_form' ) !== false ) {
if ( preg_match_all( '/\[mwai_form\s+[^\]]*id=\"?(\d+)\"?[^\]]*\]/', $content, $matches ) ) {
$ids = isset( $matches[1] ) ? $matches[1] : [];
foreach ( $ids as $form_id ) {
$form_post = get_post( intval( $form_id ) );
if ( $form_post && $form_post->post_type === 'mwai_form' ) {
$form_content = $form_post->post_content;
if ( preg_match( '/data-theme=\"([^\"]+)\"/', $form_content, $themeMatch ) ) {
$theme = strtolower( $themeMatch[1] );
if ( $theme && $theme !== 'none' ) {
$this->core->enqueue_theme( $theme );
}
}
}
}
}
}
}
/**
* Returns $content with every <!-- wp:block {"ref":N} /--> reference
* replaced by the referenced wp_block post's own content (recursively).
* Used so detection scans see shortcodes nested inside synced patterns.
*/
private static function flatten_block_refs( $content, $depth = 0, &$seen = [] ) {
if ( $depth > 3 || strpos( $content, 'wp:block' ) === false ) {
return $content;
}
return preg_replace_callback(
'/<!--\s*wp:block\s+(\{[^}]*"ref"\s*:\s*(\d+)[^}]*\})\s*\/?-->/',
function ( $m ) use ( $depth, &$seen ) {
$ref_id = (int) $m[2];
if ( !$ref_id || isset( $seen[ $ref_id ] ) ) {
return '';
}
$seen[ $ref_id ] = true;
$ref_post = get_post( $ref_id );
if ( !$ref_post || $ref_post->post_type !== 'wp_block' ) {
return '';
}
return self::flatten_block_refs( $ref_post->post_content, $depth + 1, $seen );
},
$content
);
}
public function clean_params( &$params ) {
foreach ( $params as $param => $value ) {
if ( empty( $value ) || is_array( $value ) ) {
continue;
}
$lowerCaseValue = strtolower( $value );
if ( $lowerCaseValue === 'true' || $lowerCaseValue === 'false' || is_bool( $value ) ) {
$params[$param] = filter_var( $value, FILTER_VALIDATE_BOOLEAN );
}
else if ( is_numeric( $value ) ) {
$params[$param] = filter_var( $value, FILTER_VALIDATE_FLOAT );
}
}
return $params;
}
public function fetch_system_params( $id ) {
$frontSystem = [
'id' => $id,
'userData' => $this->core->get_user_data(),
// See chatbot.php build_front_params: never embed a sessionId in cached
// HTML for guests, or page caches will share it across visitors.
'sessionId' => is_user_logged_in() ? $this->core->get_session_id() : null,
'restNonce' => wp_create_nonce( 'wp_rest' ),
'contextId' => get_the_ID(),
'pluginUrl' => untrailingslashit( MWAI_URL ),
'restUrl' => untrailingslashit( get_rest_url() ),
'debugMode' => $this->core->get_option( 'module_devtools' ) && $this->core->get_option( 'debug_mode' ),
'stream' => $this->core->get_option( 'ai_streaming' ),
];
return $frontSystem;
}
/**
* Helper method to create REST responses with automatic token refresh
*
* @param array $data The response data
* @param int $status HTTP status code
* @return WP_REST_Response
*/
protected function create_rest_response( $data, $status = 200 ) {
// Always check if we need to provide a new nonce
$current_nonce = $this->core->get_nonce( true );
$request_nonce = isset( $_SERVER['HTTP_X_WP_NONCE'] ) ? $_SERVER['HTTP_X_WP_NONCE'] : null;
// Check if nonce is approaching expiration (WordPress nonces last 12-24 hours)
// We'll refresh if the nonce is older than 10 hours to be safe
$should_refresh = false;
if ( $request_nonce ) {
// Try to determine the age of the nonce
// WordPress uses a tick system where each tick is 12 hours
// If we're in the second half of the nonce's life, refresh it
$time = time();
$nonce_tick = wp_nonce_tick();
// Verify if the nonce is still valid but getting old
$verify = wp_verify_nonce( $request_nonce, 'wp_rest' );
if ( $verify === 2 ) {
// Nonce is valid but was generated 12-24 hours ago
$should_refresh = true;
// Log will be written when token is included in response
}
}
// If the nonce has changed or should be refreshed, include the new one
if ( $should_refresh || ( $request_nonce && $current_nonce !== $request_nonce ) ) {
$data['new_token'] = $current_nonce;
// Log if server debug mode is enabled
if ( $this->core->get_option( 'server_debug_mode' ) ) {
error_log( '[AI Engine] Token refresh: Nonce refreshed (12-24 hours old)' );
}
}
return new WP_REST_Response( $data, $status );
}
public function rest_api_init() {
try {
register_rest_route( $this->namespace, '/forms/submit', [
'methods' => 'POST',
'callback' => [ $this, 'rest_submit' ],
'permission_callback' => '__return_true'
] );
}
catch ( Exception $e ) {
error_log( '[AI Engine] Forms REST API init error: ' . $e->getMessage() );
}
}
public function rest_submit( $request ) {
// Declared here and not inside the try: the catch block reads both, and an exception
// thrown before the query is built (params, moderation, files) used to hit undefined
// variables there.
$query = null;
$stream = false;
try {
// Stripped at the boundary, before the merge below lets client keys win over the
// form's own config. This endpoint is __return_true, and MWAI_FORMS_SERVER_PARAMS
// covers neither key: 'apiKey' would run the form on a key of the caller's
// choosing, and on a form configured with a speech-to-text model 'path' reaches
// Meow_MWAI_Query_Transcribe::set_path() and then file_get_contents(), which is the
// arbitrary file read the transcription endpoint was hardened against. That one is
// admin-only; this one is public.
$params = Meow_MWAI_Core::sanitize_rest_params( $request->get_json_params() );
$context = null;
$id = $params['id'] ?? null;
$stream = $params['stream'] ?? false;
$fields = $params['fields'] ?? [];
$uploadFields = $params['uploadFields'] ?? [];
// Server params (model, envId, prompt, message, mcpServers, embeddings...)
// are the form's server-side config, delivered through the
// mwai_custom_form_<id> transient. This is a public endpoint, so they must
// never be trusted from the request body: otherwise a hand-crafted call
// could force an expensive model, swap the environment (and its API key),
// or replace the prompt, and with a bogus form id (empty server config)
// turn the form into a free, fully controlled AI proxy on the site's key.
// The client only supplies id, fields, uploadFields and stream. Form
// builders (admins) are exempt. Mirrors the chatbot endpoint. See
// MWAI_FORMS_SERVER_PARAMS.
$allowClientServerParams = apply_filters(
'mwai_forms_allow_client_server_params',
$this->core->can_access_settings(),
$id,
$params
);
if ( !$allowClientServerParams && is_array( $params ) ) {
foreach ( MWAI_FORMS_SERVER_PARAMS as $serverParam ) {
unset( $params[$serverParam] );
}
// A form is single-shot; the prompt is built server-side. A client
// 'messages' array is handed to the model verbatim after the real
// system prompt, so a smuggled 'system' turn would replace the form's
// instructions. Keep only user/assistant turns. Mirrors the chatbot.
if ( !empty( $params['messages'] ) && is_array( $params['messages'] ) ) {
$params['messages'] = array_values( array_filter( $params['messages'], function ( $m ) {
$role = is_array( $m ) ? ( $m['role'] ?? '' ) : ( is_object( $m ) ? ( $m->role ?? '' ) : '' );
return in_array( $role, [ 'user', 'assistant' ], true );
} ) );
}
}
// 1) Retrieve system params from the transient
$systemParams = get_transient( 'mwai_custom_form_' . $id ) ?? [];
$systemParams['prompt'] = $systemParams['prompt'] ?? '';
$systemParams['message'] = $systemParams['message'] ?? '';
$model = isset( $systemParams['model'] ) ? $systemParams['model'] : null;
// 2) Prepare the message (based on the fields).
$message = isset( $params['message'] ) ? $params['message'] : $systemParams['message'] ?? '';
foreach ( $fields as $name => $value ) {
if ( $value === null ) {
continue;
}
if ( is_array( $value ) ) {
$value = implode( ',', $value );
}
$name = '{' . $name . '}';
$message = str_replace( '$' . $name, $value, $message );
$message = str_replace( $name, $value, $message );
}
// Remove any remaining placeholders (upload fields)
foreach ( $uploadFields as $name => $value ) {
$name = '${' . $name . '}';
$message = str_replace( $name, '', $message );
}
// 3) Finalize $systemParams => $params
$systemParams['message'] = $message;
$systemParams['scope'] = empty( $systemParams['scope'] ) ? 'form' : $systemParams['scope'];
// If chatbot mode, load chatbot config as base params
$chatbotId = $systemParams['chatbotId'] ?? null;
$chatbotParams = [];
if ( !empty( $chatbotId ) ) {
$chatbot = $this->core->get_chatbot( $chatbotId );
if ( $chatbot ) {
$chatbotParams = $chatbot;
// Map 'environment' field to 'envId' for compatibility
if ( isset( $chatbotParams['environment'] ) && !isset( $chatbotParams['envId'] ) ) {
$chatbotParams['envId'] = $chatbotParams['environment'];
}
}
}
// Merge: chatbot config (base) → system params → request params
$newParams = [];
foreach ( $chatbotParams as $key => $value ) {
$newParams[$key] = $value;
}
foreach ( $systemParams as $key => $value ) {
$newParams[$key] = $value;
}
foreach ( $params as $key => $value ) {
$newParams[$key] = $value;
}
$params = apply_filters( 'mwai_forms_submit_params', $newParams );
$message = $params['message'] ?? $message;
$model = $params['model'] ?? $model;
// 4) Retrieve model info
$envId = $params['envId'] ?? null;
$engine = Meow_MWAI_Engines_Factory::get( $this->core, $envId );
$modelObj = $engine->retrieve_model_info( $model );
if ( !empty( $envId ) && empty( $modelObj ) ) {
return $this->create_rest_response( [ 'success' => false, 'message' => 'Model not found.' ], 500 );
}
$modelFeatures = isset( $modelObj['features'] ) ? $modelObj['features'] : [];
$isTextToImage = in_array( 'text-to-image', $modelFeatures );
$isSpeechToText = in_array( 'speech-to-text', $modelFeatures );
// 5) Build the Query object
$query = null;
if ( $isTextToImage ) {
$query = new Meow_MWAI_Query_Image( $message, $model );
$query->inject_params( $params );
}
else if ( $isSpeechToText ) {
$query = new Meow_MWAI_Query_Transcribe( $message );
$query->inject_params( $params );
$query->set_message( '' );
$query->set_url( $message );
}
else {
$query = !empty( $params['assistantId'] )
? new Meow_MWAI_Query_Assistant( $message )
: new Meow_MWAI_Query_Text( $message, 4096 );
$query->inject_params( $params );
// If there's context from embeddings
$context = $this->core->retrieve_context( $params, $query );
if ( !empty( $context ) ) {
$query->set_context( $context['content'] );
}
}
// 6) Optional: If there's an uploaded image (or doc), feed it to the query
// We'll loop over each field in $uploadFields. For each field => files array
foreach ( $uploadFields as $fieldName => $fileArray ) {
// Process all files in the array (supports both single and multi-file upload)
foreach ( $fileArray as $fileInfo ) {
$internalRefId = $fileInfo['id'];
$url = $fileInfo['url'];
// Create DroppedFile object - provider-agnostic approach (same as chatbot.php)
$mimeType = $this->core->files->get_mime_type( $internalRefId );
$isIMG = in_array( $mimeType, [ 'image/jpeg', 'image/png', 'image/gif', 'image/webp' ] );
$isAudio = strpos( $mimeType, 'audio/' ) === 0;
// Images use URL (can be sent as base64 or URL in messages)
// Audio and PDFs use refId (engines will upload to their Files API or access file data directly)
if ( $isIMG ) {
$droppedFile = Meow_MWAI_Query_DroppedFile::from_url( $url, 'analysis', $mimeType );
}
else {
// For audio, PDFs and documents, use refId so engines can access file data directly
$droppedFile = Meow_MWAI_Query_DroppedFile::from_refId( $internalRefId, 'analysis', $mimeType );
}
// IMPORTANT: Always use add_file() to add to attachedFiles array
// This is the unified approach for both single and multi-file uploads
$query->add_file( $droppedFile );
// Update metadata using the internal refId
$fileId = $this->core->files->get_id_from_refId( $internalRefId );
$this->core->files->update_envId( $fileId, $engine->envId );
$this->core->files->update_purpose( $fileId, 'analysis' );
$this->core->files->add_metadata( $fileId, 'query_envId', $engine->envId );
$this->core->files->add_metadata( $fileId, 'query_session', $query->session );
}
}
// 7) Attach the 'fields' as an extra param for your own usage
$query->setExtraParam( 'fields', $fields );
// 8) Handle streaming callback
$streamCallback = null;
if ( $stream ) {
$streamCallback = function ( $reply ) use ( $query ) {
// Support both legacy string data and new Event objects
if ( is_string( $reply ) ) {
$this->core->stream_push( [ 'type' => 'live', 'data' => $reply ], $query );
}
else {
$this->core->stream_push( $reply, $query );
}
};
header( 'Cache-Control: no-cache' );
header( 'Content-Type: text/event-stream' );
header( 'X-Accel-Buffering: no' );
ob_implicit_flush( true );
ob_end_flush();
}
// 9) Possible takeover
$takeoverAnswer = apply_filters( 'mwai_form_takeover', null, $query, $params );
if ( !empty( $takeoverAnswer ) ) {
return $this->create_rest_response( [
'success' => true,
'reply' => $takeoverAnswer,
'images' => null,
'usage' => null
], 200 );
}
// 10) Finally, query the AI
$reply = $this->core->run_query( $query, $streamCallback, true );
$rawText = $reply->result;
$extra = [];
if ( $context && isset( $context['embeddings'] ) ) {
$extra = [ 'embeddings' => $context['embeddings'] ];
}
$rawText = apply_filters( 'mwai_form_reply', $rawText, $query, $params, $extra );
$restRes = [
'success' => true,
'reply' => $rawText,
'images' => $reply->get_type() === 'images' ? $reply->results : null,
'usage' => $reply->usage
];
if ( $stream ) {
$this->core->stream_push( [ 'type' => 'end', 'data' => json_encode( $restRes ) ], $query );
die();
}
else {
return $this->create_rest_response( $restRes, 200 );
}
}
catch ( Exception $e ) {
$message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
// Same rule as the chatbot: a refusal (limits, security) is written for the visitor
// and passes through, but an internal error must not leak provider details to them.
// Admins keep the real message so they can debug.
if ( !( $e instanceof Meow_MWAI_RefusedException ) && !current_user_can( 'manage_options' ) ) {
error_log( '[AI Engine Forms Error] ' . $e->getMessage() . ' in ' . $e->getFile() . ':' . $e->getLine() );
$message = Meow_MWAI_Core::get_public_error_message( $e );
}
if ( $stream ) {
$this->core->stream_push( [ 'type' => 'error', 'data' => $message ], $query );
}
else {
return $this->create_rest_response( [ 'success' => false, 'message' => $message ], 500 );
}
}
}
// Rename the keys of the atts into camelCase to match the internal params system.
public function keys_to_camel_case( $atts ) {
$atts = array_map( function ( $key, $value ) {
$key = str_replace( '_', ' ', $key );
$key = ucwords( $key );
$key = str_replace( ' ', '', $key );
$key = lcfirst( $key );
return [ $key => $value ];
}, array_keys( $atts ), $atts );
$atts = array_merge( ...$atts );
return $atts;
}
public function fetch_front_params( $atts ) {
$frontParams = [];
foreach ( MWAI_FORMS_FRONT_PARAMS as $param ) {
if ( isset( $atts[$param] ) ) {
$frontParams[$param] = $atts[$param];
}
}
$frontParams = $this->clean_params( $frontParams );
return $frontParams;
}
public function fetch_server_params( $atts ) {
$serverParams = [];
foreach ( MWAI_FORMS_SERVER_PARAMS as $param ) {
if ( isset( $atts[$param] ) ) {
$serverParams[$param] = $atts[$param];
if ( $param === 'message' ) {
$serverParams[$param] = urldecode( $serverParams[$param] );
}
// Handle mcpServers JSON string (URL decode first, then JSON decode)
if ( $param === 'mcpServers' && is_string( $serverParams[$param] ) ) {
$serverParams[$param] = urldecode( $serverParams[$param] );
$decoded = json_decode( $serverParams[$param], true );
if ( json_last_error() === JSON_ERROR_NONE ) {
$serverParams[$param] = $decoded;
}
}
}
}
$serverParams = $this->clean_params( $serverParams );
return $serverParams;
}
public function encore_params_for_html( $params ) {
$params = htmlspecialchars( json_encode( $params ), ENT_QUOTES, 'UTF-8' );
return $params;
}
public function shortcode_mwai_form_upload( $atts ) {
$atts = apply_filters( 'mwai_forms_upload_params', $atts );
$atts = $this->keys_to_camel_case( $atts );
$frontParams = $this->fetch_front_params( $atts );
// If you want to handle server-side params for the upload field (e.g., store them),
// you can do so here by calling $this->fetch_server_params( $atts ), similar to
// how you do in shortcode_mwai_form_submit(). But most often for a simple file input,
// front-end usage is enough.
// If you support a custom theme, handle it like your other blocks
$theme = isset( $frontParams['themeId'] )
? $this->core->get_theme( $frontParams['themeId'] )
: null;
// Encode as JSON for your forms.js or React code
$jsonFrontParams = $this->encore_params_for_html( $frontParams );
$jsonFrontTheme = $this->encore_params_for_html( $theme );
// Ensure the forms.js script is loaded
$this->enqueue_scripts( $frontParams['themeId'] ?? null );
// Return a simple container div. JS will take that data-params and render <FormUpload />
return "<div class='mwai-form-upload-container'
data-params='{$jsonFrontParams}'
data-theme='{$jsonFrontTheme}'></div>";
}
// Based on the id, label, type, name and options, it will return the HTML code for the field.
public function shortcode_mwai_form_field( $atts ) {
$atts = apply_filters( 'mwai_forms_field_params', $atts );
$atts = $this->keys_to_camel_case( $atts );
$frontParams = $this->fetch_front_params( $atts );
// Client-side: Prepare JSON for Front Params and System Params
$theme = isset( $frontParams['themeId'] ) ? $this->core->get_theme( $frontParams['themeId'] ) : null;
$jsonFrontParams = $this->encore_params_for_html( $frontParams );
$jsonFrontTheme = $this->encore_params_for_html( $theme );
$this->enqueue_scripts( $frontParams['themeId'] ?? null );
return "<div class='mwai-form-field-container' data-params='{$jsonFrontParams}'
data-theme='{$jsonFrontTheme}'></div>";
}
public function shortcode_mwai_form_submit( $atts ) {
$id = 'mwai-' . uniqid();
$atts = apply_filters( 'mwai_form_params', $atts );
$atts = $this->keys_to_camel_case( $atts );
$frontParams = $this->fetch_front_params( $atts );
$systemParams = $this->fetch_system_params( $id ); // Overridable by $atts later
$serverParams = $this->fetch_server_params( $atts );
// Extract the fields and selectors from the message, and build the inputs object.
$message = isset( $serverParams['message'] ) ? $serverParams['message'] : '';
$inputs = [ 'fields' => [], 'selectors' => [] ];
$matches = [];
preg_match_all( '/{([A-Za-z0-9_-]+)}/', $message, $matches );
foreach ( $matches[1] as $match ) {
$inputs['fields'][] = $match;
}
$matches = [];
preg_match_all( '/\$\{([^}]+)\}/', $message, $matches );
foreach ( $matches[1] as $match ) {
$inputs['selectors'][] = $match;
}
$frontParams['inputs'] = $inputs;
// Server-side: Keep the System Params
if ( count( $serverParams ) > 0 ) {
$id = md5( json_encode( $serverParams ) );
$systemParams['id'] = $id;
$systemParams['inputs'] = $inputs;
set_transient( 'mwai_custom_form_' . $id, $serverParams, 60 * 60 * 24 );
}
// Client-side: Prepare JSON for Front Params and System Params
$theme = isset( $frontParams['themeId'] ) ? $this->core->get_theme( $frontParams['themeId'] ) : null;
$jsonFrontParams = $this->encore_params_for_html( $frontParams );
$jsonFrontSystem = $this->encore_params_for_html( $systemParams );
$jsonFrontTheme = $this->encore_params_for_html( $theme );
$this->enqueue_scripts( $frontParams['themeId'] ?? null );
return "<div class='mwai-form-submit-container'
data-params='{$jsonFrontParams}' data-system='{$jsonFrontSystem}'
data-theme='{$jsonFrontTheme}'>
</div>";
}
public function shortcode_mwai_form_reset( $atts ) {
// Generate a unique ID for this reset block, if not provided
$resetId = 'mwai-reset-' . uniqid();
// Let plugins/themes modify the atts if needed
$atts = apply_filters( 'mwai_form_reset_params', $atts );
// Convert keys like "local_memory" => "localMemory"
$atts = $this->keys_to_camel_case( $atts );
// For front-end display/usage
$frontParams = $this->fetch_front_params( $atts );
// For system usage. We'll default to using the same unique $resetId for both
$systemParams = $this->fetch_system_params( $resetId, $resetId );
// If you have any special serverParams to parse, do that:
// (Likely not needed for a reset button, but you can adapt as needed)
$serverParams = $this->fetch_server_params( $atts );
// If you want to set a stable `id` in $systemParams:
$systemParams['id'] = md5( json_encode( $serverParams ) );
$systemParams['resetId'] = $resetId;
// If you do NOT need to store anything server side, you can skip set_transient().
// But here's an example if you do:
// set_transient( 'mwai_custom_reset_' . $systemParams['id'], $serverParams, 60 * 60 * 24 );
// Prepare JSON for front & system usage
$jsonFrontParams = $this->encore_params_for_html( $frontParams );
$jsonFrontSystem = $this->encore_params_for_html( $systemParams );
// Enqueue your needed scripts/styles
$this->enqueue_scripts( $frontParams['themeId'] ?? null );
// Return a container with data attributes, similarly to your submit function
return "<div class='mwai-form-reset-container'
data-params='{$jsonFrontParams}' data-system='{$jsonFrontSystem}'>
</div>";
}
public function shortcode_mwai_form_output( $atts ) {
$atts = apply_filters( 'mwai_forms_output_params', $atts );
$atts = $this->keys_to_camel_case( $atts );
$frontParams = $this->fetch_front_params( $atts );
// Client-side: Prepare JSON for Front Params and System Params
$theme = isset( $frontParams['themeId'] ) ? $this->core->get_theme( $frontParams['themeId'] ) : null;
$jsonFrontParams = $this->encore_params_for_html( $frontParams );
$jsonFrontTheme = $this->encore_params_for_html( $theme );
$this->enqueue_scripts( $frontParams['themeId'] ?? null );
return "<div class='mwai-form-output-container' data-params='{$jsonFrontParams}'
data-theme='{$jsonFrontTheme}'></div>";
}
public function shortcode_mwai_form_conditional( $atts ) {
$atts = $this->keys_to_camel_case( $atts );
if ( empty( $atts['conditions'] ) && ( !empty( $atts['conditionField'] ) || !empty( $atts['conditionValue'] ) ) ) {
$field = $atts['conditionField'] ?? '';
$value = $atts['conditionValue'] ?? '';
$atts['conditions'] = rawurlencode( json_encode( [ [ 'field' => $field, 'operator' => 'eq', 'value' => $value ] ] ) );
}
$frontParams = $this->fetch_front_params( $atts );
$systemParams = $this->fetch_system_params( $frontParams['id'] ?? uniqid() );
$theme = isset( $frontParams['themeId'] ) ? $this->core->get_theme( $frontParams['themeId'] ) : null;
$jsonFrontParams = $this->encore_params_for_html( $frontParams );
$jsonFrontSystem = $this->encore_params_for_html( $systemParams );
$jsonFrontTheme = $this->encore_params_for_html( $theme );
$this->enqueue_scripts( $frontParams['themeId'] ?? null );
return "<div class='mwai-form-conditional-container' data-params='{$jsonFrontParams}' data-system='{$jsonFrontSystem}' data-theme='{$jsonFrontTheme}'></div>";
}
}