first
This commit is contained in:
@ -0,0 +1,110 @@
|
||||
import controlGetValue from '../control-get-value';
|
||||
|
||||
/**
|
||||
* Compare 2 values
|
||||
*
|
||||
* @param {mixed} left Left value.
|
||||
* @param {string} operator Operator.
|
||||
* @param {mixed} right Right value.
|
||||
*
|
||||
* @return {boolean}
|
||||
*/
|
||||
function compare(left, operator, right) {
|
||||
let checkResult = true;
|
||||
|
||||
switch (operator) {
|
||||
case '==':
|
||||
// eslint-disable-next-line eqeqeq
|
||||
checkResult = left == right;
|
||||
break;
|
||||
case '===':
|
||||
checkResult = left === right;
|
||||
break;
|
||||
case '!=':
|
||||
// eslint-disable-next-line eqeqeq
|
||||
checkResult = left != right;
|
||||
break;
|
||||
case '!==':
|
||||
checkResult = left !== right;
|
||||
break;
|
||||
case '*=':
|
||||
checkResult = left.indexOf(right) !== -1;
|
||||
break;
|
||||
case '>=':
|
||||
checkResult = left >= right;
|
||||
break;
|
||||
case '<=':
|
||||
checkResult = left <= right;
|
||||
break;
|
||||
case '>':
|
||||
checkResult = left > right;
|
||||
break;
|
||||
case '<':
|
||||
checkResult = left < right;
|
||||
break;
|
||||
case '&&':
|
||||
case 'AND':
|
||||
checkResult = left && right;
|
||||
break;
|
||||
case '||':
|
||||
case 'OR':
|
||||
checkResult = left || right;
|
||||
break;
|
||||
default:
|
||||
checkResult = left;
|
||||
break;
|
||||
}
|
||||
|
||||
return checkResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* Conditions check for controls.
|
||||
*
|
||||
* @param {Object} condition - condition params.
|
||||
* @param {Object} attributes - block attributes.
|
||||
* @param {string} relation - Can be one of 'AND' or 'OR'.
|
||||
*
|
||||
* @return {boolean} is check pass.
|
||||
*/
|
||||
export default function conditionCheck(
|
||||
condition,
|
||||
attributes,
|
||||
relation = 'AND'
|
||||
) {
|
||||
// by default result will be TRUE for relation AND
|
||||
// and FALSE for relation OR.
|
||||
let result = relation === 'AND';
|
||||
|
||||
const childRelation = result ? 'OR' : 'AND';
|
||||
|
||||
condition.forEach((data) => {
|
||||
if (Array.isArray(data) && !data.control) {
|
||||
result = compare(
|
||||
result,
|
||||
relation,
|
||||
conditionCheck(data, attributes, childRelation)
|
||||
);
|
||||
} else if (data.control) {
|
||||
let left = controlGetValue(data.control, attributes);
|
||||
const operator = data.operator || '==';
|
||||
let right = typeof data.value !== 'undefined' ? data.value : 'true';
|
||||
|
||||
if (left === 'true') {
|
||||
left = true;
|
||||
} else if (left === 'false') {
|
||||
left = false;
|
||||
}
|
||||
|
||||
if (right === 'true') {
|
||||
right = true;
|
||||
} else if (right === 'false') {
|
||||
right = false;
|
||||
}
|
||||
|
||||
result = compare(result, relation, compare(left, operator, right));
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
@ -0,0 +1,111 @@
|
||||
<?php
|
||||
/**
|
||||
* Control condition check.
|
||||
*
|
||||
* @package visual-portfolio
|
||||
*/
|
||||
|
||||
/**
|
||||
* Visual_Portfolio_Control_Condition_Check
|
||||
*/
|
||||
class Visual_Portfolio_Control_Condition_Check {
|
||||
/**
|
||||
* Compare 2 values
|
||||
*
|
||||
* @param mixed $left Left value.
|
||||
* @param string $operator Operator.
|
||||
* @param mixed $right Right value.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public static function compare( $left, $operator, $right ) {
|
||||
$check_result = true;
|
||||
|
||||
switch ( $operator ) {
|
||||
case '==':
|
||||
// phpcs:ignore WordPress.PHP.StrictComparisons.LooseComparison
|
||||
$check_result = $left == $right;
|
||||
break;
|
||||
case '===':
|
||||
$check_result = $left === $right;
|
||||
break;
|
||||
case '!=':
|
||||
// phpcs:ignore WordPress.PHP.StrictComparisons.LooseComparison
|
||||
$check_result = $left != $right;
|
||||
break;
|
||||
case '!==':
|
||||
$check_result = $left !== $right;
|
||||
break;
|
||||
case '*=':
|
||||
$check_result = strpos( $left, $right ) !== false;
|
||||
break;
|
||||
case '>=':
|
||||
$check_result = $left >= $right;
|
||||
break;
|
||||
case '<=':
|
||||
$check_result = $left <= $right;
|
||||
break;
|
||||
case '>':
|
||||
$check_result = $left > $right;
|
||||
break;
|
||||
case '<':
|
||||
$check_result = $left < $right;
|
||||
break;
|
||||
case '&&':
|
||||
case 'AND':
|
||||
$check_result = $left && $right;
|
||||
break;
|
||||
case '||':
|
||||
case 'OR':
|
||||
$check_result = $left || $right;
|
||||
break;
|
||||
default:
|
||||
$check_result = $left;
|
||||
break;
|
||||
}
|
||||
|
||||
return $check_result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Conditions check for controls.
|
||||
*
|
||||
* @param array $condition - condition params.
|
||||
* @param array $attributes - block attributes.
|
||||
* @param string $relation - Can be one of 'AND' or 'OR'.
|
||||
*
|
||||
* @return boolean is check pass.
|
||||
*/
|
||||
public static function check( $condition, $attributes, $relation = 'AND' ) {
|
||||
// by default result will be TRUE for relation AND
|
||||
// and FALSE for relation OR.
|
||||
$result = 'AND' === $relation;
|
||||
$child_relation = $result ? 'OR' : 'AND';
|
||||
|
||||
foreach ( $condition as $data ) {
|
||||
if ( is_array( $data ) && ! isset( $data['control'] ) ) {
|
||||
$result = self::compare( $result, $relation, self::check( $data, $attributes, $child_relation ) );
|
||||
} elseif ( isset( $data['control'] ) ) {
|
||||
$left = Visual_Portfolio_Control_Get_Value::get( $data['control'], $attributes );
|
||||
$operator = isset( $data['operator'] ) ? $data['operator'] : '==';
|
||||
$right = isset( $data['value'] ) ? $data['value'] : 'true';
|
||||
|
||||
if ( 'true' === $left ) {
|
||||
$left = true;
|
||||
} elseif ( 'false' === $left ) {
|
||||
$left = false;
|
||||
}
|
||||
|
||||
if ( 'true' === $right ) {
|
||||
$right = true;
|
||||
} elseif ( 'false' === $right ) {
|
||||
$right = false;
|
||||
}
|
||||
|
||||
$result = self::compare( $result, $relation, self::compare( $left, $operator, $right ) );
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
/**
|
||||
* Get control value.
|
||||
* Supported array names like `images[3].format`
|
||||
*
|
||||
* @param {string} name - control name.
|
||||
* @param {Object} attributes - block attributes.
|
||||
*
|
||||
* @return {Mixed} value.
|
||||
*/
|
||||
export default function controlGetValue(name, attributes) {
|
||||
let val = attributes[name];
|
||||
|
||||
// Parse arrays and objects.
|
||||
// Example `images[3].format`.
|
||||
if (typeof val === 'undefined' && /[\[\.]/g.test(name)) {
|
||||
// Find parts, used for objects.
|
||||
// Example `images.format`
|
||||
const valObjectParts = name.split('.');
|
||||
const valParts = [];
|
||||
|
||||
if (valObjectParts && valObjectParts.length) {
|
||||
// Find parts, used for arrays.
|
||||
// Example `images[3]`
|
||||
valObjectParts.forEach((objPart) => {
|
||||
if (/[\[]/g.test(objPart)) {
|
||||
const valArrayParts = objPart.split(/[\[\]]/g);
|
||||
|
||||
if (valArrayParts && valArrayParts.length) {
|
||||
valArrayParts.forEach((arrPart) => {
|
||||
if (arrPart !== '') {
|
||||
if (`${parseInt(arrPart, 10)}` === arrPart) {
|
||||
valParts.push(parseInt(arrPart, 10));
|
||||
} else {
|
||||
valParts.push(arrPart);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
valParts.push(objPart);
|
||||
}
|
||||
});
|
||||
|
||||
// Try to find value in attributes.
|
||||
if (valParts.length) {
|
||||
let currentVal = attributes;
|
||||
|
||||
valParts.forEach((partName) => {
|
||||
if (
|
||||
currentVal &&
|
||||
typeof currentVal[partName] !== 'undefined'
|
||||
) {
|
||||
currentVal = currentVal[partName];
|
||||
} else {
|
||||
currentVal = undefined;
|
||||
}
|
||||
});
|
||||
|
||||
val = currentVal;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
<?php
|
||||
/**
|
||||
* Control condition check.
|
||||
*
|
||||
* @package visual-portfolio
|
||||
*/
|
||||
|
||||
/**
|
||||
* Visual_Portfolio_Control_Get_Value
|
||||
*/
|
||||
class Visual_Portfolio_Control_Get_Value {
|
||||
/**
|
||||
* Get control value.
|
||||
* Supported array names like `images[3].format`
|
||||
*
|
||||
* @param string $name - control name.
|
||||
* @param array $attributes - block attributes.
|
||||
*
|
||||
* @return mixed value.
|
||||
*/
|
||||
public static function get( $name, $attributes ) {
|
||||
$val = isset( $attributes[ $name ] ) ? $attributes[ $name ] : null;
|
||||
|
||||
// Parse arrays and objects.
|
||||
// Example `images[3].format`.
|
||||
if ( null !== $val && preg_match( '/[\[\.]/', $name ) ) {
|
||||
// Find parts, used for objects.
|
||||
// Example `images.format`.
|
||||
$val_object_parts = explode( '.', $name );
|
||||
$val_parts = array();
|
||||
|
||||
if ( $val_object_parts && ! empty( $val_object_parts ) ) {
|
||||
// Find parts, used for arrays.
|
||||
// Example `images[3]`.
|
||||
foreach ( $val_object_parts as $obj_part ) {
|
||||
if ( preg_match( '/[\[]/', $obj_part ) ) {
|
||||
$val_array_parts = preg_split( '/[\[\]]/', $obj_part );
|
||||
|
||||
if ( $val_array_parts && ! empty( $val_array_parts ) ) {
|
||||
foreach ( $val_array_parts as $arr_part ) {
|
||||
if ( '' !== $arr_part ) {
|
||||
$arr_part_int = (int) $arr_part;
|
||||
if ( "$arr_part_int" === $arr_part ) {
|
||||
$val_parts[] = $arr_part_int;
|
||||
} else {
|
||||
$val_parts[] = $arr_part;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$val_parts[] = $obj_part;
|
||||
}
|
||||
}
|
||||
|
||||
// Try to find value in attributes.
|
||||
if ( ! empty( $val_parts ) ) {
|
||||
$current_val = $attributes;
|
||||
|
||||
foreach ( $val_parts as $part_name ) {
|
||||
if ( $current_val && isset( $current_val[ $part_name ] ) ) {
|
||||
$current_val = $current_val[ $part_name ];
|
||||
} else {
|
||||
$current_val = null;
|
||||
}
|
||||
}
|
||||
|
||||
$val = $current_val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $val;
|
||||
}
|
||||
}
|
@ -0,0 +1,179 @@
|
||||
import { merge } from 'lodash';
|
||||
|
||||
import { applyFilters } from '@wordpress/hooks';
|
||||
|
||||
import conditionCheck from '../control-condition-check';
|
||||
import { maybeDecode } from '../encode-decode';
|
||||
|
||||
const { controls: registeredControls } = window.VPGutenbergVariables;
|
||||
|
||||
/**
|
||||
* Prepare styles from params
|
||||
* Params example:
|
||||
array(
|
||||
'element' => '$ .inner-selector',
|
||||
'property' => 'height',
|
||||
'mask' => '$px',
|
||||
)
|
||||
*
|
||||
* @param {string} selector CSS selector.
|
||||
* @param {Mixed} value Property value.
|
||||
* @param {Array} params Output params.
|
||||
*
|
||||
* @return {string}
|
||||
*/
|
||||
export function prepareStylesFromParams(selector, value, params) {
|
||||
if (
|
||||
!selector ||
|
||||
typeof value === 'undefined' ||
|
||||
value === '' ||
|
||||
value === null ||
|
||||
typeof params.property === 'undefined'
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Value mask.
|
||||
if (typeof params.mask !== 'undefined') {
|
||||
value = params.mask.replace('$', value);
|
||||
}
|
||||
|
||||
// Custom selector mask.
|
||||
if (typeof params.element !== 'undefined' && /\$/g.test(params.element)) {
|
||||
selector = params.element.replace('$', selector);
|
||||
} else {
|
||||
selector +=
|
||||
typeof params.element !== 'undefined' ? ` ${params.element}` : '';
|
||||
}
|
||||
|
||||
return {
|
||||
[selector]: {
|
||||
[params.property]: value,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if these control has dynamic CSS.
|
||||
*
|
||||
* @param {string} controlName control name.
|
||||
*
|
||||
* @return {boolean}
|
||||
*/
|
||||
export function hasDynamicCSS(controlName) {
|
||||
return (
|
||||
typeof registeredControls[controlName] !== 'undefined' &&
|
||||
typeof registeredControls[controlName].style !== 'undefined' &&
|
||||
registeredControls[controlName].style.length
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get dynamic CSS from options.
|
||||
*
|
||||
* @param {Array} options block options.
|
||||
*
|
||||
* @return {string}
|
||||
*/
|
||||
export default function getDynamicCSS(options) {
|
||||
let result = '';
|
||||
let selector = '';
|
||||
|
||||
if (typeof options.block_id !== 'undefined' && options.block_id) {
|
||||
selector = options.block_id;
|
||||
} else if (typeof options.id !== 'undefined' && options.id) {
|
||||
selector = options.id;
|
||||
}
|
||||
if (!selector) {
|
||||
return result;
|
||||
}
|
||||
|
||||
selector = `.vp-id-${selector}`;
|
||||
let controlStylesObject = {};
|
||||
|
||||
// Controls styles.
|
||||
Object.keys(registeredControls).forEach((k) => {
|
||||
const control = registeredControls[k];
|
||||
let allow = typeof control.style !== 'undefined' && control.style;
|
||||
|
||||
// Check condition.
|
||||
if (
|
||||
allow &&
|
||||
typeof control.condition !== 'undefined' &&
|
||||
control.condition.length
|
||||
) {
|
||||
allow = conditionCheck(control.condition, options);
|
||||
}
|
||||
|
||||
// Prepare styles.
|
||||
if (allow) {
|
||||
control.style.forEach((data) => {
|
||||
let val = options[control.name];
|
||||
val = applyFilters(
|
||||
'vpf.editor.controls-dynamic-css-value',
|
||||
val,
|
||||
options,
|
||||
control,
|
||||
selector,
|
||||
data
|
||||
);
|
||||
|
||||
// Prepare Aspect Ratio control value.
|
||||
if (control.type && control.type === 'aspect_ratio' && val) {
|
||||
const ratioArray = val.split(':');
|
||||
|
||||
if (ratioArray[0] && ratioArray[1]) {
|
||||
val = `${100 * (ratioArray[1] / ratioArray[0])}%`;
|
||||
}
|
||||
}
|
||||
|
||||
let stylesObject = prepareStylesFromParams(selector, val, data);
|
||||
stylesObject = applyFilters(
|
||||
'vpf.editor.controls-dynamic-css-styles-object',
|
||||
stylesObject,
|
||||
selector,
|
||||
val,
|
||||
data,
|
||||
options,
|
||||
control
|
||||
);
|
||||
|
||||
if (stylesObject) {
|
||||
controlStylesObject = merge(
|
||||
controlStylesObject,
|
||||
stylesObject
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Prepare CSS of controls.
|
||||
Object.keys(controlStylesObject).forEach((sel) => {
|
||||
result += `${sel} {\n`;
|
||||
|
||||
Object.keys(controlStylesObject[sel]).forEach((prop) => {
|
||||
result += ` ${prop}: ${controlStylesObject[sel][prop]};\n`;
|
||||
});
|
||||
|
||||
result += `}\n`;
|
||||
});
|
||||
|
||||
// Custom CSS.
|
||||
if (typeof options.custom_css !== 'undefined' && options.custom_css) {
|
||||
let customCss = options.custom_css;
|
||||
|
||||
// Decode.
|
||||
customCss = maybeDecode(customCss);
|
||||
|
||||
// replace 'selector' to actual css selector.
|
||||
customCss = customCss.replace(/selector/g, selector);
|
||||
|
||||
// a little security fix.
|
||||
customCss = customCss.replace(/<\//g, '</');
|
||||
|
||||
result += customCss;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
@ -0,0 +1,147 @@
|
||||
<?php
|
||||
/**
|
||||
* Parse controls data and generate styles output.
|
||||
*
|
||||
* @package visual-portfolio
|
||||
*/
|
||||
|
||||
/**
|
||||
* Visual_Portfolio_Controls_Dynamic_CSS
|
||||
*/
|
||||
class Visual_Portfolio_Controls_Dynamic_CSS {
|
||||
/**
|
||||
* Prepare CSS for options.
|
||||
*
|
||||
* @param array $options block options.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get( $options ) {
|
||||
$result = '';
|
||||
$selector = '';
|
||||
|
||||
if ( isset( $options['block_id'] ) ) {
|
||||
$selector = $options['block_id'];
|
||||
} elseif ( isset( $options['id'] ) ) {
|
||||
$selector = $options['id'];
|
||||
}
|
||||
if ( ! $selector ) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
$selector = '.vp-id-' . $selector;
|
||||
$registered = Visual_Portfolio_Controls::get_registered_array();
|
||||
$control_styles_array = array();
|
||||
|
||||
// Controls styles.
|
||||
foreach ( $registered as $control ) {
|
||||
$allow = isset( $control['style'] ) && ! empty( $control['style'] );
|
||||
|
||||
// Check condition.
|
||||
if ( $allow && isset( $control['condition'] ) && ! empty( $control['condition'] ) ) {
|
||||
$allow = Visual_Portfolio_Control_Condition_Check::check( $control['condition'], $options );
|
||||
}
|
||||
|
||||
// Prepare styles.
|
||||
if ( $allow ) {
|
||||
foreach ( $control['style'] as $data ) {
|
||||
$val = $options[ $control['name'] ];
|
||||
$val = apply_filters( 'vpf_controls_dynamic_css_value', $val, $options, $control, $selector, $data );
|
||||
|
||||
// Prepare Aspect Ratio control value.
|
||||
if ( isset( $control['type'] ) && 'aspect_ratio' === $control['type'] && $val ) {
|
||||
$ratio_array = explode( ':', $val );
|
||||
|
||||
if ( isset( $ratio_array[0] ) && $ratio_array[0] && isset( $ratio_array[1] ) && $ratio_array[1] ) {
|
||||
$val = ( 100 * $ratio_array[1] / $ratio_array[0] ) . '%';
|
||||
}
|
||||
}
|
||||
|
||||
$styles_array = self::prepare_styles_from_params( $selector, $val, $data );
|
||||
$styles_array = apply_filters( 'vpf_controls_dynamic_css_styles_array', $styles_array, $selector, $val, $data, $options, $control );
|
||||
|
||||
if ( $styles_array ) {
|
||||
$control_styles_array = array_merge_recursive(
|
||||
$control_styles_array,
|
||||
$styles_array
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Prepare CSS of controls.
|
||||
foreach ( $control_styles_array as $sel => $styles ) {
|
||||
$result .= $sel . " {\n";
|
||||
|
||||
foreach ( $styles as $prop => $val ) {
|
||||
$result .= " {$prop}: {$val};\n";
|
||||
}
|
||||
|
||||
$result .= "}\n";
|
||||
}
|
||||
|
||||
// Custom CSS.
|
||||
if ( isset( $options['custom_css'] ) && $options['custom_css'] ) {
|
||||
// decode.
|
||||
$custom_css = visual_portfolio_decode( $options['custom_css'] );
|
||||
|
||||
// replace 'selector' to actual css selector.
|
||||
$custom_css = str_replace( 'selector', $selector, $custom_css );
|
||||
|
||||
// a little security fix.
|
||||
$custom_css = str_replace( '</', '</', $custom_css );
|
||||
|
||||
if ( isset( $options['id'] ) ) {
|
||||
$custom_css = str_replace( '>', '>', $custom_css );
|
||||
$custom_css = str_replace( '\"', '"', $custom_css );
|
||||
$custom_css = str_replace( "\'", "'", $custom_css );
|
||||
}
|
||||
|
||||
$result .= $custom_css;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare styles from params
|
||||
* Params example:
|
||||
array(
|
||||
'element' => '$ .inner-selector',
|
||||
'property' => 'height',
|
||||
'mask' => '$px',
|
||||
)
|
||||
*
|
||||
* @param string $selector CSS selector.
|
||||
* @param mixed $value Property value.
|
||||
* @param array $params Output params.
|
||||
*
|
||||
* @return array|bool
|
||||
*/
|
||||
public static function prepare_styles_from_params( $selector, $value, $params ) {
|
||||
if ( ! $selector || ! isset( $value ) || '' === $value || null === $value || ! isset( $params['property'] ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Value mask.
|
||||
if ( isset( $params['mask'] ) ) {
|
||||
$value = str_replace( '$', $value, $params['mask'] );
|
||||
}
|
||||
|
||||
// Custom selector mask.
|
||||
if ( isset( $params['element'] ) && strpos( $params['element'], '$' ) !== false ) {
|
||||
$selector = str_replace( '$', $selector, $params['element'] );
|
||||
} else {
|
||||
$selector = $selector . ( isset( $params['element'] ) ? ( ' ' . $params['element'] ) : '' );
|
||||
}
|
||||
|
||||
$property = $params['property'];
|
||||
|
||||
return array(
|
||||
$selector => array(
|
||||
$property => $value,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,92 @@
|
||||
const eCache = {};
|
||||
const dCache = {};
|
||||
|
||||
/**
|
||||
* Encode URI component with `try {} catch` and caching.
|
||||
*
|
||||
* @param {string} str - decoded string.
|
||||
* @return {string} - new encoded string.
|
||||
*/
|
||||
export function maybeEncode(str) {
|
||||
// return cached string.
|
||||
if (eCache[str]) {
|
||||
return eCache[str];
|
||||
}
|
||||
|
||||
let result = {};
|
||||
|
||||
// Object
|
||||
if (typeof str === 'object') {
|
||||
Object.keys(str).forEach((k) => {
|
||||
result[maybeEncode(k)] = maybeEncode(str[k]);
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// String
|
||||
result = str;
|
||||
|
||||
if (typeof result === 'string') {
|
||||
try {
|
||||
// Because of these replacements, some attributes can't be exported to XML without being broken. So, we need to replace it manually with something safe.
|
||||
// https://github.com/WordPress/gutenberg/blob/88645e4b268acf5746e914159e3ce790dcb1665a/packages/blocks/src/api/serializer.js#L246-L271
|
||||
result = result.replace(/--/gm, '_u002d__u002d_');
|
||||
|
||||
result = encodeURIComponent(result);
|
||||
} catch (e) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn(e);
|
||||
}
|
||||
}
|
||||
|
||||
// save to cache.
|
||||
eCache[str] = result;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode URI component with `try {} catch` and caching.
|
||||
*
|
||||
* @param {string} str - decoded string.
|
||||
* @return {string} - new encoded string.
|
||||
*/
|
||||
export function maybeDecode(str) {
|
||||
// return cached string.
|
||||
if (dCache[str]) {
|
||||
return dCache[str];
|
||||
}
|
||||
|
||||
let result = {};
|
||||
|
||||
// Object
|
||||
if (typeof str === 'object') {
|
||||
Object.keys(str).forEach((k) => {
|
||||
result[maybeDecode(k)] = maybeDecode(str[k]);
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// String
|
||||
result = str;
|
||||
|
||||
if (typeof result === 'string') {
|
||||
try {
|
||||
result = decodeURIComponent(result);
|
||||
|
||||
// Because of these replacements, some attributes can't be exported to XML without being broken. So, we need to replace it manually with something safe.
|
||||
// https://github.com/WordPress/gutenberg/blob/88645e4b268acf5746e914159e3ce790dcb1665a/packages/blocks/src/api/serializer.js#L246-L271
|
||||
result = result.replace(/_u002d__u002d_/gm, '--');
|
||||
} catch (e) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn(e);
|
||||
}
|
||||
}
|
||||
|
||||
// save to cache.
|
||||
dCache[str] = result;
|
||||
|
||||
return result;
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
<?php
|
||||
/**
|
||||
* Encode/Decode helper functions.
|
||||
*
|
||||
* @package visual-portfolio
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode string.
|
||||
*
|
||||
* @param string|array $str - string to encode.
|
||||
*
|
||||
* @return string|array
|
||||
*/
|
||||
function visual_portfolio_encode( $str ) {
|
||||
// Array.
|
||||
if ( is_array( $str ) ) {
|
||||
$result = array();
|
||||
|
||||
foreach ( $str as $k => $val ) {
|
||||
$result[ visual_portfolio_encode( $k ) ] = visual_portfolio_encode( $val );
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
// String.
|
||||
if ( is_string( $str ) ) {
|
||||
// Because of these replacements, some attributes can't be exported to XML without being broken. So, we need to replace it manually with something safe.
|
||||
// https://github.com/WordPress/gutenberg/blob/88645e4b268acf5746e914159e3ce790dcb1665a/packages/blocks/src/api/serializer.js#L246-L271 .
|
||||
$str = str_replace( '--', '_u002d__u002d_', $str );
|
||||
|
||||
// phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.urlencode_urlencode
|
||||
$str = urlencode( $str );
|
||||
}
|
||||
|
||||
return $str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode string.
|
||||
*
|
||||
* @param string|array $str - string to decode.
|
||||
*
|
||||
* @return string|array
|
||||
*/
|
||||
function visual_portfolio_decode( $str ) {
|
||||
// Array.
|
||||
if ( is_array( $str ) ) {
|
||||
$result = array();
|
||||
|
||||
foreach ( $str as $k => $val ) {
|
||||
$result[ visual_portfolio_decode( $k ) ] = visual_portfolio_decode( $val );
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
// String.
|
||||
if ( is_string( $str ) ) {
|
||||
$str = urldecode( $str );
|
||||
|
||||
// Because of these replacements, some attributes can't be exported to XML without being broken. So, we need to replace it manually with something safe.
|
||||
// https://github.com/WordPress/gutenberg/blob/88645e4b268acf5746e914159e3ce790dcb1665a/packages/blocks/src/api/serializer.js#L246-L271 .
|
||||
$str = str_replace( '_u002d__u002d_', '--', $str );
|
||||
}
|
||||
|
||||
return $str;
|
||||
}
|
Reference in New Issue
Block a user