WP_REST_Server::READABLE, 'callback' => array( __CLASS__, 'elements' ), 'permission_callback' => array( __CLASS__, 'can_write' ), ) ); register_rest_route( self::NAMESPACE_V1, '/preview', array( 'methods' => WP_REST_Server::CREATABLE, 'callback' => array( __CLASS__, 'preview' ), 'permission_callback' => array( __CLASS__, 'can_edit_post' ), 'args' => array( 'post_id' => array( 'type' => 'integer', 'minimum' => 1, 'required' => true, ), 'content' => array( 'type' => 'string', 'required' => true, 'validate_callback' => array( __CLASS__, 'validate_content' ), ), ), ) ); } /** * Preview only for users who may edit exactly this post. * * @param WP_REST_Request $request Request. * @return bool|WP_Error */ public static function can_edit_post( $request ) { $post_id = (int) $request->get_param( 'post_id' ); if ( $post_id > 0 && get_post( $post_id ) && current_user_can( 'edit_post', $post_id ) ) { return true; } return new WP_Error( 'rest_forbidden', __( 'Sorry, you are not allowed to preview elements for this post.', '3task-toolbar-for-classic-editor' ), array( 'status' => rest_authorization_required_code() ) ); } /** * Text up to PREVIEW_MAX_BYTES bytes. * * @param mixed $value Value. * @param WP_REST_Request $request Request. * @param string $param Parameter name. * @return true|WP_Error */ public static function validate_content( $value, $request, $param ) { $valid = rest_validate_value_from_schema( $value, array( 'type' => 'string' ), $param ); if ( is_wp_error( $valid ) ) { return $valid; } if ( strlen( $value ) > self::PREVIEW_MAX_BYTES ) { /* translators: %d: number of bytes */ return new WP_Error( 'rest_invalid_param', sprintf( __( 'The preview takes at most %d bytes.', '3task-toolbar-for-classic-editor' ), self::PREVIEW_MAX_BYTES ), array( 'status' => 400 ) ); } return true; } /** * Renders the shortcode text like post content would. Users without unfiltered_html get the * same filtering WordPress applies when they save. * * @param WP_REST_Request $request Request. * @return WP_REST_Response */ public static function preview( $request ) { $content = (string) $request->get_param( 'content' ); if ( ! current_user_can( 'unfiltered_html' ) ) { $content = wp_kses_post( $content ); } $html = do_shortcode( (string) ThreeCE_Elements::number_nested( $content ) ); /** * Stylesheets the preview frame loads, ours first. Add-ons add the stylesheet of their elements. * * @since 1.0.2 * @param string[] $styles Stylesheet URLs. */ $styles = apply_filters( 'threece_preview_styles', array( THREECE_URL . 'assets/css/elements.css?ver=' . rawurlencode( THREECE_VERSION ) ) ); return rest_ensure_response( array( 'html' => $html, 'styles' => array_values( array_filter( array_map( 'esc_url_raw', (array) $styles ) ) ), ) ); } /** * Only users who write posts. * * @return bool|WP_Error */ public static function can_write() { if ( current_user_can( 'edit_posts' ) ) { return true; } return new WP_Error( 'rest_forbidden', __( 'Sorry, you are not allowed to insert elements.', '3task-toolbar-for-classic-editor' ), array( 'status' => rest_authorization_required_code() ) ); } /** * Our elements with their fields, other shortcodes by name only. * * @return WP_REST_Response */ public static function elements() { global $shortcode_tags; $other = array(); foreach ( (array) $shortcode_tags as $tag => $callback ) { // Our own and the ones that only show old Shortcodes Ultimate content are not offered for inserting. if ( is_string( $tag ) && 0 !== strpos( $tag, 'threece_' ) && array( 'ThreeCE_SU', 'render' ) !== $callback ) { $other[] = $tag; } } sort( $other ); return rest_ensure_response( array( 'groups' => ThreeCE_Elements::groups(), 'elements' => ThreeCE_Elements::catalog(), 'other' => $other, ) ); } }