forked from LiveCarta/LiveCartaWP
405 lines
10 KiB
PHP
405 lines
10 KiB
PHP
<?php
|
|
/**
|
|
* REST API controller for per-form field and setting operations.
|
|
*
|
|
* @package contact-form-7-mailchimp-extension
|
|
* @author renzo.johnson@gmail.com
|
|
* @copyright 2014-2026 https://renzojohnson.com
|
|
* @license GPL-3.0+
|
|
*/
|
|
|
|
defined( 'ABSPATH' ) || exit;
|
|
|
|
final class Cmatic_Rest_Form {
|
|
|
|
/** @var string Primary REST namespace. */
|
|
protected static $namespace = 'chimpmatic-lite/v1';
|
|
|
|
/** @var string Secondary REST namespace for form settings. */
|
|
protected static $cmatic_namespace = 'cmatic';
|
|
|
|
/** @var bool Whether initialized. */
|
|
protected static $initialized = false;
|
|
|
|
/** @var array Field pattern configuration. */
|
|
protected static $field_patterns = array(
|
|
'labeltags\\.(.+)' => array(
|
|
'type' => 'boolean',
|
|
'pro_only' => false,
|
|
'nested' => 'labeltags',
|
|
),
|
|
'field(\\d+)' => array(
|
|
'type' => 'string',
|
|
'pro_only' => false,
|
|
'direct' => true,
|
|
),
|
|
'customKey(\\d+)' => array(
|
|
'type' => 'string',
|
|
'pro_only' => false,
|
|
'direct' => true,
|
|
),
|
|
'customValue(\\d+)' => array(
|
|
'type' => 'string',
|
|
'pro_only' => false,
|
|
'direct' => true,
|
|
),
|
|
'GDPRCheck(\\d+)' => array(
|
|
'type' => 'boolean',
|
|
'pro_only' => true,
|
|
'direct' => true,
|
|
),
|
|
'GDPRCustomValue(\\d+)' => array(
|
|
'type' => 'string',
|
|
'pro_only' => true,
|
|
'direct' => true,
|
|
),
|
|
'ggCheck(\\d+)' => array(
|
|
'type' => 'boolean',
|
|
'pro_only' => true,
|
|
'direct' => true,
|
|
),
|
|
'ggCustomValue(\\d+)' => array(
|
|
'type' => 'string',
|
|
'pro_only' => true,
|
|
'direct' => true,
|
|
),
|
|
);
|
|
|
|
public static function init() {
|
|
if ( self::$initialized ) {
|
|
return;
|
|
}
|
|
add_action( 'rest_api_init', array( static::class, 'register_routes' ) );
|
|
self::$initialized = true;
|
|
}
|
|
|
|
public static function register_routes() {
|
|
register_rest_route(
|
|
self::$namespace,
|
|
'/tags/toggle',
|
|
array(
|
|
'methods' => 'POST',
|
|
'callback' => array( static::class, 'toggle_tag' ),
|
|
'permission_callback' => array( static::class, 'check_admin_permission' ),
|
|
'args' => array(
|
|
'form_id' => array(
|
|
'required' => true,
|
|
'type' => 'integer',
|
|
'sanitize_callback' => 'absint',
|
|
),
|
|
'tag' => array(
|
|
'required' => true,
|
|
'type' => 'string',
|
|
'sanitize_callback' => 'sanitize_text_field',
|
|
),
|
|
'enabled' => array(
|
|
'required' => true,
|
|
'type' => 'boolean',
|
|
'sanitize_callback' => 'rest_sanitize_boolean',
|
|
),
|
|
),
|
|
)
|
|
);
|
|
|
|
register_rest_route(
|
|
self::$namespace,
|
|
'/form/field',
|
|
array(
|
|
'methods' => 'POST',
|
|
'callback' => array( static::class, 'save_field' ),
|
|
'permission_callback' => array( static::class, 'check_form_permission' ),
|
|
'args' => array(
|
|
'form_id' => array(
|
|
'required' => true,
|
|
'type' => 'integer',
|
|
'sanitize_callback' => 'absint',
|
|
),
|
|
'field' => array(
|
|
'required' => true,
|
|
'type' => 'string',
|
|
'sanitize_callback' => 'sanitize_text_field',
|
|
),
|
|
'value' => array(
|
|
'required' => false,
|
|
'default' => null,
|
|
),
|
|
),
|
|
)
|
|
);
|
|
|
|
register_rest_route(
|
|
self::$cmatic_namespace,
|
|
'/form/setting',
|
|
array(
|
|
'methods' => 'POST',
|
|
'callback' => array( static::class, 'save_setting' ),
|
|
'permission_callback' => array( static::class, 'check_admin_permission' ),
|
|
'args' => array(
|
|
'form_id' => array(
|
|
'required' => true,
|
|
'type' => 'integer',
|
|
'sanitize_callback' => 'absint',
|
|
'validate_callback' => function ( $param ) {
|
|
return is_numeric( $param ) && $param > 0;
|
|
},
|
|
),
|
|
'field' => array(
|
|
'required' => true,
|
|
'type' => 'string',
|
|
'sanitize_callback' => 'sanitize_key',
|
|
),
|
|
'value' => array(
|
|
'required' => true,
|
|
'type' => 'boolean',
|
|
'sanitize_callback' => function ( $value ) {
|
|
return Cmatic_Utils::validate_bool( $value );
|
|
},
|
|
),
|
|
),
|
|
)
|
|
);
|
|
}
|
|
|
|
public static function check_admin_permission( $request ) {
|
|
if ( ! current_user_can( 'manage_options' ) ) {
|
|
return new WP_Error(
|
|
'rest_forbidden',
|
|
esc_html__( 'You do not have permission to access this endpoint.', 'chimpmatic-lite' ),
|
|
array( 'status' => 403 )
|
|
);
|
|
}
|
|
|
|
$nonce = $request->get_header( 'X-WP-Nonce' );
|
|
if ( ! wp_verify_nonce( $nonce, 'wp_rest' ) ) {
|
|
return new WP_Error(
|
|
'rest_cookie_invalid_nonce',
|
|
esc_html__( 'Cookie nonce is invalid.', 'chimpmatic-lite' ),
|
|
array( 'status' => 403 )
|
|
);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public static function check_form_permission( $request ) {
|
|
$form_id = $request->get_param( 'form_id' );
|
|
|
|
if ( ! current_user_can( 'wpcf7_edit_contact_form', $form_id ) ) {
|
|
return new WP_Error(
|
|
'rest_forbidden',
|
|
esc_html__( 'You do not have permission to access the API key.', 'chimpmatic-lite' ),
|
|
array( 'status' => 403 )
|
|
);
|
|
}
|
|
|
|
$nonce = $request->get_header( 'X-WP-Nonce' );
|
|
if ( ! wp_verify_nonce( $nonce, 'wp_rest' ) ) {
|
|
return new WP_Error(
|
|
'rest_cookie_invalid_nonce',
|
|
esc_html__( 'Cookie nonce is invalid.', 'chimpmatic-lite' ),
|
|
array( 'status' => 403 )
|
|
);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public static function toggle_tag( $request ) {
|
|
$form_id = $request->get_param( 'form_id' );
|
|
$tag = $request->get_param( 'tag' );
|
|
$enabled = $request->get_param( 'enabled' );
|
|
|
|
if ( ! $form_id || ! $tag ) {
|
|
return new WP_Error(
|
|
'missing_params',
|
|
__( 'Missing required parameters.', 'chimpmatic-lite' ),
|
|
array( 'status' => 400 )
|
|
);
|
|
}
|
|
|
|
$option_name = 'cf7_mch_' . $form_id;
|
|
$cf7_mch = get_option( $option_name, array() );
|
|
|
|
if ( ! isset( $cf7_mch['labeltags'] ) || ! is_array( $cf7_mch['labeltags'] ) ) {
|
|
$cf7_mch['labeltags'] = array();
|
|
}
|
|
|
|
if ( $enabled ) {
|
|
$cf7_mch['labeltags'][ $tag ] = '1';
|
|
} else {
|
|
unset( $cf7_mch['labeltags'][ $tag ] );
|
|
}
|
|
|
|
update_option( $option_name, $cf7_mch );
|
|
|
|
return rest_ensure_response(
|
|
array(
|
|
'success' => true,
|
|
'tag' => $tag,
|
|
'enabled' => $enabled,
|
|
'message' => $enabled
|
|
? sprintf( __( 'Tag [%s] enabled.', 'chimpmatic-lite' ), $tag )
|
|
: sprintf( __( 'Tag [%s] disabled.', 'chimpmatic-lite' ), $tag ),
|
|
)
|
|
);
|
|
}
|
|
|
|
public static function save_field( $request ) {
|
|
$form_id = $request->get_param( 'form_id' );
|
|
$field = $request->get_param( 'field' );
|
|
$value = $request->get_param( 'value' );
|
|
|
|
$matched_config = null;
|
|
$matched_key = null;
|
|
|
|
foreach ( self::$field_patterns as $pattern => $config ) {
|
|
if ( preg_match( '/^' . $pattern . '$/', $field, $matches ) ) {
|
|
$matched_config = $config;
|
|
$matched_key = isset( $matches[1] ) ? $matches[1] : null;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( null === $matched_config ) {
|
|
return new WP_Error(
|
|
'invalid_field',
|
|
sprintf( __( 'Field "%s" is not allowed.', 'chimpmatic-lite' ), $field ),
|
|
array( 'status' => 400 )
|
|
);
|
|
}
|
|
|
|
if ( $matched_config['pro_only'] && ! defined( 'CMATIC_VERSION' ) ) {
|
|
return new WP_Error(
|
|
'pro_required',
|
|
__( 'This field requires ChimpMatic PRO.', 'chimpmatic-lite' ),
|
|
array( 'status' => 403 )
|
|
);
|
|
}
|
|
|
|
if ( 'boolean' === $matched_config['type'] ) {
|
|
$value = rest_sanitize_boolean( $value );
|
|
} elseif ( 'string' === $matched_config['type'] ) {
|
|
$value = trim( sanitize_text_field( $value ) );
|
|
}
|
|
|
|
$option_name = 'cf7_mch_' . $form_id;
|
|
$cf7_mch = get_option( $option_name, array() );
|
|
|
|
if ( isset( $matched_config['nested'] ) ) {
|
|
$nested_key = $matched_config['nested'];
|
|
if ( ! isset( $cf7_mch[ $nested_key ] ) ) {
|
|
$cf7_mch[ $nested_key ] = array();
|
|
}
|
|
|
|
if ( $value ) {
|
|
$cf7_mch[ $nested_key ][ $matched_key ] = true;
|
|
} else {
|
|
unset( $cf7_mch[ $nested_key ][ $matched_key ] );
|
|
}
|
|
} elseif ( null === $value || '' === $value ) {
|
|
unset( $cf7_mch[ $field ] );
|
|
} else {
|
|
$cf7_mch[ $field ] = $value;
|
|
}
|
|
|
|
update_option( $option_name, $cf7_mch );
|
|
|
|
return rest_ensure_response(
|
|
array(
|
|
'success' => true,
|
|
'field' => $field,
|
|
'value' => $value,
|
|
'message' => __( 'Field saved successfully.', 'chimpmatic-lite' ),
|
|
)
|
|
);
|
|
}
|
|
|
|
public static function save_setting( $request ) {
|
|
$form_id = $request->get_param( 'form_id' );
|
|
$field = $request->get_param( 'field' );
|
|
$value = $request->get_param( 'value' );
|
|
|
|
$allowed_fields = array(
|
|
'sync_tags' => array(
|
|
'label' => __( 'Sync Tags', 'chimpmatic-lite' ),
|
|
'pro_only' => false,
|
|
),
|
|
'double_optin' => array(
|
|
'label' => __( 'Double Opt-in', 'chimpmatic-lite' ),
|
|
'pro_only' => false,
|
|
),
|
|
);
|
|
|
|
/**
|
|
* Filter the allowed per-form setting fields.
|
|
*
|
|
* Pro can extend this to add GDPR, Groups/Interests, etc.
|
|
*
|
|
* @since 0.9.69
|
|
*
|
|
* @param array $allowed_fields Associative array of field_name => config.
|
|
* @param int $form_id The CF7 form ID.
|
|
*/
|
|
$allowed_fields = apply_filters( 'cmatic_form_setting_fields', $allowed_fields, $form_id );
|
|
|
|
if ( ! array_key_exists( $field, $allowed_fields ) ) {
|
|
return new WP_Error(
|
|
'invalid_field',
|
|
sprintf(
|
|
/* translators: %s: field name */
|
|
__( 'Field "%s" is not a valid setting.', 'chimpmatic-lite' ),
|
|
$field
|
|
),
|
|
array( 'status' => 400 )
|
|
);
|
|
}
|
|
|
|
$field_config = $allowed_fields[ $field ];
|
|
|
|
if ( ! empty( $field_config['pro_only'] ) && ! defined( 'CMATIC_VERSION' ) ) {
|
|
return new WP_Error(
|
|
'pro_required',
|
|
sprintf(
|
|
/* translators: %s: field label */
|
|
__( '%s requires ChimpMatic Pro.', 'chimpmatic-lite' ),
|
|
$field_config['label']
|
|
),
|
|
array( 'status' => 403 )
|
|
);
|
|
}
|
|
|
|
$option_name = 'cf7_mch_' . $form_id;
|
|
$cf7_mch = get_option( $option_name, array() );
|
|
|
|
if ( ! is_array( $cf7_mch ) ) {
|
|
$cf7_mch = array();
|
|
}
|
|
|
|
$cf7_mch[ $field ] = $value ? 1 : 0;
|
|
|
|
update_option( $option_name, $cf7_mch );
|
|
|
|
return rest_ensure_response(
|
|
array(
|
|
'success' => true,
|
|
'form_id' => $form_id,
|
|
'field' => $field,
|
|
'value' => (bool) $value,
|
|
'message' => $value
|
|
? sprintf(
|
|
/* translators: %s: field label */
|
|
__( '%s enabled.', 'chimpmatic-lite' ),
|
|
$field_config['label']
|
|
)
|
|
: sprintf(
|
|
/* translators: %s: field label */
|
|
__( '%s disabled.', 'chimpmatic-lite' ),
|
|
$field_config['label']
|
|
),
|
|
)
|
|
);
|
|
}
|
|
|
|
private function __construct() {}
|
|
}
|