diff --git a/core/modules-manager.php b/core/modules-manager.php index e1aa7fc67045..cc3bc4b2cbee 100644 --- a/core/modules-manager.php +++ b/core/modules-manager.php @@ -85,6 +85,7 @@ public function get_modules_names() { 'page-templates', 'gutenberg', 'wp-cli', + 'wp-rest', 'safe-mode', 'ai', 'notifications', diff --git a/modules/ai/module.php b/modules/ai/module.php index e7bc58aedfe8..6c7a1f98c0c4 100644 --- a/modules/ai/module.php +++ b/modules/ai/module.php @@ -37,6 +37,8 @@ public function get_name() { public function __construct() { parent::__construct(); + ( new SitePlannerConnect\Module() ); + if ( is_admin() ) { ( new Preferences() )->register(); } diff --git a/modules/ai/site-planner-connect/module.php b/modules/ai/site-planner-connect/module.php new file mode 100644 index 000000000000..d616bf26f46b --- /dev/null +++ b/modules/ai/site-planner-connect/module.php @@ -0,0 +1,51 @@ +get_route() === '/wp/v2/users/me/application-passwords' && is_user_logged_in() ) { + $user = wp_get_current_user(); + $response->data['user_login'] = $user->user_login; + } + return $response; + }, 10, 3); + } + + public function on_rest_init(): void { + ( new WpRestApi() )->register(); + } + + public function register_menu_page() { + add_submenu_page( + null, // Hidden page + 'App Password Generator', + 'App Password', + 'manage_options', + 'site-planner-password-generator', + [ $this, 'render_menu_page' ] + ); + } + + public function render_menu_page() { + $root_url = 'https://planner.elementor.com'; + $root_url = 'http://localhost:4000'; + + ob_start(); + require_once __DIR__ . '/view.php'; + $content = ob_get_clean(); + $vars = [ + '%root_url%' => $root_url, + '%domain%' => isset( $_SERVER['HTTP_HOST'] ) ? sanitize_key( $_SERVER['HTTP_HOST'] ) : '', + ]; + + // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + echo strtr( $content, $vars ); + } +} diff --git a/modules/ai/site-planner-connect/view.php b/modules/ai/site-planner-connect/view.php new file mode 100644 index 000000000000..b2a0cfee9b8a --- /dev/null +++ b/modules/ai/site-planner-connect/view.php @@ -0,0 +1,170 @@ + + + + + + + diff --git a/modules/ai/site-planner-connect/wp-rest-api.php b/modules/ai/site-planner-connect/wp-rest-api.php new file mode 100644 index 000000000000..866ecf223dd0 --- /dev/null +++ b/modules/ai/site-planner-connect/wp-rest-api.php @@ -0,0 +1,33 @@ + \WP_REST_Server::READABLE, + 'permission_callback' => function () { + return current_user_can( 'manage_options' ); + }, + 'callback' => function ( $request ) { + try { + wp_send_json_success( [ + 'SitePlannerConnect' => true, + ] ); + } catch ( \Exception $e ) { + wp_send_json_error( [ + 'message' => $e->getMessage(), + ] ); + } + }, + ], + ] ); + } +} diff --git a/modules/wp-rest/classes/elementor-post-meta.php b/modules/wp-rest/classes/elementor-post-meta.php new file mode 100644 index 000000000000..76efbbb960e7 --- /dev/null +++ b/modules/wp-rest/classes/elementor-post-meta.php @@ -0,0 +1,111 @@ + 'string', + 'label' => 'Elementor edit mode', + 'description' => 'Elementor edit mode, `builder` is required for Elementor editing', + 'default' => 'builder', + 'single' => true, + 'show_in_rest' => true, + 'auth_callback' => [ $this, 'check_edit_permission' ], + ]); + + $document_types = Plugin::$instance->documents->get_document_types(); + + register_meta($post_type, '_elementor_template_type', [ + 'type' => 'string', + 'label' => 'Elementor template type', + 'single' => true, + 'show_in_rest' => [ + 'schema' => [ + 'description' => 'Elementor document type', + 'type' => 'string', + 'enum' => array_keys( $document_types ), + 'context' => [ 'view', 'edit' ], + ], + ], + 'auth_callback' => [ $this, 'check_edit_permission' ], + ]); + + register_meta($post_type, '_elementor_data', [ + 'single' => true, + 'show_in_rest' => [ + 'schema' => [ + 'description' => 'Elementor JSON as a string', + 'type' => 'string', + 'context' => [ 'view', 'edit' ], + ], + ], + 'auth_callback' => [ $this, 'check_edit_permission' ], + ]); + + register_meta($post_type, '_elementor_page_settings', [ + 'type' => 'object', + 'title' => 'Elementor page settings', + 'description' => 'Elementor page level settings', + 'single' => true, + 'show_in_rest' => [ + 'schema' => [ + 'description' => 'Elementor page level settings', + 'type' => 'object', + 'properties' => [ + 'hide_title' => [ + 'type' => 'string', + 'enum' => [ 'yes', 'no' ], + ], + ], + 'additionalProperties' => true, + 'context' => [ 'view', 'edit' ], + ], + ], + 'auth_callback' => [ $this, 'check_edit_permission' ], + ]); + + if ( Utils::has_pro() ) { + register_meta($post_type, '_elementor_conditions', [ + 'type' => 'object', + 'title' => 'Elementor conditions', + 'description' => 'Elementor conditions', + 'single' => true, + 'show_in_rest' => [ + 'schema' => [ + 'description' => 'Elementor conditions', + 'type' => 'array', + 'additionalProperties' => true, + 'context' => [ 'view', 'edit' ], + ], + ], + 'auth_callback' => [ $this, 'check_edit_permission' ], + ]); + } + } + } + + /** + * Check if current user has permission to edit the specific post with elementor + * + * @param bool $allowed Whether the user can add the post meta. Default false. + * @param string $meta_key The meta key. + * @param int $post_id Post ID. + * @return bool + * @since 3.27.0 + */ + public function check_edit_permission( bool $allowed, string $meta_key, int $post_id ) : bool { + $document = Plugin::$instance->documents->get( $post_id ); + + return $document && $document->is_built_with_elementor() && $document->is_editable_by_current_user(); + } +} diff --git a/modules/wp-rest/classes/elementor-settings.php b/modules/wp-rest/classes/elementor-settings.php new file mode 100644 index 000000000000..be3ff1794904 --- /dev/null +++ b/modules/wp-rest/classes/elementor-settings.php @@ -0,0 +1,84 @@ +[\w_-]+)', [ + [ + 'methods' => WP_REST_Server::READABLE, + 'permission_callback' => function () { + return current_user_can( 'manage_options' ); + }, + 'sanitize_callback' => function ( $param ) { + return esc_attr( $param ); + }, + 'validate_callback' => function ( $request ) { + /** @var WP_REST_Request $request */ + $params = $request->get_params(); + + return 0 === strpos( $params['key'], 'elementor' ); + }, + 'callback' => function ( $request ) { + try { + $key = $request->get_param( 'key' ); + $current_value = get_option( $key ); + + wp_send_json_success([ + // Nest in order to allow extending the response with more details + 'value' => $current_value, + ]); + } catch ( Exception $e ) { + wp_send_json_error([ + 'message' => $e->getMessage(), + ]); + } + }, + ], + ]); + + register_rest_route('elementor/v1', '/settings/(?P[\w_-]+)', [ + [ + 'methods' => WP_REST_Server::EDITABLE, + 'permission_callback' => function () { + return current_user_can( 'manage_options' ); + }, + 'sanitize_callback' => function ( $param ) { + return esc_attr( $param ); + }, + 'validate_callback' => function ( $request ) { + /** @var WP_REST_Request $request */ + $params = $request->get_params(); + return 0 === strpos( $params['key'], 'elementor' ) && isset( $params['value'] ); + }, + 'callback' => function ( $request ) { + $key = $request->get_param( 'key' ); + $new_value = $request->get_param( 'value' ); + $current_value = get_option( $key ); + + if ( $new_value === $current_value ) { + wp_send_json_success(); + } + + $success = update_option( $key, $new_value ); + if ( $success ) { + wp_send_json_success([ + 'message' => 'Setting updated successfully.', + ]); + } else { + wp_send_json_error([ + 'message' => 'Failed to update setting.', + ]); + } + }, + ], + ]); + } +} diff --git a/modules/wp-rest/classes/elementor-user-meta.php b/modules/wp-rest/classes/elementor-user-meta.php new file mode 100644 index 000000000000..d56ac3598b00 --- /dev/null +++ b/modules/wp-rest/classes/elementor-user-meta.php @@ -0,0 +1,45 @@ + true, + 'show_in_rest' => [ + 'schema' => [ + 'description' => 'State of modals and confirm dialogs the user has seen', + 'type' => 'object', + 'properties' => [ + 'ai_get_started' => [ + 'type' => 'boolean', + ], + ], + 'context' => [ 'view', 'edit' ], + ], + ], + 'sanitize_callback' => function ( $value, $key, $type ) { + $request = isset( $_SERVER['REQUEST_METHOD'] ) ? sanitize_key( $_SERVER['REQUEST_METHOD'] ) : ''; + + // on patch request, we need to merge the existing data with the new data + if ( 'PATCH' === $request ) { + $existing = get_metadata( $type, get_current_user_id(), $key, true ); + + if ( is_array( $existing ) && is_array( $value ) ) { + return array_merge( $existing, $value ); + } + + return $value; + } + + return $value; + }, + 'auth_callback' => function () { + return current_user_can( 'edit_users' ); + }, + ] ); + } +} diff --git a/modules/wp-rest/module.php b/modules/wp-rest/module.php new file mode 100644 index 000000000000..6e136d14a37a --- /dev/null +++ b/modules/wp-rest/module.php @@ -0,0 +1,35 @@ +register(); + ( new ElementorSettings() )->register(); + ( new ElementorUserMeta() )->register(); + } +}