843 lines
22 KiB
PHP
843 lines
22 KiB
PHP
<?php
|
|
/**
|
|
* REST endpoints for form integrations.
|
|
*
|
|
* Exposes registered provider metadata, connection management, and provider
|
|
* option lists to the form editor. Connection details stay server-side.
|
|
*
|
|
* API key storage strategy:
|
|
*
|
|
* Keys are stored as plain text in the options table, protected by the
|
|
* forms-manage capability on save/delete endpoints. We intentionally do not
|
|
* encrypt these keys because any encryption key must live on the same server.
|
|
* The real security boundary is capability access to these endpoints.
|
|
*
|
|
* @package GenerateBlocksPro
|
|
*/
|
|
|
|
if ( ! defined( 'ABSPATH' ) ) {
|
|
exit;
|
|
}
|
|
|
|
/**
|
|
* Form integration REST class.
|
|
*/
|
|
class GenerateBlocks_Pro_Form_Integration_Rest extends GenerateBlocks_Pro_Singleton {
|
|
|
|
/**
|
|
* Per-request cache for resolved connection settings.
|
|
*
|
|
* @var array<string, string>
|
|
*/
|
|
private static $connection_cache = [];
|
|
|
|
/**
|
|
* Initialize routes.
|
|
*/
|
|
public function init() {
|
|
add_action( 'rest_api_init', [ $this, 'register_routes' ] );
|
|
}
|
|
|
|
/**
|
|
* Register REST routes.
|
|
*/
|
|
public function register_routes() {
|
|
$namespace = 'generateblocks-pro/v1';
|
|
|
|
register_rest_route(
|
|
$namespace,
|
|
'/integrations/(?P<service>[a-z0-9_-]+)',
|
|
[
|
|
'methods' => WP_REST_Server::EDITABLE,
|
|
'callback' => [ $this, 'save_settings' ],
|
|
'permission_callback' => [ $this, 'admin_permission' ],
|
|
'args' => [
|
|
'service' => [
|
|
'required' => true,
|
|
'validate_callback' => [ $this, 'validate_service' ],
|
|
],
|
|
'settings' => [
|
|
'required' => false,
|
|
'type' => 'object',
|
|
],
|
|
],
|
|
]
|
|
);
|
|
|
|
register_rest_route(
|
|
$namespace,
|
|
'/integrations/(?P<service>[a-z0-9_-]+)',
|
|
[
|
|
'methods' => WP_REST_Server::DELETABLE,
|
|
'callback' => [ $this, 'delete_settings' ],
|
|
'permission_callback' => [ $this, 'admin_permission' ],
|
|
'args' => [
|
|
'service' => [
|
|
'required' => true,
|
|
'validate_callback' => [ $this, 'validate_service' ],
|
|
],
|
|
],
|
|
]
|
|
);
|
|
|
|
register_rest_route(
|
|
$namespace,
|
|
'/integrations/(?P<service>[a-z0-9_-]+)/test',
|
|
[
|
|
'methods' => WP_REST_Server::CREATABLE,
|
|
'callback' => [ $this, 'test_connection' ],
|
|
'permission_callback' => [ $this, 'admin_permission' ],
|
|
'args' => [
|
|
'service' => [
|
|
'required' => true,
|
|
'validate_callback' => [ $this, 'validate_service' ],
|
|
],
|
|
'settings' => [
|
|
'required' => false,
|
|
'type' => 'object',
|
|
],
|
|
],
|
|
]
|
|
);
|
|
|
|
register_rest_route(
|
|
$namespace,
|
|
'/integrations/(?P<service>[a-z0-9_-]+)/destinations',
|
|
[
|
|
'methods' => WP_REST_Server::READABLE,
|
|
'callback' => [ $this, 'fetch_destinations' ],
|
|
'permission_callback' => [ $this, 'admin_permission' ],
|
|
'args' => [
|
|
'service' => [
|
|
'required' => true,
|
|
'validate_callback' => [ $this, 'validate_service' ],
|
|
],
|
|
'nocache' => [
|
|
'required' => false,
|
|
'type' => 'boolean',
|
|
],
|
|
],
|
|
]
|
|
);
|
|
|
|
register_rest_route(
|
|
$namespace,
|
|
'/integrations/(?P<service>[a-z0-9_-]+)/secondary-destinations',
|
|
[
|
|
'methods' => WP_REST_Server::READABLE,
|
|
'callback' => [ $this, 'fetch_secondary_destinations' ],
|
|
'permission_callback' => [ $this, 'admin_permission' ],
|
|
'args' => [
|
|
'service' => [
|
|
'required' => true,
|
|
'validate_callback' => [ $this, 'validate_service' ],
|
|
],
|
|
'nocache' => [
|
|
'required' => false,
|
|
'type' => 'boolean',
|
|
],
|
|
],
|
|
]
|
|
);
|
|
|
|
register_rest_route(
|
|
$namespace,
|
|
'/integrations/(?P<service>[a-z0-9_-]+)/fields',
|
|
[
|
|
'methods' => WP_REST_Server::READABLE,
|
|
'callback' => [ $this, 'fetch_fields' ],
|
|
'permission_callback' => [ $this, 'admin_permission' ],
|
|
'args' => [
|
|
'service' => [
|
|
'required' => true,
|
|
'validate_callback' => [ $this, 'validate_service' ],
|
|
],
|
|
'nocache' => [
|
|
'required' => false,
|
|
'type' => 'boolean',
|
|
],
|
|
],
|
|
]
|
|
);
|
|
|
|
register_rest_route(
|
|
$namespace,
|
|
'/integrations',
|
|
[
|
|
'methods' => WP_REST_Server::READABLE,
|
|
'callback' => [ $this, 'get_integrations' ],
|
|
'permission_callback' => [ $this, 'admin_permission' ],
|
|
]
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Save provider connection settings.
|
|
*
|
|
* @param WP_REST_Request $request The request.
|
|
* @return WP_REST_Response
|
|
*/
|
|
public function save_settings( WP_REST_Request $request ) {
|
|
$service = $request->get_param( 'service' );
|
|
$settings = $this->sanitize_connection_settings(
|
|
$service,
|
|
$request->get_param( 'settings' )
|
|
);
|
|
$effective_settings = $this->get_effective_connection_settings( $service, $settings );
|
|
$validation = $this->validate_connection_settings( $service, $effective_settings );
|
|
|
|
if ( is_wp_error( $validation ) ) {
|
|
return new WP_REST_Response(
|
|
[
|
|
'success' => false,
|
|
'message' => $validation->get_error_message(),
|
|
],
|
|
200
|
|
);
|
|
}
|
|
|
|
$integrations = get_option( 'generateblocks_pro_form_integrations', [] );
|
|
$integrations = is_array( $integrations ) ? $integrations : [];
|
|
$current = isset( $integrations[ $service ] ) && is_array( $integrations[ $service ] )
|
|
? $integrations[ $service ]
|
|
: [];
|
|
$provider = GenerateBlocks_Pro_Form_Integration_Registry::get_provider( $service );
|
|
$connection = $provider['connection'] ?? [];
|
|
|
|
foreach ( $connection['fields'] ?? [] as $field ) {
|
|
$key = $field['key'];
|
|
|
|
if (
|
|
array_key_exists( $key, $settings )
|
|
&& ! in_array( $this->get_connection_field_source( $service, $field ), [ 'define', 'code' ], true )
|
|
) {
|
|
$current[ $key ] = $settings[ $key ];
|
|
}
|
|
}
|
|
|
|
$integrations[ $service ] = $current;
|
|
|
|
update_option( 'generateblocks_pro_form_integrations', $integrations, false );
|
|
|
|
self::clear_service_cache( $service );
|
|
|
|
return new WP_REST_Response( [ 'success' => true ], 200 );
|
|
}
|
|
|
|
/**
|
|
* Delete provider connection settings.
|
|
*
|
|
* @param WP_REST_Request $request The request.
|
|
* @return WP_REST_Response
|
|
*/
|
|
public function delete_settings( WP_REST_Request $request ) {
|
|
$service = $request->get_param( 'service' );
|
|
$integrations = get_option( 'generateblocks_pro_form_integrations', [] );
|
|
$integrations = is_array( $integrations ) ? $integrations : [];
|
|
|
|
unset( $integrations[ $service ] );
|
|
|
|
update_option( 'generateblocks_pro_form_integrations', $integrations, false );
|
|
|
|
self::clear_service_cache( $service );
|
|
|
|
return new WP_REST_Response( [ 'success' => true ], 200 );
|
|
}
|
|
|
|
/**
|
|
* Test a service connection with provided settings.
|
|
*
|
|
* @param WP_REST_Request $request The request.
|
|
* @return WP_REST_Response
|
|
*/
|
|
public function test_connection( WP_REST_Request $request ) {
|
|
$service = $request->get_param( 'service' );
|
|
$settings = $this->sanitize_connection_settings(
|
|
$service,
|
|
$request->get_param( 'settings' )
|
|
);
|
|
$effective_settings = $this->get_effective_connection_settings( $service, $settings );
|
|
$validation = $this->validate_connection_settings( $service, $effective_settings, true );
|
|
|
|
if ( is_wp_error( $validation ) ) {
|
|
return new WP_REST_Response(
|
|
[
|
|
'success' => false,
|
|
'message' => $validation->get_error_message(),
|
|
],
|
|
200
|
|
);
|
|
}
|
|
|
|
$result = $this->test_service( $service, $effective_settings );
|
|
|
|
if ( is_wp_error( $result ) ) {
|
|
return new WP_REST_Response(
|
|
[
|
|
'success' => false,
|
|
'message' => $result->get_error_message(),
|
|
],
|
|
200
|
|
);
|
|
}
|
|
|
|
return new WP_REST_Response(
|
|
[
|
|
'success' => true,
|
|
'message' => __( 'Connected successfully.', 'generateblocks-pro' ),
|
|
],
|
|
200
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Fetch primary destination options for a provider.
|
|
*
|
|
* @param WP_REST_Request $request The request.
|
|
* @return WP_REST_Response
|
|
*/
|
|
public function fetch_destinations( WP_REST_Request $request ) {
|
|
return $this->fetch_provider_options( $request, 'destination' );
|
|
}
|
|
|
|
/**
|
|
* Fetch secondary destination options for a provider.
|
|
*
|
|
* @param WP_REST_Request $request The request.
|
|
* @return WP_REST_Response
|
|
*/
|
|
public function fetch_secondary_destinations( WP_REST_Request $request ) {
|
|
return $this->fetch_provider_options( $request, 'secondary_destination' );
|
|
}
|
|
|
|
/**
|
|
* Fetch field-map options for a provider.
|
|
*
|
|
* @param WP_REST_Request $request The request.
|
|
* @return WP_REST_Response
|
|
*/
|
|
public function fetch_fields( WP_REST_Request $request ) {
|
|
return $this->fetch_provider_options( $request, 'field_map' );
|
|
}
|
|
|
|
/**
|
|
* Fetch options from a provider callback.
|
|
*
|
|
* @param WP_REST_Request $request The request.
|
|
* @param string $key Provider option key.
|
|
* @return WP_REST_Response
|
|
*/
|
|
private function fetch_provider_options( WP_REST_Request $request, $key ) {
|
|
$service = $request->get_param( 'service' );
|
|
$provider = GenerateBlocks_Pro_Form_Integration_Registry::get_provider( $service );
|
|
$config = $provider[ $key ] ?? [];
|
|
$callback = $config['options_callback'] ?? null;
|
|
|
|
if ( ! is_callable( $callback ) ) {
|
|
return new WP_REST_Response(
|
|
[
|
|
'success' => true,
|
|
'options' => [],
|
|
],
|
|
200
|
|
);
|
|
}
|
|
|
|
$connection_ready = $this->connection_ready_for_options( $service );
|
|
|
|
if ( is_wp_error( $connection_ready ) ) {
|
|
return new WP_REST_Response(
|
|
[
|
|
'success' => false,
|
|
'message' => $connection_ready->get_error_message(),
|
|
],
|
|
200
|
|
);
|
|
}
|
|
|
|
if ( ! $connection_ready ) {
|
|
return new WP_REST_Response(
|
|
[
|
|
'success' => false,
|
|
'message' => __( 'Integration is not connected.', 'generateblocks-pro' ),
|
|
],
|
|
200
|
|
);
|
|
}
|
|
|
|
$settings = $this->get_option_request_settings( $request, $service );
|
|
$cache_key = 'gb_form_options_' . $service . '_' . $key . '_' . md5(
|
|
wp_json_encode( [ self::connection_cache_hash( $service ), $settings ] )
|
|
);
|
|
$nocache = (bool) $request->get_param( 'nocache' );
|
|
$cached = $nocache ? false : get_transient( $cache_key );
|
|
|
|
if ( false !== $cached ) {
|
|
return new WP_REST_Response(
|
|
[
|
|
'success' => true,
|
|
'options' => $cached,
|
|
],
|
|
200
|
|
);
|
|
}
|
|
|
|
$options = call_user_func( $callback, $settings, $request, $service );
|
|
|
|
if ( is_wp_error( $options ) ) {
|
|
return new WP_REST_Response(
|
|
[
|
|
'success' => false,
|
|
'message' => $options->get_error_message(),
|
|
],
|
|
200
|
|
);
|
|
}
|
|
|
|
$options = GenerateBlocks_Pro_Form_Integration_Registry::normalize_options( $options );
|
|
|
|
set_transient( $cache_key, $options, 5 * MINUTE_IN_SECONDS );
|
|
|
|
return new WP_REST_Response(
|
|
[
|
|
'success' => true,
|
|
'options' => $options,
|
|
],
|
|
200
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Get public integration definitions and connection state.
|
|
*
|
|
* @return WP_REST_Response
|
|
*/
|
|
public function get_integrations() {
|
|
$connected = [];
|
|
|
|
foreach ( GenerateBlocks_Pro_Form_Integration_Registry::get_all() as $service => $provider ) {
|
|
$connected[ $service ] = $this->get_connection_state( $service, $provider );
|
|
}
|
|
|
|
return new WP_REST_Response(
|
|
[
|
|
'success' => true,
|
|
'integrations' => GenerateBlocks_Pro_Form_Integration_Registry::get_public_definitions(),
|
|
'connected' => $connected,
|
|
],
|
|
200
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Get the API key for a service.
|
|
*
|
|
* @param string $service The service name.
|
|
* @return string The API key, or empty string if not configured.
|
|
*/
|
|
public static function get_api_key_for( $service ) {
|
|
return self::get_connection_setting_for( $service, 'api_key' );
|
|
}
|
|
|
|
/**
|
|
* Get the site key for a service.
|
|
*
|
|
* @param string $service The service name.
|
|
* @return string The site key, or empty string if not configured.
|
|
*/
|
|
public static function get_site_key_for( $service ) {
|
|
return self::get_connection_setting_for( $service, 'site_key' );
|
|
}
|
|
|
|
/**
|
|
* Get a connection setting for a service.
|
|
*
|
|
* Priority chain:
|
|
* 1. wp-config.php define registered on the field.
|
|
* 2. In-memory registered key for api_key.
|
|
* 3. Database option saved via admin UI.
|
|
*
|
|
* @param string $service Service ID.
|
|
* @param string $key Setting key.
|
|
* @return string
|
|
*/
|
|
public static function get_connection_setting_for( $service, $key ) {
|
|
$service = sanitize_key( $service );
|
|
$key = preg_replace( '/[^A-Za-z0-9_]/', '', (string) $key );
|
|
$cache_key = $service . ':' . $key;
|
|
|
|
if ( array_key_exists( $cache_key, self::$connection_cache ) ) {
|
|
return self::$connection_cache[ $cache_key ];
|
|
}
|
|
|
|
$value = self::resolve_connection_setting( $service, $key );
|
|
|
|
self::$connection_cache[ $cache_key ] = $value;
|
|
|
|
return $value;
|
|
}
|
|
|
|
/**
|
|
* Resolve a connection setting without cache.
|
|
*
|
|
* @param string $service Service ID.
|
|
* @param string $key Setting key.
|
|
* @return string
|
|
*/
|
|
private static function resolve_connection_setting( $service, $key ) {
|
|
$provider = GenerateBlocks_Pro_Form_Integration_Registry::get_provider( $service );
|
|
$connection = $provider['connection'] ?? [];
|
|
$define = '';
|
|
|
|
foreach ( $connection['fields'] ?? [] as $field ) {
|
|
if ( $field['key'] === $key ) {
|
|
$define = $field['define'];
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( $define && defined( $define ) ) {
|
|
$value = (string) constant( $define );
|
|
|
|
if ( '' !== trim( $value ) ) {
|
|
return $value;
|
|
}
|
|
}
|
|
|
|
if ( 'api_key' === $key ) {
|
|
$registered = GenerateBlocks_Pro_Form_Integration_Registry::get( $service );
|
|
|
|
if ( ! empty( $registered ) ) {
|
|
return (string) $registered;
|
|
}
|
|
}
|
|
|
|
$integrations = get_option( 'generateblocks_pro_form_integrations', [] );
|
|
$integrations = is_array( $integrations ) ? $integrations : [];
|
|
|
|
return isset( $integrations[ $service ][ $key ] )
|
|
? (string) $integrations[ $service ][ $key ]
|
|
: '';
|
|
}
|
|
|
|
/**
|
|
* Sanitize connection settings against registered connection fields.
|
|
*
|
|
* @param string $service Service ID.
|
|
* @param array $settings Raw settings.
|
|
* @return array
|
|
*/
|
|
private function sanitize_connection_settings( $service, $settings ) {
|
|
if ( ! is_array( $settings ) ) {
|
|
return [];
|
|
}
|
|
|
|
$provider = GenerateBlocks_Pro_Form_Integration_Registry::get_provider( $service );
|
|
$fields = $provider['connection']['fields'] ?? [];
|
|
$out = [];
|
|
|
|
foreach ( $fields as $field ) {
|
|
$key = $field['key'];
|
|
|
|
if ( isset( $settings[ $key ] ) && ! is_array( $settings[ $key ] ) && ! is_object( $settings[ $key ] ) ) {
|
|
$value = sanitize_text_field( (string) $settings[ $key ] );
|
|
|
|
if ( '' !== trim( $value ) ) {
|
|
$out[ $key ] = $value;
|
|
}
|
|
}
|
|
}
|
|
|
|
return $out;
|
|
}
|
|
|
|
/**
|
|
* Merge submitted settings with currently resolved settings.
|
|
*
|
|
* Blank modal fields mean "leave the existing code/DB value alone".
|
|
*
|
|
* @param string $service Service ID.
|
|
* @param array $settings Sanitized submitted settings.
|
|
* @return array
|
|
*/
|
|
private function get_effective_connection_settings( $service, $settings ) {
|
|
$provider = GenerateBlocks_Pro_Form_Integration_Registry::get_provider( $service );
|
|
$fields = $provider['connection']['fields'] ?? [];
|
|
$out = [];
|
|
|
|
foreach ( $fields as $field ) {
|
|
$key = $field['key'];
|
|
|
|
$out[ $key ] = array_key_exists( $key, $settings )
|
|
? $settings[ $key ]
|
|
: self::get_connection_setting_for( $service, $key );
|
|
}
|
|
|
|
return $out;
|
|
}
|
|
|
|
/**
|
|
* Validate sanitized connection settings against required fields.
|
|
*
|
|
* @param string $service Service ID.
|
|
* @param array $settings Sanitized settings.
|
|
* @param bool $for_test Whether this validation is for a connection test.
|
|
* @return true|WP_Error
|
|
*/
|
|
private function validate_connection_settings( $service, $settings, $for_test = false ) {
|
|
$provider = GenerateBlocks_Pro_Form_Integration_Registry::get_provider( $service );
|
|
$fields = $provider['connection']['fields'] ?? [];
|
|
|
|
foreach ( $fields as $field ) {
|
|
$required_key = $for_test ? 'test_required' : 'required';
|
|
|
|
if ( empty( $field[ $required_key ] ) ) {
|
|
continue;
|
|
}
|
|
|
|
$key = $field['key'];
|
|
$value = isset( $settings[ $key ] ) ? trim( (string) $settings[ $key ] ) : '';
|
|
|
|
if ( '' === $value ) {
|
|
return new WP_Error(
|
|
'missing_connection_setting',
|
|
sprintf(
|
|
/* translators: %s: connection setting label */
|
|
__( '%s is required.', 'generateblocks-pro' ),
|
|
$field['label']
|
|
)
|
|
);
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Build sanitized settings from option route query params.
|
|
*
|
|
* @param WP_REST_Request $request The request.
|
|
* @param string $service Service ID.
|
|
* @return array
|
|
*/
|
|
private function get_option_request_settings( WP_REST_Request $request, $service ) {
|
|
$provider = GenerateBlocks_Pro_Form_Integration_Registry::get_provider( $service );
|
|
$params = $request->get_params();
|
|
$allowed = [
|
|
'destinationId' => true,
|
|
'secondaryDestinationId' => true,
|
|
];
|
|
$out = [];
|
|
|
|
foreach ( $provider['connection']['fields'] ?? [] as $field ) {
|
|
$allowed[ $field['key'] ] = true;
|
|
}
|
|
|
|
foreach ( $params as $key => $value ) {
|
|
$key = (string) $key;
|
|
|
|
if ( ! isset( $allowed[ $key ] ) || is_array( $value ) || is_object( $value ) ) {
|
|
continue;
|
|
}
|
|
|
|
$out[ $key ] = sanitize_text_field( (string) $value );
|
|
}
|
|
|
|
ksort( $out );
|
|
|
|
return $out;
|
|
}
|
|
|
|
/**
|
|
* Test a specific provider connection.
|
|
*
|
|
* @param string $service Service ID.
|
|
* @param array $settings Connection settings.
|
|
* @return true|WP_Error
|
|
*/
|
|
private function test_service( $service, $settings ) {
|
|
$provider = GenerateBlocks_Pro_Form_Integration_Registry::get_provider( $service );
|
|
$callback = $provider['connection']['test_callback'] ?? null;
|
|
|
|
if ( ! is_callable( $callback ) ) {
|
|
return true;
|
|
}
|
|
|
|
return call_user_func( $callback, $settings, $service );
|
|
}
|
|
|
|
/**
|
|
* Determine whether a provider is connected enough to fetch options.
|
|
*
|
|
* @param string $service Service ID.
|
|
* @return bool|WP_Error
|
|
*/
|
|
private function connection_ready_for_options( $service ) {
|
|
$provider = GenerateBlocks_Pro_Form_Integration_Registry::get_provider( $service );
|
|
$connection = $provider['connection'] ?? [];
|
|
|
|
if ( empty( $connection ) || 'none' === $connection['type'] ) {
|
|
return true;
|
|
}
|
|
|
|
if ( is_callable( $connection['connected_callback'] ) ) {
|
|
return call_user_func( $connection['connected_callback'], $service );
|
|
}
|
|
|
|
foreach ( $connection['fields'] ?? [] as $field ) {
|
|
if ( ! empty( $field['required'] ) && '' === self::get_connection_setting_for( $service, $field['key'] ) ) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Get connection state for the editor.
|
|
*
|
|
* @param string $service Service ID.
|
|
* @param array $provider Provider definition.
|
|
* @return array
|
|
*/
|
|
private function get_connection_state( $service, $provider ) {
|
|
$connection = $provider['connection'] ?? [];
|
|
$callback_result = null;
|
|
$source = '';
|
|
$fields = [];
|
|
$public_fields = [];
|
|
$connected = true;
|
|
|
|
if ( empty( $connection ) || 'none' === $connection['type'] ) {
|
|
return [
|
|
'connected' => true,
|
|
'source' => '',
|
|
'fields' => [],
|
|
];
|
|
}
|
|
|
|
if ( is_callable( $connection['connected_callback'] ) ) {
|
|
$callback_result = call_user_func( $connection['connected_callback'], $service );
|
|
$connected = ! is_wp_error( $callback_result ) && (bool) $callback_result;
|
|
}
|
|
|
|
foreach ( $connection['fields'] ?? [] as $field ) {
|
|
$value = self::get_connection_setting_for( $service, $field['key'] );
|
|
$field_key = $field['key'];
|
|
$field_state = [
|
|
'configured' => '' !== $value,
|
|
'source' => $this->get_connection_field_source( $service, $field ),
|
|
];
|
|
|
|
$fields[ $field_key ] = $field_state;
|
|
|
|
if ( ! empty( $field['public'] ) && '' !== $value ) {
|
|
$public_fields[ $field_key ] = $value;
|
|
}
|
|
|
|
if ( '' === $source && '' !== $field_state['source'] ) {
|
|
$source = $field_state['source'];
|
|
}
|
|
|
|
if ( ! empty( $field['required'] ) && '' === $value ) {
|
|
$connected = false;
|
|
}
|
|
}
|
|
|
|
$state = [
|
|
'connected' => $connected,
|
|
'source' => $source,
|
|
'fields' => $fields,
|
|
];
|
|
|
|
if ( is_wp_error( $callback_result ) ) {
|
|
$state['message'] = $callback_result->get_error_message();
|
|
}
|
|
|
|
if ( ! empty( $public_fields ) ) {
|
|
$state['publicFields'] = $public_fields;
|
|
}
|
|
|
|
return $state;
|
|
}
|
|
|
|
/**
|
|
* Get the source for a connection field.
|
|
*
|
|
* @param string $service Service ID.
|
|
* @param array $field Connection field.
|
|
* @return string
|
|
*/
|
|
private function get_connection_field_source( $service, $field ) {
|
|
$define = $field['define'];
|
|
|
|
if ( $define && defined( $define ) && '' !== trim( (string) constant( $define ) ) ) {
|
|
return 'define';
|
|
}
|
|
|
|
if ( 'api_key' === $field['key'] && ! empty( GenerateBlocks_Pro_Form_Integration_Registry::get( $service ) ) ) {
|
|
return 'code';
|
|
}
|
|
|
|
$integrations = get_option( 'generateblocks_pro_form_integrations', [] );
|
|
$integrations = is_array( $integrations ) ? $integrations : [];
|
|
|
|
if ( ! empty( $integrations[ $service ][ $field['key'] ] ) ) {
|
|
return 'db';
|
|
}
|
|
|
|
return '';
|
|
}
|
|
|
|
/**
|
|
* Build a hash of current connection settings for option-cache keys.
|
|
*
|
|
* @param string $service Service ID.
|
|
* @return string
|
|
*/
|
|
private static function connection_cache_hash( $service ) {
|
|
$provider = GenerateBlocks_Pro_Form_Integration_Registry::get_provider( $service );
|
|
$values = [];
|
|
|
|
foreach ( $provider['connection']['fields'] ?? [] as $field ) {
|
|
$values[ $field['key'] ] = self::get_connection_setting_for( $service, $field['key'] );
|
|
}
|
|
|
|
return md5( wp_json_encode( $values ) );
|
|
}
|
|
|
|
/**
|
|
* Clear the per-request connection cache for a service.
|
|
*
|
|
* @param string $service Service ID.
|
|
*/
|
|
public static function clear_service_cache( $service ) {
|
|
$service = sanitize_key( $service );
|
|
|
|
foreach ( array_keys( self::$connection_cache ) as $key ) {
|
|
if ( 0 === strpos( $key, $service . ':' ) ) {
|
|
unset( self::$connection_cache[ $key ] );
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Validate that the service parameter is registered.
|
|
*
|
|
* @param string $value The service name.
|
|
* @return bool
|
|
*/
|
|
public function validate_service( $value ) {
|
|
return (bool) GenerateBlocks_Pro_Form_Integration_Registry::get_provider( $value );
|
|
}
|
|
|
|
/**
|
|
* Permission check for all integration routes.
|
|
*
|
|
* @return bool
|
|
*/
|
|
public function admin_permission() {
|
|
return current_user_can( 'manage_options' );
|
|
}
|
|
}
|