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() {} }