File: //home/dfwparty/santadallas.com/wp-content/plugins/ws-form-pro/includes/class-ws-form-common.php
<?php
// Exit if accessed directly
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Common functions used by this plugin
*/
class WS_Form_Common {
// Cookie prefix
const WS_FORM_COOKIE_PREFIX = 'ws_form_';
// Admin messages
public static $admin_messages = array();
// IP lookup response
public static $ip_lookup_response = false;
// NONCE verified
public static $nonce_verified = false;
// Options cache (Don't use WordPress option caching as it is so slow)
public static $options = array();
// Groups cache
public static $groups = false;
// Sections cache
public static $sections = false;
// Fields cache
public static $fields = false;
// Field types cache
public static $field_types = false;
// Admin messages - Push
public static function admin_message_push($message, $type = 'notice-success', $dismissible = true, $nag_notice = true) {
self::$admin_messages[] = array(
'message' => $message,
'type' => $type,
'dismissible' => $dismissible,
'nag_notice' => $nag_notice
);
}
// Admin messages - Render
public static function admin_messages_render() {
// Server side notices
foreach(self::$admin_messages as $admin_message) {
$message = $admin_message['message'];
$type = isset($admin_message['type']) ? $admin_message['type'] : 'notice-success';
$dismissible = isset($admin_message['dismissible']) ? $admin_message['dismissible'] : true;
$nag_notice = isset($admin_message['nag_notice']) ? $admin_message['nag_notice'] : false;
self::admin_message_render($message, $type, $dismissible, $nag_notice);
}
}
// Admin messages - Render single
public static function admin_message_render($message, $type = 'notice-success', $dismissible = true, $nag_notice = false, $class = '') {
if(!(defined('DISABLE_NAG_NOTICES') && DISABLE_NAG_NOTICES && $nag_notice)) {
$message = str_replace("\n", "<br />\n", $message);
self::echo_html(sprintf(
'<div class="notice %s"><p>%s</p></div>',
esc_attr($type . ($dismissible ? ' is-dismissible' : '') . ($class ? ' ' . $class : '')),
$message
));
}
}
// Admin messages - Get count
public static function get_admin_message_count() {
return count(self::$admin_messages);
}
// Wrapper classes
public static function wrapper_classes() {
$wrapper_classes_array = array('wrap');
// Detect if this plugin is being hosted on wordpress.com
if(
isset($_SERVER) && // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
isset($_SERVER['HTTP_X_PRESSABLE_PROXY']) && // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
($_SERVER['HTTP_X_PRESSABLE_PROXY'] == 'wordpress') // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
) {
$wrapper_classes_array[] = 'wsf-wpcom';
}
// Output classes
self::echo_esc_attr(implode(' ', $wrapper_classes_array));
}
// Get option name and options
public static function get_options($key, $enable_cache) {
// Default return values
$option_name = WS_FORM_OPTION_NAME;
$options = false;
// Check for action related keys (Disabled by default)
// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- All hooks prefixed with wsf_
if(apply_filters('wsf_option_separate_action', WS_FORM_OPTION_SEPARATE_ACTION)) {
if(strpos($key, 'action_') === 0) {
$next_underscore = strpos($key, '_', 7);
if($next_underscore !== false) {
// Set key prefix
$key_prefix = substr($key, 0, $next_underscore);
// Set option name
$option_name = sprintf('%s_%s', WS_FORM_OPTION_NAME, $key_prefix);
// Get options
$options = self::get_options_by_option_name($option_name, $key_prefix, $enable_cache);
}
}
}
// Check for CSS related keys (Enabled by default)
// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- All hooks prefixed with wsf_
if(apply_filters('wsf_option_separate_css', WS_FORM_OPTION_SEPARATE_CSS)) {
if(strpos($key, 'css_') === 0) {
// Set key prefix
$key_prefix = 'css';
// Set option name
$option_name = sprintf('%s_%s', WS_FORM_OPTION_NAME, $key_prefix);
// Get options
$options = self::get_options_by_option_name($option_name, $key_prefix, $enable_cache);
}
}
// Translation data (can be large; keep out of main options — same idea as css_* → ws_form_css)
// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- All hooks prefixed with wsf_
if(apply_filters('wsf_option_separate_translate', WS_FORM_OPTION_SEPARATE_TRANSLATE)) {
if(strpos($key, 'translate_') === 0) {
$key_prefix = 'translate';
$option_name = sprintf('%s_%s', WS_FORM_OPTION_NAME, $key_prefix);
$options = self::get_options_by_option_name($option_name, $key_prefix, $enable_cache);
}
}
// Load options if they haven't been loaded already
if($options === false) {
// Check cache
if(
$enable_cache &&
isset(self::$options[$option_name]) &&
is_array(self::$options[$option_name])
) {
$options = self::$options[$option_name];
} else {
// Clear cache
wp_cache_delete($option_name, 'options');
// Get fresh copy of options
$options = get_option($option_name, false);
// Check options
if(!is_array($options)) { $options = array(); }
// Cache options
self::$options[$option_name] = $options;
}
}
// Return option name
return array('name' => $option_name, 'options' => $options);
}
// Migrate check
public static function get_options_by_option_name($option_name, $key_prefix, $enable_cache) {
// Check cache
if(
$enable_cache &&
isset(self::$options[$option_name]) &&
is_array(self::$options[$option_name])
) {
return self::$options[$option_name];
} else {
// Clear cache
wp_cache_delete($option_name, 'options');
// Check if options have already been migrated
$options = get_option($option_name, false);
// If no options found, migrate any existing options to the new option name
if($options === false) {
$options = self::options_migrate($option_name, $key_prefix);
}
// Check options
if(!is_array($options)) { $options = array(); }
// Cache options
self::$options[$option_name] = $options;
return $options;
}
}
// Migrate
public static function options_migrate($option_name_new, $key_prefix) {
// Get main options data
$options = get_option(WS_FORM_OPTION_NAME, false);
// Build old and new options array
$options_old = array();
$options_new = array();
// If options exist, extract keys that start with key_prefix
if(is_array($options)) {
foreach($options as $key => $value) {
if(strpos($key, $key_prefix) === 0) {
$options_new[$key] = $value;
} else {
$options_old[$key] = $value;
}
}
// Write new options
if(update_option($option_name_new, $options_new, 'no')) {
// Cache new options
self::$options[$option_name_new] = $options_new;
// Write old options
update_option(WS_FORM_OPTION_NAME, $options_old, 'no');
// Cache old options
self::$options[WS_FORM_OPTION_NAME] = $options_old;
}
}
return $options_new;
}
// Get plugin option key value
public static function option_get($key, $default = false, $default_set = false, $enable_cache = true, $use_default_if_blank = false, $bypass_filter = false) {
// Get option name
$option_name_return = self::get_options($key, $enable_cache);
$option_name = $option_name_return['name'];
$options = $option_name_return['options'];
// Return default
$value = $default;
// If key exists, return the value
if(isset($options[$key])) {
$value = $options[$key];
} else {
// Set value
if($default_set) { self::option_set($key, $default); }
}
// If value is blank check to see if we should return the default value
if(($value === '') && $use_default_if_blank) {
$value = $default;
}
// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- All hooks prefixed with wsf_
return $bypass_filter ? $value : apply_filters('wsf_option_get', $value, $key);
}
// Set plugin option key value
public static function option_set($key, $value, $update = true) {
// Get option name
$option_name_return = self::get_options($key, false);
$option_name = $option_name_return['name'];
$options = $option_name_return['options'];
// Set value
if((isset($options[$key]) && $update) || (!isset($options[$key]))) {
// Set key to value in options array
// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- All hooks prefixed with wsf_
$options[$key] = apply_filters('wsf_option_set', $value, $key);
// Cache options
if(
isset(self::$options[$option_name]) &&
is_array(self::$options[$option_name]) &&
is_array($options)
) {
self::$options[$option_name] = $options;
}
// Update WordPress option
update_option($option_name, $options, 'no');
}
}
// Remove plugin option key value
public static function option_remove($key) {
// Get option name
$option_name_return = self::get_options($key, false);
$option_name = $option_name_return['name'];
$options = $option_name_return['options'];
// If key exists, unset it
if(isset($options[$key])) {
// Remove key
unset($options[$key]);
// Cache options
self::$options[$option_name] = $options;
// Update WordPress option
update_option($option_name, $options, 'no');
// Key found and removed
return true;
}
// Did not find key
return false;
}
// Force WS Form framework
public static function option_get_framework_ws_form($value, $key) {
switch($key) {
case 'framework' : return 'ws-form';
case 'css_compile' : return false;
case 'css_inline' : return false;
default : return $value;
}
}
// Get admin URL
public static function get_admin_url($page_slug = '', $item_id = false, $path_extra = '') {
$page_path = 'admin.php';
if($page_slug != '') { $page_path .= '?page=' . $page_slug; }
if($item_id !== false) { $item_id = absint($item_id); $page_path .= '&id=' . $item_id; }
if($path_extra) { $page_path .= '&' . $path_extra; }
return admin_url($page_path);
}
// Get plugin website link
public static function get_plugin_website_url($path = '', $medium = false) {
return sprintf('https://wsform.com%s?utm_source=ws_form_pro%s', $path, (($medium !== false) ? '&utm_medium=' . $medium : ''));
}
// Get customize URL
public static function get_customize_url($panel = 'ws_form', $preview_form_id = 0) {
return sprintf(
'customize.php?return=%s&wsf_panel_open=%s%s',
urlencode(
remove_query_arg(
wp_removable_query_args(),
sanitize_url(wp_unslash(isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : ''))
)
),
$panel,
(
($preview_form_id > 0) ? sprintf('&wsf_preview_form_id=%u', $preview_form_id) : ''
)
);
}
// Get query var (NONCE is not available)
public static function get_query_var($var, $default = '', $parameters = false, $esc_sql = false, $strip_slashes = true, $request_method = false) {
// REST parameters
if($parameters !== false) {
if(isset($parameters[$var])) {
$return_value = $esc_sql ? esc_sql($parameters[$var]) : $parameters[$var];
$return_value = self::mod_security_fix($return_value);
return $strip_slashes ? stripslashes_deep($return_value) : $return_value;
}
}
// Get request method
$request_method = ($request_method === false) ? self::get_request_method() : $request_method;
if(!$request_method) { return $default; }
// Regular GET, POST, PUT handling
switch($request_method) {
case 'GET' :
// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitizedDetected, WordPress.Security.NonceVerification.Recommended -- NONCE check not required
$post_vars = $_GET;
break;
case 'POST' :
// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitizedDetected, WordPress.Security.NonceVerification.Missing -- NONCE check not required
$post_vars = $_POST;
break;
case 'PUT' :
// PUT method data is in php://input so parse that into $post_vars
// phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents -- Required for reading raw POST data from php://input stream
parse_str(file_get_contents('php://input'), $post_vars);
$strip_slashes = false;
break;
default :
return $default;
}
// DATA param (This overcomes standard 1000 POST parameter limitation in PHP)
if(
isset($post_vars['data'])
) {
$data = $strip_slashes ? stripslashes_deep($post_vars['data']) : $post_vars['data'];
$data = self::mod_security_fix($data);
$data_array = is_string($data) ? json_decode($data, true) : array();
if(isset($data_array[$var])) { return $data_array[$var]; }
}
// Get return value
$return_value = isset($post_vars[$var]) ? ($esc_sql ? esc_sql($post_vars[$var]) : $post_vars[$var]) : $default;
$return_value = self::mod_security_fix($return_value);
return $strip_slashes ? stripslashes_deep($return_value) : $return_value;
}
// Get request var
public static function get_query_var_nonce($var, $default = '', $parameters = false, $esc_sql = false, $strip_slashes = true, $request_method_required = false, $request_method = false) {
// REST parameters
if($parameters !== false) {
if(isset($parameters[$var])) {
$return_value = $esc_sql ? esc_sql($parameters[$var]) : $parameters[$var];
$return_value = self::mod_security_fix($return_value);
return $strip_slashes ? stripslashes_deep($return_value) : $return_value;
}
}
// Get from standard _GET _POST arrays
$request_method = ($request_method === false) ? self::get_request_method() : $request_method;
if(!$request_method) { return $default; }
if(
($request_method_required !== false) &&
($request_method_required !== $request_method)
) {
return $default;
}
// NONCE enabled
$nonce_enabled = is_admin() || is_user_logged_in() || self::option_get('security_nonce');
// Check wp_verify_nonce exists
if($nonce_enabled && !function_exists('wp_verify_nonce')) { self::error_nonce(); }
// Regular GET, POST, PUT handling
switch($request_method) {
case 'GET' :
// If value is not set, return the default value
if(!isset($_GET)) { return $default; } // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitizedDetected
if(!isset($_GET[$var]) && !isset($_GET['data'])) { return $default; } // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitizedDetected
// NONCE
if(
$nonce_enabled &&
!self::$nonce_verified &&
(
!isset($_GET[WS_FORM_POST_NONCE_FIELD_NAME]) || // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitizedDetected.Missing, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Only checking if not set
!wp_verify_nonce(wp_unslash($_GET[WS_FORM_POST_NONCE_FIELD_NAME]), WS_FORM_POST_NONCE_ACTION_NAME) // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitizedDetected.Missing, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Only checking if not set
)
) {
self::error_nonce();
} else {
self::$nonce_verified = true;
}
$post_vars = $_GET; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitizedDetected.Missing, WordPress.Security.ValidatedSanitizedInput.InputNotSanitizedDetected -- Sanitized below
break;
case 'POST' :
// If value is not set, return the default value
if(!isset($_POST)) { return $default; } // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitizedDetected.Missing, WordPress.Security.ValidatedSanitizedInput.InputNotSanitizedDetected -- Sanitized below
if(!isset($_POST[$var]) && !isset($_POST['data'])) { return $default; } // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitizedDetected.Missing, WordPress.Security.ValidatedSanitizedInput.InputNotSanitizedDetected -- Sanitized below
// NONCE
if(
$nonce_enabled &&
!self::$nonce_verified &&
(
!isset($_POST[WS_FORM_POST_NONCE_FIELD_NAME]) || // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitizedDetected.Missing, WordPress.Security.ValidatedSanitizedInput.InputNotSanitizedDetected, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Sanitized below
!wp_verify_nonce(wp_unslash($_POST[WS_FORM_POST_NONCE_FIELD_NAME]), WS_FORM_POST_NONCE_ACTION_NAME) // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitizedDetected.Missing, WordPress.Security.ValidatedSanitizedInput.InputNotSanitizedDetected, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Sanitized below
)
) {
self::error_nonce();
} else {
self::$nonce_verified = true;
}
$post_vars = $_POST; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitizedDetected.Missing, WordPress.Security.ValidatedSanitizedInput.InputNotSanitizedDetected -- Sanitized below
break;
case 'PUT' :
// PUT method data is in php://input so parse that into $post_vars
parse_str(file_get_contents('php://input'), $post_vars); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents -- Required for reading raw POST data from php://input stream
// NONCE
if(
$nonce_enabled &&
!self::$nonce_verified &&
(
!isset($post_vars[WS_FORM_POST_NONCE_FIELD_NAME]) ||
!wp_verify_nonce(wp_unslash($post_vars[WS_FORM_POST_NONCE_FIELD_NAME]), WS_FORM_POST_NONCE_ACTION_NAME)
)
) {
self::error_nonce();
} else {
self::$nonce_verified = true;
}
$strip_slashes = false;
break;
default :
return $default;
}
// DATA param (This overcomes standard 1000 POST parameter limitation in PHP)
if(
isset($post_vars['data'])
) {
$data = $strip_slashes ? stripslashes_deep($post_vars['data']) : $post_vars['data'];
$data = self::mod_security_fix($data);
$data_array = is_string($data) ? json_decode($data) : array();
if(isset($data_array->{$var})) { return $data_array->{$var}; }
}
// Get return value
$return_value = isset($post_vars[$var]) ? ($esc_sql ? esc_sql($post_vars[$var]) : $post_vars[$var]) : $default;
$return_value = self::mod_security_fix($return_value);
return $strip_slashes ? stripslashes_deep($return_value) : $return_value;
}
// nonce error
public static function error_nonce() {
// Simulate WordPress error
$code = 'rest_forbidden';
$message = __('Sorry, you are not allowed to do that (WSF).', 'ws-form');
$status = rest_authorization_required_code();
// Build response
$response = array(
'code' => $code,
'message' => $message,
'data' => array(
'status' => $status
)
);
// Set HTTP content type header
header('Content-Type: application/json');
// Set HTTP response code in case a hook has changed this
http_response_code($status);
// Send response
self::echo_wp_json_encode($response);
exit;
}
// Return string with wp_filter_post_kses applied if user does not have unfiltered_html capability
// If DISALLOW_UNFILTERED_HTML is true then unfiltered_html capability is removed in core
public static function santitize_unfiltered_input($value, $key = false) {
$user_unfiltered_html = self::can_user('unfiltered_html');
// User is permitted to use unfiltered HTML to return value
if($user_unfiltered_html) { return $value; }
// Strings
if(is_string($value)) {
return wp_kses_post($value);
}
// Arrays
if(is_array($value)) {
// Check for custom attributes
switch($key) {
// Check the attribute names and attempt to filter anything that might result in JavaScript execution.
case 'custom_attributes' :
foreach($value as $custom_attribute_index => $custom_attribute_row) {
// Check that name and value exist in repeater row
if(!isset($custom_attribute_row->custom_attribute_name)) { continue; }
if(!isset($custom_attribute_row->custom_attribute_value)) { continue; }
// Get attribute name
$attribute_name = $custom_attribute_row->custom_attribute_name;
if(empty($attribute_name)) { continue; }
// Sanitize the name
$attribute_name_sanitized = strtolower(trim(preg_replace('/[^A-Za-z]/', '', $attribute_name)));
// HTML event attributes begin with 'on'
if(strpos($attribute_name_sanitized, 'on') === 0) {
// Remove row containing HTML event attribute
unset($value[$custom_attribute_index]);
continue;
}
// Get attribute value
$attribute_value = $custom_attribute_row->custom_attribute_value;
// Sanitize name and value
$value[$custom_attribute_index]->custom_attribute_name = preg_replace('/[^\p{L}0-9_.-]/', '', $attribute_name);
$value[$custom_attribute_index]->custom_attribute_value = esc_attr($attribute_value);
}
return $value;
}
}
// Objects
if(is_object($value)) {
// Check for custom attributes
switch($key) {
// Data grids
case 'data_grid_datalist' :
case 'data_grid_select' :
case 'data_grid_select_price' :
case 'data_grid_checkbox' :
case 'data_grid_checkbox_price' :
case 'data_grid_radio' :
case 'data_grid_radio_price' :
return self::santitize_unfiltered_input_data_grid($value);
}
}
return $value;
}
// Sanitize data grid
public static function santitize_unfiltered_input_data_grid($value) {
// Get groups
if(!property_exists($value, 'groups')) { return $value; }
if(!is_array($value->groups)) { return $value; }
$groups = $value->groups;
foreach($groups as $group_index => $group) {
// Get rows
if(!property_exists($group, 'rows')) { continue; }
if(!is_array($group->rows)) { continue; }
$rows = $group->rows;
foreach($rows as $row_index => $row) {
// Get data
if(!property_exists($row, 'data')) { continue; }
if(!is_array($row->data)) { continue; }
$data = $row->data;
foreach($data as $data_index => $data_value) {
$value->groups[$group_index]->rows[$row_index]->data[$data_index] = wp_kses_post($data_value);
}
}
}
return $value;
}
// mod_security fix
public static function mod_security_fix($fix_this) {
if(is_string($fix_this)) {
$fix_this = str_replace('~WSF%23~', '#', $fix_this);
$fix_this = str_replace('~WSF%60~', '<', $fix_this);
$fix_this = str_replace('~WSF%62~', '>', $fix_this);
$fix_this = str_replace('~WSFTCELES~', 'SELECT', $fix_this);
$fix_this = str_replace('~WSFtceles~', 'select', $fix_this);
$fix_this = str_replace('~WSFtceleS~', 'Select', $fix_this);
$fix_this = str_replace('~WSFelyts~', 'style', $fix_this);
$fix_this = str_replace('~WSFELYTS~', 'STYLE', $fix_this);
$fix_this = str_replace('~WSFcrs~', 'src', $fix_this);
$fix_this = str_replace('~WSFCRS~', 'SRC', $fix_this);
$fix_this = str_replace('~WSFsnlmx~', 'xmlns', $fix_this);
$fix_this = str_replace('~WSFSNLMX~', 'XMLNS', $fix_this);
$fix_this = str_replace('~WSFid_tcejbo~', 'object_id', $fix_this);
return $fix_this;
}
if(is_array($fix_this)) {
foreach($fix_this as $key => $fix_this_single) {
$fix_this[$key] = self::mod_security_fix($fix_this_single);
}
return $fix_this;
}
return $fix_this;
}
// Get IP lookup
public static function get_ip_lookup($var_array, $ip_lookup_method = '') {
if(!is_array($var_array)) { $var_array = array($var_array); }
if(self::$ip_lookup_response === false) {
// Get remote IP address (Sanitized with sanitize_ip_address below)
$remote_addr = self::get_ip();
if($remote_addr == '') { return ''; }
// Split IP (IP can be comma separated if proxy in use)
$ip_array = explode(',', $remote_addr);
$ip_lookup = false;
foreach($ip_array as $ip) {
// Trim
$ip = trim($ip);
// Validate IP
if(self::sanitize_ip_address($ip) === false) { continue; }
// Use valid IP found
$ip_lookup = $ip;
break;
}
if($ip_lookup !== false) {
// Build URL
switch($ip_lookup_method) {
case 'ipinfo' :
// Check for API key
$ip_lookup_ipinfo_key = sanitize_text_field(self::option_get('ip_lookup_ipinfo_key'));
if(!empty($ip_lookup_ipinfo_key)) {
// Commercial use
$url = sprintf('https://ipinfo.io/%s/json?token=%s', $ip_lookup, $ip_lookup_ipinfo_key);
} else {
// Non-commercial use
$url = sprintf('https://ipinfo.io/%s/json', $ip_lookup);
}
break;
case 'ipapi' :
// Check for API key
$ip_lookup_ipapi_key = sanitize_text_field(self::option_get('ip_lookup_ipapi_key'));
if(!empty($ip_lookup_ipapi_key)) {
// Commercial use
$url = sprintf('https://pro.ip-api.com/json/%s?fields=country,region,city,zip,lat,lon,timezone&key=%s', $ip_lookup, $ip_lookup_ipapi_key);
} else {
// Non-commercial use (HTTP only)
$url = sprintf('http://ip-api.com/json/%s?fields=country,region,city,zip,lat,lon,timezone', $ip_lookup);
}
break;
case 'ipapico' :
// Check for API key
$ip_lookup_ipapico_key = sanitize_text_field(self::option_get('ip_lookup_ipapico_key'));
if(!empty($ip_lookup_ipapico_key)) {
// Commercial use
$url = sprintf('https://ipapi.co/%s/json?key=%s', $ip_lookup, $ip_lookup_ipapico_key);
} else {
// Non-commercial use (HTTP only)
$url = sprintf('http://ipapi.co/%s/json', $ip_lookup);
}
break;
default :
// Data requested from geoplugin.net that uses GeoLite data created by MaxMind, available from http://www.maxmind.com
// Check for API key
$ip_lookup_geoplugin_key = sanitize_text_field(self::option_get('ip_lookup_geoplugin_key'));
if(!empty($ip_lookup_geoplugin_key)) {
$url = sprintf('https://ssl.geoplugin.net/json.gp?ip=%s&k=%s', $ip_lookup, $ip_lookup_geoplugin_key);
} else {
$url = sprintf('http://www.geoplugin.net/json.gp?ip=%s', $ip_lookup);
}
}
// Sanitize URL
$url = sanitize_url($url);
// Build args
$args = array(
'headers' => array(
// Set referrer. PHP CURL defaults to request URL.
'referer' => self::get_referrer()
),
'user-agent' => self::get_request_user_agent(),
'timeout' => self::get_request_timeout(),
'sslverify' => self::get_request_sslverify()
);
// Do IP Lookup
$wp_remote_get_response = wp_remote_get($url, $args);
// Check for errors
if(!is_wp_error($wp_remote_get_response)) {
$ip_lookup_response = wp_remote_retrieve_body($wp_remote_get_response);
// Build data
self::$ip_lookup_response = json_decode($ip_lookup_response);
if(is_null(self::$ip_lookup_response)) {
// Set to true if error so we don't request again
self::$ip_lookup_response = true;
} else {
// Convert to array
self::$ip_lookup_response = (array) self::$ip_lookup_response;
}
} else {
// Set to true so we don't make any further requests
self::$ip_lookup_response = true;
}
}
}
// Lookup geo data and return the result
if(is_array(self::$ip_lookup_response)) {
$return_array = array();
foreach($var_array as $var) {
if(isset(self::$ip_lookup_response[$var])) {
$return_array[] = self::$ip_lookup_response[$var];
}
}
return implode(',', $return_array);
}
return '';
}
// Get MySQL date
public static function get_mysql_date($date = false) {
$time = ($date === false) ? time() : strtotime($date);
if($time === false) { return false; }
$date = gmdate('Y-m-d H:i:s', $time);
return $date;
}
// Get request method
public static function get_request_method($valid_request_methods = false) {
// Check for valid request methods
if(!$valid_request_methods) { $valid_request_methods = ['GET', 'POST', 'PUT', 'DELETE']; }
// Read request method
$request_method = strtoupper(
wp_unslash(isset($_SERVER["REQUEST_METHOD"]) ? $_SERVER["REQUEST_METHOD"] : '') // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitizedDetected.Missing, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Sanitized to check for valid request method below
);
// Ensure it is valid
if(!in_array($request_method, $valid_request_methods)) { return false; }
return ($request_method != '') ? $request_method : false;
}
// Get current user ID (TO DO: We're going to drop this function in future versions)
public static function get_user_id($exit_on_zero = true) {
$user_id = get_current_user_id();
if(($user_id == 0) && $exit_on_zero) { exit; }
return($user_id);
}
// Get request URL
public static function get_request_url() {
return home_url(sanitize_url(wp_unslash(isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : '')));
}
// Add query arg from key value pair, but retain periods in keys
public static function wsf_add_query_args($params, $url) {
if(!is_array($params)) { return $url; }
foreach($params as $key => $value) {
// The function add_query_arg changes periods to underscores
// We don't want this because some APIs (e.g. AWeber) require periods in keys
// Lets change periods to a different string so we can recover them later
$key = str_replace('.', '~WSFPERIOD~', $key);
// URL encode the value(s)
if(is_array($value)) {
array_walk_recursive($value, function (&$value) {
$value = rawurlencode($value);
});
} else {
$value = rawurlencode($value);
}
// Add key value to URL
$url = add_query_arg($key, $value, $url);
}
// Recover periods
$url = str_replace('~WSFPERIOD~', '.', $url);
return $url;
}
// Get current URL (Used by add-ons during oAuth)
public static function get_current_url() {
// Check $_SERVER global exists
// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.NonceVerification.Missing -- Checking exists, sanitized below
if(!isset($_SERVER)) { return ''; }
// Get server
// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.NonceVerification.Missing -- Method ultimately uses sanitize_url
$server = $_SERVER;
// Build prefix
$request_url = (isset($server['HTTPS']) && $server['HTTPS'] === 'on') ? 'https://' : 'http://';
// Add hostname
if(isset($server['HTTP_HOST'])) { $request_url .= $server['HTTP_HOST']; }
// Add request URI
if(isset($server['REQUEST_URI'])) { $request_url .= $server['REQUEST_URI']; }
return sanitize_url($request_url);
}
// Add query string to URL
public static function add_query_string($url, $query_string) {
$url_parsed = wp_parse_url($url);
if(!isset($url_parsed['path'])) { $url .= '/'; }
$separator = isset($url_parsed['query']) ? '&' : '?';
$url .= $separator . $query_string;
return $url;
}
// Echo comment - CSS
public static function comment_css($comment) {
// Should CSS be commented?
$comments_css = self::option_get('comments_css', true);
if($comments_css) {
// Echo comment
$return_css = sprintf("/* %s */\n", esc_html($comment));
} else {
$return_css = '';
}
return $return_css;
}
// SVG Render
public static function render_icon_16_svg($id) {
self::echo_esc_svg(WS_Form_Config::get_icon_16_svg($id));
}
// Check form status
public static function check_form_status($status) {
return in_array($status, array(
'draft',
'publish',
'trash'
), true) ? $status : '';
}
// Check form order by
public static function check_form_order_by($order_by) {
return in_array($order_by, array(
'status',
'label',
'id',
'count_submit',
'count_stat_view',
'conversion'
), true) ? $order_by : '';
}
// Check form order
public static function check_form_order($order) {
return in_array($order, array(
'asc',
'desc'
), true) ? $order : '';
}
// Check style status
public static function check_style_status($status) {
return in_array($status, array(
'draft',
'publish',
'trash'
), true) ? $status : '';
}
// Check style order by
public static function check_style_order_by($order_by) {
return in_array($order_by, array(
'label',
'id'
), true) ? $order_by : '';
}
// Check style order
public static function check_style_order($order) {
return in_array($order, array(
'asc',
'desc'
), true) ? $order : '';
}
// Check submit status
public static function check_submit_status($status) {
return in_array($status, array(
'draft',
'publish',
'error',
'spam',
'trash'
), true) ? $status : '';
}
// Get API base path
public static function get_api_path($path = '', $query_string = false) {
// Check permalinks
if(get_option('permalink_structure') != '') {
$api_path = rest_url() . WS_FORM_RESTFUL_NAMESPACE . '/' . $path;
if($query_string !== false) { $api_path .= '?' . $query_string; }
} else {
// Split path and inline query
$path_parts = explode('?', $path, 2);
$path_encoded = rawurlencode('/' . WS_FORM_RESTFUL_NAMESPACE . '/' . $path_parts[0]);
$api_path = get_site_url(null, '/') . '?rest_route=' . $path_encoded;
// Inline query (from path itself)
if(!empty($path_parts[1])) {
$api_path .= '&' . $path_parts[1];
}
// Additional query string parameter (passed via $query_string)
if($query_string !== false) {
$api_path .= '&' . $query_string;
}
}
return $api_path;
}
// Is debug enabled?
public static function debug_enabled() {
if(
self::is_block_editor() ||
self::is_customize_preview()
) { return false; }
$debug_enabled = false;
switch(self::option_get('helper_debug', 'off')) {
case 'administrator' :
if(function_exists('wp_get_current_user')) {
// Works better for multisite than checking roles. Roles are not available in WP_User on multisite
$debug_enabled = current_user_can('activate_plugins');
}
break;
case 'on' :
$debug_enabled = true;
break;
}
// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- All hooks prefixed with wsf_
return apply_filters('wsf_debug_enabled', $debug_enabled);
}
// Is abilities API enabled?
public static function abilities_api_enabled() {
return (
// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- All hooks prefixed with wsf_
apply_filters('wsf_abilities_api_enabled', WS_FORM_ABILITY_API) &&
class_exists('WP_Ability')
);
}
// Is MCP adapter enabled?
public static function mcp_adapter_enabled($include_setting = true) {
return (
// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- All hooks prefixed with wsf_
apply_filters('wsf_mcp_adapter_enabled', WS_FORM_MCP_ADAPTER) &&
self::abilities_api_enabled() &&
// Available via the MCP Adapter plugin or as a Composer dependency of another plugin (e.g. WooCommerce)
class_exists('WP\MCP\Core\McpAdapter') &&
($include_setting ? self::option_get('mcp_adapter', false) : true)
);
}
// Is Angie enabled?
public static function angie_enabled($include_setting = true) {
return (
// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- All hooks prefixed with wsf_
apply_filters('wsf_angie_enabled', WS_FORM_ANGIE) &&
defined('ANGIE_VERSION') &&
($include_setting ? self::option_get('angie', true) : true)
);
}
// Is WP AI client enabled?
public static function wp_ai_client_enabled() {
return (
// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- All hooks prefixed with wsf_
apply_filters('wsf_ai_wp_client_enabled', WS_FORM_WP_AI_CLIENT) &&
class_exists('WordPress\AiClient\AiClient') &&
function_exists('wp_ai_client_prompt') // WP AI Client
);
}
// Is WP AI client usable?
public static function wp_ai_client_usable() {
if(!self::wp_ai_client_enabled()) { return false; }
try {
// Returns true only if a configured, text-capable AI provider is available
return \WordPress\AiClient\AiClient::prompt()->isSupportedForTextGeneration();
} catch(Exception $e) {
return false;
}
}
// Is styler enabled?
public static function styler_enabled() {
return (
// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- All hooks prefixed with wsf_
apply_filters('wsf_styler_enabled', WS_FORM_STYLER) &&
(self::option_get('framework', 'ws-form', false, true, false, true) === 'ws-form')
);
}
// Is styler visible in admin?
public static function styler_visible_admin() {
return (
self::styler_enabled() &&
self::can_user('read_form_style')
);
}
// Should styler be visible on site?
public static function styler_visible_public() {
return (
self::styler_visible_admin() &&
(
!empty(self::get_query_var('wsf_preview_style_id')) ||
!empty(self::get_query_var('wsf_preview_styler'))
)
);
}
// Is styler preview template being shown?
public static function styler_preview_template_shown() {
return (
self::styler_visible_public() &&
!empty(self::get_query_var('wsf_preview_template_id'))
);
}
// Is customizer enabled?
public static function customizer_enabled() {
return !self::styler_enabled();
}
// Is customizer visible?
public static function customizer_visible() {
return (
self::customizer_enabled() &&
(self::option_get('framework', 'ws-form') === 'ws-form') &&
self::can_user('customize') &&
self::can_user('read_form')
);
}
// Legacy color functions for add-ons
public static function hex_lighten_percentage($hex, $percentage) {
return WS_Form_Color::hex_color_lighten_percentage($hex, $percentage);
}
public static function hex_darken_percentage($hex, $percentage) {
return WS_Form_Color::hex_color_darken_percentage($hex, $percentage);
}
// Clean wp_remote_post
public static function wp_remote_post_clean( $url, $args = array() ) {
// Backup existing filters
global $wp_filter;
$saved_filters = array();
$filter_keys = array('http_request_args', 'http_api_curl', 'pre_http_request', 'http_response');
foreach($filter_keys as $key) {
if(isset($wp_filter[$key])) {
$saved_filters[$key] = $wp_filter[$key];
remove_all_filters($key);
}
}
// Make the request
$response = wp_remote_post($url, $args);
// Restore filters
foreach($saved_filters as $key => $filters) {
$wp_filter[$key] = $filters;
}
return $response;
}
// Check to see if object should show
public static function object_show($object, $object_prefix, $current_user, $user_roles) {
// Object user status
$object_user_status = self::get_object_meta_value($object, $object_prefix . '_user_status', '');
$object_user_roles = self::get_object_meta_value($object, $object_prefix . '_user_roles', false);
$object_user_capabilities = self::get_object_meta_value($object, $object_prefix . '_user_capabilities', false);
if($object_user_status) {
$object_show = false;
switch($object_user_status) {
// Must be logged in
case 'on' :
if($current_user->ID > 0) { $object_show = true; }
break;
// Must be logged out
case 'out' :
if($current_user->ID == 0) { $object_show = true; }
break;
// Must have user role or capability
case 'role_capability' :
if(is_array($object_user_roles) && (count($object_user_roles) > 0)) {
$user_role_ok = false;
if(is_user_logged_in()) {
foreach($object_user_roles as $object_user_role) {
if(in_array($object_user_role, $user_roles)) {
$user_role_ok = true;
}
}
}
} else {
$user_role_ok = true;
}
if(is_array($object_user_capabilities) && (count($object_user_capabilities) > 0)) {
$user_capability_ok = false;
if(is_user_logged_in()) {
foreach($object_user_capabilities as $object_user_capability) {
if(self::can_user($object_user_capability)) {
$user_capability_ok = true;
}
}
}
} else {
$user_capability_ok = true;
}
if($user_role_ok && $user_capability_ok) { $object_show = true; }
break;
}
} else {
return true;
}
return $object_show;
}
// Get all fields from form
public static function get_fields_from_form($form_object, $no_cache = false, $filter_group_ids = false, $filter_section_ids = false) {
// Retrieve from cache
if(!$no_cache && (self::$fields !== false)) { return self::$fields; }
// Get fields
$fields = self::get_fields_from_form_group($form_object->groups, $filter_group_ids, $filter_section_ids);
// Add to cache
self::$fields = $fields;
return $fields;
}
// Get all fields from form
public static function get_field_types($no_cache = false) {
// Retrieve from cache
if(!$no_cache && (self::$field_types !== false)) { return self::$field_types; }
// Get field types
$field_types = WS_Form_Config::get_field_types_flat();
// Add to cache
self::$field_types = $field_types;
return $field_types;
}
// Run through each group
public static function get_fields_from_form_group($groups, $filter_group_ids, $filter_section_ids) {
$fields = array();
foreach($groups as $key => $group) {
// Get group ID
$group_id = $group->id;
// Filter group IDs
if(
($filter_group_ids !== false) &&
!in_array($group_id, $filter_group_ids)
) {
continue;
}
if(isset($groups[$key]->sections)) {
$section_fields = self::get_fields_from_form_section($key, $group->sections, $filter_section_ids);
$fields = $fields + $section_fields;
}
}
return $fields;
}
// Run through each section
public static function get_fields_from_form_section($group_key, $sections, $filter_section_ids) {
$fields = array();
foreach($sections as $section_key => $section) {
// Get section ID
$section_id = $section->id;
// Filter section IDs
if(
($filter_section_ids !== false) &&
!in_array($section_id, $filter_section_ids)
) {
continue;
}
// Check if repeatable
$section_repeatable = isset($section->meta) && isset($section->meta->section_repeatable) && !empty($section->meta->section_repeatable);
if(isset($sections[$section_key]->fields)) {
$section_fields = array();
foreach($section->fields as $field_key => $field) {
$field->group_key = $group_key;
$field->section_key = $section_key;
$field->field_key = $field_key;
$field->section_id = $section_id;
$field->section_repeatable = $section_repeatable;
$section_fields[$field->id] = $field;
}
$fields = $fields + $section_fields;
}
}
return $fields;
}
// Get all sections from form
public static function get_sections_from_form($form_object, $no_cache = false, $get_fields = true, $get_meta = true) {
// Retrieve from cache
if(!$no_cache && (self::$sections !== false)) { return self::$sections; }
// Get sections
$sections = self::get_sections_from_form_group($form_object->groups, $get_fields, $get_meta);
// Add to cache
self::$sections = $sections;
return $sections;
}
// Run through each group
public static function get_sections_from_form_group($groups, $get_fields = true, $get_meta = true) {
$sections_return = array();
foreach($groups as $key => $group) {
if(isset($groups[$key]->sections)) {
$section_fields = self::get_sections_from_form_section($group->sections, $get_fields, $get_meta);
$sections_return = $sections_return + $section_fields;
}
}
return $sections_return;
}
// Run through each section
public static function get_sections_from_form_section($sections, $get_fields = true, $get_meta = true) {
$sections_return = array();
foreach($sections as $key => $section) {
// Get section ID
$section_id = $section->id;
$sections_return[$section_id] = new stdClass();
$sections_return[$section_id]->label = $section->label;
$sections_return[$section_id]->fields = array();
$sections_return[$section_id]->meta = new stdClass();
// Check if repeatable
$sections_return[$section_id]->repeatable = isset($section->meta) && isset($section->meta->section_repeatable) && !empty($section->meta->section_repeatable);
if(isset($section->fields) && $get_fields) {
$section_fields = array();
foreach($section->fields as $field) {
$section_fields[$field->id] = $field;
}
$sections_return[$section_id]->fields = $section_fields;
}
if(isset($section->meta) && $get_meta) {
$sections_return[$section_id]->meta = $section->meta;
}
}
return $sections_return;
}
// Get all groups from form
public static function get_groups_from_form($form_object, $no_cache = false) {
// Retrieve from cache
if(!$no_cache && (self::$groups !== false)) { return self::$groups; }
// Get groups
$groups = array();
foreach($form_object->groups as $key => $group) {
$groups[$group->id] = new stdClass();
$groups[$group->id]->label = $group->label;
}
// Add to cache
self::$groups = $groups;
return $groups;
}
// Get field type config meta keys
public static function get_field_type_config_meta_keys($field_type_config, $meta_keys, $meta_keys_return = array()) {
if(!isset($field_type_config['fieldsets'])) { return $meta_keys_return; }
foreach($field_type_config['fieldsets'] as $id => $fieldset) {
// Process meta_keys
if(isset($fieldset['meta_keys'])) {
foreach($fieldset['meta_keys'] as $meta_key) {
// Check for key
if(!isset($meta_keys[$meta_key])) { continue; }
$meta_key_config = $meta_keys[$meta_key];
if(isset($meta_key_config['key'])) {
$meta_key = $meta_key_config['key'];
}
$meta_keys_return[$meta_key] = true;
}
}
// Process fieldsets
if(isset($fieldset['fieldsets'])) {
$meta_keys_return = self::get_field_type_config_meta_keys($fieldset, $meta_keys, $meta_keys_return);
}
}
return $meta_keys_return;
}
// Mask parse
public static function mask_parse($mask, $values, $prefix = '#', $single_parse = false) {
if($mask == '') { return ''; }
// Final sort
uksort($values, function($variable_a, $variable_b) {
if($variable_a === $variable_b) { return 0; }
$variable_a_is_function = (strpos($variable_a, '(') !== false);
$variable_b_is_function = (strpos($variable_b, '(') !== false);
if($variable_a_is_function && $variable_b_is_function) {
return $variable_a < $variable_b ? 1 : -1;
}
if(
(!$variable_a_is_function && $variable_b_is_function) ||
($variable_a_is_function && !$variable_b_is_function)
) {
return $variable_a_is_function < $variable_b_is_function ? 1 : -1;
}
return $variable_a < $variable_b ? 1 : -1;
});
foreach($values as $key => $value) {
if(is_null($value)) { $value = ''; }
if($single_parse) {
// Single parse
$replace = '/' . preg_quote($prefix . $key, '/') . '/';
$mask = preg_replace($replace, $value, $mask, 1);
} else {
// Multi parse (Default)
$mask = str_replace($prefix . $key, $value, $mask);
}
}
return $mask;
}
// Create block markup
public static function block_markup($form_id = false) {
// Get block markup
$block = array(
'blockName' => 'wsf-block/form-add',
'attrs' => array( 'form_id' => (string) $form_id ),
'innerBlocks' => array(),
'innerHTML' => '',
);
// Return data
return serialize_block( $block );
}
// Create shortcode
public static function shortcode($form_id = false) {
$form_id = absint($form_id);
if($form_id === 0) { return ''; }
return sprintf('[%s id="%u"]', WS_FORM_SHORTCODE, esc_attr($form_id));
}
// Check file upload capabilities
public static function uploads_check() {
// Create file warnings
$files_warning = [];
// max_file_uploads
// Default: 20
$max_file_uploads = absint(ini_get('max_file_uploads') ? ini_get('max_file_uploads') : '20');
// Check file permissions
$upload_dir_create = self::upload_dir_create();
if($upload_dir_create['error']) { $files_warning[] = $upload_dir_create['message']; }
// Return result
return ['max_upload_size' => wp_max_upload_size(), 'max_uploads' => $max_file_uploads, 'errors' => $files_warning];
}
// Make sure upload folder can be created. Create it if it doesn't exist.
public static function upload_dir_create($dir = '') {
// Get base upload_dir
$upload_dir = wp_upload_dir()['basedir'];
// Check upload directory can be written to
if(!WS_Form_File::is_writeable($upload_dir)) { return ['error' => true, 'message' => esc_html__('Your WordPress uploads directory cannot be written to.', 'ws-form')]; }
// Get WS Form upload dir
$upload_dir_path = WS_FORM_UPLOAD_DIR . (($dir != '') ? '/' . $dir : '');
$upload_dir_ws_form = $upload_dir . '/' . $upload_dir_path;
// Check to see if WS Forms upload folder exists
if(!WS_Form_File::file_exists($upload_dir_ws_form)) {
if(!wp_mkdir_p($upload_dir_ws_form)) { return ['error' => true, 'message' => sprintf(
/* translators: %s: Upload path */
esc_html__('Unable to create upload folder for uploaded files (wp-content/uploads/%s).', 'ws-form'),
$upload_dir_path
)]; }
}
return ['error' => false, 'dir' => $upload_dir_ws_form, 'path' => $upload_dir_path];
}
// Check path is valid
public static function check_path($path_base) {
$illegal_paths = array('..', '~');
foreach($illegal_paths as $illegal_path) {
if(strpos($path_base, $illegal_path) !== false) { wp_die(esc_html__('Invalid Path', 'ws-form')); }
}
$path = realpath($path_base);
if(strpos($path, $path_base) !== 0 || strpos($path, $path_base) === false) { wp_die(esc_html__('Invalid Path', 'ws-form')); }
return $path_base;
}
// Get HTTP environment variable (Accepts array for multiple HTTP environment variable checks)
// Return from this function must be sanitized
public static function get_http_env_raw($variable_array) {
// Checks
if(!isset($_SERVER)) { return ''; } // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
if(!is_array($variable_array)) { $variable_array = array($variable_array); }
$variable_array_index_last = count($variable_array) - 1;
// Run through each variable
foreach($variable_array as $variable_array_index => $variable) {
$server_variable = wp_unslash(isset($_SERVER[$variable]) ? $_SERVER[$variable] : ''); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Return function sanitizes
if($variable_array_index == $variable_array_index_last) {
return $server_variable;
} else {
if(!empty($server_variable)) return $server_variable;
}
}
return '';
}
// Get IP
public static function get_ip() {
return self::sanitize_ip_address(self::get_http_env_raw(array(
'HTTP_CF_CONNECTING_IP', // Cloudflare passthrough IP address
'HTTP_CLIENT_IP', // Client IP
'HTTP_X_FORWARDED_FOR', // Forwarded IP
'REMOTE_ADDR' // Remote address
)));
}
// Ger user agent
public static function get_user_agent() {
return sanitize_text_field(self::get_http_env_raw(array('HTTP_USER_AGENT')));
}
// Get referrer
public static function get_referrer() {
return sanitize_url(self::get_http_env_raw(array('HTTP_REFERER')));
}
// Get wp_remote_* user agent string
public static function get_request_user_agent() {
return sprintf('WSForm/%s (wsform.com)', WS_FORM_VERSION);
}
// Get wp_remote_* timeout
public static function get_request_timeout($timeout = WS_FORM_API_CALL_TIMEOUT) {
// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- All hooks prefixed with wsf_
return apply_filters('wsf_api_call_timeout', $timeout);
}
// Get wp_remote_* sslverify
public static function get_request_sslverify($ssl_verify = WS_FORM_API_CALL_SSL_VERIFY) {
// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- All hooks prefixed with wsf_
return apply_filters('wsf_api_call_verify_ssl', $ssl_verify);
}
// Get object property
public static function get_object_property($object, $property, $default_value = '') {
// Check for meta data
if(
!is_object($object) ||
!property_exists($object, $property)
) {
return $default_value;
}
return $object->{$property};
}
// Get object var (Legacy)
public static function get_object_var($object, $property, $default_value = '') {
return self::get_object_property($object, $property, $default_value);
}
// Get object meta value
public static function get_object_meta_value($object, $meta_key, $default_value = '') {
// Checks
if(
!is_object($object) ||
!property_exists($object, 'meta') ||
!property_exists($object->meta, $meta_key)
) {
return $default_value;
}
return $object->meta->{$meta_key};
}
// Get array meta value
public static function get_array_meta_value($array, $meta_key, $default_value = '') {
// Check for meta data
if(!isset($array['meta'])) { return $default_value; }
// Check for meta_key
if(!isset($array['meta']->{$meta_key})) { return $default_value; }
return $array['meta']->{$meta_key};
}
// Get URL from string
public static function get_url($url_input) {
return (filter_var($url_input, FILTER_VALIDATE_URL) ? $url_input : '');
}
// Get tel from string
public static function get_tel($tel_input) {
return preg_replace('/[^+\d]+/', '', $tel_input);
}
// Get email address from string
public static function get_email($email_input) {
return (filter_var($email_input, FILTER_VALIDATE_EMAIL) ? $email_input : '');
}
// Get string from any type of input
public static function get_string($value, $delimiter = ',') {
// Check for string
if(is_string($value)) { return $value; }
// Check for boolean
if(is_bool($value)) { return $value ? '1' : '0'; }
// Check for number
if(is_numeric($value)) { return strval($value); }
// Check for object
if(is_object($value)) { $value = (array) $value; }
// Ensure value is a string
if(is_array($value)) {
$value_new = array();
foreach($value as $value_element) {
if(
is_string($value_element) ||
is_numeric($value_element)
) {
$value_new[] = (string) $value_element;
}
}
$value = implode($delimiter, $value_new);
}
return $value;
}
// Get float with fraction from string
public static function get_number($number_input, $default_value = 0, $process_currency = false, $decimals = false) {
// Convert numbers to text
if(is_numeric($number_input)) { $number_input = strval($number_input); }
// Check input is a string
if(!is_string($number_input)) { return 0; }
// Trim input
$number_input = trim($number_input);
// Convert from current currency
if($process_currency) {
$currency = self::get_currency();
// Filter characters required for floatval
$decimal_separator = $currency['decimal_separator'];
$thousand_separator = $currency['thousand_separator'];
// Ensure the decimal separator setting is included in the regex (Add ,. too in case default value includes alternatives)
$number_input = preg_replace('/[^0-9-' . $decimal_separator . ']/', '', $number_input);
if($decimal_separator === $thousand_separator) {
// Convert decimal separators to periods so floatval works
if(substr($number_input, -3, 1) === $decimal_separator) {
$decimal_index = (strlen($number_input) - 3);
$number_input = substr($number_input, 0, $decimal_index) . '[dec]' . substr($number_input, $decimal_index + 1);
}
// Remove thousand separators
$number_input = str_replace($thousand_separator, '', $number_input);
// Replace [dec] back to decimal separator for floatval
$number_input = str_replace('[dec]', '.', $number_input);
} else {
// Replace [dec] back to decimal separator for floatval
$number_input = str_replace($decimal_separator, '.', $number_input);
}
}
// floatval converts decimal separator to period to ensure that function works
$number_output = (trim($number_input) === '') ? $default_value : (!is_numeric($number_input) ? $default_value : floatVal($number_input));
// Round
if($decimals !== false) { $number_output = round(floatval($number_output), $decimals); }
return $number_output;
}
// Get array of MIME types
public static function get_mime_array($value) {
if(is_array($value)) { return $value; }
$mime_array = explode(',', $value);
$mime_array_return = array();
foreach($mime_array as $mime) {
$mime_split = $mime_array = explode('/', $mime);
if(count($mime_split) !== 2) { continue; }
if(strlen($mime_split[0]) == 0) { continue; }
if(strlen($mime_split[1]) == 0) { continue; }
$mime_array_return[] = strtolower(trim($mime));
}
return $mime_array_return;
}
// Get accept string
public static function get_accept_string($mime_type_filter_include = false, $mime_type_filter_exclude = false) {
// Get MIME types
$mime_types = wp_get_mime_types();
// Build accept array
$accept_array = array();
foreach($mime_types as $extensions => $mime_type) {
// Filter - Include
if($mime_type_filter_include !== false) {
foreach($mime_type_filter_include as $mime_type_filter) {
if(strpos($mime_type, $mime_type_filter) === false) { continue 2; }
}
}
// Filter - Exclude
if($mime_type_filter_exclude !== false) {
foreach($mime_type_filter_exclude as $mime_type_filter) {
if(strpos($mime_type, $mime_type_filter) !== false) { continue 2; }
}
}
// Split extensions
$extension_array = explode('|', $extensions);
foreach($extension_array as $extension) {
$accept_array[] = sprintf('.%s', $extension);
}
// Add MIME type
$accept_array[] = $mime_type;
}
return implode(',', $accept_array);
}
// Add datestamp to filename
public static function filename_datestamp($filename_prefix, $filename_suffix) {
$filename = $filename_prefix . (self::wp_version_at_least('5.3') ? current_datetime()->format('-Y-m-d-H-i-s') : current_time('-Y-m-d-H-i-s')) . '.' . $filename_suffix;
return sanitize_file_name($filename);
}
// Output file download headers
public static function file_download_headers($filename, $mime_type, $encoding = 'binary') {
$filename = sanitize_file_name($filename); // WordPress function
// HTTP headers
header('Pragma: public');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Cache-Control: private', false);
header('Content-Type: ' . $mime_type);
header('Content-Disposition: attachment; filename=' . $filename);
header('Content-Transfer-Encoding: ' . $encoding);
}
// Get tracking data
public static function get_tracking_data($form, $submit, $content_type = 'text/html') {
$tracking_data = array();
// Check form and submit meta data
if(
($form === false) ||
!isset($submit->meta)
) {
return $tracking_data;
}
// Process tracking config
foreach(WS_Form_Config::get_tracking(false) as $meta_key => $tracking) {
// Check meta_key is enabled
if(!self::get_object_meta_value($form, $meta_key, false)) { continue; }
// Check meta exists in submit data
if(!isset($submit->meta[$meta_key])) {
$meta_value = '';
} else {
// Get value
$meta = array(
'type' => $tracking['type'],
'value' => $submit->meta[$meta_key]
);
// Get parsed version
$meta_value = self::parse_variables_meta_value($form, $meta, $content_type);
// Sanitize
$meta_value = sanitize_text_field($meta_value);
// Convert # to HTML character (e.g. from tracking_hash) to prevent WS Form variable injection
$meta_value = str_replace('#', '#', $meta_value);
}
// Add to tracking data
$tracking_data[] = array(
'label' => $tracking['label'],
// phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key
'meta_key' => $meta_key,
// phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_value
'meta_value' => $meta_value,
);
}
return $tracking_data;
}
/**
* Normalize a BCP47 language tag or POSIX-style locale to WordPress/POSIX form (underscore separator).
*
* @param mixed $language_tag Language tag or locale string.
*
* @return string Normalized locale (e.g. en_US) or empty string if invalid.
*/
public static function language_tag_to_locale( $language_tag ) {
if ( ! is_string( $language_tag ) ) {
return '';
}
$language_tag = trim( $language_tag );
if ( $language_tag === '' ) {
return '';
}
return str_replace( '-', '_', $language_tag );
}
/**
* Convert a POSIX-style locale to a BCP47 language tag (hyphen separator; language lower, region upper).
*
* @param mixed $locale Locale string (e.g. en_US, es).
*
* @return string BCP47-style tag (e.g. en-US, es) or empty string if invalid.
*/
public static function locale_to_language_tag( $locale ) {
if ( ! is_string( $locale ) ) {
return '';
}
$locale = self::language_tag_to_locale( $locale );
if ( $locale === '' ) {
return '';
}
$parts = explode( '_', $locale, 3 );
$language = isset( $parts[0] ) ? strtolower( $parts[0] ) : '';
if ( $language === '' ) {
return '';
}
if ( ! isset( $parts[1] ) || ( $parts[1] === '' ) ) {
return $language;
}
return $language . '-' . strtoupper( $parts[1] );
}
/**
* Extract the primary language subtag from a locale or language tag.
*
* @param mixed $locale Locale or tag.
*
* @return string Lowercase language code (e.g. en, fr) or empty string.
*/
public static function get_language_code( $locale ) {
$locale = self::language_tag_to_locale( $locale );
if ( $locale === '' ) {
return '';
}
$parts = explode( '_', $locale, 3 );
return isset( $parts[0] ) ? strtolower( $parts[0] ) : '';
}
/**
* Extract the region/country subtag from a locale or language tag.
*
* @param mixed $locale Locale or tag.
*
* @return string Uppercase region code (e.g. US, CA) or empty string if none.
*/
public static function get_country_code( $locale ) {
$locale = self::language_tag_to_locale( $locale );
if ( $locale === '' ) {
return '';
}
$parts = explode( '_', $locale, 3 );
if ( ! isset( $parts[1] ) || ( $parts[1] === '' ) ) {
return '';
}
return strtoupper( $parts[1] );
}
// Parse WS Form variables
public static function parse_variables_process($parse_string, $form = false, $submit = false, $content_type = 'text/html', $scope = false, $section_repeatable_index = false, $section_row_number = 1, $exclude_secure = false, $action_config = false, $depth = 1) {
if(!is_string($parse_string)) { return $parse_string; }
// Checks to speed up this function
if(strpos($parse_string, '#') === false) { return $parse_string; }
// Exclude secure on nested parses?
$exclude_secure_nested_parse = true;
// Get post
$post = self::get_post_root();
// Get user
$user = self::get_user();
// Initialize variables
$variables = array();
$variables_single_parse = array();
// Parse type
$lookups_contain_singles = false;
// Check for too many iterations
if($depth > 100) { return ''; }
// Get parse variables config
$parse_variables_config = WS_Form_Config::get_parse_variables();
// Process each parse variable key
foreach($parse_variables_config as $parse_variables_key => $parse_variables) {
// Check for prefix (for performance)
$var_lookup_found = false;
foreach($parse_variables['var_lookups'] as $var_lookup) {
// Check if parse string contains lookup value
if(strpos($parse_string, $var_lookup) !== false) {
$var_lookup_found = true;
break;
}
}
// If lookup not found, skip this variable group
if(!$var_lookup_found) { continue; }
foreach($parse_variables['variables'] as $parse_variable => $parse_variable_config) {
// Skip variables that are not in scope
if($scope !== false) {
$parse_variable_scope = isset($parse_variable_config['scope']) ? $parse_variable_config['scope'] : array();
if(is_array($parse_variable_scope)) {
if(!in_array($scope, $parse_variable_scope)) { continue; }
} else {
continue;
}
}
if(strpos($parse_string, '#' . $parse_variable) === false) { continue; }
$parsed_variable = '';
switch($parse_variable) {
case 'email_tracking' :
// Get tracking data
$tracking_data = self::get_tracking_data($form, $submit, $content_type);
foreach($tracking_data as $tracking) {
// Get label
$label = $tracking['label'];
// Get value
$meta_value = $tracking['meta_value'];
// Add to fields_all HTML
switch($content_type) {
case 'text/html' :
// $meta_value already sanitied by get_tracking_data
$parsed_variable .= '<p style="font-family: sans-serif; font-size: 14px; font-weight: normal; margin: 0; margin-bottom: 10px;"><strong>' . esc_html($label) . '</strong><br />' . $meta_value . '</p>';
break;
default :
$parsed_variable .= $label . "\n" . $meta_value . "\n\n";
break;
}
}
$variables[$parse_variable] = $parsed_variable;
break;
default :
// Get value
$parse_variable_value = (isset($parse_variable_config['value'])) ? $parse_variable_config['value'] : false;
// Get value from function
$parse_variable_function = (isset($parse_variable_config['function'])) ? $parse_variable_config['function'] : false;
if(
($parse_variable_function !== false) &&
is_array($parse_variable_function) &&
(count($parse_variable_function) == 2)
) {
// Get class
$parse_variable_function_class = $parse_variable_function[0];
// Get method
$parse_variable_function_method = $parse_variable_function[1];
// Call method
$parse_variable_value = $parse_variable_function_class->$parse_variable_function_method($form, $submit, $content_type, $section_repeatable_index, $action_config);
}
// Get attributes
$parse_variable_attributes = (isset($parse_variable_config['attributes'])) ? $parse_variable_config['attributes'] : false;
// Single parse? (Used if different value returned each parse, e.g. random_number)
$parse_variable_single_parse = isset($parse_variable_config['single_parse']) ? $parse_variable_config['single_parse'] : false;
// If no attributes specified, then just set the value
if(($parse_variable_attributes === false) && ($parse_variable_value !== false)) { $variables[$parse_variable] = $parse_variable_value; break; }
// Get number of attributes required
$variable_attribute_count = isset($parse_variable_config['attributes']) ? count($parse_variable_attributes) : 0;
// Handle variables
if($variable_attribute_count > 0) {
// Do until no more found
$variable_index_start = 0;
do {
$parsed_variable = '';
// Find position of variable and brackets
$variable_index_of = strpos($parse_string, '#' . $parse_variable, $variable_index_start);
// No more instances of variable found
if($variable_index_of === false) { continue; }
// Find bracket positions
$variable_index_of_bracket_start = false;
$variable_index_of_bracket_finish = false;
$parse_string_function = substr($parse_string, $variable_index_of + strlen('#' . $parse_variable));
// Bracket should immediately follow the variable name
if(substr($parse_string_function, 0, 1) == '(') {
$variable_index_of_bracket_start = $variable_index_of + strlen('#' . $parse_variable);
$variable_index_of_bracket_finish = self::closing_string_index($parse_string, ')', '(', $variable_index_of_bracket_start + 1);
}
// Check brackets found
if( ($variable_index_of_bracket_start === false) ||
($variable_index_of_bracket_finish === false) ) {
// Shift index to look for next instance
$variable_index_start = $variable_index_of + strlen('#' . $parse_variable);
// Get full string to parse
$parse_variable_full = '#' . $parse_variable;
// No brackets found so set attributes as blank
$variable_attribute_array = array();
} else {
// Shift index to look for next instance
$variable_index_start = $variable_index_of_bracket_finish + 1;
// Ensure bracket starts immediate after parse_variable
if((($variable_index_of_bracket_start - $variable_index_of) - strlen('#' . $parse_variable)) !== 0) { continue; };
// Get full string to parse
$parse_variable_full = substr($parse_string, $variable_index_of, ($variable_index_of_bracket_finish + 1) - $variable_index_of);
// Get attribute string
$variable_attribute_string = substr($parse_string, $variable_index_of_bracket_start + 1, ($variable_index_of_bracket_finish - 1) - $variable_index_of_bracket_start);
// Replace non standard double quotes
$variable_attribute_string = str_replace('“', '"', $variable_attribute_string);
$variable_attribute_string = str_replace('”', '"', $variable_attribute_string);
// Get separator
$separator = isset($parse_variable_config['attribute_separator']) ? $parse_variable_config['attribute_separator'] : ',';
// Get attribute array
$variable_attribute_array = self::string_to_attributes($variable_attribute_string, $separator);
// Trim and strip double quotes
foreach($variable_attribute_array as $key => $e) {
$e = preg_replace('/^"(.+(?="$))"$/', '', $e);
$variable_attribute_array[$key] = $e;
}
}
// Check each attribute
foreach($parse_variable_attributes as $parse_variable_attributes_index => $parse_variable_attribute) {
$parse_variable_attribute_id = $parse_variable_attribute['id'];
// Was attribute provided for this index?
$parse_variable_attribute_supplied = isset($variable_attribute_array[$parse_variable_attributes_index]);
// Check required
$parse_variable_attribute_required = (isset($parse_variable_attribute['required']) ? $parse_variable_attribute['required'] : true);
if($parse_variable_attribute_required && !$parse_variable_attribute_supplied) {
// Syntax error - Attribute count
self::throw_error(sprintf(
/* translators: %1$s: Parse variable, %2$s: Attribute ID */
esc_html__('Syntax error, missing attribute: %1$s (Expected: %2$s)', 'ws-form'),
'#' . $parse_variable,
$parse_variable_attribute_id
));
continue;
}
// Check default
$parse_variable_attribute_default = isset($parse_variable_attribute['default']) ? $parse_variable_attribute['default'] : false;
if(($parse_variable_attribute_default !== false) && !$parse_variable_attribute_supplied) {
$variable_attribute_array[$parse_variable_attributes_index] = $parse_variable_attribute_default;
}
// Check trim
$parse_variable_attribute_trim = isset($parse_variable_attribute['trim']) ? $parse_variable_attribute['trim'] : true;
if(
$parse_variable_attribute_trim &&
isset($variable_attribute_array[$parse_variable_attributes_index]) &&
is_string($variable_attribute_array[$parse_variable_attributes_index])
) {
$variable_attribute_array[$parse_variable_attributes_index] = trim($variable_attribute_array[$parse_variable_attributes_index]);
}
// Check validity
$parse_variable_attribute_valid = isset($parse_variable_attribute['valid']) ? $parse_variable_attribute['valid'] : false;
if($parse_variable_attribute_valid !== false) {
if(
isset($variable_attribute_array[$parse_variable_attributes_index]) &&
!in_array($variable_attribute_array[$parse_variable_attributes_index], $parse_variable_attribute_valid)
) {
// Syntax error - Attribute count
self::throw_error(sprintf(
/* translators: %1$s: Parse variable, %2$s: Valid attributes */
esc_html__('Syntax error, invalid attribute: %1$s (Expected: %2$s)', 'ws-form'),
'#' . $parse_variable,
implode(', ', $parse_variable_attribute_valid)
));
}
}
}
// Process variable
switch($parse_variable) {
case 'query_var' :
case 'post_var' :
$parsed_variable = self::get_query_var($variable_attribute_array[0], $variable_attribute_array[1]);
if($content_type == 'text/html') { $parsed_variable = esc_html($parsed_variable); }
break;
case 'email_submission' :
if(!isset($submit->meta)) { break; }
$render_group_labels = $variable_attribute_array[0];
$render_section_labels = $variable_attribute_array[1];
$render_field_labels = $variable_attribute_array[2];
$render_blank_fields = ($variable_attribute_array[3] == 'true');
$render_static_fields = ($variable_attribute_array[4] == 'true');
// Get hidden array
if(isset($submit->meta['wsf_meta_key_hidden'])) {
$hidden_array = $submit->meta['wsf_meta_key_hidden'];
} else {
$hidden_array = explode(',', self::get_query_var_nonce('wsf_hidden', ''));
}
$value = self::parse_variables_fields_all((object) $form, $submit, $content_type, $render_group_labels, $render_section_labels, $render_field_labels, $render_blank_fields, $render_static_fields, $hidden_array, $action_config);
$parsed_variable = self::parse_variables_process($value, $form, $submit, $content_type, $scope, $section_repeatable_index, $section_row_number, $exclude_secure_nested_parse, $action_config, $depth + 1);
break;
case 'if' :
$endif_position = self::closing_string_index($parse_string, '#endif', '#if', $variable_index_of_bracket_finish);
if($endif_position === false) {
self::throw_error(sprintf(
/* translators: %s: IF condition */
esc_html__('Syntax error, missing #endif for #if(%s)', 'ws-form'),
$variable_attribute_string
));
}
// Valid operators
$operators_valid = array('==', '!=', '>', '>=', '<=', '<', '^=', '$=', '!^=', '!$=', '*=', '!*=');
// Valid logic previous
$logic_previous_valid = array('&&', '||');
// Run through each attribute and build boolean array
$if_boolean_array = array();
$if_boolean_array_index = 0;
$if_part = 0;
foreach($variable_attribute_array as $variable_attribute) {
if($if_part === 0) {
$if_boolean_array[$if_boolean_array_index] = array(
'value_a' => '',
'operator' => '!=',
'value_b' => ''
);
}
// Decode operators and logic
if(($if_part == 1) || ($if_part == 3)) {
// Convert HTML encoding caused by TinyMCE
$variable_attribute = str_replace('&', '&', $variable_attribute);
$variable_attribute = str_replace('<', '<', $variable_attribute);
$variable_attribute = str_replace('>', '>', $variable_attribute);
}
// Check for numeric values
if(($if_part == 0) || ($if_part == 2)) {
$variable_attribute = $variable_attribute_string = self::parse_variables_process($variable_attribute, $form, $submit, $content_type, $scope, $section_repeatable_index, $section_row_number, $exclude_secure_nested_parse, $action_config, $depth + 1);
if(is_numeric($variable_attribute)) { $variable_attribute = floatval($variable_attribute); }
}
// Short form #if
if(
($if_part == 1) &&
in_array($variable_attribute, $logic_previous_valid)
) {
$if_part = 3;
}
// Process IF parts
switch($if_part) {
case 0 :
case 2 :
$if_part_key = ($if_part == 0) ? 'value_a' : 'value_b';
$if_boolean_array[$if_boolean_array_index][$if_part_key] = $variable_attribute;
$if_boolean_array[$if_boolean_array_index][$if_part_key . '_string'] = $variable_attribute_string;
break;
case 1 :
if(!in_array($variable_attribute, $operators_valid)) {
self::throw_error(sprintf(
/* translators: %1$s: Operator, %2$s: IF condition */
esc_html__('Syntax error, invalid operator %1$s in #if(%2$s)', 'ws-form'),
$variable_attribute,
$variable_attribute_string
));
}
$if_boolean_array[$if_boolean_array_index]['operator'] = $variable_attribute;
break;
case 3 :
if(!in_array($variable_attribute, $logic_previous_valid)) {
self::throw_error(sprintf(
/* translators: %1$s: Logic, %2$s: IF condition */
esc_html__('Syntax error, invalid logic %1$s in #if(%2$s)', 'ws-form'),
$variable_attribute,
$variable_attribute_string
));
}
$if_boolean_array[$if_boolean_array_index]['logic_next'] = $variable_attribute;
break;
}
$if_part++;
if($if_part > 3) {
$if_part = 0;
$if_boolean_array_index++;
}
}
$result = false;
$logic_next = '&&';
foreach($if_boolean_array as $if_boolean_array_index => $if_boolean) {
switch($if_boolean['operator']) {
// Equals
case '==' :
$result_single = ($if_boolean['value_a'] == $if_boolean['value_b']);
break;
// Not equals
case '!=' :
$result_single = ($if_boolean['value_a'] != $if_boolean['value_b']);
break;
// Less than
case '<' :
$result_single = ($if_boolean['value_a'] < $if_boolean['value_b']);
break;
// Greater than
case '>' :
$result_single = ($if_boolean['value_a'] > $if_boolean['value_b']);
break;
// Less than or equal
case '<=' :
$result_single = ($if_boolean['value_a'] <= $if_boolean['value_b']);
break;
// Greater than or equal
case '>=' :
$result_single = ($if_boolean['value_a'] >= $if_boolean['value_b']);
break;
// Contains
case '*=' :
$result_single = ($if_boolean['value_b_string'] !== '') ? (strpos($if_boolean['value_a_string'], $if_boolean['value_b_string']) !== false) : false;
break;
// Does not contain
case '!*=' :
$result_single = ($if_boolean['value_b_string'] !== '') ? (strpos($if_boolean['value_a_string'], $if_boolean['value_b_string']) === false) : false;
break;
// Starts with
case '^=' :
$result_single = ($if_boolean['value_b_string'] !== '') ? (strpos($if_boolean['value_a_string'], $if_boolean['value_b_string']) === 0) : false;
break;
// Does not start with
case '!^=' :
$result_single = ($if_boolean['value_b_string'] !== '') ? (strpos($if_boolean['value_a_string'], $if_boolean['value_b_string']) > 0) : false;
break;
// Ends with
case '$=' :
$result_single = ($if_boolean['value_b_string'] !== '') ? (strpos($if_boolean['value_a_string'], $if_boolean['value_b_string']) === (strlen($if_boolean['value_a_string']) - strlen($if_boolean['value_b_string']))) : false;
break;
// Does not end with
case '!$=' :
$result_single = ($if_boolean['value_b_string'] !== '') ? (strpos($if_boolean['value_a_string'], $if_boolean['value_b_string']) !== (strlen($if_boolean['value_a']) - strlen($if_boolean['value_b_string']))) : false;
break;
}
$result = ($if_boolean_array_index == 0) ? $result_single : (($logic_next == '&&') ? ($result && $result_single) : ($result || $result_single));
$logic_next = isset($if_boolean['logic_next']) ? $if_boolean['logic_next'] : '&&';
}
$parsed_variable = false;
if($result) {
// Remove the endif
$parse_string = substr($parse_string, 0, $endif_position) . substr($parse_string, $endif_position + 6);
// Remove the if
$parse_string = substr($parse_string, 0, $variable_index_of) . substr($parse_string, $variable_index_of_bracket_finish + 1);
} else {
// Remove from if to endif
$parse_string = substr($parse_string, 0, $variable_index_of) . substr($parse_string, $endif_position + 6);
}
$variable_index_start = 0;
break;
case 'section_rows_start' :
if($submit === false) { break; }
if(!is_numeric($variable_attribute_array[0])) { break; }
$section_rows_end_position = self::closing_string_index($parse_string, '#section_rows_end', '#section_rows_start', $variable_index_of_bracket_finish);
if($section_rows_end_position === false) {
self::throw_error(sprintf(
/* translators: %s: Variable attribute string */
esc_html__('Syntax error, missing #section_rows_end for #section_rows_start(%s)', 'ws-form'),
$variable_attribute_string
));
}
// Get section_id
$section_id = absint($variable_attribute_array[0]);
if($section_id === 0) { break; }
// Get string to loop
$parse_string_loop = substr($parse_string, $variable_index_of_bracket_finish + 1, $section_rows_end_position - ($variable_index_of_bracket_finish + 1));
// Unserialize section_repeatable
$section_repeatable = is_serialized($submit->section_repeatable) ? self::maybe_unserialize($submit->section_repeatable) : false;
// Build section ID string
$section_id_string = 'section_' . $section_id;
$section_repeatable_array = (
($section_repeatable !== false) &&
isset($section_repeatable[$section_id_string]) &&
isset($section_repeatable[$section_id_string]['index'])
) ? $section_repeatable[$section_id_string]['index'] : [false];
// Loop through section_repeatable_array
$parsed_string = '';
$section_row_number = 1;
foreach($section_repeatable_array as $section_repeatable_array_index => $section_repeatable_index_row) {
// Parse at same depth
$parsed_string .= self::parse_variables_process($parse_string_loop, $form, $submit, $content_type, $scope, $section_repeatable_index_row, $section_row_number++, false, $action_config, $depth);
}
// Remove from section_rows_start to section_rows_end
$parse_string = substr($parse_string, 0, $variable_index_of) . $parsed_string . substr($parse_string, $section_rows_end_position + 17);
$variable_index_start = 0;
break;
case 'section_row_count' :
if($submit === false) { break; }
if(!is_numeric($variable_attribute_array[0])) { break; }
// Get section_id
$section_id = absint($variable_attribute_array[0]);
if($section_id === 0) { break; }
// Unserialize section_repeatable
$section_repeatable = is_serialized($submit->section_repeatable) ? self::maybe_unserialize($submit->section_repeatable) : false;
// Build section ID string
$section_id_string = 'section_' . $section_id;
// Get row count
$parsed_variable = (
($section_repeatable !== false) &&
isset($section_repeatable[$section_id_string]) &&
isset($section_repeatable[$section_id_string]['index']) &&
is_array($section_repeatable[$section_id_string]['index'])
) ? count($section_repeatable[$section_id_string]['index']) : 0;
break;
case 'tab_label' :
if(!is_numeric($variable_attribute_array[0])) { break; }
// Get group_id
$group_id = absint($variable_attribute_array[0]);
if($group_id === 0) { break; }
// Get groups
$groups = self::get_groups_from_form($form);
if(
isset($groups[$group_id]) &&
isset($groups[$group_id]->label)
) {
$parsed_variable = self::parse_variables_process($groups[$group_id]->label, $form, $submit, $content_type, $scope, $section_repeatable_index, $section_row_number, $exclude_secure_nested_parse, $action_config, $depth + 1);
} else {
self::throw_error(sprintf(
/* translators: %u: Tab ID */
esc_html__('Syntax error, invalid group ID in #group_label(%u)', 'ws-form'),
$group_id
));
}
break;
case 'section_label' :
if(!is_numeric($variable_attribute_array[0])) { break; }
// Get section_id
$section_id = absint($variable_attribute_array[0]);
if($section_id === 0) { break; }
// Get sections
$sections = self::get_sections_from_form($form);
if(
isset($sections[$section_id]) &&
isset($sections[$section_id]->label)
) {
$parsed_variable = self::parse_variables_process($sections[$section_id]->label, $form, $submit, $content_type, $scope, $section_repeatable_index, $section_row_number, $exclude_secure_nested_parse, $action_config, $depth + 1);
} else {
self::throw_error(sprintf(
/* translators: %u: Section ID */
esc_html__('Syntax error, invalid section ID in #section_label(%u)', 'ws-form'),
$section_id
));
}
break;
case 'cookie_get' :
// Get cookie value
$parsed_variable = esc_html(self::cookie_get_raw($variable_attribute_array[0]));
break;
case 'field_label' :
if(!is_numeric($variable_attribute_array[0])) { break; }
// Get field_id
$field_id = absint($variable_attribute_array[0]);
if($field_id === 0) { break; }
// Get fields
$fields = self::get_fields_from_form($form);
if(
isset($fields[$field_id]) &&
isset($fields[$field_id]->label)
) {
$parsed_variable = self::parse_variables_process($fields[$field_id]->label, $form, $submit, $content_type, $scope, $section_repeatable_index, $section_row_number, $exclude_secure_nested_parse, $action_config, $depth + 1);
} else {
self::throw_error(sprintf(
/* translators: %u: Field ID */
esc_html__('Syntax error, invalid field ID in #field_label(%u)', 'ws-form'),
$field_id
));
}
break;
case 'text' :
if(isset($variable_attribute_array[0])) {
$value = $variable_attribute_array[0];
$parsed_variable = self::parse_variables_process($value, $form, $submit, $content_type, $scope, $section_repeatable_index, $section_row_number, $exclude_secure_nested_parse, $action_config, $depth + 1);
}
break;
case 'field_min_id' :
case 'field_max_id' :
case 'field_min_value' :
case 'field_max_value' :
case 'field_min_label' :
case 'field_max_label' :
$field_ids = [];
$field_min_id = 0;
$field_min_value = 0;
$field_min_label = '';
$field_max_id = 0;
$field_max_value = 0;
$field_max_label = '';
$variable_attribute_array_index = 0;
// Get fields
$fields = self::get_fields_from_form($form);
// Loop through provided field ID's
while(isset($variable_attribute_array[$variable_attribute_array_index])) {
// Get field ID
$field_id = absint($variable_attribute_array[$variable_attribute_array_index]);
if(empty($field_id)) { $variable_attribute_array_index++; continue; }
// Get field
if(!isset($fields[$field_id])) { break; }
$field = $fields[$field_id];
// Get meta key
$meta_key = WS_FORM_FIELD_PREFIX . $field_id;
if(
($section_repeatable_index !== false) &&
!empty($field->section_repeatable)
) {
$meta_key .= '_' . $section_repeatable_index;
}
if(isset($submit->meta[$meta_key])) {
// Get value
$meta = $submit->meta[$meta_key];
// Get delimiter
$delimiter = isset($variable_attribute_array[1]) ? $variable_attribute_array[1] : NULL;
// Get column
$column_override = isset($variable_attribute_array[2]) ? $variable_attribute_array[2] : false;
$field_value = self::parse_variables_meta_value($form, $meta, $content_type, false, 'parse_variable', 0, NULL, false, false, false, false);
} else {
$field_value = 0;
}
/// Get field label
$field_label = $field->label;
// Set min and max
if($variable_attribute_array_index == 0) {
// Initial values
$field_max_id = $field_min_id = $field_id;
$field_max_value = $field_min_value = $field_value;
$field_max_label = $field_min_label = $field_label;
} else {
// Min / max calculations
if($field_value < $field_min_value) {
$field_min_id = $field_id;
$field_min_value = $field_value;
$field_min_label = $field_label;
}
if($field_value > $field_max_value) {
$field_max_id = $field_id;
$field_max_value = $field_value;
$field_max_label = $field_label;
}
}
// Go to next variable attribute
$variable_attribute_array_index++;
}
switch($parse_variable) {
case 'field_min_id' :
$parsed_variable = $field_min_id;
break;
case 'field_max_id' :
$parsed_variable = $field_max_id;
break;
case 'field_min_value' :
$parsed_variable = $field_min_value;
break;
case 'field_max_value' :
$parsed_variable = $field_max_value;
break;
case 'field_min_label' :
$parsed_variable = $field_min_label;
break;
case 'field_max_label' :
$parsed_variable = $field_max_label;
break;
}
break;
case 'date_format' :
// Parse date
$date_input = self::parse_variables_process($variable_attribute_array[0], $form, $submit, $content_type, $scope, $section_repeatable_index, $section_row_number, $exclude_secure_nested_parse, $action_config, $depth + 1);
// Parse date format
$date_format = self::parse_variables_process($variable_attribute_array[1], $form, $submit, $content_type, $scope, $section_repeatable_index, $section_row_number, $exclude_secure_nested_parse, $action_config, $depth + 1);
// Get time
$time_input = strtotime($date_input);
// Check time
if($time_input === false) {
self::throw_error(sprintf(
/* translators: %s: Date input */
esc_html__('Syntax error, invalid input date: %s', 'ws-form'),
$date_input
));
}
// Process date
$parsed_variable = gmdate($date_format, $time_input);
break;
case 'field' :
case 'field_float' :
case 'field_date_format' :
case 'field_date_offset' :
case 'ecommerce_field_price' :
if(!isset($submit->meta)) { break; }
if(!is_numeric($variable_attribute_array[0])) { break; }
// Get field ID
$field_id = $variable_attribute_array[0];
// Get fields
$fields = self::get_fields_from_form($form);
// Get field
if(!isset($fields[$field_id])) { break; }
$field = $fields[$field_id];
// Get field type
if(!isset($field->type)) { break; }
$field_type = $field->type;
// Get field types in single dimension array
$field_types = self::get_field_types();
// Get field config
if(!isset($field_types[$field_type])) { break; }
$field_type_config = $field_types[$field_type];
// WPAutoP?
$wpautop = self::wpautop_parse_variable($field, $field_type_config);
$html_encode = !($wpautop && ($content_type == 'text/html'));
// Defaults
$index = false;
$delimiter_row = null; // New line used by default
$delimiter_section = '';
$section_repeatable = false;
// Unserialize section_repeatable
if(
!empty($submit->section_repeatable) &&
is_string($submit->section_repeatable)
) {
// Get section ID
if(!isset($field->section_id)) { break; }
$section_id = $field->section_id;
// Get section key
$section_key = sprintf('section_%u', $section_id);
// Get section repeatable data
$section_repeatable = is_serialized($submit->section_repeatable) ? self::maybe_unserialize($submit->section_repeatable) : false;
if(
($section_repeatable !== false) &&
is_array($section_repeatable) &&
isset($section_repeatable[$section_key]) &&
is_array($section_repeatable[$section_key]) &&
isset($section_repeatable[$section_key]['index']) &&
is_array($section_repeatable[$section_key]['index'])
) {
// Get delimiter_section
$delimiter_section = (
isset($section_repeatable[$section_key]) &&
isset($section_repeatable[$section_key]['delimiter_section'])
) ? $section_repeatable[$section_key]['delimiter_section'] : WS_FORM_SECTION_REPEATABLE_DELIMITER_SECTION;
// Get delimiter_row
$delimiter_row = (
isset($section_repeatable[$section_key]) &&
isset($section_repeatable[$section_key]['delimiter_row'])
) ? $section_repeatable[$section_key]['delimiter_row'] : WS_FORM_SECTION_REPEATABLE_DELIMITER_ROW;
// Get index array
$index = $section_repeatable[$section_key]['index'];
}
}
// Sanitize delimiters
$delimiter_section = self::delimiter_sanitize($delimiter_section);
$delimiter_row = self::delimiter_sanitize($delimiter_row);
// Build meta key array (One element per section row)
$meta_key_array = array();
// Get meta key
$meta_key = WS_FORM_FIELD_PREFIX . $field_id;
// Check if field is in a repeatable section
if(is_array($index)) {
// Check if repeatable index has been specified (i.e. we only want one row)
if($section_repeatable_index !== false) {
// Repeatable index specified
$meta_key_array[] = $meta_key . '_' . $section_repeatable_index;
} else {
// Process section repeatable index
foreach($index as $section_repeatable_index) {
$meta_key_array[] = $meta_key . '_' . $section_repeatable_index;
}
}
} else {
// Regular field outside of a repeater
$meta_key_array[] = $meta_key;
}
$parsed_variables_array = array();
foreach($meta_key_array as $meta_key) {
if(isset($submit->meta[$meta_key])) {
// Get value
$meta = $submit->meta[$meta_key];
// Get delimiter
$delimiter_row = isset($variable_attribute_array[1]) ? $variable_attribute_array[1] : $delimiter_row;
// Get column
$column_override = isset($variable_attribute_array[2]) ? $variable_attribute_array[2] : false;
// Get value
$value = self::parse_variables_meta_value($form, $meta, $content_type, $html_encode, 'parse_variable', 0, $delimiter_row, false, false, false, $column_override);
} else {
// No submitted value, get static
$value = '';
// Check for static fields
$field_static = isset($field_type_config['static']) ? $field_type_config['static'] : false;
if($field_static) {
if($field_static === true) {
// If static set to true, we use the mask_field
$value = isset($field_type_config['mask_field_static']) ? $field_type_config['mask_field_static'] : '';
} else {
// Get value
$value = self::get_object_meta_value($field, $field_static, '');
}
}
}
// Parse value
$parsed_variable = self::parse_variables_process($value, $form, $submit, $content_type, $scope, $section_repeatable_index, $section_row_number, $exclude_secure_nested_parse, $action_config, $depth + 1);
// Process by parse variable
switch($parse_variable) {
case 'ecommerce_field_price' :
$parsed_variable = self::get_price(self::get_number($parsed_variable, 0, true));
break;
case 'field_date_format' :
if($field_type !== 'datetime') { break; }
// Get date/time type
$input_type_datetime = self::get_object_meta_value($field, 'input_type_datetime', 'date');
// Get input date
$parsed_variable_date = self::get_date_by_type($parsed_variable, (object) $field, 'Y-m-d H:i:s');
// Ensure parsed_variable_date is a date
if($parsed_variable_date !== false) {
// Check for format
if(
isset($variable_attribute_array[1]) &&
($variable_attribute_array[1] != '')
) {
$format_date = $variable_attribute_array[1];
} else {
// Get date format
$format_date = self::get_object_meta_value($field, 'format_date_input', get_option('date_format'));
}
if(empty($format_date)) { $format_date = get_option('date_format'); }
// Process date
$parsed_variable = gmdate($format_date, strtotime($parsed_variable_date));
}
break;
case 'field_date_offset' :
if($field_type !== 'datetime') { break; }
// Get date/time type
$input_type_datetime = self::get_object_meta_value($field, 'input_type_datetime', 'date');
// Get input date
$parsed_variable_date = self::get_date_by_type($parsed_variable, (object) $field, 'Y-m-d H:i:s');
// Ensure parsed_variable_date is a date
if($parsed_variable_date !== false) {
// Check for format
if(
isset($variable_attribute_array[2]) &&
($variable_attribute_array[2] != '')
) {
$format_date = $variable_attribute_array[2];
} else {
// Get date format
$format_date = self::get_object_meta_value($field, 'format_date_input', get_option('date_format'));
}
if(empty($format_date)) { $format_date = get_option('date_format'); }
// Check for offset
$seconds_offset = intval(self::parse_variables_process($variable_attribute_array[1], $form, $submit, $content_type, $scope, $section_repeatable_index, $section_row_number, $exclude_secure_nested_parse, $action_config, $depth + 1));
// Process date
$parsed_variable = gmdate($format_date, strtotime($parsed_variable_date) + $seconds_offset);
}
break;
case 'field_float' :
$parsed_variable = self::get_number($parsed_variable, 0, true);
break;
}
$parsed_variables_array[] = $parsed_variable;
}
// Implode into string (Joins each section row)
$parsed_variable = implode($delimiter_section, $parsed_variables_array);
// WPAutoP
if($wpautop && ($content_type == 'text/html')) { $parsed_variable = wpautop($parsed_variable); }
break;
case 'post_meta' :
if(is_null($post)) { break; }
$meta_key = $variable_attribute_array[0];
$parsed_variable = get_post_meta($post->ID, $meta_key, true);
if($parsed_variable === false) { $parsed_variable = ''; }
if(is_array($parsed_variable)) { $parsed_variable = serialize($parsed_variable); }
break;
case 'user_meta' :
// Check we have user data
if(($user === false) || !$user->ID) { break; }
$meta_key = $variable_attribute_array[0];
$parsed_variable = get_user_meta($user->ID, $meta_key, true);
if(is_array($parsed_variable)) { $parsed_variable = serialize($parsed_variable); }
break;
case 'ecommerce_price' :
$value = $variable_attribute_array[0];
$parsed_variable = self::parse_variables_process($value, $form, $submit, $content_type, $scope, $section_repeatable_index, $section_row_number, $exclude_secure_nested_parse, $action_config, $depth + 1);
$parsed_variable = self::get_price(self::get_number($parsed_variable, 0, true));
break;
case 'number_format' :
// Get num
$num = $variable_attribute_array[0];
$num = self::parse_variables_process($num, $form, $submit, $content_type, $scope, $section_repeatable_index, $section_row_number, $exclude_secure_nested_parse, $action_config, $depth + 1);
$num = self::get_number($num, 0, true);
// Get decimals
$decimals = $variable_attribute_array[1];
// Get decimal separator
$decimal_separator = $variable_attribute_array[2];
// Get thousands separator
$thousands_separator = $variable_attribute_array[3];
// Format
$parsed_variable = number_format($num, $decimals, $decimal_separator, $thousands_separator);
break;
case 'select_option_text' :
case 'checkbox_label' :
case 'radio_label' :
if(!isset($submit->meta)) { break; }
if(!is_numeric($variable_attribute_array[0])) { break; }
$field_id = $variable_attribute_array[0];
$datagrid_delimiter = isset($variable_attribute_array[1]) ? $variable_attribute_array[1] : NULL;
// Get meta key
$meta_key = WS_FORM_FIELD_PREFIX . $field_id;
if($section_repeatable_index !== false) {
$meta_key .= '_' . $section_repeatable_index;
}
if(!isset($submit->meta[$meta_key])) { break; }
// Get value
$meta = $submit->meta[$meta_key];
$value = self::parse_variables_meta_value($form, $meta, $content_type, true, 'label', 0, $datagrid_delimiter);
$parsed_variable = self::parse_variables_process($value, $form, $submit, $content_type, $scope, $section_repeatable_index, $section_row_number, $exclude_secure_nested_parse, $action_config, $depth + 1);
break;
case 'acf_repeater_field' :
if(is_null($post)) { break; }
$parent_field = $variable_attribute_array[0];
$sub_field = $variable_attribute_array[1];
$parent_field_array = explode(',', $parent_field);
foreach($parent_field_array as $key => $value) {
$parent_field_array[$key] = trim($value);
}
$parsed_variable = WS_Form_ACF::acf_repeater_field_walker($parent_field_array, $sub_field, $post);
break;
// Post and server date custom
case 'post_date_custom' :
case 'post_date_modified_custom' :
case 'server_date_custom' :
$seconds_offset = intval(isset($variable_attribute_array[1]) ? self::parse_variables_process($variable_attribute_array[1], $form, $submit, $content_type, $scope, $section_repeatable_index, $section_row_number, $exclude_secure_nested_parse, $action_config, $depth + 1) : 0);
$parsed_variable = gmdate($variable_attribute_array[0], strtotime($parse_variable_value) + $seconds_offset);
if($content_type == 'text/html') { $parsed_variable = esc_html($parsed_variable); }
break;
// Option - Get
case 'option_get' :
// Get option name
$option_name = $variable_attribute_array[0];
// Get option value
$option_value = get_option($option_name);
// Check for error with get_option
if($option_value === false) {
// Syntax error
self::throw_error(sprintf(
/* translators: %s: Option name */
esc_html__('Syntax error, option name %s not found in #option_get', 'ws-form'),
esc_html($option_name)
));
$option_value = '';
}
// Check if returned value is an object
if(is_object($option_value)) {
// Has a parameter been provided?
if(isset($variable_attribute_array[1])) {
$option_property = $variable_attribute_array[1];
if(property_exists($option_value, $option_property)) {
$option_value = $option_value->$option_property;
} else {
$option_value = '';
}
} else {
// Syntax error
self::throw_error(sprintf(
/* translators: %s: Option name */
esc_html__('Syntax error, option name %s is an object, missing parameter in #option_get', 'ws-form'),
esc_html($option_name)
));
$option_value = '';
}
}
// Check if returned value is an array
if(is_array($option_value)) {
// Has a parameter been provided?
if(isset($variable_attribute_array[1])) {
$option_property = $variable_attribute_array[1];
if(isset($option_value[$option_property])) {
$option_value = $option_value[$option_property];
} else {
$option_value = '';
}
} else {
// Syntax error
self::throw_error(sprintf(
/* translators: %s: Option name */
esc_html__('Syntax error, option name %s is an array, missing key in #option_get', 'ws-form'),
esc_html($option_name)
));
$option_value = '';
}
}
if(is_string($option_value)) {
$parsed_variable = $option_value;
}
break;
// Submit date added custom
case 'submit_date_added_custom' :
$date_format = isset($variable_attribute_array[0]) ? $variable_attribute_array[0] : '';
$submit_date_added = self::get_object_property($submit, 'date_added', '');
$parsed_variable = !empty($submit_date_added) ? get_date_from_gmt($submit_date_added, $date_format) : '';
if($content_type == 'text/html') { $parsed_variable = esc_html($parsed_variable); }
break;
// Random number
case 'random_number' :
$random_number_min = intval($variable_attribute_array[0]);
$random_number_max = intval($variable_attribute_array[1]);
$parsed_variable = wp_rand($random_number_min, $random_number_max);
break;
// Random string
case 'random_string' :
$random_string_length = absint($variable_attribute_array[0]);
$random_string_characters = $variable_attribute_array[1];
$random_string_character_length = strlen($random_string_characters) - 1;
$parsed_variable = '';
for($random_string_index = 0; $random_string_index < $random_string_length; $random_string_index++) { $parsed_variable .= $random_string_characters[wp_rand(0, $random_string_character_length)]; }
break;
// Date
case 'blog_date_custom' :
$seconds_offset = intval(isset($variable_attribute_array[1]) ? self::parse_variables_process($variable_attribute_array[1], $form, $submit, $content_type, $scope, $section_repeatable_index, $section_row_number, $exclude_secure_nested_parse, $action_config, $depth + 1) : 0);
$parsed_variable = gmdate($variable_attribute_array[0], current_time('timestamp') + $seconds_offset);
if($content_type == 'text/html') { $parsed_variable = esc_html($parsed_variable); }
break;
// User
case 'user_lost_password_url' :
// Check we have user data
if(($user === false) || !$user->ID) { break; }
// Check we can produce a lost password URL
if(!(
isset($user->lost_password_key) &&
($user->lost_password_key != '') &&
isset($user->user_login) &&
($user->user_login != '')
)) { break; }
// Get path
$path = $variable_attribute_array[0];
if($path !== '') {
$parsed_variable = network_site_url(sprintf('%s?key=%s&login=%s', $path, rawurlencode($user->lost_password_key),rawurlencode($user->user_login)));
} else {
$parsed_variable = network_site_url(sprintf('wp-login.php?action=rp&key=%s&login=%s', rawurlencode($user->lost_password_key), rawurlencode($user->user_login)), 'login');
}
break;
// Uppercase
case 'upper' :
case 'lower' :
case 'ucwords' :
case 'ucfirst' :
case 'capitalize' :
case 'sentence' :
case 'wpautop' :
case 'trim' :
case 'slug' :
case 'hash_md5' :
case 'hash_sha256' :
case 'name_prefix' :
case 'name_first' :
case 'name_middle' :
case 'name_last' :
case 'name_suffix' :
// Get input value
$input_value = self::parse_variables_process($variable_attribute_array[0], $form, $submit, $content_type, $scope, $section_repeatable_index, $section_row_number, $exclude_secure_nested_parse, $action_config, $depth + 1);
switch($parse_variable) {
// Uppercase
case 'upper' :
$parsed_variable = strtoupper($input_value);
break;
// Lowercase
case 'lower' :
$parsed_variable = strtolower($input_value);
break;
// Uppercase words
case 'ucwords' :
$parsed_variable = ucwords($input_value);
break;
// Uppercase first
case 'ucfirst' :
$parsed_variable = ucfirst($input_value);
break;
// Capitalize
case 'capitalize' :
$parsed_variable = ucwords(strtolower($input_value));
break;
// Sentence
case 'sentence' :
$parsed_variable = ucfirst(strtolower($input_value));
break;
// WPAutoP
case 'wpautop' :
$parsed_variable = wpautop($input_value);
break;
// Trim
case 'trim' :
$parsed_variable = trim($input_value);
break;
// Slug
case 'slug' :
$parsed_variable = sanitize_title($input_value);
break;
// Hash - MD5
case 'hash_md5' :
$parsed_variable = md5($input_value);
break;
// Hash - SHA-256
case 'hash_sha256' :
$parsed_variable = hash('sha256', $input_value);
break;
// Name components
case 'name_prefix' :
case 'name_first' :
case 'name_middle' :
case 'name_last' :
case 'name_suffix' :
$parsed_variable = self::get_full_name_components($input_value)[$parse_variable];
break;
}
break;
}
// Assign value
if($parsed_variable !== false) {
if($parse_variable_single_parse) {
$variables_single_parse[substr($parse_variable_full, 1)] = $parsed_variable;
} else {
$variables[substr($parse_variable_full, 1)] = $parsed_variable;
}
}
} while ($variable_index_of !== false);
// Secure variables
if($exclude_secure) { $variables = self::parse_variables_exclude_secure($variables); }
// Parse function
$parse_string = self::mask_parse($parse_string, $variables);
}
}
}
}
// Release memory
$parse_variables_config = null;
if($scope === false) {
// Blog
if(strpos($parse_string, 'blog') !== false) {
$variables['blog_admin_email'] = get_bloginfo('admin_email');
}
// Seconds
if(strpos($parse_string, 'seconds_epoch') !== false) {
$variables['seconds_epoch'] = gmdate('U');
}
// Form
if(strpos($parse_string, 'form') !== false) {
$variables['form_label'] = self::get_object_property($form, 'label', '');
$variables['form_id'] = self::get_object_property($form, 'id', '');
$variables['form_checksum'] = self::get_object_property($form, 'published_checksum', '');
// These variables are only available on the public side
$variables['form_obj_id'] = '';
$variables['form_framework'] = '';
$variables['form_instance_id'] = 0;
}
// Section
if(strpos($parse_string, 'section') !== false) {
$variables['section_row_index'] = $section_repeatable_index;
$variables['section_row_number'] = $section_row_number;
}
// Post
if(strpos($parse_string, 'post') !== false) {
$post_not_null = !is_null($post);
$variables['post_id'] = ($post_not_null ? $post->ID : '');
$variables['post_type'] = ($post_not_null ? $post->post_type : '');
$variables['post_title'] = ($post_not_null ? $post->post_title : '');
$variables['post_name'] = ($post_not_null ? $post->post_name : '');
$variables['post_content'] = ($post_not_null ? $post->post_content : '');
$variables['post_excerpt'] = ($post_not_null ? $post->post_excerpt : '');
$variables['post_parent'] = ($post_not_null ? $post->post_parent : '');
$variables['post_status'] = ($post_not_null ? $post->post_status : '');
$variables['post_url'] = ($post_not_null ? get_permalink($post->ID) : '');
$variables['post_url_edit'] = ($post_not_null ? get_edit_post_link($post->ID) : '');
$variables['post_date'] = ($post_not_null ? gmdate(get_option('date_format'), strtotime($post->post_date)) : '');
$variables['post_time'] = ($post_not_null ? gmdate(get_option('time_format'), strtotime($post->post_date)) : '');
$variables['post_date_modified'] = ($post_not_null ? gmdate(get_option('date_format'), strtotime($post->post_modified)) : '');
$variables['post_time_modified'] = ($post_not_null ? gmdate(get_option('time_format'), strtotime($post->post_modified)) : '');
}
// User
if(strpos($parse_string, 'user') !== false) {
$user_id = (($user === false) ? 0 : $user->ID);
$variables['user_id'] = $user_id;
$variables['user_login'] = (($user_id > 0) ? $user->user_login : '');
$variables['user_nicename'] = (($user_id > 0) ? $user->user_nicename : '');
$variables['user_email'] = (($user_id > 0) ? $user->user_email : '');
$variables['user_display_name'] = (($user_id > 0) ? $user->display_name : '');
$variables['user_url'] = (($user_id > 0) ? $user->user_url : '');
$variables['user_registered'] = (($user_id > 0) ? $user->user_registered : '');
// Build names
$user_full_name_array = array();
$user_first_name = (($user_id > 0) ? get_user_meta($user_id, 'first_name', true) : '');
if(!empty($user_first_name)) { $user_full_name_array[] = $user_first_name; }
$user_last_name = (($user_id > 0) ? get_user_meta($user_id, 'last_name', true) : '');
if(!empty($user_last_name)) { $user_full_name_array[] = $user_last_name; }
$user_full_name = implode(' ', $user_full_name_array);
$variables['user_first_name'] = $user_first_name;
$variables['user_last_name'] = $user_last_name;
$variables['user_full_name'] = $user_full_name;
$variables['user_bio'] = (($user_id > 0) ? get_user_meta($user_id, 'description', true) : '');
$variables['user_nickname'] = (($user_id > 0) ? get_user_meta($user_id, 'nickname', true) : '');
$variables['user_admin_color'] = (($user_id > 0) ? get_user_meta($user_id, 'admin_color', true) : '');
$variables['user_lost_password_key'] = (($user_id > 0) ? $user->lost_password_key : '');
// User locale (get_user_locale(); falls back to site locale; respects multilingual plugins via WordPress).
$user_locale_raw = get_user_locale();
$user_locale = is_string( $user_locale_raw ) ? self::language_tag_to_locale( $user_locale_raw ) : '';
$variables['user_locale'] = $user_locale;
$variables['user_language'] = self::locale_to_language_tag( $user_locale );
$variables['user_locale_language_code'] = self::get_language_code( $user_locale );
$variables['user_locale_country_code'] = self::get_country_code( $user_locale );
}
// Author
if(strpos($parse_string, 'author') !== false) {
$post_author_id = !is_null($post) ? $post->post_author : 0;
$variables['author_id'] = $post_author_id;
$variables['author_display_name'] = get_the_author_meta('display_name', $post_author_id);
$variables['author_first_name'] = get_the_author_meta('first_name', $post_author_id);
$variables['author_last_name'] = get_the_author_meta('last_name', $post_author_id);
$variables['author_nickname'] = get_the_author_meta('nickname', $post_author_id);
$variables['author_email'] = get_the_author_meta('user_email', $post_author_id);
}
// Submit
if(
(strpos($parse_string, 'submit') !== false) &&
is_object($submit)
) {
$submit_id = self::get_object_property($submit, 'id', '');
$submit_hash = self::get_object_property($submit, 'hash', '');
$submit_token = self::get_object_property($submit, 'token', '');
$submit_date_added = self::get_object_property($submit, 'date_added', '');
$variables['submit_id'] = $submit_id;
$variables['submit_user_id'] = self::get_object_property($submit, 'user_id', '');
$variables['submit_date_added'] = !empty($submit_date_added) ? get_date_from_gmt($submit_date_added, sprintf(
'%s %s',
get_option('date_format'),
get_option('time_format')
)) : '';
$variables['submit_hash'] = $submit_hash;
$variables['submit_status'] = self::get_object_property($submit, 'status', '');
$variables['submit_status_label'] = WS_Form_Submit::db_get_status_name(self::get_object_property($submit, 'status', ''));
// Get form ID
$form_id = absint(self::get_object_property($form, 'id', ''));
// Build submit admin URL and link
if($form_id && $submit_id) {
$submit_admin_url = esc_url(get_admin_url(null, 'admin.php?page=ws-form-submit&id=' . $form_id . '#' . $submit_id));
$variables['submit_admin_url'] = $submit_admin_url;
$variables['submit_admin_link'] = sprintf('<a href="%s" target="_blank">%s</a>', esc_url($submit_admin_url), esc_html($submit_admin_url));
}
// Build submit URL and link
if($form_id && $submit_hash) {
$referrer = self::get_referrer();;
$wsf_hash = rawurlencode(wp_json_encode(array(
// Save single submit hash
array('id' => $form_id, 'hash' => $submit_hash, 'token' => $submit_token)
)));
$submit_url = add_query_arg('wsf_hash', $wsf_hash, $referrer);
$variables['submit_url'] = $submit_url;
$variables['submit_url_hash'] = $wsf_hash;
$variables['submit_link'] = sprintf('<a href="%1$s" target="_blank">%1$s</a>', $submit_url);
}
}
// URL
if(strpos($parse_string, 'url') !== false) {
// URL
if(strpos($parse_string, 'url_login') !== false) { $variables['url_login'] = wp_login_url(); }
if(strpos($parse_string, 'url_logout') !== false) { $variables['url_logout'] = wp_logout_url(); }
if(strpos($parse_string, 'url_lost_password') !== false) { $variables['url_lost_password'] = wp_lostpassword_url(); }
if(strpos($parse_string, 'url_register') !== false) { $variables['url_register'] = wp_registration_url(); }
}
// E-Mail
if(strpos($parse_string, 'email') !== false) {
// Get email logo
if(strpos($parse_string, '#email_logo') !== false) {
$action_email_logo = absint(self::option_get('action_email_logo'));
$action_email_logo_size = self::option_get('action_email_logo_size');
if($action_email_logo_size == '') { $action_email_logo_size = 'full'; }
if($action_email_logo > 0) {
$variables['email_logo'] = self::get_attachment_img_html($action_email_logo, $action_email_logo_size);
}
}
$variables['email_promo'] = sprintf(
/* translators: %s: WS Form */
esc_html__('Powered by %s.', 'ws-form'),
sprintf(($content_type == 'text/html') ? '<a href="%s" style="color: #999999; font-size: 12px; text-align: center; text-decoration: none;">WS Form</a>' : 'WS Form %s', self::get_plugin_website_url('', 'email_footer'))
);
}
// E-mail - CSS
if(strpos($parse_string, 'email_css') !== false) {
$ws_form_css = new WS_Form_CSS();
$css = $ws_form_css->get_email();
$variables['email_css'] = $css;
}
// E-mail - E-Commerce
if(strpos($parse_string, 'email_ecommerce') !== false) {
$variables['email_ecommerce'] = self::parse_variables_ecommerce($submit);
}
// E-Commerce
if(strpos($parse_string, 'ecommerce') !== false) {
// Get e-commerce config
$ecommerce_config = WS_Form_Config::get_ecommerce();
foreach($ecommerce_config['cart_price_types'] as $meta_key => $cart_price_type) {
$meta_key = 'ecommerce_cart_' . $meta_key;
if(strpos($parse_string, $meta_key) !== false) {
$value = isset($submit->meta[$meta_key]) ? $submit->meta[$meta_key] : false;
if(($value !== '') && ($value !== false)) {
$variables[$meta_key] = $value;
$variables[$meta_key . '_currency'] = self::get_price($value);
} else {
$variables[$meta_key] = self::get_price(0);
}
}
}
foreach($ecommerce_config['meta_keys'] as $meta_key => $meta_key_config) {
if(strpos($parse_string, $meta_key) !== false) {
$value = isset($submit->meta[$meta_key]) ? $submit->meta[$meta_key] : false;
if(($value !== '') && ($value !== false)) {
// Lookup?
if(
(isset($meta_key_config['lookup'])) &&
(isset($ecommerce_config[$meta_key_config['lookup']])) &&
(isset($ecommerce_config[$meta_key_config['lookup']][$value]))
) {
$value = $ecommerce_config[$meta_key_config['lookup']][$value]['label'];
}
// Type
if(isset($meta_key_config['type'])) {
switch($meta_key_config['type']) {
case 'price' : $variables[$meta_key . '_currency'] = self::get_price($value); break;
}
}
$variables[$meta_key] = $value;
}
}
}
}
// Tracking
if(strpos($parse_string, 'tracking') !== false) {
// Get tracking data
$tracking_data = self::get_tracking_data($form, $submit, $content_type);
foreach($tracking_data as $tracking) {
// Add to variables
$variables[$tracking['meta_key']] = $tracking['meta_value'];
}
}
}
// Variables filter
// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- All hooks prefixed with wsf_
$variables = apply_filters('wsf_parse_variables', $variables, $parse_string, $form, $submit, $content_type);
// Secure variables
if($exclude_secure) { $variables = self::parse_variables_exclude_secure($variables); }
// Parse until no more changes made
$parse_string_before = $parse_string;
$parse_string = self::mask_parse($parse_string, $variables);
$parse_string = self::mask_parse($parse_string, $variables_single_parse, '#', true);
// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- All hooks prefixed with wsf_
$parse_string = apply_filters('wsf_config_parse_string', $parse_string);
if(
($parse_string !== $parse_string_before) &&
(strpos($parse_string, '#') !== false)
) {
$parse_string = self::parse_variables_process($parse_string, $form, $submit, $content_type, $scope, $section_repeatable_index, $section_row_number, $exclude_secure_nested_parse, $action_config, $depth + 1);
}
return $parse_string;
}
// Blank secure parse variables
public static function parse_variables_exclude_secure($variables) {
$parse_variables_secure = WS_Form_Config::get_parse_variables_secure();
foreach($parse_variables_secure as $parse_variable_key) {
// Exact match
if(isset($variables[$parse_variable_key])) {
$variables[$parse_variable_key] = '#' . $parse_variable_key;
break;
}
// Variable has attributes
foreach($variables as $variable_key => $variable_value) {
if(strpos($variable_key, $parse_variable_key . '(') === 0) {
$variables[$variable_key] = '#' . $variable_key;
}
}
}
return $variables;
}
// Parse string to attributes
public static function string_to_attributes($input_string, $separator = ',') {
if(
!is_string($input_string) ||
($input_string == '')
) {
return array();
}
$bracket_index = 1;
$input_string_index = 0;
$skip_double_quotes = false;
$attribute_single = '';
$attribute_array = array();
// Replace non standard double quotes
$input_string = str_replace('“', '"', $input_string);
$input_string = str_replace('”', '"', $input_string);
// Get input string length
$input_string_length = strlen($input_string);
while($input_string_index < $input_string_length) {
if(!isset($input_string[$input_string_index])) { break; }
// Get character
$character = $input_string[$input_string_index];
if(
($character === $separator) &&
($bracket_index === 1) &&
!$skip_double_quotes
) {
// Create attribute
$attribute_array[] = $attribute_single;
$attribute_single = '';
// Jump to next $character
$input_string_index++;
continue;
}
// If double quotes that are not in another function
if(
($character === '"') &&
($bracket_index === 1)
) {
// Clear $attribute_single if start
if(!$skip_double_quotes) { $attribute_single = ''; }
// Toggle skip double quotes
$skip_double_quotes = !$skip_double_quotes;
// Jump to next $character
$input_string_index++;
continue;
}
// If not in double quotes, process brackets
if(!$skip_double_quotes) {
switch($character) {
case '(' : $bracket_index++; break;
case ')' : $bracket_index--; break;
}
if($bracket_index === 0) { break; }
}
// Add $character to $attribute_single
$attribute_single .= $character;
$input_string_index++;
}
$attribute_array[] = $attribute_single;
// Strip double quotes at the beginning and end of each attribute
if(count($attribute_array) > 0) {
$attribute_array = array_map(function($attribute) {
return preg_replace('/^"(.+(?="$))"$/', '$1', $attribute);
}, $attribute_array);
}
return $attribute_array;
}
// Find closing string
public static function closing_string_index($parse_string, $closing_string, $opening_string, $index) {
$depth = 1;
while($depth > 0) {
// Look for embedded if
$opening_string_index = strpos($parse_string, $opening_string, $index);
$closing_string_index = strpos($parse_string, $closing_string, $index);
// Embedded opening string
if(
($opening_string_index !== false) &&
($closing_string_index !== false) &&
($opening_string_index < $closing_string_index)
) {
$index = $opening_string_index + strlen($opening_string);
$depth++;
continue;
}
// Embedded closing string
if(
($closing_string_index !== false) &&
($depth > 1)
) {
$index = $closing_string_index + strlen($closing_string);
$depth--;
continue;
}
// Associated closing string
if(
($closing_string_index !== false) &&
($depth === 1)
) {
break;
}
break;
}
return $closing_string_index;
}
// Parse form data for use with parse_variables
public static function parse_variables_meta_value($form, $meta, $content_type, $html_encode = true, $column = 'parse_variable', $column_id_default = 0, $delimiter_row = NULL, $action_config = false, $field = false, $submit = false, $column_override = false) {
$type = $meta['type'];
$value = $meta['value'];
if($value == '') { return ''; }
// Content type override
if($content_type == 'column_value') {
$content_type = 'text/plain';
$column = 'value';
}
// HTML encode values
if($content_type == 'text/html' && !is_array($value)) {
if($html_encode) { $value = esc_html($value); }
switch($type) {
case 'url' :
$value_url = self::get_url($value);
$value = !empty($value_url) ? sprintf(
'<a href="%s" target="_blank">%s</a>',
esc_url($value_url),
esc_html($value)
) : esc_html($value);
break;
case 'tel' :
$value_tel = self::get_tel($value);
$value = !empty($value_tel) ? sprintf(
'<a href="%s">%s</a>',
esc_url('tel:' . $value_tel),
esc_html($value)
) : esc_html($value);
break;
case 'email' :
$value_email = self::get_email($value);
$value = !empty($value_email) ? sprintf(
'<a href="%s">%s</a>',
esc_url('mailto:' . $value_email),
esc_html($value)
) : esc_html($value);
break;
case 'ip' :
// Get lookup URL mask
$ip_lookup_url_mask = self::option_get('ip_lookup_url_mask');
if(empty($ip_lookup_url_mask)) { $value = esc_html($value); break; }
// Split IP (IP can be comma separated if proxy in use)
$ip_array = explode(',', $value);
$value_array = [];
foreach($ip_array as $ip) {
// Trim
$ip = trim($ip);
// Validate IP
if(inet_pton($ip) === false) { continue; }
// Get #value for mask
$ip_lookup_url_mask_values = array('value' => $ip);
// Build lookup URL
$ip_lookup_url = self::mask_parse($ip_lookup_url_mask, $ip_lookup_url_mask_values);
$value_array[] = sprintf('<a href="%s" target="_blank">%s</a>', esc_url($ip_lookup_url), esc_html($ip));
}
$value = implode('<br />', $value_array);
break;
case 'latlon' :
if(preg_match('/^(\-?\d+(\.\d+)?),\s*(\-?\d+(\.\d+)?)$/', $value) == 1) {
// Get lookup URL mask
$latlon_lookup_url_mask = self::option_get('latlon_lookup_url_mask');
if(empty($latlon_lookup_url_mask)) { $value = esc_html($value); break; }
// Get #value for mask
$latlon_lookup_url_mask_values = array('value' => $value);
// Build lookup URL
$latlon_lookup_url = self::mask_parse($latlon_lookup_url_mask, $latlon_lookup_url_mask_values);
$value = sprintf('<a href="%s" target="_blank">%s</a>', esc_url($latlon_lookup_url), esc_html($value));
} else {
switch(absint($value)) {
case 1 :
$value = __('User denied the request for geo location', 'ws-form');
break;
case 2 :
$value = __('Geo location information was unavailable', 'ws-form');
break;
case 3 :
$value = __('The request to get user geo location timed out', 'ws-form');
break;
default :
$value = '-';
}
}
break;
}
}
// Process by field type
switch($type) {
case 'file' :
case 'mediacapture' :
case 'signature' :
$files = $meta['value'];
if(!is_array($files)) { break; }
// File links? (Email action settings)
if(
($action_config !== false) &&
is_array($action_config) &&
isset($action_config['meta']) &&
isset($action_config['meta']['action_email_message_file_links'])
) {
$file_links = $action_config['meta']['action_email_message_file_links'];
} else {
$file_links = self::option_get('action_email_embed_image_link', false);
}
// File embed? (Global setting)
$file_embed = self::option_get('action_email_embed_images', true);
// File description? (Global setting)
$file_description = self::option_get('action_email_embed_image_description', true);
$value_array = array();
foreach($files as $file_object_index => $file_object) {
if(!is_array($file_object)) { continue; }
// Get file handler
$file_handler = isset($file_object['handler']) ? $file_object['handler'] : '';
if($file_handler == '') { $file_handler = 'wsform'; }
if(!isset(WS_Form_File_Handler::$file_handlers[$file_handler])) { continue; }
$file_handler = WS_Form_File_Handler::$file_handlers[$file_handler];
// Get field ID
$field_id = (($field !== false) && isset($field->id)) ? $field->id : false;
// Get value array
if(method_exists($file_handler, 'get_value_parse_variable')) {
// Get hash
$hash = (($submit !== false) && isset($submit->hash)) ? $submit->hash : '';
// Use file handler to get the value for parse variables
$value_array[] = $file_handler->get_value_parse_variable($file_object, $field_id, $file_object_index, $hash, $file_links, $file_embed, $content_type, $file_description, $type);
} else {
// Fallback
$file_size = self::get_file_size($file_object['size']);
$value_array[] = sprintf('%s (%s)', $file_object['name'], $file_size);
}
}
$value = implode((($content_type == 'text/html') ? '<br />' : "\n"), $value_array);
break;
case 'datetime' :
$fields = self::get_fields_from_form($form);
if(!isset($fields[$meta['id']])) { break; }
$field = $fields[$meta['id']];
// If submit is read from database, it is split into MySQL and presentable formats
if(is_array($value) && isset($value['mysql'])) { $value = $value['mysql']; }
$value = self::get_date_by_type($value, (object) $field);
break;
case 'googlemap' :
if(
is_array($value) &&
isset($value['lat']) &&
isset($value['lng'])
) {
$value = sprintf('%.7f,%.7f', $value['lat'], $value['lng']);
if($content_type == 'text/html') {
// Get lookup URL mask
$latlon_lookup_url_mask = self::option_get('latlon_lookup_url_mask');
if(empty($latlon_lookup_url_mask)) { break; }
// Get #value for mask
$latlon_lookup_url_mask_values = array('value' => $value);
// Build lookup URL
$latlon_lookup_url = self::mask_parse($latlon_lookup_url_mask, $latlon_lookup_url_mask_values);
$value = sprintf('<a href="%s" target="_blank">%s</a>', esc_url($latlon_lookup_url), esc_html($value));
}
} else {
$value = '';
}
break;
case 'price_select' :
case 'select' :
case 'price_checkbox' :
case 'checkbox' :
case 'price_radio' :
case 'radio' :
// If value_array is set, we'll use that in case we have repeaters
if(isset($meta['value_array'])) {
$value = $meta['value_array'];
}
$fields = self::get_fields_from_form($form);
if(!isset($fields[$meta['id']])) { break; }
$field = $fields[$meta['id']];
if(is_null($delimiter_row)) {
$delimiter_text_plain = "\n";
$delimiter_text_html = "<br />";
} else {
$delimiter_text_plain = $delimiter_text_html = $delimiter_row;
}
// Build default value
$default_value = is_array($value) ? (($content_type == 'text/html') ? implode($delimiter_text_html, $value) : implode($delimiter_text_plain, $value)) : $value;
// Get data grid value
$value = self::get_datagrid_value($field, $value, $content_type, $default_value, $column, $column_id_default, $delimiter_row, $column_override);
break;
default :
$value = is_array($value) ? (($content_type == 'text/html') ? implode("<br />", $value) : implode("\n", $value)) : $value;
}
return $value;
}
// #email_ecommerce
public static function parse_variables_ecommerce($submit) {
$ecommerce_html = '';
$ecommerce_rows = array();
// Get e-commerce config
$ecommerce_config = WS_Form_Config::get_ecommerce();
foreach($ecommerce_config['cart_price_types'] as $meta_key => $cart_price_type) {
$meta_key = 'ecommerce_cart_' . $meta_key;
$value = isset($submit->meta[$meta_key]) ? $submit->meta[$meta_key] : false;
if(($value !== '') && ($value !== false)) {
$priority = isset($cart_price_type['priority']) ? $cart_price_type['priority'] : 10000;
$value = self::get_price($value);
$ecommerce_rows[] = array('label' => $cart_price_type['label'], 'value' => $value, 'priority' => $priority);
} else {
continue;
}
}
foreach($ecommerce_config['meta_keys'] as $meta_key => $meta_key_config) {
$value = isset($submit->meta[$meta_key]) ? $submit->meta[$meta_key] : false;
if(($value !== '') && ($value !== false)) {
$label = $meta_key_config['label'];
$priority = isset($meta_key_config['priority']) ? $meta_key_config['priority'] : 10000;
// Lookup?
if(
(isset($meta_key_config['lookup'])) &&
(isset($ecommerce_config[$meta_key_config['lookup']])) &&
(isset($ecommerce_config[$meta_key_config['lookup']][$value]))
) {
$value = $ecommerce_config[$meta_key_config['lookup']][$value]['label'];
}
// Type
if(isset($meta_key_config['type'])) {
switch($meta_key_config['type']) {
case 'price' : $value = self::get_price($value); break;
}
}
// Push to e-commerce rows
$ecommerce_rows[] = array('label' => $label, 'value' => $value, 'priority' => $priority);
}
}
// Sort e-commerce rows by priority
uasort($ecommerce_rows, function ($ecommerce_rows_1, $ecommerce_rows_2) {
return ($ecommerce_rows_1['priority'] == $ecommerce_rows_2['priority']) ? 0 : (($ecommerce_rows_1['priority'] < $ecommerce_rows_2['priority']) ? -1 : 1);
});
if(count($ecommerce_rows) > 0) {
foreach($ecommerce_rows as $ecommerce_row) {
$ecommerce_html .= '<p style="font-family: sans-serif; font-size: 14px; font-weight: normal; margin: 0; margin-bottom: 10px;"><strong>' . esc_html($ecommerce_row['label']) . '</strong><br />' . $ecommerce_row['value'] . '</p>';
}
}
return $ecommerce_html;
}
// #email_submission
public static function parse_variables_fields_all($form, $submit, $content_type, $render_group_labels, $render_section_labels, $render_field_labels, $render_blank_fields, $render_static_fields, $hidden_array, $action_config) {
$fields_all = self::parse_variables_fields_all_group($form->groups, $form, $submit, $content_type, $render_group_labels, $render_section_labels, $render_field_labels, $render_blank_fields, $render_static_fields, $hidden_array, $action_config);
return $fields_all;
}
// Run through each group
public static function parse_variables_fields_all_group($groups, $form, $submit, $content_type, $render_group_labels, $render_section_labels, $render_field_labels, $render_blank_fields, $render_static_fields, $hidden_array, $action_config) {
$groups_html = '';
$group_count = count($groups);
$group_label_join = '';
foreach($groups as $key => $group) {
if(isset($groups[$key]->sections)) {
$sections_html = self::parse_variables_fields_all_section($group->sections, $form, $submit, $content_type, $render_section_labels, $render_field_labels, $render_blank_fields, $render_static_fields, $hidden_array, $action_config);
// Should label be rendered?
$render_label = (
(
$render_group_labels == 'true'
)
||
(
($render_group_labels == 'auto') &&
($sections_html != '')
)
) && self::get_object_meta_value($group, 'label_render');
if(($group_count > 0) && $render_label) {
switch($content_type) {
case 'text/html' :
$groups_html .= $group_label_join . ($render_label ? '<h2>' . esc_html($group->label) . "</h2>\n" : '');
$group_label_join = "<hr style=\"margin: 20px 0\" />\n";
break;
default :
$groups_html .= $group_label_join . "** " . $group->label . " **\n\n";
$group_label_join = "\n";
}
}
$groups_html .= $sections_html;
}
}
return $groups_html;
}
// Run through each section
public static function parse_variables_fields_all_section($sections, $form, $submit, $content_type, $render_section_labels, $render_field_labels, $render_blank_fields, $render_static_fields, $hidden_array, $action_config) {
$sections_html = '';
$section_count = count($sections);
$section_label_join = '';
// Unserialize section_repeatable
$section_repeatable = is_serialized($submit->section_repeatable) ? self::maybe_unserialize($submit->section_repeatable) : false;
// Get field types in single dimension array
$field_types = WS_Form_Config::get_field_types_flat();
foreach($sections as $key => $section) {
// Build section ID string
$section_id_string = 'section_' . $section->id;
$section_repeatable_array = (
($section_repeatable !== false) &&
isset($section_repeatable[$section_id_string]) &&
isset($section_repeatable[$section_id_string]['index'])
) ? $section_repeatable[$section_id_string]['index'] : [false];
if(!isset($sections[$key]->fields)) { continue; }
// Loop through section_repeatable_array
foreach($section_repeatable_array as $section_repeatable_array_index => $section_repeatable_index) {
$fields_html = '';
// Check if repeatable
$section_repeatable_html = '';
$section_repeatable_suffix = '';
// Repeatable, so render fieldset and set field_name suffix
if($section_repeatable_index !== false) {
// Repeatable section found
$section_repeatable_index = absint($section_repeatable_index);
if($section_repeatable_index === 0) { continue; }
switch($content_type) {
case 'text/html' :
// Render fieldset
$section_repeatable_html = '<h4>#' . (absint($section_repeatable_array_index) + 1) . "</h4>\n";
break;
default :
$section_repeatable_html = '#' . (absint($section_repeatable_array_index) + 1) . "\n";
}
// Set field_name suffix
$section_repeatable_suffix = '_' . $section_repeatable_index;
}
// Process fields
foreach($section->fields as $field) {
$field_type = $field->type;
$field_type_config = $field_types[$field_type];
// Remove layout editor only fields
$layout_editor_only = isset($field_type_config['layout_editor_only']) ? $field_type_config['layout_editor_only'] : false;
if($layout_editor_only) { continue; }
// Check for excluded fields
$exclude_email = self::get_object_meta_value($field, 'exclude_email', false);
if($exclude_email) { continue; }
// Check for static fields
$field_static = isset($field_type_config['static']) ? $field_type_config['static'] : false;
if($render_static_fields && $field_static) {
// do_shortcode (Only on static fields)
$meta_do_shortcode = isset($field_type_config['meta_do_shortcode']) ? $field_type_config['meta_do_shortcode'] : false;
if($meta_do_shortcode !== false) {
if(!is_array($meta_do_shortcode)) { $meta_do_shortcode = array($meta_do_shortcode); }
foreach($meta_do_shortcode as $meta_do_shortcode_meta_key) {
// Check meta key exists
if(
!isset($field->meta) ||
!isset($field->meta->{$meta_do_shortcode_meta_key})
) { continue; }
// Update form_object
$field->meta->{$meta_do_shortcode_meta_key} = self::do_shortcode($field->meta->{$meta_do_shortcode_meta_key});
}
}
// Build field name
$field_name = WS_FORM_FIELD_PREFIX . $field->id;
if($section_repeatable_index !== false) {
$field_name = sprintf('%s[%u]', $field_name, $section_repeatable_index);
}
// Bypass hidden static elements
if(in_array($field_name, $hidden_array)) {
continue;
}
if($field_static === true) {
// If static set to true, we use the mask_field
$mask_field = isset($field_type_config['mask_field_static']) ? $field_type_config['mask_field_static'] : (isset($field_type_config['mask_field']) ? $field_type_config['mask_field'] : '');
$fields_html .= self::parse_variables_process($mask_field, $form, $submit, $content_type);
} else {
// Get value
$value = self::get_object_meta_value($field, $field_static, '');
// WPAutoP?
$wpautop = self::wpautop_parse_variable($field, $field_type_config);
if($wpautop && ($content_type == 'text/html')) { $value = wpautop($value); }
// Get meta value
$fields_html .= self::parse_variables_process($value, $form, $submit, $content_type);
}
continue;
}
// Check to ensure this field is saved
$submit_save = isset($field_type_config['submit_save']) ? $field_type_config['submit_save'] : false;
if(!$submit_save) { continue; }
// Get field label
$label = $field->label;
// Should label be rendered?
$render_label = (
($render_field_labels == 'true')
||
(
($render_field_labels == 'auto') &&
self::get_object_meta_value($field, 'label_render')
)
);
// Build field name
$field_name = WS_FORM_FIELD_PREFIX . $field->id . $section_repeatable_suffix;
// WPAutoP
$wpautop = self::wpautop_parse_variable($field, $field_type_config);
$html_encode = !$wpautop;
if(isset($submit->meta[$field_name])) {
// Get submit meta
$meta = $submit->meta[$field_name];
// Get field value
$value = self::parse_variables_meta_value($form, $meta, $content_type, $html_encode, 'parse_variable', 0, NULL, $action_config, $field, $submit);
} else {
$value = '';
}
// No submit value found
if($value == '') {
if($render_blank_fields) {
$value = '-';
} else {
continue;
}
}
// Add to fields_html HTML
switch($content_type) {
case 'text/html' :
// WPAutoP?
if($wpautop) { $value = wpautop($value); }
$fields_html .= '<div class="wsf-field">' . ($render_label ? ('<strong>' . esc_html($label) . '</strong><br />') : '') . $value . "</div>\n";
break;
default :
$fields_html .= ($render_label ? ($label . "\n") : '') . $value . "\n\n";
break;
}
}
// Should label be rendered?
$render_label = (
($render_section_labels == 'true')
||
(
($render_section_labels == 'auto') &&
($fields_html != '')
)
)
&& self::get_object_meta_value($section, 'label_render')
&& ($section_repeatable_array_index == 0);
// Add section title if fields found
if($render_label) {
switch($content_type) {
case 'text/html' :
$sections_html .= $render_label ? '<h3>' . esc_html($section->label) . "</h3>\n" : '';
break;
default :
$sections_html .= $section_label_join . "* " . $section->label . " *\n\n";
$section_label_join = "\n\n";
}
}
// Add fields
if($fields_html != '') { $sections_html .= $section_repeatable_html . $fields_html; }
}
}
return $sections_html;
}
// WPAutoP
public static function wpautop_parse_variable($field, $field_type_config) {
// Check for wpautop do not process
if(self::get_object_meta_value($field, 'wpautop_do_not_process', '') == 'on') { return false; }
// Meta wpautop_parse_variable
$wpautop_parse_variable = isset($field_type_config['wpautop_parse_variable']) ? $field_type_config['wpautop_parse_variable'] : false;
if(is_array($wpautop_parse_variable)) {
$condition_output = false;
foreach($wpautop_parse_variable as $condition) {
if(self::get_object_meta_value($field, $condition['meta_key'], '') === $condition['meta_value']) {
$condition_output = true;
}
}
$wpautop_parse_variable = $condition_output;
}
return $wpautop_parse_variable;
}
// Get value label lookup
public static function get_datagrid_value($field, $value_array, $content_type, $default_value, $column = 'parse_variable', $column_id_default = 0, $datagrid_delimiter = NULL, $column_override = false) {
$return_array = array();
if(!is_array($value_array)) { return $default_value; }
// Get meta key prefix
$meta_key_prefix = $field->type;
// Apply fix to meta key prefix
switch($meta_key_prefix) {
case 'price_select' :
$meta_key_prefix = 'select_price';
break;
case 'price_checkbox' :
$meta_key_prefix = 'checkbox_price';
break;
case 'price_radio' :
$meta_key_prefix = 'radio_price';
break;
}
// Get data grid
$datagrid = self::get_object_meta_value($field, sprintf('data_grid_%s', $meta_key_prefix), false);
if($datagrid === false) { return $default_value; }
// Get value mapping column ID
$value_column_id = self::get_object_meta_value($field, sprintf('%s_field_value', $meta_key_prefix), 0);
$value_column_id = absint($value_column_id);
// Get column ID to return
$return_column_id = self::get_object_meta_value($field, sprintf('%s_field_%s', $meta_key_prefix, $column), $column_id_default);
$return_column_id = absint($return_column_id);
// Preparsing columns
$label_column_id = self::get_object_meta_value($field, sprintf('%s_field_label', $meta_key_prefix), 0);
$label_column_id = absint($label_column_id);
$price_column_id = self::get_object_meta_value($field, sprintf('%s_field_price', $meta_key_prefix), 0);
$price_column_id = absint($price_column_id);
$parse_variable_column_id = self::get_object_meta_value($field, sprintf('%s_field_parse_variable', $meta_key_prefix), 0);
$parse_variable_column_id = absint($parse_variable_column_id);
$wc_column_id = self::get_object_meta_value($field, sprintf('%s_field_wc', $meta_key_prefix), 0);
$wc_column_id = absint($wc_column_id);
// Get data grid columns
if(!isset($datagrid->columns)) { return $default_value; }
if(!is_array($datagrid->columns)) { return $default_value; }
$columns = $datagrid->columns;
// Get return_column_index from return_column_id
$return_column_index = false;
$value_column_index = false;
$label_column_index = false;
$price_column_index = false;
$parse_variable_column_index = false;
$wc_column_index = false;
// If column_override specified
if($column_override !== false) {
$return_column_index = absint($column_override);
}
foreach($columns as $index => $column) {
// Check
if(!isset($column->id)) { continue; }
// Set indexes if column ID found
if($column_override === false) {
if($column->id === $return_column_id) { $return_column_index = $index; }
} else {
if($column->label == $column_override) { $return_column_index = $index; }
}
if($column->id === $value_column_id) { $value_column_index = $index; }
if($column->id === $label_column_id) { $label_column_index = $index; }
if($column->id === $price_column_id) { $price_column_index = $index; }
if($column->id === $parse_variable_column_id) { $parse_variable_column_index = $index; }
if($column->id === $wc_column_id) { $wc_column_index = $index; }
}
// Check that we got indexes back
if(
($return_column_index === false) ||
($value_column_index === false)
) {
return $default_value;
}
// Get data grid rows
if(!isset($datagrid->groups)) { return $default_value; }
if(!is_array($datagrid->groups)) { return $default_value; }
$groups = $datagrid->groups;
foreach($groups as $group) {
if(!isset($group->rows)) { continue; }
if(!is_array($group->rows)) { continue; }
$rows = $group->rows;
foreach($rows as $row) {
// Get data
if(!isset($row->data)) { continue; }
if(!is_array($row->data)) { continue; }
$data = $row->data;
// Check value and return indexes exist
if(!isset($data[$value_column_index])) { continue; }
if(!isset($data[$return_column_index])) { continue; }
// Pre-parsing
$mask_values_row = array(
'data_grid_row_price' => '',
'data_grid_row_price_currency' => '',
'data_grid_row_woocommerce_cart' => '',
'data_grid_row_value' => $data[$value_column_index],
'data_grid_row_action_variable' => '',
'data_grid_row_label' => ''
);
// Label
if(
($label_column_index !== false) &&
isset($data[$label_column_index])
) {
$mask_values_row['data_grid_row_label'] = $data[$label_column_index];
}
// Price
if(
($price_column_index !== false) &&
isset($data[$price_column_index])
) {
$mask_values_row['data_grid_row_price_currency'] = self::get_price($data[$price_column_index]);
$mask_values_row['data_grid_row_price'] = self::get_number($data[$price_column_index]);
}
// Parse Variable
if(
($parse_variable_column_index !== false) &&
isset($data[$parse_variable_column_index])
) {
$mask_values_row['data_grid_row_action_variable'] = $data[$parse_variable_column_index];
}
// WooCommerce
if(
($wc_column_index !== false) &&
isset($data[$wc_column_index])
) {
$mask_values_row['data_grid_row_woocommerce_cart'] = $data[$wc_column_index];
}
// Parse columns
foreach($data as $column_index => $column) {
$data[$column_index] = self::mask_parse($column, $mask_values_row);
}
// Check if value matches
$value_array_index = array_search($data[$value_column_index], $value_array);
// Process each found instance of the input value_array (This ensure if a user selects the same value in a repeater that it returns both values)
while($value_array_index !== false) {
// Add column value to the return array
$return_array[] = $data[$return_column_index];
// Remove found value from input value_array
unset($value_array[$value_array_index]);
// Check if any other values exist
if(count($value_array) === 0) { break; }
// Check if another value matches
$value_array_index = array_search($data[$value_column_index], $value_array);
}
}
}
// Add any value_array elements that were not found
$return_array = array_merge($return_array, $value_array);
// Return unique values to avoid duplicates if there are duplicate values
// $return_array = array_unique($return_array);
if(is_null($datagrid_delimiter)) {
$delimiter_text_plain = "\n";
$delimiter_text_html = "<br />";
} else {
$delimiter_text_plain = $delimiter_text_html = $datagrid_delimiter;
}
return (($content_type == 'text/html') ? implode($delimiter_text_html, $return_array) : implode($delimiter_text_plain, $return_array));
}
// Check if user is logged in
public static function logged_in() {
if(!function_exists('is_user_logged_in')) {
include(ABSPATH . 'wp-includes/pluggable.php');
}
return is_user_logged_in();
}
// Check if user has WordPress capability
public static function can_user($capability) {
if(!function_exists('wp_get_current_user')) {
include(ABSPATH . 'wp-includes/pluggable.php');
}
return current_user_can($capability);
}
// Check if user has WordPress capability, if not, throw an error
public static function user_must($capability, $bypass_user_capability_check = false) {
// Bypass
if($bypass_user_capability_check) { return true; }
// Check if user has capability
if(self::can_user($capability)) {
return true;
} else {
// Throw error
throw new Exception(sprintf(
/* translators: %s: Capability */
esc_html__('Insufficient user capabilities (%s)', 'ws-form'),
esc_html($capability)
));
}
}
// Loader
public static function loader() {
?>
<!-- Loader -->
<div id="wsf-loader"></div>
<!-- /Loader -->
<?php
}
// Review
public static function review() {
// Review nag
$review_nag = self::option_get('review_nag', false);
if($review_nag) { return; }
// Determine if review nag should be shown
$install_timestamp = absint(self::option_get('install_timestamp', time(), true));
$review_nag_show = (time() > ($install_timestamp + (WS_FORM_REVIEW_NAG_DURATION * 86400)));
if(!$review_nag_show) { return; }
// Show nag
self::admin_message_render(
sprintf(
'<p><strong>%s</strong></p><p>%s</p><p class="buttons"><a href="https://wordpress.org/support/plugin/ws-form/reviews/#new-post" class="button button-primary" data-wsf-review-nag-dismiss target="_blank">%s</a> <a href="#" class="button" data-wsf-review-nag-dismiss>%s</a></p>',
sprintf(
/* translators: %s: Presentable plugin name, e.g. WS Form PRO */
esc_html__('Thank you for using %s!', 'ws-form'),
WS_FORM_NAME_PRESENTABLE
),
sprintf(
/* translators: %s: Presentable plugin name, e.g. WS Form PRO */
esc_html__('We hope you have enjoyed using the plugin. Positive reviews from awesome users like you help others to feel confident about choosing %s too. If convenient, we would greatly appreciate you sharing your happy experiences with the WordPress community. Thank you in advance for helping us out!', 'ws-form'),
WS_FORM_NAME_PRESENTABLE
),
esc_html__('Leave a review', 'ws-form'),
esc_html__('No thanks', 'ws-form')
),
'notice-success',
false,
false,
'wsf-review'
);
?>
<script>
(function($) {
'use strict';
$('[data-wsf-review-nag-dismiss]').on('click', function() {
// Hide nag
$('.wsf-review').hide();
// Call AJAX to prevent review nag appearing again
$.ajax({ method: 'POST', url: '<?php self::echo_esc_html(self::get_api_path('helper/review-nag/dismiss/')); ?>', data: { '_wpnonce': '<?php self::echo_esc_attr(wp_create_nonce('wp_rest')); ?>' } });
});
})(jQuery);
</script>
<?php
}
// API check - Show a dismissable warning if the welcome screen could not reach the REST API
public static function api_check() {
// Only relevant for users who can resolve the issue
if(!self::can_user('manage_options_wsform')) { return; }
// Only show if the welcome screen flagged a failed REST API check
$api_check_warning = self::option_get('api_check_warning', false);
if(!$api_check_warning) { return; }
// Show warning (nag_notice = true so it is suppressed on the welcome screen)
self::admin_message_render(
sprintf(
'<p><strong>%s</strong></p><p>%s</p><p class="buttons"><a href="%s" class="button button-primary" target="_blank">%s</a> <a href="#" class="button" data-wsf-api-check-dismiss>%s</a></p>',
sprintf(
/* translators: %s: Presentable plugin name, e.g. WS Form PRO */
esc_html__('%s could not connect to the REST API', 'ws-form'),
WS_FORM_NAME_PRESENTABLE
),
esc_html__('A background check was unable to reach the REST API on your website. Some features may not work correctly until this is resolved.', 'ws-form'),
esc_url(self::get_plugin_website_url('/knowledgebase/installation-troubleshooting/', 'api_check')),
esc_html__('Troubleshoot', 'ws-form'),
esc_html__('Dismiss', 'ws-form')
),
'notice-warning',
false,
true,
'wsf-api-check'
);
?>
<script>
(function() {
'use strict';
function wsf_api_check_dismiss(e) {
if(e) { e.preventDefault(); }
// Hide warning
var notices = document.querySelectorAll('.wsf-api-check');
for(var i = 0; i < notices.length; i++) { notices[i].style.display = 'none'; }
// Call AJAX to prevent the warning appearing again
if(window.fetch) {
var data = new FormData();
data.append('_wpnonce', '<?php self::echo_esc_attr(wp_create_nonce('wp_rest')); ?>');
fetch('<?php self::echo_esc_html(self::get_api_path('helper/api-check/dismiss/')); ?>', { method: 'POST', credentials: 'same-origin', body: data });
}
}
document.addEventListener('DOMContentLoaded', function() {
var buttons = document.querySelectorAll('[data-wsf-api-check-dismiss]');
for(var i = 0; i < buttons.length; i++) { buttons[i].addEventListener('click', wsf_api_check_dismiss); }
});
})();
</script>
<?php
}
// Check edition
public static function is_edition($edition) {
switch($edition) {
case 'basic' :
return true;
case 'pro' :
return true;
default :
return false;
}
}
// Build data grid meta
public static function build_data_grid_meta($meta_key, $group_name = false, $columns = false, $rows = false) {
// Get base meta
$meta_keys = WS_Form_Config::get_meta_keys_data_grids();
if(
!isset($meta_keys[$meta_key]) ||
!isset($meta_keys[$meta_key]['default'])
) {
return false;
}
$meta = $meta_keys[$meta_key]['default'];
if($group_name !== false) { $meta['groups'][0]['label'] = $group_name; }
if($columns !== false) { $meta['columns'] = $columns; }
if($rows !== false) { $meta['groups'][0]['rows'] = $rows; }
return $meta;
}
// Get nice file size
public static function get_file_size($bytes) {
if($bytes >= 1048576) {
$bytes = number_format($bytes / 1048576, 2) . ' MB';
} elseif ($bytes >= 1024) {
$bytes = number_format($bytes / 1024, 2) . ' KB';
} elseif ($bytes > 1) {
$bytes = $bytes . ' bytes';
} elseif ($bytes == 1) {
$bytes = $bytes . ' byte';
} else {
$bytes = '0 bytes';
}
$bytes = str_replace('.00', '', $bytes);
return $bytes;
}
// PHP to MySQL Date Format
public static function php_to_mysql_date_format($format_string) {
// Cannot convert: N, z, t, L, o
$php_to_mysql_date_format_character_array = array(
'd' => '%d',
'a' => '%p',
'D' => '%a',
'j' => '%e',
'u' => '%f',
'W' => '%u',
'l' => '%W',
'w' => '%w',
'M' => '%b',
'F' => '%M',
'm' => '%m',
'n' => '%c',
'Y' => '%Y',
'y' => '%y',
'A' => '%p',
'g' => '%l',
'G' => '%k',
'h' => '%h',
'H' => '%H',
'i' => '%i',
's' => '%S',
);
foreach($php_to_mysql_date_format_character_array as $from => $to) {
$format_string = str_replace($from, $to, $format_string);
}
return $format_string;
}
// Get m/d/Y formatted date
public static function get_date_by_site($date) {
$format_date = get_option('date_format');
switch($format_date) {
case 'd/m/Y' :
$date = str_replace('/', '.', $date);
break;
}
// Strip commas
$date = str_replace(',', '', $date);
return $date;
}
// Get nice date by type
public static function get_date_by_type($date, $field_object, $format_output = false) {
if(empty($date)) { return ''; }
if(!is_string($date)) { return ''; }
// Remember date
$date_source = $date;
// Get date format
$format_date = self::get_object_meta_value($field_object, 'format_date', get_option('date_format'));
if(empty($format_date)) { $format_date = get_option('date_format'); }
// Get time format
$format_time = self::get_object_meta_value($field_object, 'format_time', get_option('time_format'));
if(empty($format_time)) { $format_time = get_option('time_format'); }
// Process by date format
switch($format_date) {
case 'd/m/Y' :
// Convert / to - so that strtotime works with d/m/Y format
$date = str_replace('/', '-', $date);
break;
case 'd.m.Y' :
case 'j.n.Y' :
// Convert . to - so that strtotime works with d.m.Y or j.n.Y format
$date = str_replace('.', '-', $date);
break;
}
// Translate date
$date = self::field_date_translate($date);
// Strip commas (Required for European formats such as j F, Y, e.g. 8 June, 2018)
$date = str_replace(',', '', $date);
// Convert date to time
$time = strtotime($date);
// We'll use UTC so that wp_date doesn't offset the date
$utc = new DateTimeZone('UTC');
// Check WordPress version
$wp_new = self::wp_version_at_least('5.3');
// If conversion failed, return the source date
if($time === false) { return $date_source; }
if($format_output === false) {
$input_type_datetime = self::get_object_meta_value($field_object, 'input_type_datetime', 'date');
switch($input_type_datetime) {
case 'date' :
return $wp_new ? wp_date($format_date, $time, $utc) : gmdate($format_date, $time);
case 'month' :
return $wp_new ? wp_date('F Y', $time, $utc) : gmdate('F Y', $time);
case 'time' :
return $wp_new ? wp_date($format_time, $time, $utc) : gmdate($format_time, $time);
case 'week' :
return __('Week', 'ws-form') . ' ' . ($wp_new ? wp_date('W, Y', $time, $utc) : gmdate('W, Y', $time));
default :
return $wp_new ? wp_date($format_date . ' ' . $format_time, $time, $utc) : gmdate($format_date . ' ' . $format_time, $time);
}
} else {
return $wp_new ? wp_date($format_output, strtotime($date), $utc) : gmdate($format_output, strtotime($date));
}
}
// Throw error
public static function throw_error($error) {
throw new Exception(esc_html($error));
}
// Get system report
public static function get_system_report_html() {
// Get system report
$system_report = WS_Form_Config::get_system();
// Build system report HTML
$system_report_html = '<table class="wsf-table-system">';
// Check WordPress version
$wp_new = self::wp_version_at_least('5.3');
foreach($system_report as $group_id => $group) {
$system_report_html .= '<tbody>';
$system_report_html .= '<tr><th colspan="2"><h2>' . esc_html($group['label']) . '</h2></th></tr>';
foreach($group['variables'] as $item_id => $item) {
// Valid
// 0 = Ignore, 1 = Yes, 2 = No
$valid = isset($item['valid']) ? ($item['valid'] ? 1 : 2) : 0;
$system_report_html .= '<tr';
switch($valid) {
case 1 : $system_report_html .= ' class="wsf-system-valid"'; break;
case 2 : $system_report_html .= ' class="wsf-system-invalid"'; break;
}
// Label
$system_report_html .= '><td><b>' . esc_html($item['label']);
if(isset($item['min'])) { $system_report_html .= ' (Min: ' . $item['min'] . ')'; }
$system_report_html .= '</b></td>';
// Value
$system_report_html .= '<td>';
$value = isset($item['value']) ? $item['value'] : '-';
$type = isset($item['type']) ? $item['type'] : 'text';
switch($type) {
case 'plugins' :
if(is_array($value)) {
$plugin_array = array();
foreach($value as $plugin_path) {
$plugin_data = get_plugin_data(WP_PLUGIN_DIR . '/' . $plugin_path);
$plugin_array[] = sprintf('<a href="%s" target="_blank">%s</a> (%s)', $plugin_data['PluginURI'], $plugin_data['Name'], $plugin_data['Version']);
}
$value = implode('<br />', $plugin_array);
}
break;
case 'theme' :
if(is_object($value)) {
$value = sprintf('<a href="%s" target="_blank">%s</a> (%s)', $value->get('ThemeURI'), $value->get('Name'), $value->get('Version'));
}
break;
case 'boolean' :
$value = $value ? __('Yes', 'ws-form') : __('No', 'ws-form');
break;
case 'url' :
$value = sprintf('<a href="%1$s" target="_blank">%1$s</a>', $value);
break;
case 'size' :
$value = size_format($value);
break;
case 'edition' :
switch($value) {
case 'basic' : $value = 'Basic'; break;
case 'pro' : $value = 'PRO'; break;
}
break;
case 'date' :
$value = ($value != '') ? ($wp_new ? wp_date(get_option('date_format'), $value) : gmdate(get_option('date_format'), $value)) : '-';
break;
}
$system_report_html .= $value;
// Suffix
if(isset($item['suffix'])) { $system_report_html .= ' ' . $item['suffix']; }
// Valid
switch($valid) {
case 1 : $system_report_html .= WS_Form_Config::get_icon_16_svg('check'); break;
case 2 : $system_report_html .= WS_Form_Config::get_icon_16_svg('warning'); break;
}
$system_report_html .= '</td></tr>';
}
$system_report_html .= '</tbody>';
}
$system_report_html .= '</table>';
return $system_report_html;
}
// Get a string formatted for SMTP email addresses
public static function get_email_address($email, $name = '') {
// Ensure email is valid
if(!filter_var($email, FILTER_VALIDATE_EMAIL)) { return false; }
// Check length
if(strlen($name) > 255) { $name = substr($name, 0, 255); }
// Determine if double quotes and escaping of the name is required
if(preg_match('/[^\w\s!#$%&\'*+\/=?^_`{|}~.-]|^\s|\s$|\s{2,}/', $name)) {
// Correct escaping of double quotes for name
// $name = str_replace('"', '\"', $name);
// There is a bug in wp_mail that does not handle escaped double quotes properly, therefore we'll remove double quotes other wise double quotes turn into a forward slash
$name = str_replace('"', '', $name);
// Enclose in double quotes
$name = sprintf('"%s"', $name);
}
// Return full email address
return ($name != '') ? sprintf('%s <%s>', $name, $email) : $email;
}
// Get encryption status HTML
public static function get_encryption_status_html() {
$ws_form_encryption = new WS_Form_Encryption();
if($ws_form_encryption->key_found === false) {
$encryption_status_html = '<p>' . sprintf(
/* translators: %s: wp-config.php */
esc_html__('Copy and paste the following code into your %s file after the Authentication Unique Keys and Salts section.', 'ws-form'),
'<strong>wp-config.php</strong>'
) . '</p>';
$encryption_key = esc_html($ws_form_encryption->create_random_key());
$encryption_status_html .= "<textarea class=\"wsf-field wsf-encryption-snippet\" rows=\"6\" readonly>/** Encryption Key For WS Form */\ndefine('WS_FORM_ENCRYPTION_KEY', '$encryption_key');</textarea>";
$encryption_status_html .= sprintf(
'<p><strong style="color: #bb0000;">%s:</strong> %s</p>',
esc_html__('Caution', 'ws-form'),
esc_html__('Once installed, do not change this key. Changing your encryption key at a later date will make it impossible to decrypt existing submission data. THIS KEY IS ONLY GENERATED ONCE. PLEASE ENSURE YOU DO NOT LOSE THIS KEY AND KEEP IT IN A SECURE PLACE. ENCRYPTED DATA AND KEYS CANNOT BE RECOVERED IF THE KEY IS LOST.', 'ws-form')
);
} else {
$encryption_status_html = '<p>' . sprintf(
/* translators: %s: wp-config.php */
esc_html__('Key successfully found in %s', 'ws-form'),
'<strong>wp-config.php</strong>'
) . '</p>';
if($ws_form_encryption->can_encrypt) {
$encryption_status_html .= '<p><strong>' . __('Encrypting submission meta data.', 'ws-form') . '</strong></p>';
} else {
$encryption_status_html .= '<p><strong>' . __('Submission meta data is not being encrypted.', 'ws-form') . '</strong></p>';
}
}
return $encryption_status_html;
}
// Get preview URL
public static function get_preview_url($form_id = 0, $template_id = false, $style_id = false, $styler = false, $conversational = false, $submit_hash = false, $skin_id = 'ws_form') {
$url = get_home_url(null, '/');
// Form ID
$url = add_query_arg(sprintf('wsf_preview%s_form_id', ($conversational ? '_conversational' : '')), $form_id, $url);
// Template ID
if(!empty($template_id) && self::styler_enabled()) {
$url = add_query_arg('wsf_preview_template_id', $template_id, $url);
}
// Style ID
if(!empty($style_id) && self::styler_enabled()) {
$url = add_query_arg('wsf_preview_style_id', $style_id, $url);
}
if($styler && self::styler_enabled()) {
$url = add_query_arg('wsf_preview_styler', 'true', $url);
}
// Skin ID
if(!empty($skin_id) && !self::styler_enabled()) {
$url = add_query_arg('wsf_skin_id', $skin_id, $url);
}
// Submit hash
if($submit_hash !== false) {
$url = add_query_arg('wsf_submit_hash', $submit_hash, $url);
}
// Random
$url = add_query_arg('wsf_rand', wp_generate_password(12, false, false), $url);
return $url;
}
// Get obscure license key
public static function get_license_key_obscured($license_key = false) {
// License key
if($license_key === false) {
$license_key = self::option_get('license_key', '');
}
$license_key_length = strlen($license_key);
$license_key_obscured = ($license_key_length > 6) ? (str_repeat('*', $license_key_length - 6) . substr($license_key, -6)) : '';
return ($license_key != '') ? $license_key_obscured : __('Unlicensed', 'ws-form');
}
// Get currency
public static function get_currency() {
$return_array = array();
$price_decimals = absint(self::option_get('price_decimals'));
$currency_position = self::option_get('currency_position');
// Get currency symbol
$currency_symbol = self::get_currency_symbol();
$return_array['prefix'] = $currency_symbol;
$return_array['suffix'] = '';
switch($currency_position) {
case 'right' :
$return_array['prefix'] = '';
$return_array['suffix'] = $currency_symbol;
break;
case 'left_space' :
$return_array['prefix'] = $currency_symbol . ' ';
break;
case 'right_space' :
$return_array['prefix'] = '';
$return_array['suffix'] = ' ' . $currency_symbol;
break;
}
// Price decimals
$return_array['decimals'] = ($price_decimals < 0) ? 0 : $price_decimals;
// Separators
$return_array['decimal_separator'] = self::option_get('price_decimal_separator');
$return_array['thousand_separator'] = self::option_get('price_thousand_separator');
return $return_array;
}
public static function get_currency_symbol() {
$currencies = WS_Form_Config::get_currencies();
$currency = self::option_get('currency', self::get_currency_default());
$currency_found = isset($currencies[$currency]) && isset($currencies[$currency]['s']);
return ($currency_found ? $currencies[$currency]['s'] : '$');
}
public static function get_currency_default() {
// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- All hooks prefixed with wsf_
return apply_filters('wsf_currency_default', 'USD');
}
public static function get_price($price_float, $currency = false, $currency_symbol_render = true) {
if($currency === false) { $currency = self::get_currency(); }
if(!is_numeric($price_float)) { $price_float = floatVal($price_float); }
return ($currency_symbol_render ? $currency['prefix'] : '') . number_format($price_float, absint($currency['decimals']), $currency['decimal_separator'], $currency['thousand_separator']) . ($currency_symbol_render ? $currency['suffix'] : '');
}
public static function get_admin_icon($color = '#a0a5aa', $base64 = true) {
$svg = sprintf('<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 400"><path fill="%s" d="M0 0v400h400V0H0zm336.6 118.9c6.7-.1 13.4 5.4 13.4 13.6-.1 7.4-5.9 13.4-13.4 13.4-8.1 0-13.6-6.7-13.5-13.7 0-7.3 6.1-13.5 13.5-13.3zm-124.4 6.5c-12 48.8-24 97.6-36.1 146.3 0 .2-.2.2-.2.4-.8.1-6 .2-10.4.2h-1.9c-2.1 0-3.7-.1-4.1-.1-.2-.2-.3-.4-.3-.6-.1-.2-.1-.5-.2-.7-1.5-6.6-2.9-13.2-4.4-19.8-2.8-12.2-5.5-24.4-8.2-36.6-2.3-10.2-4.5-20.4-6.8-30.6-.9-4.2-1.9-8.3-2.8-12.5-.6-3-1.1-6.1-1.7-9.1-1-5.5-2-11.2-3-16.7-.1-.4-.2-.8-.3-1.5-.2.6-.3.8-.4 1.1-1.5 9-3.4 17.9-5.2 26.8-.9 4.7-2.1 9.5-3.2 14.2-2.8 12.3-5.7 24.6-8.5 36.9-3.6 15.8-7.3 31.6-11 47.5-.1.5-.3 1-.4 1.5-.2.1-.5.2-.6.2H86.7c-.6-.3-.6-.8-.7-1.2-1.2-4.8-2.3-9.6-3.5-14.5-3.6-15.4-7.4-30.9-11-46.4-3.9-16.4-7.8-32.7-11.7-49.1-2.8-11.5-5.5-22.9-8.1-34.3-.2-.7-.5-1.4-.4-2.1 1.2-.2 11.9-.3 14-.1.1.3.2.7.4 1.1 2.4 10 4.7 19.9 7 29.9 2.5 10.7 5 21.4 7.5 32 1.8 7.8 3.7 15.6 5.5 23.3 1.7 7.4 3.2 14.8 4.7 22.2 1.4 6.8 2.8 13.7 4.3 20.5.1.5.2.9.4 1.3.1.2.3.2.6.3.2-.6.3-1.1.4-1.7 1.8-13.1 4.4-25.9 7.4-38.8 4.3-18.6 8.7-37.2 13.1-55.8l7.8-33.3c.1-.5.2-.9.4-1.4 1.7-.1 3.3 0 5-.1h5c1.7 0 3.3-.1 5 .1.2.6.3 1.2.5 1.7 3.8 16.1 7.6 32.2 11.4 48.2 3 12.7 6 25.3 8.9 38 1.3 5.5 2.3 11.2 3.4 16.8 1.3 6.9 2.5 13.8 3.7 20.6.3 1.7.6 3.2.9 4.9.1.3.2.6.7.6l.3-1.2c.8-5.1 1.8-10 2.9-15 3.9-18.1 8.2-36.1 12.4-54.3 3.6-15.2 7.1-30.4 10.7-45.6 1-4.5 2.1-9 3.2-13.5.1-.3.2-.7.4-1.1 1.2-.2 2.4-.1 3.5-.1h6.8c1.2 0 2.4-.2 3.6.2-.8.5-.8.7-.9 1zm86.3 124.5c-3.6 11.5-11.3 19.1-22.8 22.8-3.2 1-6.6 1.7-10 2-5.2.6-10.4.5-15.7-.1-7-.7-13.8-2.7-20.2-5.9-1.2-.6-2.4-1.2-3.5-2.1.6-1.6 5.4-9.7 6.2-10.7.3.2.6.2.9.5 1.7 1.1 3.5 1.8 5.4 2.5 3.2 1.1 6.3 2.1 9.7 2.8 5.1.9 10.1 1.3 15.3.8 12.9-1.4 19.2-10 21.3-18 1.5-5.6 1.6-11.3.2-16.9-.9-3.9-2.8-7.3-5.4-10.2-1.8-2-3.8-3.8-5.9-5.4-4.2-3.3-8.7-6.2-13.3-8.9-4.7-2.8-9.3-5.5-13.8-8.6-2.9-2.1-5.9-4.1-8.4-6.6-3.7-3.6-6.7-7.7-8.9-12.4-1.8-3.9-2.8-8.1-3.2-12.3-.2-2.5-.2-5.1-.1-7.7.6-8.8 4.2-16.2 10.6-22.3 5.9-5.5 12.8-8.9 20.6-10.4 5.3-1 10.7-1.2 16.1-.7 7.4.6 14.5 2.5 21.1 5.9 1.3.7 2.6 1.4 3.9 2.2.3.2.6.5.9.6-.5 1.3-3.8 7.1-5.7 10.1-.2.2-.3.4-.6.6l-1.2-.6c-5.4-3.1-11.1-5.3-17.2-6.2-5.6-.9-11.2-.9-16.7.5-2.8.7-5.4 1.7-7.8 3.3-5.9 3.9-9.3 9.3-10.2 16.2-.6 4.5-.2 8.9 1.2 13.3 1.1 3.5 3 6.5 5.5 9 2.6 2.6 5.5 4.8 8.5 7 3.3 2.3 6.8 4.4 10.3 6.5 5.8 3.4 11.5 7 16.8 11 2.3 1.7 4.6 3.6 6.6 5.6 5.9 5.9 9.5 13 10.6 21.2 1.4 7.2 1.1 14.5-1.1 21.6zm38 26.4c-7.5.1-13.5-6.2-13.5-13.5 0-6.7 5.4-13.5 13.5-13.4 7.4 0 13.4 5.9 13.4 13.4.1 8-6.5 13.6-13.4 13.5zm-.1-64.8c-7.9-.1-13.4-6.6-13.4-13.4 0-7.7 6.4-13.7 13.5-13.5 6.4-.2 13.4 5.1 13.5 13.5 0 7.4-6.1 13.5-13.6 13.4z"></path></svg>', $color);
return $base64 ? 'data:image/svg+xml;base64,' . base64_encode($svg) : $svg;
}
// Load content via AJAX
public static function ajax_load($url, $id = 'wsf-settings-content') {
// Build action product IDs
$action_license_item_id_array = array();
foreach(get_declared_classes() as $class){
if(strpos($class, 'WS_Form_Action_') === false) { continue; }
if(!is_subclass_of($class, 'WS_Form_Action')) { continue; }
$action = New $class();
if(method_exists($action, 'get_license_item_id')) {
$action_license_item_id_array[] = $action->get_license_item_id();
}
}
$action_license_item_ids = implode(',', $action_license_item_id_array);
$url_variables = array(
'locale' => rawurlencode(get_locale()),
'locale_user' => rawurlencode(get_user_locale()),
'version' => rawurlencode(WS_FORM_VERSION),
'action_license_item_ids' => rawurlencode($action_license_item_ids)
);
$url = self::mask_parse($url, $url_variables);
$error_message = sprintf(
'<a href="%s" target="_blank">%s</a>',
esc_url( self::get_plugin_website_url( '', 'settings' ) ),
sprintf(
/* translators: %s: WS Form */
esc_html__( 'Click here to learn more about %s', 'ws-form' ),
esc_html( WS_FORM_NAME_GENERIC )
)
);
printf(
'<div id="wsf-settings-content"><script>(function($) {\'use strict\';$(\'#%1$s\').load(\'%2$s\', function(response, status, xhr) { if(status == \'error\') { $(\'#%1$s\').html(\'%3$s\'); }});})(jQuery);</script></div>',
esc_js( $id ),
esc_js( $url ),
esc_js( $error_message )
);
}
// Get root post
public static function get_post_root() {
// Load post (This uses the post ID set before any of the page renders)
$post = (isset($GLOBALS) && isset($GLOBALS['ws_form_post_root'])) ? $GLOBALS['ws_form_post_root'] : null;
// Load post by query string (Used by actions when a form is submitted)
if(is_null($post)) {
$post_id = absint(self::get_query_var('wsf_post_id', 0));
if($post_id == 0) { $post_id = absint(self::get_query_var('post_id', 0)); }
$post = ($post_id > 0) ? get_post($post_id) : null;
$GLOBALS['ws_form_post_root'] = $post;
}
return $post;
}
// Get user
public static function get_user() {
// Load user
$user = (isset($GLOBALS) && isset($GLOBALS['ws_form_user'])) ? $GLOBALS['ws_form_user'] : false;
// Load user by current_user
if(
($user === false) &&
function_exists('wp_get_current_user')
) {
$user = wp_get_current_user();
}
return $user;
}
// Get editable user roles
public function get_editable_roles() {
global $wp_roles;
$all_roles = $wp_roles->roles;
// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- This is a WordPress filter hook
$editable_roles = apply_filters('editable_roles', $all_roles);
return $editable_roles;
}
// Is block editor on page?
public static function is_block_editor() {
// Check for query variable
if(!empty(self::get_query_var('wsf_block_editor'))) { return true; }
// Check by current screen
if(!function_exists('get_current_screen')) { return false; }
if(!is_object(get_current_screen())) { return false; }
if(!method_exists(get_current_screen(), 'is_block_editor')) { return false; }
return get_current_screen()->is_block_editor();
}
// Is this a REST request
public static function is_rest_request() {
return (defined('REST_REQUEST') && REST_REQUEST);
}
// Is this customize preview?
public static function is_customize_preview() {
return (self::get_query_var('customize_theme') != '');
}
// Is input true?
public static function is_true($input) {
// Check for boolean
if(is_bool($input)) {
return $input;
}
// Check for object
if(is_object($input)) {
$input = (array) $input;
}
// Check for array
if(is_array($input)) {
$input = isset($input[0]) ? $input[0] : '';
}
// Check for numeric
if(is_numeric($input)) {
$input = strval($input);
}
// Check for string
if(!is_string($input)) {
return false;
}
// True values
$true_array = array('1', 'on', 'yes', 'true');
// Trim and lowercase input
$input = trim(strtolower($input));
// Return if true
return in_array($input, $true_array);
}
// Convert any value to an array
public static function to_array($value) {
// If already an array, just return it
if (is_array($value)) {
return $value;
}
// If null, return an empty array
if (is_null($value)) {
return [];
}
// If object, cast to array
if (is_object($value)) {
return (array) $value;
}
// For scalar values (string, int, float, bool, resource), wrap in array
return [$value];
}
// Convert any value to an object
public static function to_object($value) {
// If already an object, return as-is
if (is_object($value)) {
return $value;
}
// If array, cast to object
if (is_array($value)) {
return (object) $value;
}
// If null, return an empty object
if (is_null($value)) {
return new stdClass();
}
// For scalar values (string, int, float, bool, resource), wrap in object
$obj = new stdClass();
$obj->scalar = $value;
return $obj;
}
// do_shortcode
public static function do_shortcode($input) {
// Get shortcode regex
$shortcode_regex = get_shortcode_regex();
// If there are shortcodes in the input
if(
preg_match_all('/'. $shortcode_regex .'/s', $input, $matches) &&
array_key_exists(2, $matches) &&
!in_array(WS_FORM_SHORTCODE, $matches[2])
) {
// Run do_shortcode
$input = do_shortcode($input);
}
return $input;
}
// Convert a CSV file to a meta value containing a new data grid
public static function csv_file_to_data_grid_meta_value($file, $meta_key, $meta_value) {
// Ensure meta value is an object
$meta_value = json_decode(wp_json_encode($meta_value));
// Read file data
$file_name = sanitize_file_name($file['name']);
$file_type = sanitize_mime_type($file['type']);
$file_tmp_name = wp_normalize_path($file['tmp_name']);
$file_error = absint($file['error']);
$file_size = absint($file['size']);
$file_string = isset($file['string']) ? $file['string'] : WS_Form_File::file_get_contents($file_tmp_name);
// Error
if($file_error !== 0) { self::throw_error(esc_html__('File upload error', 'ws-form') . ': ' . $file_error); }
// Check file extension
$ext = strtolower(pathinfo($file_name, PATHINFO_EXTENSION));
if($ext !== 'csv') { self::throw_error(esc_html__('Unsupported file extension', 'ws-form') . ': ' . $ext); }
// Determine character encoding
$first2 = substr($file_string, 0, 2);
$first3 = substr($file_string, 0, 3);
$first4 = substr($file_string, 0, 3);
$char_encoding = false;
if($first3 == WS_FORM_UTF8_BOM) $char_encoding = 'UTF-8';
elseif($first4 == WS_FORM_UTF32_BIG_ENDIAN_BOM) $char_encoding = 'UTF-32BE';
elseif($first4 == WS_FORM_UTF32_LITTLE_ENDIAN_BOM) $char_encoding = 'UTF-32LE';
elseif($first2 == WS_FORM_UTF16_BIG_ENDIAN_BOM) $char_encoding = 'UTF-16BE';
elseif($first2 == WS_FORM_UTF16_LITTLE_ENDIAN_BOM) $char_encoding = 'UTF-16LE';
// Convert string
if($char_encoding) {
$file_string = mb_convert_encoding($file_string, 'UTF-8', $char_encoding);
}
// Load CSV data as file pointer
$fp = fopen("php://temp", 'r+'); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fopen
fputs($fp, $file_string); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fputs
rewind($fp); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_rewind
// Read header
$columns = fgetcsv($fp); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fgetcsv -- Stream wrapper not supported by WP_Filesystem
if($columns === false) { self::throw_error(esc_html__('Unable to read header row of file', 'ws-form')); }
if(is_null($columns)) { self::throw_error(esc_html__('Unable to read header row of file', 'ws-form')); }
if(count($columns) == 0) { self::throw_error(esc_html__('No columns to process', 'ws-form')); }
// Set group_index to 0 (Select first tab)
$meta_value->group_index = 0;
// Build columns
$columns_new = array();
$column_key_id = -1;
$column_key_wsf_id = -1;
$column_key_wsf_default = -1;
$column_key_wsf_required = -1;
$column_key_wsf_disabled = -1;
$column_key_wsf_hidden = -1;
$column_key_wsf_group = -1;
$column_index = 0;
foreach($columns as $key => $column) {
switch(strtolower($column)) {
case 'wsf_id' :
$column_key_wsf_id = $key;
break;
case 'wsf_default' :
$column_key_wsf_default = $key;
break;
case 'wsf_required' :
$column_key_wsf_required = $key;
break;
case 'wsf_disabled' :
$column_key_wsf_disabled = $key;
break;
case 'wsf_hidden' :
$column_key_wsf_hidden = $key;
break;
case 'wsf_group' :
$column_key_wsf_group = $key;
break;
case 'id' :
$column_key_id = $key;
default:
$columns_new[] = (object) array(
'id' => $column_index,
'label' => $column
);
$column_index++;
}
}
$meta_value->columns = $columns_new;
// Get default group configuration
$meta_keys = WS_Form_Config::get_meta_keys(0, false);
if(!isset($meta_keys[$meta_key])) { self::throw_error(esc_html__('Unknown meta key', 'ws-form') + ': ' + $meta_key); }
if(!isset($meta_keys[$meta_key]['default'])) { self::throw_error(esc_html__('Default not found', 'ws-form') + ': ' + $meta_key); }
if(!isset($meta_keys[$meta_key]['default']['groups'])) { self::throw_error(esc_html__('Groups not found', 'ws-form') + ': ' + $meta_key); }
if(!isset($meta_keys[$meta_key]['default']['groups'][0])) { self::throw_error(esc_html__('Group[0] not found', 'ws-form') + ': ' + $meta_key); }
$group = json_decode(wp_json_encode($meta_keys[$meta_key]['default']['groups'][0]));
$use_wsf_group = ($column_key_wsf_group !== -1);
$grouped_row_map = array();
$group_order = array();
// Re-process array to match required format for data grid
$id_array = array();
$key = 0;
$array = array();
while($row = fgetcsv($fp)) { // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fgetcsv -- Stream wrapper not supported by WP_Filesystem
if(($row === false) || is_null($row)) { continue; }
// UTF-8 encode the row
$row_id = -1;
$id = null;
$column_index = 0;
$data = array();
$default = '';
$required = '';
$disabled = '';
$hidden = '';
$row_group_label = '';
foreach($row as $column_key => $field) {
if(($row === false) || is_null($field)) { continue 2; }
$field_lower = strtolower($field);
switch($column_key) {
case $column_key_wsf_id:
$row_id = is_numeric($field_lower) ? absint($field_lower) : -1;
if($row_id > 0) { $id = $row_id; }
break;
case $column_key_wsf_default:
$default = ($field_lower != '') ? 'on' : '';
break;
case $column_key_wsf_required :
$required = ($field_lower != '') ? 'on' : '';
break;
case $column_key_wsf_disabled :
$disabled = ($field_lower != '') ? 'on' : '';
break;
case $column_key_wsf_hidden :
$hidden = ($field_lower != '') ? 'on' : '';
break;
case $column_key_wsf_group :
$row_group_label = $field;
break;
case $column_key_id :
$row_id = is_numeric($field_lower) ? absint($field_lower) : -1;
if($row_id > 0) { $id = $row_id; }
default :
$data[$column_index] = $field;
$column_index++;
}
}
// Check for duplicate row IDs (Attempt to fix import data errors)
if($row_id > 0) {
if(in_array($row_id, $id_array, true)) {
$row_id = -1;
}
}
// ID row not found
if($row_id == -1) {
$max_id = 0;
foreach($id_array as $id) {
if($id > $max_id) { $max_id = $id; }
}
$id = $max_id + 1;
}
// Build row
$row_new = (object) array(
'id' => $id,
'data' => $data
);
// Add ID to ID array
$id_array[] = $id;
if($default == 'on') { $row_new->default = 'on'; }
if($disabled == 'on') { $row_new->disabled = 'on'; }
if($required == 'on') { $row_new->required = 'on'; }
if($hidden == 'on') { $row_new->hidden = 'on'; }
if($use_wsf_group) {
$bucket_label = trim($row_group_label);
if($bucket_label === '') {
$bucket_label = __('Default', 'ws-form');
}
if(!isset($grouped_row_map[ $bucket_label ])) {
$grouped_row_map[ $bucket_label ] = array();
$group_order[] = $bucket_label;
}
$grouped_row_map[ $bucket_label ][] = $row_new;
} else {
$array[ $key ] = $row_new;
}
$key++;
}
// Build group label (single-group import and header-only wsf_group import)
if(isset($file['group_label'])) {
$group_label = $file['group_label'];
} else {
$group_label = strtolower($file_name);
$group_label = str_replace('_', ' ', $group_label);
$group_label = str_replace('-', ' ', $group_label);
$group_label = str_replace('.csv', '', $group_label);
$group_label = ucwords($group_label);
}
if($use_wsf_group) {
if(count($group_order) === 0) {
$group_new = json_decode(wp_json_encode($meta_keys[ $meta_key ]['default']['groups'][0]));
$group_new->label = $group_label;
$group_new->page = 0;
$group_new->rows = array();
$meta_value->groups = array($group_new);
} else {
$meta_value->groups = array();
foreach($group_order as $bucket_label) {
$group_new = json_decode(wp_json_encode($meta_keys[ $meta_key ]['default']['groups'][0]));
$group_new->label = $bucket_label;
$group_new->page = 0;
$group_new->rows = $grouped_row_map[ $bucket_label ];
$meta_value->groups[] = $group_new;
}
}
$meta_value->group_index = 0;
} else {
// Build group
$group->label = $group_label;
$group->page = 0;
$group->rows = $array;
// Add to meta value
$meta_value->groups = array($group);
$meta_value->group_index = 0;
}
return $meta_value;
}
// Get key value array (Used by third party visual builders)
public static function get_forms_array($placeholder = true) {
// Build form list
$ws_form_form = new WS_Form_Form();
$forms = $ws_form_form->db_read_all('', "NOT (status = 'trash')", 'label ASC, id ASC', '', '', false, true);
$form_array = $placeholder ? array('' => __('Select form...', 'ws-form')) : array();
if($forms) {
foreach($forms as $form) {
$form_array[$form['id']] = sprintf(
'%s (%s: %u)',
esc_html($form['label']),
esc_html__('ID', 'ws-form'),
$form['id']
);
}
}
return $form_array;
}
// Sanitize keyword
public static function sanitize_keyword($keyword) {
// Keyword should be a string
if(!is_string($keyword)) { return ''; }
// Ensure keyword is lowercase for the purpose of searching
$keyword = function_exists('mb_strtolower') ? mb_strtolower(trim($keyword), 'UTF-8') : strtolower(trim($keyword));
// Sanitize
return sanitize_text_field($keyword);
}
// Sanitize keyword array
public static function sanitize_keyword_array($keywords) {
// Check keywords
if(!is_array($keywords)) { return array(); }
// Sanitize keywords
$keywords_sanitized = array();
foreach($keywords as $keyword) {
$keyword = self::sanitize_keyword($keyword);
if(!empty($keyword)) { $keywords_sanitized[] = $keyword; }
}
return $keywords_sanitized;
}
// Sanitize IP addresses (supports CIDR notation)
public static function sanitize_ip_address($ip, $cidr_allowed = false) {
// IP address should be a string
if(!is_string($ip)) { return ''; }
// Normalize
$ip = strtolower(trim($ip));
// Check if it's a CIDR range
if($cidr_allowed && strpos($ip, '/') !== false) {
list($ip_part, $mask) = explode('/', $ip, 2);
// Validate IP part
if(!filter_var($ip_part, FILTER_VALIDATE_IP)) {
return '';
}
// Validate mask
$mask = (int)$mask;
// IPv4: 0-32, IPv6: 0-128
$is_ipv6 = filter_var($ip_part, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6);
$max_mask = $is_ipv6 ? 128 : 32;
if($mask < 0 || $mask > $max_mask) {
return '';
}
return $ip_part . '/' . $mask;
}
// Validate regular IP
return filter_var($ip, FILTER_VALIDATE_IP) ? $ip : '';
}
// Sanitize IP address array
public static function sanitize_ip_address_array($ips, $cidr_allowed = false) {
// Check ips
if(!is_array($ips)) { return array(); }
// Sanitize IPs
$ips_sanitized = array();
foreach($ips as $ip) {
$ip = self::sanitize_ip_address($ip, $cidr_allowed);
if(!empty($ip)) { $ips_sanitized[] = $ip; }
}
return $ips_sanitized;
}
// Sanitize phone numbers
public static function sanitize_tel($tel) {
// Check for malicious patterns
$patterns = [
'/javascript:/i',
'/data:/i',
'/<script.*?>.*?<\/script>/i',
'/<.*?>/i',
'/(onerror|onload)=/i',
'/(SELECT|INSERT|DELETE|UPDATE|DROP|UNION)/i',
'/[\|\;\&\`]/',
'/[\x00-\x1F\x7F]/',
];
foreach ($patterns as $pattern) {
if (preg_match($pattern, $tel)) {
return '';
}
}
// Strip characters
$tel = preg_replace('/[^0-9+\-\(\)\. \/\,\;xext\*\# ]/i', '', $tel);
// Trim
return rtrim($tel, ',; ');
}
// Sanitize CSS value
public static function sanitize_css_value($css_value, $pattern_match = false) {
if($css_value == '') { return ''; }
// Strip tags
$css_value = wp_strip_all_tags($css_value);
// Strip invalid UTF-8
$css_value = wp_check_invalid_utf8($css_value, true);
// Remove semi-colons
$css_value = str_replace(';', '', $css_value);
// Close open brackets
$css_value = self::close_open_brackets($css_value);
// Trim any whitespace from the value
$css_value = trim($css_value);
return $css_value;
}
// Close open brackets
public static function close_open_brackets($input) {
if(empty($input)) { return $input; }
// Count the number of open and close parentheses
$open_count = substr_count($input, '(');
$close_count = substr_count($input, ')');
// Determine how many closing parentheses are needed
$missing_closing = $open_count - $close_count;
// If there are missing closing parentheses, append them
if ($missing_closing > 0) {
$input .= str_repeat(')', $missing_closing);
}
return $input;
}
// Escape CSS output
public static function esc_css($css_value) {
// Strip tags
$css_value = wp_strip_all_tags($css_value);
// Strip invalid UTF-8
$css_value = wp_check_invalid_utf8($css_value, true);
return $css_value;
}
// Allowed HTML tags/attributes for inline SVG (used by esc_svg() and echo_html() with SVG fragments).
public static function get_allowed_html_svg() {
return array(
'svg' => array(
'id' => true,
'class' => true,
'aria-hidden' => true,
'aria-label' => true,
'aria-labelledby' => true,
'role' => true,
'xmlns' => true,
'width' => true,
'height' => true,
'viewbox' => true,
'viewBox' => true,
'fill' => true,
'stroke' => true,
),
'defs' => array(),
'style' => array(
'type' => true,
),
'linearGradient' => array(
'id' => true,
'x1' => true,
'y1' => true,
'x2' => true,
'y2' => true,
),
'stop' => array(
'offset' => true,
'style' => true,
'stop-color' => true,
'stop-opacity' => true,
),
'g' => array(
'fill' => true,
'stroke' => true,
'transform' => true,
),
'text' => array(
'dominant-baseline' => true,
'fill' => true,
'class' => true,
'font-family' => true,
'font-size' => true,
'font-weight' => true,
'line-spacing' => true,
'text-anchor' => true,
'transform' => true,
'x' => true,
'y' => true,
),
'tspan' => array(
'x' => true,
'y' => true,
'fill' => true,
'class' => true,
'text-anchor' => true,
'font-size' => true,
),
'path' => array(
'd' => true,
'fill' => true,
'stroke' => true,
'stroke-width' => true,
'stroke-linecap' => true,
'stroke-linejoin' => true,
'transform' => true,
'title' => true,
),
'circle' => array(
'cx' => true,
'cy' => true,
'r' => true,
'fill' => true,
'stroke' => true,
'stroke-width' => true,
'title' => true,
),
'rect' => array(
'x' => true,
'y' => true,
'width' => true,
'height' => true,
'fill' => true,
'stroke' => true,
'stroke-width' => true,
'stroke-dasharray' => true,
'rx' => true,
'ry' => true,
),
'line' => array(
'x1' => true,
'y1' => true,
'x2' => true,
'y2' => true,
'stroke' => true,
'stroke-width' => true,
),
'polygon' => array(
'points' => true,
'fill' => true,
'stroke' => true,
'stroke-width' => true,
),
'polyline' => array(
'points' => true,
'fill' => true,
'stroke' => true,
'stroke-width' => true,
),
);
}
/**
* wp_kses rules for settings copy-inline row: post content tags plus SVG plus clipboard UI attributes.
*/
public static function get_allowed_html_settings_copy_inline() {
$allowed = array_merge(wp_kses_allowed_html('post'), self::get_allowed_html_svg());
foreach (array('code', 'button') as $tag) {
$base = (isset($allowed[ $tag ]) && is_array($allowed[ $tag ])) ? $allowed[ $tag ] : array();
$merge = array(
'tabindex' => true,
'role' => true,
'data-action' => true,
'data-copy-text' => true,
'class' => true,
);
if ('button' === $tag) {
$merge['title'] = true;
$merge['aria-label'] = true;
$merge['type'] = true;
}
$allowed[ $tag ] = array_merge($base, $merge);
}
$span_base = (isset($allowed['span']) && is_array($allowed['span'])) ? $allowed['span'] : array();
$allowed['span'] = array_merge($span_base, array(
'aria-hidden' => true,
'class' => true,
));
return $allowed;
}
// Escape SVG output
public static function esc_svg($svg) {
return wp_kses($svg, self::get_allowed_html_svg());
}
// Echo escaped SVG content
public static function echo_esc_svg($svg) {
if(empty($svg)) { return ''; }
echo self::esc_svg($svg); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- SVG escaped
}
// Escape array of attributes
public static function esc_attributes( $attributes ) {
if ( ! is_array( $attributes ) ) {
return '';
}
$output = '';
foreach ( $attributes as $key => $value ) {
if ( $value === '' || $value === null || $value === false ) {
// Boolean attribute - output only the key
$output .= ' ' . esc_attr( $key );
} else {
// Key-value attribute
$output .= ' ' . esc_attr( $key ) . '="' . esc_attr( $value ) . '"';
}
}
return $output;
}
// Output settings attributes
public static function echo_esc_attributes( $attributes ) {
echo self::esc_attributes($attributes); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Attributes escaped
}
// Echo a string escaped using esc_html without a language domain
// This is used to echo and escape HTML that should not be translated
public static function echo_esc_html($text) {
echo esc_html($text);
}
// Echo a string containing HTML and use wp_kses_post to ensure it only contains allowed HTML
public static function echo_html($html, $allowed_html = false) {
echo ($allowed_html !== false) ? wp_kses($html, $allowed_html) : wp_kses_post($html);
}
// Echo a string escaped using esc_attr without a language domain
// This is used to echo and escape attributes that should not be translated
public static function echo_esc_attr($text) {
echo esc_attr($text);
}
// Echo a string escaped using esc_url
public static function echo_esc_url($url) {
echo esc_url($url);
}
// Echo data using wp_json_encode
public static function echo_wp_json_encode($data) {
echo wp_json_encode($data);
}
// Echo escaped CSS output
public static function echo_esc_css($css) {
if(empty($css)) { return ''; }
echo self::esc_css($css); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- CSS escaped
}
// Echo escaped CSS output inline
public static function echo_esc_css_inline($css) {
if(empty($css)) { return ''; }
echo '<style>' . self::esc_css($css) . '</style>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- CSS escaped
}
// Echo urlencode
public static function echo_urlencode($url) {
echo urlencode($url);
}
// Echo admin icon
public static function echo_get_admin_icon($color = '#a0a5aa', $base64 = true) {
self::echo_esc_svg(self::get_admin_icon($color, $base64));
}
// Echo logo
public static function echo_logo() {
self::echo_esc_svg(WS_Form_Config::get_logo_svg());
}
// Echo JSON
// This function is only used when we know it is pure JSON output encoded using wp_json_encode()
public static function echo_json( $json ) {
// If not a string, assume it needs encoding
if ( ! is_string( $json ) ) {
echo wp_json_encode( $json );
return;
}
// Validate that the string is valid JSON
json_decode( $json );
if ( json_last_error() !== JSON_ERROR_NONE ) {
// Not valid JSON, try to encode it
echo wp_json_encode( $json );
return;
}
echo $json; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- JSON encoded with wp_json_encode() and validated
}
// Return escape inline tooltip attributes string
public static function esc_attr_tooltip($title, $position = 'bottom-center') {
return self::esc_attributes(self::get_tooltips_attributes($title, $position));
}
// Echo escape inline tooltip attributes string
public static function echo_esc_attr_tooltip($title, $position = 'bottom-center') {
self::echo_esc_attributes(self::get_tooltips_attributes($title, $position));
}
// Get tooltips attributes
public static function get_tooltips_attributes($title, $position = 'bottom-center') {
$helper_icon_tooltip = self::option_get('helper_icon_tooltip', true);
$attributes = array(
'title' => $title
);
if($helper_icon_tooltip) {
$attributes['data-wsf-tooltip'] = $position;
}
return $attributes;
}
// Check form ID
public static function check_form_id($form_id) {
if(
(absint($form_id) === 0)
) {
self::throw_error(esc_html__('Invalid form ID (WS_Form_Common | check_form_id)', 'ws-form'));
}
return true;
}
// Check submit hash
public static function check_submit_hash($hash) {
if(
($hash == '') ||
!preg_match('/^[a-f0-9]{32}$/i', $hash)
) {
return false;
}
return true;
}
// Set cookie
// $cookie_expiry: false = session cookie (no expiry set), true = use the WS Form cookie timeout option,
// integer = expiry in seconds from now (0 = expire immediately, negative = expire in the past / reset)
public static function cookie_set($cookie_name, $cookie_value = '', $cookie_expiry = true, $form_id = false, $cookie_prefix_bypass = false) {
// Cookie name
if($cookie_prefix_bypass === false) {
$cookie_prefix = self::option_get('cookie_prefix', '');
if($cookie_prefix == '') { return false; }
} else {
$cookie_prefix = '';
}
if($cookie_prefix != '') { $cookie_prefix = $cookie_prefix . '_'; }
// Build cookie name
$cookie_name = sprintf('%s%s%s', $cookie_prefix, (($form_id !== false) ? sprintf('%u_', $form_id) : ''), $cookie_name);
// Cookie expires (in seconds from now)
$set_expires = true;
if($cookie_value != '') {
if($cookie_expiry === false) {
// Session cookie - do not set an expiry
$set_expires = false;
} elseif($cookie_expiry === true) {
// Use the WS Form cookie timeout option
$cookie_timeout = absint(self::option_get('cookie_timeout', 60 * 60 * 24 * 28));
} else {
// Explicit expiry in seconds (0 = expire immediately, negative = expire in the past)
$cookie_timeout = intval($cookie_expiry);
}
// Filter cookie expiry (in seconds)
if($set_expires) {
// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- All hooks prefixed with wsf_
$cookie_timeout = intval(apply_filters('wsf_cookie_expiry', $cookie_timeout, $cookie_name, $cookie_value, $form_id));
}
} else {
// Empty value always deletes the cookie (expiry set in the past)
$cookie_existing_value = self::cookie_get_raw($cookie_name);
if($cookie_existing_value == '') { return false; }
$cookie_timeout = (86400 * -1000);
}
if($set_expires) {
$cookie_timeout_date = new DateTime();
$cookie_timeout_date->setTimestamp(time() + $cookie_timeout);
$cookie_timeout_date->setTimezone(new DateTimeZone('GMT'));
$cookie_expires = sprintf(' expires=%s;', $cookie_timeout_date->format('D, d M Y H:i:s e'));
} else {
$cookie_expires = '';
}
// Set cookie
header(sprintf('Set-Cookie: %s=%s;%s path=/; SameSite=Strict; Secure', $cookie_name, $cookie_value, $cookie_expires));
return true;
}
// Get cookie raw
// Calling function must sanitize
public static function cookie_get_raw($cookie_name, $default_value = '') {
// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Calling function sanitizes
return (($cookie_name === '') || !isset($_COOKIE) || !isset($_COOKIE[$cookie_name])) ? $default_value : wp_unslash($_COOKIE[$cookie_name]);
}
// Get object from POST $_FILE
public static function get_object_from_post_file($object_type = false) {
// Run through files
// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitizedDetected, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.NonceVerification.Missing -- Sanitized below
$file = (isset($_FILES) && isset($_FILES['file'])) ? $_FILES['file'] : false;
if($file === false) { self::throw_error(esc_html__('No files found', 'ws-form')); }
// Read file data
$file_name = sanitize_file_name($file['name']);
$file_type = sanitize_mime_type($file['type']);
$file_tmp_name = wp_normalize_path($file['tmp_name']);
$file_error = absint($file['error']);
$file_size = absint($file['size']);
// Error checking
if($file_error != 0) { self::throw_error(esc_html__('File upload error', 'ws-form') . ': ' . $file_error); }
if($file_size == 0) { self::throw_error(esc_html__('File empty', 'ws-form')); }
// Check file extension
$ext = strtolower(pathinfo($file_name, PATHINFO_EXTENSION));
if($ext !== 'json') { self::throw_error(sprintf(
/* translators: %s: Extension */
esc_html__('Unsupported file extension: %s', 'ws-form'),
$ext
)); }
// Check file format
if(!WS_Form_File::file_exists($file_tmp_name)) { self::throw_error(esc_html__('Unable to read uploaded file', 'ws-form')); }
$json = WS_Form_File::file_get_contents($file_tmp_name);
// Get form object from JSON
$object = self::get_object_from_json($json, true, $object_type);
return $object;
}
// Get object from JSON and check JSON is valid
public static function get_object_from_json($json, $checksum_check = false, $object_type = false) {
// Remove BOM if present
if(substr($json, 0,3) == pack('CCC', 0xef, 0xbb, 0xbf)) {
$json = substr($json, 3);
}
// Check form JSON format
$object = json_decode($json);
if(is_null($object)) {
self::throw_error(sprintf(
/* translators: %s: json_decode last error message */
esc_html__('JSON corrupt (%s)', 'ws-form'),
json_last_error_msg()
));
}
if(!is_object($object)) { self::throw_error(esc_html__('JSON corrupt (Not object)', 'ws-form')); }
// Checksum test
if(
$checksum_check &&
!self::object_checksum_check($object)
) {
self::throw_error(esc_html__('JSON corrupt (Checksum error)', 'ws-form'));
}
// Check identifier
if(
!isset($object->identifier) ||
($object->identifier !== WS_FORM_IDENTIFIER)
) {
self::throw_error(sprintf(
/* translators: %s: WS Form */
esc_html__('JSON corrupt (Not a %s JSON file)', 'ws-form'),
WS_FORM_NAME_GENERIC
));
}
// Check type
if(
($object_type !== false) &&
!empty($object->meta->export_object) &&
($object_type != $object->meta->export_object)
) {
self::throw_error(esc_html__('Import error (Invalid import type)', 'ws-form'));
}
// Check label
if(!isset($object->label)) { self::throw_error(esc_html__('JSON corrupt (No label)', 'ws-form')); }
// Check meta
if(!isset($object->meta)) { self::throw_error(esc_html__('JSON corrupt (No meta data)', 'ws-form')); }
return $object;
}
// Form object checksum check
public static function object_checksum_check($object) {
// Should checksum be checked?
// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- All hooks prefixed with wsf_
if(!apply_filters('wsf_form_checksum_check', true)) {
return true;
}
// Check integrity of object
if(
!is_object($object) ||
!property_exists($object, 'checksum')
) {
return false;
}
// Get checksum
$checksum = $object->checksum;
// Build checksum
$object_checksum_check = clone $object;
unset($object_checksum_check->checksum);
$checksum_file = md5(wp_json_encode($object_checksum_check));
// Release memory
$object_checksum_check = null;
// Check checksum
return ($checksum == $checksum_file);
}
// Get meta value array
public static function get_meta_value_array($field_id, $fields, $field_types) {
$meta_value_array = array();
// Get field
$field = $fields[$field_id];
// Get field type config
$field_type = $field->type;
if(!isset($field_types[$field_type])) { return array(); }
$field_type_config = $field_types[$field_type];
// If has data grid data source
if(
isset($field_type_config['datagrid_column_value']) &&
isset($field_type_config['data_source']) &&
($field_type_config['data_source']['type'] == 'data_grid')
) {
// Get data source
$data_source_id = $field_type_config['data_source']['id'];
$data_source = self::get_object_meta_value($field, $data_source_id, 0);
// Get columns
if(!isset($data_source->columns)) { return array(); }
$columns = $data_source->columns;
// Get data grid column ID
$datagrid_column_value = $field_type_config['datagrid_column_value'];
$datagrid_column_id = self::get_object_meta_value($field, $datagrid_column_value, 0);
// Get data grid column index
$data_grid_column_index = false;
foreach($columns as $column_index => $column) {
if($column->id == $datagrid_column_id) {
$data_grid_column_index = $column_index;
break;
}
}
if($data_grid_column_index === false) { return array(); }
// Get data
if(
isset($data_source->groups) &&
isset($data_source->groups[0]) &&
isset($data_source->groups[0]->rows)
) {
foreach($data_source->groups[0]->rows as $row) {
if(
isset($row->data) &&
isset($row->data[$data_grid_column_index])
) {
$meta_value_array[] = $row->data[$data_grid_column_index];
}
}
}
}
return $meta_value_array;
}
// Inject array at index
public static function array_inject_element($array_old, $element, $index) {
$array_new = array_slice($array_old, 0, $index, true);
$array_new[] = $element;
$array_new = array_merge($array_new, array_slice($array_old, $index, NULL, true));
return $array_new;
}
// Add dot notation value
public static function set_path_value(&$data, $path, $value, $dedupe = true, $repeatable = false, $repeatable_index = 0) {
// Pre-process path
$path_processed = trim($path);
$path_processed = str_replace('[', '.[', $path_processed);
$path_processed = str_replace(']', '].', $path_processed);
// Split path by dot
$path_array = array_filter(explode('.', $path_processed));
$path_array_index_max = (count($path_array) - 1);
foreach($path_array as $path_array_index => $node) {
// Remove square brackets (arrays)
$node = str_replace('[', '', $node);
$node = str_replace(']', '', $node);
// If this node already has a value set on it, reset it
if(
isset($data[$node]) &&
!is_array($data[$node]) &&
($path_array_index < $path_array_index_max)
) {
throw new Exception(sprintf(
/* translators: %s: Node path */
esc_html__('Node %s not valid or duplicate node.', 'ws-form'),
esc_html($path)
));
}
if(
$repeatable &&
($path_array_index == $path_array_index_max)
) {
$data = &$data[$repeatable_index];
$data = &$data[$node];
} else {
$data = &$data[$node];
}
}
// Create array if value already exists
if(!is_null($data)) {
// Turn it into an array to handle multiple values
if(!is_array($data)) {
$data = array($data);
}
// Set node
$data[] = $value;
// Make it unique
if($dedupe) {
$data = array_unique($data);
}
} else {
$data = $value;
}
return $data;
}
// Get dot notation value
public static function get_path_value($data, $path) {
// Pre-process path
$path_processed = trim($path);
$path_processed = str_replace('[', '.[', $path_processed);
$path_processed = str_replace(']', '].', $path_processed);
// Split path by dot
$path_array = array_filter(explode('.', $path_processed));
foreach($path_array as $node) {
// Remove square brackets (arrays)
$node = str_replace('[', '', $node);
$node = str_replace(']', '', $node);
if(is_numeric($node)) {
if(isset($data[$node])) {
$data = $data[$node];
} else {
throw new Exception(sprintf(
/* translators: %s: Node path */
esc_html__('Node %s not found in response data.', 'ws-form'),
esc_html($path)
));
}
} else {
if(property_exists($data, $node)) {
$data = $data->$node;
} else {
throw new Exception(sprintf(
/* translators: %s: Node path */
esc_html__('Node %s not found in response data.', 'ws-form'),
esc_html($path)
));
}
}
}
return $data;
}
// Get uploads base directory and ensure paths are https (Known bug with wp_upload_dir)
public static function get_upload_dir_base_url() {
$upload_dir_base_url = wp_upload_dir()['baseurl'];
if(is_ssl()) {
$upload_dir_base_url = str_replace('http://', 'https://', $upload_dir_base_url);
}
return $upload_dir_base_url;
}
// Get attachment img (Used by email action to avoid any third party filters breaking the return of wp_get_attachment_image, e.g. Avada image lazy load)
public static function get_attachment_img_html($attachment_id, $image_size = 'thumbnail') {
// Get email logo attachment data
$attachment_image_src = wp_get_attachment_image_src($attachment_id, $image_size);
if($attachment_image_src !== false) {
// Try to get alt text for attachment
$email_logo_alt = get_post_meta($attachment_id, '_wp_attachment_image_alt', true);
// Return email logo
return sprintf(
'<img src="%s" width="%u" height="%u"%s />',
esc_attr($attachment_image_src[0]),
esc_attr($attachment_image_src[1]),
esc_attr($attachment_image_src[2]),
(!empty($email_logo_alt) ? sprintf(' alt="%s"', esc_attr($email_logo_alt)) : '')
);
} else {
// Attachment not found
return '';
}
}
// Wordress version compare
public static function wp_version_at_least($ver) {
global $wp_version;
return (self::version_compare($wp_version, $ver) >= 0);
}
// Version compare
public static function version_compare($ver_a, $ver_b) {
$ver_a_parts = explode('-', $ver_a);
$ver_b_parts = explode('-', $ver_b);
$semver_a = array_shift($ver_a_parts);
$semver_b = array_shift($ver_b_parts);
$comparison = version_compare($semver_a, $semver_b);
if(0 !== $comparison) {
return $comparison;
}
$prerelease_a = array_shift($ver_a_parts);
$prerelease_b = array_shift($ver_b_parts);
$comparison = strcmp(is_string($prerelease_a) ? $prerelease_a : '', is_string($prerelease_b) ? $prerelease_b : '');
if(0 !== $comparison) {
return $comparison;
}
$rev_a = absint(array_shift($ver_a_parts));
$rev_b = absint(array_shift($ver_b_parts));
$src_a = 'src' === array_shift($ver_a_parts);
$src_b = 'src' === array_shift($ver_b_parts);
if($src_a xor $src_b) {
return 0;
}
// Compare revision numbers.
return $rev_b - $rev_a;
}
// Translate date to English for JavaScript validation
public static function field_date_translate($date_string) {
// Check date_string is a string
if(!is_string($date_string)) { return $date_string; }
// Get translations for current locale
$translations = self::field_date_translations();
if($translations === false) { return $date_string; }
// Convert date_string to lowercase
$date_string = strtolower($date_string);
// Convert HTML entities back to characters
$date_string = html_entity_decode($date_string);
// Get months in English
$months_english = array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December');
// Translate - Months - Long
if(isset($translations['m'])) {
$date_string = self::field_date_translate_replace($date_string, $translations['m'], $months_english, 12);
}
// Translate - Months - Short
if(isset($translations['n'])) {
$date_string = self::field_date_translate_replace($date_string, $translations['n'], $months_english, 12);
}
// Get days in English
$days_english = array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday');
// Translate - Days - Long
if(isset($translations['b'])) {
$date_string = self::field_date_translate_replace($date_string, $translations['b'], $days_english, 7);
}
// Translate - Days - Short
if(isset($translations['a'])) {
$date_string = self::field_date_translate_replace($date_string, $translations['a'], $days_english, 7);
}
return $date_string;
}
public static function field_date_translate_replace($date_string, $lookups, $replacements, $count) {
if(
!is_array($lookups) ||
!is_array($replacements)
) {
return $date_string;
}
$date_string_original = $date_string;
// Run through each lookup
for($index = 0; $index < $count; $index++) {
$lookup_value = $lookups[$index];
if(is_array($lookup_value)) {
// If multiple lookup values exist, process each
foreach($lookup_value as $lookup_value_single) {
$date_string = preg_replace('/\b' . strtolower($lookup_value_single) . '\b/u', $replacements[$index], $date_string);
}
} else {
// Straight string swap
$date_string = preg_replace('/\b' . strtolower($lookup_value) . '\b/u', $replacements[$index], $date_string);
}
// There should only be one replacements in a date string, so return if a change occurs
if($date_string != $date_string_original) { return $date_string; }
}
return $date_string;
}
// Get translations
public static function field_date_translations() {
// Get locale
$locale = get_user_locale();
// Get language
$language = substr($locale, 0, 2);
// Check for English
if($language == 'en') { return false; }
// Translation lookups
$translations = array(
'ar' => array( // Arabic
'm' => array('كانون الثاني','شباط','آذار','نيسان','مايو','حزيران','تموز','آب','أيلول','تشرين الأول','تشرين الثاني','كانون الأول'),
'a' => array('ن','ث','ع','خ','ج','س','ح'),
'b' => array('الأحد','الاثنين','الثلاثاء','الأربعاء','الخميس','الجمعة','السبت','الأحد')
),
'ro' => array( // Romanian
'm' => array('Ianuarie','Februarie','Martie','Aprilie','Mai','Iunie','Iulie','August','Septembrie','Octombrie','Noiembrie','Decembrie'),
'a' => array('Du','Lu','Ma','Mi','Jo','Vi','Sâ'),
'b' => array('Duminică','Luni','Marţi','Miercuri','Joi','Vineri','Sâmbătă')
),
'id' => array( // Indonesian
'm' => array('Januari','Februari','Maret','April','Mei','Juni','Juli','Agustus','September','Oktober','November','Desember'),
'a' => array('Min','Sen','Sel','Rab','Kam','Jum','Sab'),
'b' => array('Minggu','Senin','Selasa','Rabu','Kamis','Jumat','Sabtu')
),
'is' => array( // Icelandic
'm' => array('Janúar','Febrúar','Mars','Apríl','Maí','Júní','Júlí','Ágúst','September','Október','Nóvember','Desember'),
'a' => array('Sun','Mán','Þrið','Mið','Fim','Fös','Lau'),
'b' => array('Sunnudagur','Mánudagur','Þriðjudagur','Miðvikudagur','Fimmtudagur','Föstudagur','Laugardagur')
),
'bg' => array( // Bulgarian
'm' => array('Януари','Февруари','Март','Април','Май','Юни','Юли','Август','Септември','Октомври','Ноември','Декември'),
'a' => array('Нд','Пн','Вт','Ср','Чт','Пт','Сб'),
'b' => array('Неделя','Понеделник','Вторник','Сряда','Четвъртък','Петък','Събота')
),
'fa' => array( // Persian/Farsi
'm' => array('فروردین','اردیبهشت','خرداد','تیر','مرداد','شهریور','مهر','آبان','آذر','دی','بهمن','اسفند'),
'a' => array('یکشنبه','دوشنبه','سه شنبه','چهارشنبه','پنجشنبه','جمعه','شنبه'),
'b' => array('یکشنبه','دوشنبه','سهشنبه','چهارشنبه','پنجشنبه','جمعه','شنبه','یکشنبه')
),
'ru' => array( // Russian
'm' => array('Январь','Февраль','Март','Апрель','Май','Июнь','Июль','Август','Сентябрь','Октябрь','Ноябрь','Декабрь'),
'a' => array('Вс','Пн','Вт','Ср','Чт','Пт','Сб'),
'b' => array('Воскресенье','Понедельник','Вторник','Среда','Четверг','Пятница','Суббота')
),
'uk' => array( // Ukrainian
'm' => array('Січень','Лютий','Березень','Квітень','Травень','Червень','Липень','Серпень','Вересень','Жовтень','Листопад','Грудень'),
'a' => array('Ндл','Пнд','Втр','Срд','Чтв','Птн','Сбт'),
'b' => array('Неділя','Понеділок','Вівторок','Середа','Четвер','П\'ятниця','Субота')
),
'en' => array( // English
'm' => array('January','February','March','April','May','June','July','August','September','October','November','December'),
'a' => array('Sun','Mon','Tue','Wed','Thu','Fri','Sat'),
'b' => array('Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday')
),
'el' => array( // Ελληνικά
'm' => array('Ιανουάριος','Φεβρουάριος','Μάρτιος','Απρίλιος','Μάιος','Ιούνιος','Ιούλιος','Αύγουστος','Σεπτέμβριος','Οκτώβριος','Νοέμβριος','Δεκέμβριος'),
'a' => array('Κυρ','Δευ','Τρι','Τετ','Πεμ','Παρ','Σαβ'),
'b' => array('Κυριακή','Δευτέρα','Τρίτη','Τετάρτη','Πέμπτη','Παρασκευή','Σάββατο')
),
'de' => array( // German
'm' => array('Januar','Februar',array('März','Marz'),'April','Mai','Juni','Juli','August','September','Oktober','November','Dezember'),
'n' => array(array('Jan','Jän'),'Feb',array('März','Marz'),'Apr','Mai','Juni','Juli','Aug','Sept','Okt','Nov','Dez'),
'a' => array('So','Mo','Di','Mi','Do','Fr','Sa'),
'b' => array('Sonntag','Montag','Dienstag','Mittwoch','Donnerstag','Freitag','Samstag')
),
'nl' => array( // Dutch
'm' => array('januari','februari','maart','april','mei','juni','juli','augustus','september','oktober','november','december'),
'n' => array('jan','feb','maart','apr','mei','juni','juli','aug','sept',array('oct','okt'),'nov','dec'),
'a' => array('zo','ma','di','wo','do','vr','za'),
'b' => array('zondag','maandag','dinsdag','woensdag','donderdag','vrijdag','zaterdag')
),
'tr' => array( // Turkish
'm' => array('Ocak','Şubat','Mart','Nisan','Mayıs','Haziran','Temmuz','Ağustos','Eylül','Ekim','Kasım','Aralık'),
'a' => array('Paz','Pts','Sal','Çar','Per','Cum','Cts'),
'b' => array('Pazar','Pazartesi','Salı','Çarşamba','Perşembe','Cuma','Cumartesi')
),
'fr' => array( //French
'm' => array('Janvier','Février','Mars','Avril','Mai','Juin','Juillet',array('Août','Aout'),'Septembre','Octobre','Novembre','Décembre'),
'n' => array('janv','févr','mars','avril','mai','juin','juil',array('août','aout'),'sept','oct','nov',array('dec','déc')),
'a' => array('Dim','Lun','Mar','Mer','Jeu','Ven','Sam'),
'b' => array('dimanche','lundi','mardi','mercredi','jeudi','vendredi','samedi')
),
'es' => array( // Spanish
'm' => array('Enero','Febrero','Marzo','Abril','Mayo','Junio','Julio','Agosto','Septiembre','Octubre','Noviembre','Diciembre'),
'n' => array('enero','feb','marzo','abr','mayo','jun','jul','agosto',array('sept','set'),'oct','nov','dic'),
'a' => array('Dom','Lun','Mar','Mié','Jue','Vie','Sáb'),
'b' => array('Domingo','Lunes','Martes','Miércoles','Jueves','Viernes','Sábado')
),
'th' => array( // Thai
'm' => array('มกราคม','กุมภาพันธ์','มีนาคม','เมษายน','พฤษภาคม','มิถุนายน','กรกฎาคม','สิงหาคม','กันยายน','ตุลาคม','พฤศจิกายน','ธันวาคม'),
'a' => array('อา.','จ.','อ.','พ.','พฤ.','ศ.','ส.'),
'b' => array('อาทิตย์','จันทร์','อังคาร','พุธ','พฤหัส','ศุกร์','เสาร์','อาทิตย์')
),
'pl' => array( // Polish
'm' => array('styczeń','luty','marzec','kwiecień','maj','czerwiec','lipiec','sierpień','wrzesień','październik','listopad','grudzień'),
'n' => array('stycz','luty','mar','kwiec','maj','czerw','lip','sierp','wrzes','pazdz','listop','grudz'),
'a' => array('nd','pn','wt','śr','cz','pt','sb'),
'b' => array('niedziela','poniedziałek','wtorek','środa','czwartek','piątek','sobota')
),
'pt' => array( // Portuguese
'm' => array('Janeiro','Fevereiro','Março','Abril','Maio','Junho','Julho','Agosto','Setembro','Outubro','Novembro','Dezembro'),
'n' => array('jan','fev','março','abril','maio','junho','julho','agosto','set','out','nov','dez'),
'a' => array('Dom','Seg','Ter','Qua','Qui','Sex','Sab'),
'b' => array('Domingo','Segunda','Terça','Quarta','Quinta','Sexta','Sábado')
),
'ch' => array( // Simplified Chinese
'm' => array('一月','二月','三月','四月','五月','六月','七月','八月','九月','十月','十一月','十二月'),
'a' => array('日','一','二','三','四','五','六')
),
'se' => array( // Swedish
'm' => array('Januari','Februari','Mars','April','Maj','Juni','Juli','Augusti','September', 'Oktober','November','December'),
'n' => array('jan','febr','mars','april','maj','juni','juli','aug','sept','okt','nov','dec'),
'a' => array('Sön','Mån','Tis','Ons','Tor','Fre','Lör')
),
'km' => array( // Khmer (ភាសាខ្មែរ)
'm' => array('មករា','កុម្ភៈ','មិនា','មេសា','ឧសភា','មិថុនា','កក្កដា','សីហា','កញ្ញា','តុលា','វិច្ឆិកា','ធ្នូ'),
'a' => array('អាទិ','ច័ន្ទ','អង្គារ','ពុធ','ព្រហ','សុក្រ','សៅរ៍'),
'b' => array('អាទិត្យ','ច័ន្ទ','អង្គារ','ពុធ','ព្រហស្បតិ៍','សុក្រ','សៅរ៍')
),
'kr' => array( // Korean
'm' => array('1월','2월','3월','4월','5월','6월','7월','8월','9월','10월','11월','12월'),
'a' => array('일','월','화','수','목','금','토'),
'b' => array('일요일','월요일','화요일','수요일','목요일','금요일','토요일')
),
'it' => array( // Italian
'm' => array('Gennaio','Febbraio','Marzo','Aprile','Maggio','Giugno','Luglio','Agosto','Settembre','Ottobre','Novembre','Dicembre'),
'n' => array('genn','febbr','mar','apr','magg','giugno','luglio','ag','sett','ott','nov','dic'),
'a' => array('Dom','Lun','Mar','Mer','Gio','Ven','Sab'),
'b' => array('Domenica','Lunedì','Martedì','Mercoledì','Giovedì','Venerdì','Sabato')
),
'da' => array( // Dansk
'm' => array('Januar','Februar','Marts','April','Maj','Juni','Juli','August','September','Oktober','November','December'),
'n' => array('jan','febr','marts','april','maj','juni','juli','aug','sept','okt','nov','dec'),
'a' => array('Søn','Man','Tir','Ons','Tor','Fre','Lør'),
'b' => array('søndag','mandag','tirsdag','onsdag','torsdag','fredag','lørdag')
),
'no' => array( // Norwegian
'm' => array('Januar','Februar','Mars','April','Mai','Juni','Juli','August','September','Oktober','November','Desember'),
'n' => array('jan','febr','mars','april','mai','juni','juli','aug','sept','okt','nov','des'),
'a' => array('Søn','Man','Tir','Ons','Tor','Fre','Lør'),
'b' => array('Søndag','Mandag','Tirsdag','Onsdag','Torsdag','Fredag','Lørdag')
),
'ja' => array( // Japanese
'm' => array('1月','2月','3月','4月','5月','6月','7月','8月','9月','10月','11月','12月'),
'a' => array('日','月','火','水','木','金','土'),
'b' => array('日曜','月曜','火曜','水曜','木曜','金曜','土曜')
),
'vi' => array( // Vietnamese
'm' => array('Tháng 1','Tháng 2','Tháng 3','Tháng 4','Tháng 5','Tháng 6','Tháng 7','Tháng 8','Tháng 9','Tháng 10','Tháng 11','Tháng 12'),
'a' => array('CN','T2','T3','T4','T5','T6','T7'),
'b' => array('Chủ nhật','Thứ hai','Thứ ba','Thứ tư','Thứ năm','Thứ sáu','Thứ bảy')
),
'sl' => array( // Slovenščina
'm' => array('Januar','Februar','Marec','April','Maj','Junij','Julij','Avgust','September','Oktober','November','December'),
'a' => array('Ned','Pon','Tor','Sre','Čet','Pet','Sob'),
'b' => array('Nedelja','Ponedeljek','Torek','Sreda','Četrtek','Petek','Sobota')
),
'cs' => array( // Čeština
'm' => array('Leden','Únor','Březen','Duben','Květen','Červen','Červenec','Srpen','Září','Říjen','Listopad','Prosinec'),
'a' => array('Ne','Po','Út','St','Čt','Pá','So')
),
'hu' => array( // Hungarian
'm' => array('Január','Február','Március','Április','Május','Június','Július','Augusztus','Szeptember','Október','November','December'),
'a' => array('Va','Hé','Ke','Sze','Cs','Pé','Szo'),
'b' => array('vasárnap','hétfő','kedd','szerda','csütörtök','péntek','szombat')
),
'az' => array( //Azerbaijanian (Azeri)
'm' => array('Yanvar','Fevral','Mart','Aprel','May','Iyun','Iyul','Avqust','Sentyabr','Oktyabr','Noyabr','Dekabr'),
'a' => array('B','Be','Ça','Ç','Ca','C','Ş'),
'b' => array('Bazar','Bazar ertəsi','Çərşənbə axşamı','Çərşənbə','Cümə axşamı','Cümə','Şənbə')
),
'bs' => array( //Bosanski
'm' => array('Januar','Februar','Mart','April','Maj','Jun','Jul','Avgust','Septembar','Oktobar','Novembar','Decembar'),
'a' => array('Ned','Pon','Uto','Sri','Čet','Pet','Sub'),
'b' => array('Nedjelja','Ponedjeljak','Utorak','Srijeda','Četvrtak','Petak','Subota')
),
'ca' => array( //Català
'm' => array('Gener','Febrer','Març','Abril','Maig','Juny','Juliol','Agost','Setembre','Octubre','Novembre','Desembre'),
'a' => array('Dg','Dl','Dt','Dc','Dj','Dv','Ds'),
'b' => array('Diumenge','Dilluns','Dimarts','Dimecres','Dijous','Divendres','Dissabte')
),
'et' => array( //'Eesti'
'm' => array('Jaanuar','Veebruar','Märts','Aprill','Mai','Juuni','Juuli','August','September','Oktoober','November','Detsember'),
'a' => array('P','E','T','K','N','R','L'),
'b' => array('Pühapäev','Esmaspäev','Teisipäev','Kolmapäev','Neljapäev','Reede','Laupäev')
),
'eu' => array( //Euskara
'm' => array('Urtarrila','Otsaila','Martxoa','Apirila','Maiatza','Ekaina','Uztaila','Abuztua','Iraila','Urria','Azaroa','Abendua'),
'a' => array('Ig.','Al.','Ar.','Az.','Og.','Or.','La.'),
'b' => array('Igandea','Astelehena','Asteartea','Asteazkena','Osteguna','Ostirala','Larunbata')
),
'fi' => array( //Finnish (Suomi)
'm' => array('Tammikuu','Helmikuu','Maaliskuu','Huhtikuu','Toukokuu','Kesäkuu','Heinäkuu','Elokuu','Syyskuu','Lokakuu','Marraskuu','Joulukuu'),
'a' => array('Su','Ma','Ti','Ke','To','Pe','La'),
'b' => array('sunnuntai','maanantai','tiistai','keskiviikko','torstai','perjantai','lauantai')
),
'gl' => array( //Galego
'm' => array('Xan','Feb','Maz','Abr','Mai','Xun','Xul','Ago','Set','Out','Nov','Dec'),
'a' => array('Dom','Lun','Mar','Mer','Xov','Ven','Sab'),
'b' => array('Domingo','Luns','Martes','Mércores','Xoves','Venres','Sábado')
),
'hr' => array( //Hrvatski
'm' => array('Siječanj','Veljača','Ožujak','Travanj','Svibanj','Lipanj','Srpanj','Kolovoz','Rujan','Listopad','Studeni','Prosinac'),
'a' => array('Ned','Pon','Uto','Sri','Čet','Pet','Sub'),
'b' => array('Nedjelja','Ponedjeljak','Utorak','Srijeda','Četvrtak','Petak','Subota')
),
'ko' => array( //Korean (한국어)
'm' => array('1월','2월','3월','4월','5월','6월','7월','8월','9월','10월','11월','12월'),
'a' => array('일','월','화','수','목','금','토'),
'b' => array('일요일','월요일','화요일','수요일','목요일','금요일','토요일')
),
'lt' => array( //Lithuanian (lietuvių)
'm' => array('Sausio','Vasario','Kovo','Balandžio','Gegužės','Birželio','Liepos','Rugpjūčio','Rugsėjo','Spalio','Lapkričio','Gruodžio'),
'a' => array('Sek','Pir','Ant','Tre','Ket','Pen','Šeš'),
'b' => array('Sekmadienis','Pirmadienis','Antradienis','Trečiadienis','Ketvirtadienis','Penktadienis','Šeštadienis')
),
'lv' => array( //Latvian (Latviešu)
'm' => array('Janvāris','Februāris','Marts','Aprīlis ','Maijs','Jūnijs','Jūlijs','Augusts','Septembris','Oktobris','Novembris','Decembris'),
'a' => array('Sv','Pr','Ot','Tr','Ct','Pk','St'),
'b' => array('Svētdiena','Pirmdiena','Otrdiena','Trešdiena','Ceturtdiena','Piektdiena','Sestdiena')
),
'mk' => array( //Macedonian (Македонски)
'm' => array('јануари','февруари','март','април','мај','јуни','јули','август','септември','октомври','ноември','декември'),
'a' => array('нед','пон','вто','сре','чет','пет','саб'),
'b' => array('Недела','Понеделник','Вторник','Среда','Четврток','Петок','Сабота')
),
'mn' => array( //Mongolian (Монгол)
'm' => array('1-р сар','2-р сар','3-р сар','4-р сар','5-р сар','6-р сар','7-р сар','8-р сар','9-р сар','10-р сар','11-р сар','12-р сар'),
'a' => array('Дав','Мяг','Лха','Пүр','Бсн','Бям','Ням'),
'b' => array('Даваа','Мягмар','Лхагва','Пүрэв','Баасан','Бямба','Ням')
),
'pt_BR' => array( //Português(Brasil)
'm' => array('Janeiro','Fevereiro','Março','Abril','Maio','Junho','Julho','Agosto','Setembro','Outubro','Novembro','Dezembro'),
'a' => array('Dom','Seg','Ter','Qua','Qui','Sex','Sáb'),
'b' => array('Domingo','Segunda','Terça','Quarta','Quinta','Sexta','Sábado')
),
'sk' => array( //Slovenčina
'm' => array('Január','Február','Marec','Apríl','Máj','Jún','Júl','August','September','Október','November','December'),
'a' => array('Ne','Po','Ut','St','Št','Pi','So'),
'b' => array('Nedeľa','Pondelok','Utorok','Streda','Štvrtok','Piatok','Sobota')
),
'sq' => array( //Albanian (Shqip)
'm' => array('Janar','Shkurt','Mars','Prill','Maj','Qershor','Korrik','Gusht','Shtator','Tetor','Nëntor','Dhjetor'),
'a' => array('Die','Hën','Mar','Mër','Enj','Pre','Shtu'),
'b' => array('E Diel','E Hënë','E Martē','E Mërkurë','E Enjte','E Premte','E Shtunë')
),
'sr_YU' => array( //Serbian (Srpski)
'm' => array('Januar','Februar','Mart','April','Maj','Jun','Jul','Avgust','Septembar','Oktobar','Novembar','Decembar'),
'a' => array('Ned','Pon','Uto','Sre','čet','Pet','Sub'),
'b' => array('Nedelja','Ponedeljak','Utorak','Sreda','Četvrtak','Petak','Subota')
),
'sr' => array( //Serbian Cyrillic (Српски)
'm' => array('јануар','фебруар','март','април','мај','јун','јул','август','септембар','октобар','новембар','децембар'),
'a' => array('нед','пон','уто','сре','чет','пет','суб'),
'b' => array('Недеља','Понедељак','Уторак','Среда','Четвртак','Петак','Субота')
),
'sv' => array( //Svenska
'm' => array('Januari','Februari','Mars','April','Maj','Juni','Juli','Augusti','September','Oktober','November','December'),
'a' => array('Sön','Mån','Tis','Ons','Tor','Fre','Lör'),
'b' => array('Söndag','Måndag','Tisdag','Onsdag','Torsdag','Fredag','Lördag')
),
'zh_TW' => array( //Traditional Chinese (繁體中文)
'm' => array('一月','二月','三月','四月','五月','六月','七月','八月','九月','十月','十一月','十二月'),
'a' => array('日','一','二','三','四','五','六'),
'b' => array('星期日','星期一','星期二','星期三','星期四','星期五','星期六')
),
'zh' => array( //Simplified Chinese (简体中文)
'm' => array('一月','二月','三月','四月','五月','六月','七月','八月','九月','十月','十一月','十二月'),
'a' => array('日','一','二','三','四','五','六'),
'b' => array('星期日','星期一','星期二','星期三','星期四','星期五','星期六')
),
'ug' => array( // Uyghur(ئۇيغۇرچە)
'm' => array('1-ئاي','2-ئاي','3-ئاي','4-ئاي','5-ئاي','6-ئاي','7-ئاي','8-ئاي','9-ئاي','10-ئاي','11-ئاي','12-ئاي'),
'b' => array('يەكشەنبە','دۈشەنبە','سەيشەنبە','چارشەنبە','پەيشەنبە','جۈمە','شەنبە')
),
'he' => array( //Hebrew (עברית)
'm' => array('ינואר','פברואר','מרץ','אפריל','מאי','יוני','יולי','אוגוסט','ספטמבר','אוקטובר','נובמבר','דצמבר'),
'a' => array('א\'','ב\'','ג\'','ד\'','ה\'','ו\'','שבת'),
'b' => array('ראשון','שני','שלישי','רביעי','חמישי','שישי','שבת','ראשון')
),
'hy' => array( // Armenian
'm' => array('Հունվար','Փետրվար','Մարտ','Ապրիլ','Մայիս','Հունիս','Հուլիս','Օգոստոս','Սեպտեմբեր','Հոկտեմբեր','Նոյեմբեր','Դեկտեմբեր'),
'a' => array('Կի','Երկ','Երք','Չոր','Հնգ','Ուրբ','Շբթ'),
'b' => array('Կիրակի','Երկուշաբթի','Երեքշաբթի','Չորեքշաբթի','Հինգշաբթի','Ուրբաթ','Շաբաթ')
),
'kg' => array( // Kyrgyz
'm' => array('Үчтүн айы','Бирдин айы','Жалган Куран','Чын Куран','Бугу','Кулжа','Теке','Баш Оона','Аяк Оона','Тогуздун айы','Жетинин айы','Бештин айы'),
'a' => array('Жек','Дүй','Шей','Шар','Бей','Жум','Ише'),
'b' => array('Жекшемб','Дүйшөмб','Шейшемб','Шаршемб','Бейшемби','Жума','Ишенб')
),
'rm' => array( // Romansh
'm' => array('Schaner','Favrer','Mars','Avrigl','Matg','Zercladur','Fanadur','Avust','Settember','October','November','December'),
'a' => array('Du','Gli','Ma','Me','Gie','Ve','So'),
'b' => array('Dumengia','Glindesdi','Mardi','Mesemna','Gievgia','Venderdi','Sonda')
),
'ka' => array( // Georgian
'm' => array('იანვარი','თებერვალი','მარტი','აპრილი','მაისი','ივნისი','ივლისი','აგვისტო','სექტემბერი','ოქტომბერი','ნოემბერი','დეკემბერი'),
'a' => array('კვ','ორშ','სამშ','ოთხ','ხუთ','პარ','შაბ'),
'b' => array('კვირა','ორშაბათი','სამშაბათი','ოთხშაბათი','ხუთშაბათი','პარასკევი','შაბათი')
)
);
// Attempt to find exact locale
if(isset($translations[$locale])) {
return $translations[$locale];
}
// Attempt to find by language
if(isset($translations[$language])) {
return $translations[$language];
}
return false;
}
// Toolbar enabled
public static function toolbar_enabled() {
return (
!self::option_get('disable_toolbar_menu') &&
self::can_user('edit_form') &&
self::can_user('read_submission')
);
}
// Toolbar CSS
public static function toolbar_css() {
if(!self::toolbar_enabled()) { return; }
if(!is_admin_bar_showing()) { return; }
?>
<style>
#wp-admin-bar-ws-form-node .ab-icon {
width: 20px !important;
height: 30px !important;
}
#wp-admin-bar-ws-form-node .ab-icon svg {
margin-top: 2px;
width: 20px;
}
#wp-admin-bar-ws-form-node:hover .ab-icon svg path,
#wp-admin-bar-ws-form-node.hover .ab-icon svg path {
fill: #00b9eb;
}
@media screen and ( max-width: 782px ) {
#wpadminbar #wp-admin-bar-ws-form-node .ab-icon svg {
margin: 9px 12px 0 12px;
height: 28px !important;
width: 28px !important;
display: block;
}
#wpadminbar li#wp-admin-bar-ws-form-node {
width: 52px;
display: block;
}
}
</style>
<?php
}
// Toolbar JS
public static function toolbar_js() {
if(!self::toolbar_enabled()) { return; }
if(!is_admin_bar_showing()) { return; }
// Get enqueue args
$enqueue_args = self::get_enqueue_args();
// Path to toolbar JS
$toolbar_js = sprintf('%sshared/js/ws-form-toolbar%s.js', WS_FORM_PLUGIN_DIR_URL, (SCRIPT_DEBUG ? '' : '.min'));
// Register toolbar JS
wp_register_script(WS_FORM_NAME . '-toolbar', $toolbar_js, array('jquery'), WS_FORM_VERSION, $enqueue_args);
// Localize toolbar JS
wp_localize_script(WS_FORM_NAME . '-toolbar', 'ws_form_toolbar', array(
'api_url_debug' => self::get_api_path('helper/debug/'),
'api_url_styler' => self::get_api_path('helper/styler/'),
'x_wp_nonce' => wp_create_nonce('wp_rest')
));
// Enqueue toolbar JS
wp_enqueue_script(WS_FORM_NAME . '-toolbar');
}
// Get enqueue args
public static function get_enqueue_args() {
$enqueue_args = array(
// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- All hooks prefixed with wsf_
'in_footer' => apply_filters('wsf_enqueue_script_in_footer', (self::option_get('jquery_footer', '') == 'on'))
);
// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- All hooks prefixed with wsf_
if(apply_filters('wsf_enqueue_script_strategy_defer', (self::option_get('js_defer', '') == 'on'))) {
$enqueue_args['strategy'] = 'defer';
}
return $enqueue_args;
}
public static function get_admin_submit_filters() {
// Build filters
$filters = array();
// Get status
$status = self::get_query_var('ws-form-status');
if(!empty($status)) {
$filters[] = array(
'field' => 'status',
'operator' => '==',
'value' => $status
);
}
// Get date from
$date_from = self::get_query_var('date_from');
if(!empty($date_from)) {
$filters[] = array(
'field' => 'date_from',
'operator' => '==',
'value' => $date_from
);
}
// Get date to
$date_to = self::get_query_var('date_to');
if(!empty($date_to)) {
$filters[] = array(
'field' => 'date_to',
'operator' => '==',
'value' => $date_to
);
}
// Get ids
$ids = self::get_query_var('submit_ids');
if(!empty($ids)) {
$filters[] = array(
'field' => 'id',
'operator' => 'in',
'value' => $ids
);
}
return $filters;
}
public static function get_full_name_components($full_name) {
if(!is_string($full_name)) {
return array(
'name_prefix' => '',
'name_first' => '',
'name_middle' => '',
'name_last' => '',
'name_suffix' => ''
);
}
$parts = preg_split('/\s+/', trim($full_name));
$name_prefix = '';
$name_suffix = '';
$name_first = '';
$name_middle = '';
$name_last = '';
// Remove prefix
if(
!empty($parts) &&
in_array(
strtolower(rtrim($parts[0], '.')),
self::get_name_prefixes()
)
) {
$name_prefix = array_shift($parts);
}
// Remove suffix
if(
count($parts) > 1 &&
in_array(
strtolower(rtrim(end($parts), '.')),
self::get_name_suffixes()
)
) {
$name_suffix = array_pop($parts);
}
$count = count($parts);
if ($count === 1) {
$name_first = $parts[0];
} elseif ($count === 2) {
$name_first = $parts[0];
$name_last = $parts[1];
} elseif ($count > 2) {
$name_first = $parts[0];
$name_last = $parts[$count - 1];
$name_middle = implode(' ', array_slice($parts, 1, -1));
}
return array(
'name_prefix' => $name_prefix,
'name_first' => $name_first,
'name_middle' => $name_middle,
'name_last' => $name_last,
'name_suffix' => $name_suffix
);
}
public static function get_name_prefixes() {
// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- All hooks prefixed with wsf_
return apply_filters('wsf_name_prefixes', array(
'mr', 'mrs', 'ms', 'miss', 'mx', 'dr', 'prof', 'rev', 'fr', 'sr', 'sra', 'br', 'srta', 'madam', 'mme', 'mlle',
'lord', 'lady', 'sir', 'dame', 'hon', 'judge', 'justice', 'pres', 'gov', 'amb', 'sec', 'min', 'supt', 'rep', 'sen',
'gen', 'lt', 'col', 'maj', 'capt', 'cmdr', 'cpl', 'sgt', 'adm', 'ens', 'pvt', 'officer', 'chief',
'rabbi', 'imam', 'pastor', 'bishop', 'cardinal', 'archbishop', 'elder', 'deacon',
'canon', 'monsignor', 'father', 'mother', 'brother', 'sister'
));
}
public static function get_name_suffixes() {
// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- All hooks prefixed with wsf_
return apply_filters('wsf_name_suffixes', array(
'jr', 'sr', 'i', 'ii', 'iii', 'iv', 'v', 'vi',
'phd', 'md', 'jd', 'mba', 'ms', 'ma', 'ba', 'bs', 'bsc', 'msc', 'dphil', 'edd', 'dvm', 'od', 'do',
'esq', 'cpa', 'pe', 'esquire', 'rn', 'lpn', 'esq.',
'sj', 'osb', 'op', 'ofm', 'ocist',
'ret', 'usa', 'usaf', 'usmc', 'usn', 'uscg',
'kc', 'qc', 'cbe', 'obe', 'mbe', 'frcp', 'frcs', 'dds', 'dmd', 'esq'
));
}
// Label to autocomplete
public static function label_to_autocomplete($label) {
// Check by field type
switch(strtolower($label)) {
case 'first name' :
case 'given name' :
return 'given-name';
case 'family name' :
case 'last name' :
case 'surname' :
return 'family-name';
case 'email' :
case 'email address' :
return 'email';
case 'cell' :
case 'phone' :
case 'tel' :
return 'tel';
case 'url' :
case 'web site' :
case 'website' :
return 'url';
case 'company' :
case 'company name' :
case 'organization' :
case 'organization name' :
return 'organization';
case 'title' :
case 'company title' :
case 'job title' :
case 'role' :
return 'organization-title';
case 'address' :
case 'address 1' :
case 'address line 1' :
return 'address-line1';
case 'address 2' :
case 'address line 2' :
return 'address-line2';
case 'city' :
case 'town' :
return 'address-level2';
case 'county' :
case 'state' :
case 'state / county / province' :
return 'address-level1';
case 'post code' :
case 'postal code' :
case 'zip' :
case 'zip code' :
case 'zipcode' :
return 'postal-code';
case 'country' :
return 'country-name';
case 'date of birth' :
return 'bday';
default :
return false;
}
}
// Some hosting companies break serialized data when changing a hostname
// This function attempts to fix that if it occurs
public static function maybe_unserialize($serialized_string) {
// Prevent object injection attacks
$options = array(
'allowed_classes' => array('stdClass')
);
// If we can't detect a serialized string, return it as is
if(!is_serialized($serialized_string)) {
return $serialized_string;
}
// Check for serialized false
if($serialized_string === 'b:0;') {
return false;
}
// Attempt a regular unserialize
$unserialized_string = @unserialize(
$serialized_string,
$options
);
// If the unserialize fails, attempt to fix it
if($unserialized_string === false) {
$unserialized_string = @unserialize(
self::repair_serialized($serialized_string),
$options
);
}
// Check if __PHP_Incomplete_Class returned from unserialize
if($unserialized_string instanceof __PHP_Incomplete_Class) {
return '';
}
return $unserialized_string;
}
// Attempt to fix a serialized string if the lengths are wrong
public static function repair_serialized($serialized) {
$offset = 0;
$result = '';
while(($pos = strpos($serialized, 's:', $offset)) !== false) {
// Add everything before this string
$result .= substr($serialized, $offset, $pos - $offset);
// Find the length declaration
$length_start = $pos + 2;
$length_end = strpos($serialized, ':"', $length_start);
if($length_end === false) {
// Malformed, just add the rest and break
$result .= substr($serialized, $pos);
break;
}
$declared_length = (int)substr($serialized, $length_start, $length_end - $length_start);
$content_start = $length_end + 2;
// Find the actual ending quote and semicolon
$actual_end = strpos($serialized, '";', $content_start);
if($actual_end === false) {
// Malformed, just add the rest and break
$result .= substr($serialized, $pos);
break;
}
$actual_content = substr($serialized, $content_start, $actual_end - $content_start);
$actual_length = strlen($actual_content);
// Add the corrected string
$result .= 's:' . $actual_length . ':"' . $actual_content . '";';
// Move offset past this string
$offset = $actual_end + 2;
}
// Add any remaining content
$result .= substr($serialized, $offset);
return $result;
}
// Safely strip slashes we allow for delimiters
public static function delimiter_sanitize($input) {
// Sanitize
$input = sanitize_text_field($input);
// New line
$input = str_replace('\n', "\n", $input);
// Tab
$input = str_replace('\t', "\t", $input);
return $input;
}
}