From 455145558b7d2d528a6091ae5109fc87ed1cd54b Mon Sep 17 00:00:00 2001 From: Matth_eu Date: Wed, 2 Mar 2016 13:00:45 +0000 Subject: [PATCH 01/13] Use WP Rest API infrastructure for previews --- inc/class-shortcode-ui.php | 102 +++-- inc/shortcode-ui.php | 421 +++++++++++++++++++ js-tests/build/specs.js | 103 +---- js-tests/src/utils/mceViewConstructorSpec.js | 59 --- js/build/shortcode-ui.js | 44 +- js/src/utils/fetcher.js | 11 +- js/src/utils/shortcode-view-constructor.js | 33 -- js/src/views/wip-shortcode.js | 39 ++ 8 files changed, 562 insertions(+), 250 deletions(-) create mode 100644 inc/shortcode-ui.php create mode 100644 js/src/views/wip-shortcode.js diff --git a/inc/class-shortcode-ui.php b/inc/class-shortcode-ui.php index b761eb2e..e33dbb32 100644 --- a/inc/class-shortcode-ui.php +++ b/inc/class-shortcode-ui.php @@ -68,9 +68,34 @@ private function setup_actions() { add_action( 'admin_enqueue_scripts', array( $this, 'action_admin_enqueue_scripts' ) ); add_action( 'wp_enqueue_editor', array( $this, 'action_wp_enqueue_editor' ) ); add_action( 'wp_ajax_bulk_do_shortcode', array( $this, 'handle_ajax_bulk_do_shortcode' ) ); + add_action( 'rest_api_init', array( $this, 'action_rest_api_init' ) ); add_filter( 'wp_editor_settings', array( $this, 'filter_wp_editor_settings' ), 10, 2 ); } + public function action_rest_api_init() { + + register_rest_route( 'shortcode-ui/v1', 'preview', array( + 'methods' => 'POST', + 'callback' => array( $this, 'handle_shortcode_preview' ), + 'args' => array( + 'query' => array( + 'sanitize_callback' => array( $this, 'sanitize_rest_arg_arg_query' ), + ), + ) + ) ); + + register_rest_route( 'shortcode-ui/v1', 'preview/bulk', array( + 'methods' => 'POST', + 'callback' => array( $this, 'handle_shortcode_preview_bulk' ), + 'args' => array( + 'queries' => array( + 'sanitize_callback' => array( $this, 'sanitize_rest_arg_arg_queries' ), + ), + ), + ) ); + + } + /** * When a WP_Editor is initialized on a page, call the 'register_shortcode_ui' action. * @@ -244,9 +269,13 @@ public function enqueue() { 'insert_content_label' => __( 'Insert Content', 'shortcode-ui' ), ), 'nonces' => array( - 'preview' => wp_create_nonce( 'shortcode-ui-preview' ), + 'wp_rest' => wp_create_nonce( 'wp_rest' ), 'thumbnailImage' => wp_create_nonce( 'shortcode-ui-get-thumbnail-image' ), ), + 'urls' => array( + 'preview' => home_url( '/wp-json/shortcode-ui/v1/preview' ), + 'bulkPreview' => home_url( '/wp-json/shortcode-ui/v1/preview/bulk' ), + ), ) ); // add templates to the footer, instead of where we're at now @@ -336,7 +365,7 @@ private function render_shortcode_for_preview( $shortcode, $post_id = null ) { } if ( ! current_user_can( 'edit_post', $post_id ) ) { - return esc_html__( "Something's rotten in the state of Denmark", 'shortcode-ui' ); + return $shortcode; } if ( ! empty( $post_id ) ) { @@ -366,38 +395,63 @@ private function render_shortcode_for_preview( $shortcode, $post_id = null ) { } /** - * Get a bunch of shortcodes to render in MCE preview. + * Get a preview for a single shortcode to render in MCE preview. */ - public function handle_ajax_bulk_do_shortcode() { - - if ( is_array( $_POST['queries'] ) ) { + public function handle_shortcode_preview( WP_REST_Request $request ) { + return $this->get_shortcode_preview( $request->get_param('query') ); + } - $responses = array(); + /** + * Get a bunch of shortcodes to render in MCE preview. + */ + public function handle_shortcode_preview_bulk( WP_REST_Request $request ) { - foreach ( $_POST['queries'] as $posted_query ) { - - // Don't sanitize shortcodes — can contain HTML kses doesn't allow (e.g. sourcecode shortcode) - if ( ! empty( $posted_query['shortcode'] ) ) { - $shortcode = stripslashes( $posted_query['shortcode'] ); - } else { - $shortcode = null; - } - if ( isset( $posted_query['post_id'] ) ) { - $post_id = intval( $posted_query['post_id'] ); - } else { - $post_id = null; - } + $queries = $request->get_param('queries'); + $responses = array(); + if ( is_array( $queries ) ) { + foreach ( $queries as $posted_query ) { $responses[ $posted_query['counter'] ] = array( - 'query' => $posted_query, - 'response' => $this->render_shortcode_for_preview( $shortcode, $post_id ), + 'query' => $posted_query, + 'response' => $this->render_shortcode_for_preview( $posted_query['shortcode'], $posted_query['post_id'] ), ); } + } + + return array_filter( $responses ); + + } + + public function sanitize_rest_arg_arg_query( $dirty_args ) { + + $clean_args = array( + 'shortcode' => null, + 'post_id' => null, + ); + + // Don't sanitize shortcodes — can contain HTML kses doesn't allow (e.g. sourcecode shortcode) + if ( ! empty( $dirty_args['shortcode'] ) ) { + $clean_args['shortcode'] = stripslashes( $dirty_args['shortcode'] ); + } + + if ( isset( $dirty_args['post_id'] ) ) { + $clean_args['post_id'] = intval( $dirty_args['post_id'] ); + } + + if ( isset( $dirty_args['nonce'] ) ) { + $clean_args['nonce'] = sanitize_text_field( $dirty_args['nonce'] ); + } - wp_send_json_success( $responses ); - exit; + if ( isset( $dirty_args['counter'] ) ) { + $clean_args['counter'] = intval( $dirty_args['counter'] ); } + return $clean_args; + + } + + public function sanitize_rest_arg_arg_queries( $arg ) { + return array_map( array( $this, 'sanitize_rest_arg_arg_query' ), (array) $arg ); } /** diff --git a/inc/shortcode-ui.php b/inc/shortcode-ui.php new file mode 100644 index 00000000..a4ca7f5a --- /dev/null +++ b/inc/shortcode-ui.php @@ -0,0 +1,421 @@ + esc_html__( 'Inner Content', 'shortcode-ui' ), + 'description' => '', + ); + } + + if ( ! isset( $args['attrs'] ) ) { + $args['attrs'] = array(); + } + + $args['shortcode_tag'] = $shortcode_tag; + $shortcode_ui_shortcodes[ $shortcode_tag ] = $args; + + // Setup filter to handle decoding encoded attributes. + add_filter( "shortcode_atts_{$shortcode_tag}", 'shortcode_ui_filter_shortcode_atts_decode_encoded', 5, 3 ); + +} + +/** + * Get configuration parameters for all shortcodes with UI. + * + * @return array + */ +function shortcode_ui_get_shortcodes() { + + global $shortcode_ui_shortcodes; + + if ( ! did_action( 'register_shortcode_ui' ) ) { + + /** + * Register shortcode UI for shortcodes. + * + * Can be used to register shortcode UI only when an editor is being enqueued. + * + * @param array $settings Settings array for the ective WP_Editor. + */ + do_action( 'register_shortcode_ui', array(), '' ); + } + + /** + * Filter the returned shortcode UI configuration parameters. + * + * Used to remove shortcode UI that's already been registered. + * + * @param array $shortcodes + */ + $shortcodes = apply_filters( 'shortcode_ui_shortcodes', $shortcode_ui_shortcodes ); + + foreach ( $shortcodes as $shortcode => $args ) { + + foreach ( $args['attrs'] as $key => $value ) { + foreach ( array( 'label', 'description' ) as $field ) { + if ( ! empty( $value[ $field ] ) ) { + $shortcodes[ $shortcode ]['attrs'][ $key ][ $field ] = wp_kses_post( $value[ $field ] ); + } + } + } + + foreach ( array( 'label', 'description' ) as $field ) { + if ( ! empty( $args['inner_content'][ $field ] ) ) { + $shortcodes[ $shortcode ]['inner_content'][ $field ] = wp_kses_post( $args['inner_content'][ $field ] ); + } + } + + } + + return $shortcodes; +} + +/** + * Get UI configuration parameters for a given shortcode. + * + * @return array|false + */ +function shortcode_ui_get_shortcode( $shortcode_tag ) { + + $shortcodes = shortcode_ui_get_shortcodes(); + + if ( isset( $shortcodes[ $shortcode_tag ] ) ) { + return $shortcodes[ $shortcode_tag ]; + } + + return false; + +} + +/** + * When a WP_Editor is initialized on a page, call the 'register_shortcode_ui' action. + * + * This action can be used to register styles and shortcode UI for any + * shortcake-powered shortcodes, only on views which actually include a WP + * Editor. + */ +function shortcode_ui_filter_wp_editor_settings( $settings, $editor_id ) { + + if ( ! did_action( 'register_shortcode_ui' ) ) { + + /** + * Register shortcode UI for shortcodes. + * + * Can be used to register shortcode UI only when an editor is being enqueued. + * + * @param array $settings Settings array for the ective WP_Editor. + */ + do_action( 'register_shortcode_ui', $settings, $editor_id ); + } + + return $settings; +} + +/** + * Enqueue scripts and styles used in the admin. + * + * Editor styles needs to be added before wp_enqueue_editor. + * + * @param array $editor_supports Whether or not the editor being enqueued has 'tinymce' or 'quicktags' + */ +function shortcode_ui_action_admin_enqueue_scripts( $editor_supports ) { + $plugin_url = trailingslashit( plugin_dir_url( dirname( __FILE__ ) ) ); + add_editor_style( $plugin_url . 'css/shortcode-ui-editor-styles.css' ); +} + +/** + * Enqueue scripts and styles needed for shortcode UI. + */ +function shortcode_ui_enqueue() { + + if ( did_action( 'enqueue_shortcode_ui' ) ) { + return; + } + + wp_enqueue_media(); + + $shortcodes = array_values( shortcode_ui_get_shortcodes() ); + $current_post_type = get_post_type(); + if ( $current_post_type ) { + foreach ( $shortcodes as $key => $args ) { + if ( ! empty( $args['post_type'] ) && ! in_array( $current_post_type, $args['post_type'], true ) ) { + unset( $shortcodes[ $key ] ); + } + } + } + + if ( empty( $shortcodes ) ) { + return; + } + + usort( $shortcodes, 'shortcode_ui_compare_shortcodes_by_label' ); + + // Load minified version of wp-js-hooks if not debugging. + $wp_js_hooks_file = 'wp-js-hooks' . ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '.min' : '' ) . '.js'; + + wp_enqueue_script( 'shortcode-ui-js-hooks', plugin_dir_url( dirname( __FILE__ ) ) . 'lib/wp-js-hooks/' . $wp_js_hooks_file, array(), '2015-03-19' ); + wp_enqueue_script( 'shortcode-ui', plugin_dir_url( dirname( __FILE__ ) ) . 'js/build/shortcode-ui.js', array( 'jquery', 'backbone', 'mce-view', 'shortcode-ui-js-hooks' ) ); + wp_enqueue_style( 'shortcode-ui', plugin_dir_url( dirname( __FILE__ ) ) . 'css/shortcode-ui.css', array() ); + + wp_localize_script( 'shortcode-ui', ' shortcodeUIData', array( + 'shortcodes' => $shortcodes, + 'strings' => array( + 'media_frame_title' => __( 'Insert Post Element', 'shortcode-ui' ), + 'media_frame_menu_insert_label' => __( 'Insert Post Element', 'shortcode-ui' ), + 'media_frame_menu_update_label' => __( '%s Details', 'shortcode-ui' ), // Substituted in JS + 'media_frame_toolbar_insert_label' => __( 'Insert Element', 'shortcode-ui' ), + 'media_frame_toolbar_update_label' => __( 'Update', 'shortcode-ui' ), + 'media_frame_no_attributes_message' => __( 'There are no attributes to configure for this Post Element.', 'shortcode-ui' ), + 'mce_view_error' => __( 'Failed to load preview', 'shortcode-ui' ), + 'search_placeholder' => __( 'Search', 'shortcode-ui' ), + 'insert_content_label' => __( 'Insert Content', 'shortcode-ui' ), + ), + 'nonces' => array( + 'preview' => wp_create_nonce( 'shortcode-ui-preview' ), + 'thumbnailImage' => wp_create_nonce( 'shortcode-ui-get-thumbnail-image' ), + ), + ) ); + + // add templates to the footer, instead of where we're at now + add_action( 'admin_print_footer_scripts', 'shortcode_ui_action_admin_print_footer_scripts' ); + + /** + * Fires after shortcode UI assets have been enqueued. + * + * Will only fire once per page load. + */ + do_action( 'enqueue_shortcode_ui' ); +} + +/** + * Enqueue shortcode UI assets when the editor is enqueued. + */ +function shortcode_ui_action_wp_enqueue_editor() { + + shortcode_ui_enqueue(); + + /** + * Fires after shortcode UI assets have been loaded for the editor. + * + * Will fire every time the editor is loaded. + */ + do_action( 'shortcode_ui_loaded_editor' ); +} + +/** + * Output an "Add Post Element" button with the media buttons. + */ +function shortcode_ui_action_media_buttons( $editor_id ) { + printf( '', + esc_attr( $editor_id ), + esc_html__( 'Add Post Element', 'shortcode-ui' ) + ); +} + +/** + * Output required underscore.js templates in the footer + */ +function shortcode_ui_action_admin_print_footer_scripts() { + + echo shortcode_ui_get_view( 'media-frame' ); // WPCS: xss ok + echo shortcode_ui_get_view( 'list-item' ); // WPCS: xss ok + echo shortcode_ui_get_view( 'edit-form' ); // WPCS: xss ok + + /** + * Fires after base shortcode UI templates have been loaded. + * + * Allows custom shortcode UI field types to load their own templates. + */ + do_action( 'print_shortcode_ui_templates' ); +} + +/** + * Helper function for displaying a PHP template file. + * + * Template args array is extracted and passed to the template file. + * + * @param string $template full template file path. Or name of template file in inc/templates. + * @return string the template contents + */ +function shortcode_ui_get_view( $template ) { + + if ( ! file_exists( $template ) ) { + + $template_dir = plugin_dir_path( dirname( __FILE__ ) ) . 'inc/templates/'; + $template = $template_dir . $template . '.tpl.php'; + + if ( ! file_exists( $template ) ) { + return ''; + } + } + + ob_start(); + include $template; + + return ob_get_clean(); +} + +/** + * Sort labels alphabetically. + * + * @param array $a + * @param array $b + * @return int + */ +function shortcode_ui_compare_shortcodes_by_label( $a, $b ) { + return strcmp( $a['label'], $b['label'] ); +} + +/** + * Render a shortcode body for preview. + */ +function shortcode_ui_render_shortcode_for_preview( $shortcode, $post_id = null ) { + + if ( ! defined( 'SHORTCODE_UI_DOING_PREVIEW' ) ) { + define( 'SHORTCODE_UI_DOING_PREVIEW', true ); + } + + if ( ! current_user_can( 'edit_post', $post_id ) ) { + return esc_html__( "Something's rotten in the state of Denmark", 'shortcode-ui' ); + } + + if ( ! empty( $post_id ) ) { + // @codingStandardsIgnoreStart + global $post; + $post = get_post( $post_id ); + setup_postdata( $post ); + // @codingStandardsIgnoreEnd + } + + ob_start(); + /** + * Fires before shortcode is rendered in preview. + * + * @param string $shortcode Full shortcode including attributes + */ + do_action( 'shortcode_ui_before_do_shortcode', $shortcode ); + echo do_shortcode( $shortcode ); // WPCS: xss ok + /** + * Fires after shortcode is rendered in preview. + * + * @param string $shortcode Full shortcode including attributes + */ + do_action( 'shortcode_ui_after_do_shortcode', $shortcode ); + + return ob_get_clean(); +} + +/** + * Get a bunch of shortcodes to render in MCE preview. + */ +function shortcode_ui_handle_ajax_bulk_do_shortcode() { + + if ( is_array( $_POST['queries'] ) ) { + + $responses = array(); + + foreach ( $_POST['queries'] as $posted_query ) { + + // Don't sanitize shortcodes — can contain HTML kses doesn't allow (e.g. sourcecode shortcode) + if ( ! empty( $posted_query['shortcode'] ) ) { + $shortcode = stripslashes( $posted_query['shortcode'] ); + } else { + $shortcode = null; + } + if ( isset( $posted_query['post_id'] ) ) { + $post_id = intval( $posted_query['post_id'] ); + } else { + $post_id = null; + } + + $responses[ $posted_query['counter'] ] = array( + 'query' => $posted_query, + 'response' => shortcode_ui_render_shortcode_for_preview( $shortcode, $post_id ), + ); + } + + wp_send_json_success( $responses ); + exit; + } + +} + +/** + * Decode any encoded attributes. + * + * @param array $out The output array of shortcode attributes. + * @param array $pairs The supported attributes and their defaults. + * @param array $atts The user defined shortcode attributes. + * @return array $out The output array of shortcode attributes. + */ +function shortcode_ui_filter_shortcode_atts_decode_encoded( $out, $pairs, $atts ) { + + global $shortcode_ui_shortcodes; + + // Get current shortcode tag from the current filter + // by stripping `shortcode_atts_` from start of string. + $shortcode_tag = substr( current_filter(), 15 ); + + if ( ! isset( $shortcode_ui_shortcodes[ $shortcode_tag ] ) ) { + return $out; + } + + $fields = Shortcode_UI_Fields::get_instance()->get_fields(); + $args = $shortcode_ui_shortcodes[ $shortcode_tag ]; + + foreach ( $args['attrs'] as $attr ) { + + $default = isset( $fields[ $attr['type'] ]['encode'] ) ? $fields[ $attr['type'] ]['encode'] : false; + $encoded = isset( $attr['encode'] ) ? $attr['encode'] : $default; + + if ( $encoded && isset( $out[ $attr['attr'] ] ) ) { + $out[ $attr['attr'] ] = rawurldecode( $out[ $attr['attr'] ] ); + } + } + + return $out; + +} diff --git a/js-tests/build/specs.js b/js-tests/build/specs.js index 00c87622..98460d32 100644 --- a/js-tests/build/specs.js +++ b/js-tests/build/specs.js @@ -382,65 +382,6 @@ describe( "MCE View Constructor", function() { } ); - describe( "Fetch preview HTML", function() { - - beforeEach(function() { - jasmine.Ajax.install(); - }); - - afterEach(function() { - jasmine.Ajax.uninstall(); - }); - - var constructor = jQuery.extend( true, { - render: function( force ) {}, - }, MceViewConstructor ); - - // Mock shortcode model data. - constructor.shortcodeModel = jQuery.extend( true, {}, sui.shortcodes.first() ); - - it( 'Fetches data success', function(){ - - spyOn( wp.ajax, "post" ).and.callThrough(); - spyOn( constructor, "render" ); - - constructor.fetch(); - - expect( constructor.fetching ).toEqual( true ); - expect( constructor.content ).toEqual( undefined ); - expect( wp.ajax.post ).toHaveBeenCalled(); - expect( constructor.render ).not.toHaveBeenCalled(); - - jasmine.Ajax.requests.mostRecent().respondWith( { - 'status': 200, - 'responseText': '{"success":true,"data":"test preview response body"}' - } ); - - expect( constructor.fetching ).toEqual( undefined ); - expect( constructor.content ).toEqual( 'test preview response body' ); - expect( constructor.render ).toHaveBeenCalled(); - - }); - - it( 'Handles errors when fetching data', function() { - - spyOn( constructor, "render" ); - - constructor.fetch(); - - jasmine.Ajax.requests.mostRecent().respondWith( { - 'status': 500, - 'responseText': '{"success":false}' - }); - - expect( constructor.fetching ).toEqual( undefined ); - expect( constructor.content ).toContain( 'shortcake-error' ); - expect( constructor.render ).toHaveBeenCalled(); - - } ); - - } ); - it( 'parses simple shortcode', function() { var shortcode = MceViewConstructor.parseShortcodeString( '[test_shortcode attr="test value"]'); expect( shortcode instanceof Shortcode ).toEqual( true ); @@ -792,13 +733,16 @@ var Fetcher = (function() { return; } - var request = $.post( ajaxurl + '?action=bulk_do_shortcode', { + var request = $.post( shortcodeUIData.urls.bulkPreview, { + _wpnonce: shortcodeUIData.nonces.wp_rest, queries: _.pluck( fetcher.queries, 'query' ) } ); - request.done( function( response ) { - _.each( response.data, function( result, index ) { + request.done( function( responses ) { + + _.each( responses, function( result, index ) { + var matchedQuery = _.findWhere( fetcher.queries, { counter: parseInt( index ), }); @@ -807,7 +751,9 @@ var Fetcher = (function() { fetcher.queries = _.without( fetcher.queries, matchedQuery ); matchedQuery.promise.resolve( result ); } + } ); + } ); }; @@ -944,42 +890,9 @@ var shortcodeViewConstructor = { return fetcher.queueToFetch({ post_id: $( '#post_ID' ).val(), shortcode: this.shortcodeModel.formatShortcode(), - nonce: shortcodeUIData.nonces.preview, }); }, - /** - * Fetch a preview of a single shortcode. - * - * Async. Sets this.content and calls this.render. - * - * @return undefined - */ - fetch: function() { - var self = this; - - if ( ! this.fetching ) { - this.fetching = true; - - wp.ajax.post( 'do_shortcode', { - post_id: $( '#post_ID' ).val(), - shortcode: this.shortcodeModel.formatShortcode(), - nonce: shortcodeUIData.nonces.preview, - }).done( function( response ) { - if ( '' === response ) { - self.content = '' + self.shortcodeModel.formatShortcode() + ''; - } else { - self.content = response; - } - }).fail( function() { - self.content = '' + shortcodeUIData.strings.mce_view_error + ''; - } ).always( function() { - delete self.fetching; - self.render( null, true ); - } ); - } - }, - /** * Get the shortcode model and open modal UI for editing. * diff --git a/js-tests/src/utils/mceViewConstructorSpec.js b/js-tests/src/utils/mceViewConstructorSpec.js index befb43d3..9ca376b3 100644 --- a/js-tests/src/utils/mceViewConstructorSpec.js +++ b/js-tests/src/utils/mceViewConstructorSpec.js @@ -73,65 +73,6 @@ describe( "MCE View Constructor", function() { } ); - describe( "Fetch preview HTML", function() { - - beforeEach(function() { - jasmine.Ajax.install(); - }); - - afterEach(function() { - jasmine.Ajax.uninstall(); - }); - - var constructor = jQuery.extend( true, { - render: function( force ) {}, - }, MceViewConstructor ); - - // Mock shortcode model data. - constructor.shortcodeModel = jQuery.extend( true, {}, sui.shortcodes.first() ); - - it( 'Fetches data success', function(){ - - spyOn( wp.ajax, "post" ).and.callThrough(); - spyOn( constructor, "render" ); - - constructor.fetch(); - - expect( constructor.fetching ).toEqual( true ); - expect( constructor.content ).toEqual( undefined ); - expect( wp.ajax.post ).toHaveBeenCalled(); - expect( constructor.render ).not.toHaveBeenCalled(); - - jasmine.Ajax.requests.mostRecent().respondWith( { - 'status': 200, - 'responseText': '{"success":true,"data":"test preview response body"}' - } ); - - expect( constructor.fetching ).toEqual( undefined ); - expect( constructor.content ).toEqual( 'test preview response body' ); - expect( constructor.render ).toHaveBeenCalled(); - - }); - - it( 'Handles errors when fetching data', function() { - - spyOn( constructor, "render" ); - - constructor.fetch(); - - jasmine.Ajax.requests.mostRecent().respondWith( { - 'status': 500, - 'responseText': '{"success":false}' - }); - - expect( constructor.fetching ).toEqual( undefined ); - expect( constructor.content ).toContain( 'shortcake-error' ); - expect( constructor.render ).toHaveBeenCalled(); - - } ); - - } ); - it( 'parses simple shortcode', function() { var shortcode = MceViewConstructor.parseShortcodeString( '[test_shortcode attr="test value"]'); expect( shortcode instanceof Shortcode ).toEqual( true ); diff --git a/js/build/shortcode-ui.js b/js/build/shortcode-ui.js index 3d6b77bc..b76bd179 100644 --- a/js/build/shortcode-ui.js +++ b/js/build/shortcode-ui.js @@ -365,13 +365,16 @@ var Fetcher = (function() { return; } - var request = $.post( ajaxurl + '?action=bulk_do_shortcode', { + var request = $.post( shortcodeUIData.urls.bulkPreview, { + _wpnonce: shortcodeUIData.nonces.wp_rest, queries: _.pluck( fetcher.queries, 'query' ) } ); - request.done( function( response ) { - _.each( response.data, function( result, index ) { + request.done( function( responses ) { + + _.each( responses, function( result, index ) { + var matchedQuery = _.findWhere( fetcher.queries, { counter: parseInt( index ), }); @@ -380,7 +383,9 @@ var Fetcher = (function() { fetcher.queries = _.without( fetcher.queries, matchedQuery ); matchedQuery.promise.resolve( result ); } + } ); + } ); }; @@ -517,42 +522,9 @@ var shortcodeViewConstructor = { return fetcher.queueToFetch({ post_id: $( '#post_ID' ).val(), shortcode: this.shortcodeModel.formatShortcode(), - nonce: shortcodeUIData.nonces.preview, }); }, - /** - * Fetch a preview of a single shortcode. - * - * Async. Sets this.content and calls this.render. - * - * @return undefined - */ - fetch: function() { - var self = this; - - if ( ! this.fetching ) { - this.fetching = true; - - wp.ajax.post( 'do_shortcode', { - post_id: $( '#post_ID' ).val(), - shortcode: this.shortcodeModel.formatShortcode(), - nonce: shortcodeUIData.nonces.preview, - }).done( function( response ) { - if ( '' === response ) { - self.content = '' + self.shortcodeModel.formatShortcode() + ''; - } else { - self.content = response; - } - }).fail( function() { - self.content = '' + shortcodeUIData.strings.mce_view_error + ''; - } ).always( function() { - delete self.fetching; - self.render( null, true ); - } ); - } - }, - /** * Get the shortcode model and open modal UI for editing. * diff --git a/js/src/utils/fetcher.js b/js/src/utils/fetcher.js index a406c7a2..c79e061d 100644 --- a/js/src/utils/fetcher.js +++ b/js/src/utils/fetcher.js @@ -81,13 +81,16 @@ var Fetcher = (function() { return; } - var request = $.post( ajaxurl + '?action=bulk_do_shortcode', { + var request = $.post( shortcodeUIData.urls.bulkPreview, { + _wpnonce: shortcodeUIData.nonces.wp_rest, queries: _.pluck( fetcher.queries, 'query' ) } ); - request.done( function( response ) { - _.each( response.data, function( result, index ) { + request.done( function( responses ) { + + _.each( responses, function( result, index ) { + var matchedQuery = _.findWhere( fetcher.queries, { counter: parseInt( index ), }); @@ -96,7 +99,9 @@ var Fetcher = (function() { fetcher.queries = _.without( fetcher.queries, matchedQuery ); matchedQuery.promise.resolve( result ); } + } ); + } ); }; diff --git a/js/src/utils/shortcode-view-constructor.js b/js/src/utils/shortcode-view-constructor.js index 6c2b101e..bb8af4e7 100644 --- a/js/src/utils/shortcode-view-constructor.js +++ b/js/src/utils/shortcode-view-constructor.js @@ -118,42 +118,9 @@ var shortcodeViewConstructor = { return fetcher.queueToFetch({ post_id: $( '#post_ID' ).val(), shortcode: this.shortcodeModel.formatShortcode(), - nonce: shortcodeUIData.nonces.preview, }); }, - /** - * Fetch a preview of a single shortcode. - * - * Async. Sets this.content and calls this.render. - * - * @return undefined - */ - fetch: function() { - var self = this; - - if ( ! this.fetching ) { - this.fetching = true; - - wp.ajax.post( 'do_shortcode', { - post_id: $( '#post_ID' ).val(), - shortcode: this.shortcodeModel.formatShortcode(), - nonce: shortcodeUIData.nonces.preview, - }).done( function( response ) { - if ( '' === response ) { - self.content = '' + self.shortcodeModel.formatShortcode() + ''; - } else { - self.content = response; - } - }).fail( function() { - self.content = '' + shortcodeUIData.strings.mce_view_error + ''; - } ).always( function() { - delete self.fetching; - self.render( null, true ); - } ); - } - }, - /** * Get the shortcode model and open modal UI for editing. * diff --git a/js/src/views/wip-shortcode.js b/js/src/views/wip-shortcode.js new file mode 100644 index 00000000..b8267063 --- /dev/null +++ b/js/src/views/wip-shortcode.js @@ -0,0 +1,39 @@ + +var preview = Backbone.View.extend({ + + shortcode: null, + post_id: null, + + templateEmpty: '<%= notice %>', + + initialize: function( options ) { + this.post_id = options.post_id; + this.shortcode = options.shortcode; + }, + + render: function() {}, + + fetch: function() { + + var self = this, template; + + wp.ajax.post( 'do_shortcode', { + post_id: this.post_id, + shortcode: this.shortcode.formatShortcode(), + nonce: shortcodeUIData.nonces.preview, + }).done( function( response ) { + if ( '' === response ) { + template = _.template( this.templateEmpty ); + self.content = template( { notice: self.shortcodeModel.formatShortcode() } ); + } else { + self.content = response; + } + }).fail( function() { + self.content = '' + shortcodeUIData.strings.mce_view_error + ''; + } ).always( function() { + delete self.fetching; + self.render( null, true ); + } ); + } + +}); From 983fd81a41096109234f3cd30e5bb1522046af16 Mon Sep 17 00:00:00 2001 From: Matth_eu Date: Wed, 2 Mar 2016 13:17:57 +0000 Subject: [PATCH 02/13] Use GET not POST for previews --- inc/class-shortcode-ui.php | 4 ++-- js-tests/build/specs.js | 4 ++-- js/build/shortcode-ui.js | 4 ++-- js/src/utils/fetcher.js | 2 +- js/src/utils/shortcode-view-constructor.js | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/inc/class-shortcode-ui.php b/inc/class-shortcode-ui.php index e33dbb32..16beb69c 100644 --- a/inc/class-shortcode-ui.php +++ b/inc/class-shortcode-ui.php @@ -75,7 +75,7 @@ private function setup_actions() { public function action_rest_api_init() { register_rest_route( 'shortcode-ui/v1', 'preview', array( - 'methods' => 'POST', + 'methods' => 'GET', 'callback' => array( $this, 'handle_shortcode_preview' ), 'args' => array( 'query' => array( @@ -85,7 +85,7 @@ public function action_rest_api_init() { ) ); register_rest_route( 'shortcode-ui/v1', 'preview/bulk', array( - 'methods' => 'POST', + 'methods' => 'GET', 'callback' => array( $this, 'handle_shortcode_preview_bulk' ), 'args' => array( 'queries' => array( diff --git a/js-tests/build/specs.js b/js-tests/build/specs.js index 98460d32..94cb7bfe 100644 --- a/js-tests/build/specs.js +++ b/js-tests/build/specs.js @@ -733,7 +733,7 @@ var Fetcher = (function() { return; } - var request = $.post( shortcodeUIData.urls.bulkPreview, { + var request = $.get( shortcodeUIData.urls.bulkPreview, { _wpnonce: shortcodeUIData.nonces.wp_rest, queries: _.pluck( fetcher.queries, 'query' ) } @@ -888,7 +888,7 @@ var shortcodeViewConstructor = { */ delayedFetch: function() { return fetcher.queueToFetch({ - post_id: $( '#post_ID' ).val(), + post_id: $( '#post_ID' ).val(), shortcode: this.shortcodeModel.formatShortcode(), }); }, diff --git a/js/build/shortcode-ui.js b/js/build/shortcode-ui.js index b76bd179..883a72ab 100644 --- a/js/build/shortcode-ui.js +++ b/js/build/shortcode-ui.js @@ -365,7 +365,7 @@ var Fetcher = (function() { return; } - var request = $.post( shortcodeUIData.urls.bulkPreview, { + var request = $.get( shortcodeUIData.urls.bulkPreview, { _wpnonce: shortcodeUIData.nonces.wp_rest, queries: _.pluck( fetcher.queries, 'query' ) } @@ -520,7 +520,7 @@ var shortcodeViewConstructor = { */ delayedFetch: function() { return fetcher.queueToFetch({ - post_id: $( '#post_ID' ).val(), + post_id: $( '#post_ID' ).val(), shortcode: this.shortcodeModel.formatShortcode(), }); }, diff --git a/js/src/utils/fetcher.js b/js/src/utils/fetcher.js index c79e061d..011cba54 100644 --- a/js/src/utils/fetcher.js +++ b/js/src/utils/fetcher.js @@ -81,7 +81,7 @@ var Fetcher = (function() { return; } - var request = $.post( shortcodeUIData.urls.bulkPreview, { + var request = $.get( shortcodeUIData.urls.bulkPreview, { _wpnonce: shortcodeUIData.nonces.wp_rest, queries: _.pluck( fetcher.queries, 'query' ) } diff --git a/js/src/utils/shortcode-view-constructor.js b/js/src/utils/shortcode-view-constructor.js index bb8af4e7..e9495a62 100644 --- a/js/src/utils/shortcode-view-constructor.js +++ b/js/src/utils/shortcode-view-constructor.js @@ -116,7 +116,7 @@ var shortcodeViewConstructor = { */ delayedFetch: function() { return fetcher.queueToFetch({ - post_id: $( '#post_ID' ).val(), + post_id: $( '#post_ID' ).val(), shortcode: this.shortcodeModel.formatShortcode(), }); }, From ee1a85b6bfb8ceb83f0661477d9a966ded3d504b Mon Sep 17 00:00:00 2001 From: Matth_eu Date: Wed, 2 Mar 2016 13:29:27 +0000 Subject: [PATCH 03/13] Clean up files --- inc/shortcode-ui.php | 421 ---------------------------------- js/src/views/wip-shortcode.js | 39 ---- 2 files changed, 460 deletions(-) delete mode 100644 inc/shortcode-ui.php delete mode 100644 js/src/views/wip-shortcode.js diff --git a/inc/shortcode-ui.php b/inc/shortcode-ui.php deleted file mode 100644 index a4ca7f5a..00000000 --- a/inc/shortcode-ui.php +++ /dev/null @@ -1,421 +0,0 @@ - esc_html__( 'Inner Content', 'shortcode-ui' ), - 'description' => '', - ); - } - - if ( ! isset( $args['attrs'] ) ) { - $args['attrs'] = array(); - } - - $args['shortcode_tag'] = $shortcode_tag; - $shortcode_ui_shortcodes[ $shortcode_tag ] = $args; - - // Setup filter to handle decoding encoded attributes. - add_filter( "shortcode_atts_{$shortcode_tag}", 'shortcode_ui_filter_shortcode_atts_decode_encoded', 5, 3 ); - -} - -/** - * Get configuration parameters for all shortcodes with UI. - * - * @return array - */ -function shortcode_ui_get_shortcodes() { - - global $shortcode_ui_shortcodes; - - if ( ! did_action( 'register_shortcode_ui' ) ) { - - /** - * Register shortcode UI for shortcodes. - * - * Can be used to register shortcode UI only when an editor is being enqueued. - * - * @param array $settings Settings array for the ective WP_Editor. - */ - do_action( 'register_shortcode_ui', array(), '' ); - } - - /** - * Filter the returned shortcode UI configuration parameters. - * - * Used to remove shortcode UI that's already been registered. - * - * @param array $shortcodes - */ - $shortcodes = apply_filters( 'shortcode_ui_shortcodes', $shortcode_ui_shortcodes ); - - foreach ( $shortcodes as $shortcode => $args ) { - - foreach ( $args['attrs'] as $key => $value ) { - foreach ( array( 'label', 'description' ) as $field ) { - if ( ! empty( $value[ $field ] ) ) { - $shortcodes[ $shortcode ]['attrs'][ $key ][ $field ] = wp_kses_post( $value[ $field ] ); - } - } - } - - foreach ( array( 'label', 'description' ) as $field ) { - if ( ! empty( $args['inner_content'][ $field ] ) ) { - $shortcodes[ $shortcode ]['inner_content'][ $field ] = wp_kses_post( $args['inner_content'][ $field ] ); - } - } - - } - - return $shortcodes; -} - -/** - * Get UI configuration parameters for a given shortcode. - * - * @return array|false - */ -function shortcode_ui_get_shortcode( $shortcode_tag ) { - - $shortcodes = shortcode_ui_get_shortcodes(); - - if ( isset( $shortcodes[ $shortcode_tag ] ) ) { - return $shortcodes[ $shortcode_tag ]; - } - - return false; - -} - -/** - * When a WP_Editor is initialized on a page, call the 'register_shortcode_ui' action. - * - * This action can be used to register styles and shortcode UI for any - * shortcake-powered shortcodes, only on views which actually include a WP - * Editor. - */ -function shortcode_ui_filter_wp_editor_settings( $settings, $editor_id ) { - - if ( ! did_action( 'register_shortcode_ui' ) ) { - - /** - * Register shortcode UI for shortcodes. - * - * Can be used to register shortcode UI only when an editor is being enqueued. - * - * @param array $settings Settings array for the ective WP_Editor. - */ - do_action( 'register_shortcode_ui', $settings, $editor_id ); - } - - return $settings; -} - -/** - * Enqueue scripts and styles used in the admin. - * - * Editor styles needs to be added before wp_enqueue_editor. - * - * @param array $editor_supports Whether or not the editor being enqueued has 'tinymce' or 'quicktags' - */ -function shortcode_ui_action_admin_enqueue_scripts( $editor_supports ) { - $plugin_url = trailingslashit( plugin_dir_url( dirname( __FILE__ ) ) ); - add_editor_style( $plugin_url . 'css/shortcode-ui-editor-styles.css' ); -} - -/** - * Enqueue scripts and styles needed for shortcode UI. - */ -function shortcode_ui_enqueue() { - - if ( did_action( 'enqueue_shortcode_ui' ) ) { - return; - } - - wp_enqueue_media(); - - $shortcodes = array_values( shortcode_ui_get_shortcodes() ); - $current_post_type = get_post_type(); - if ( $current_post_type ) { - foreach ( $shortcodes as $key => $args ) { - if ( ! empty( $args['post_type'] ) && ! in_array( $current_post_type, $args['post_type'], true ) ) { - unset( $shortcodes[ $key ] ); - } - } - } - - if ( empty( $shortcodes ) ) { - return; - } - - usort( $shortcodes, 'shortcode_ui_compare_shortcodes_by_label' ); - - // Load minified version of wp-js-hooks if not debugging. - $wp_js_hooks_file = 'wp-js-hooks' . ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '.min' : '' ) . '.js'; - - wp_enqueue_script( 'shortcode-ui-js-hooks', plugin_dir_url( dirname( __FILE__ ) ) . 'lib/wp-js-hooks/' . $wp_js_hooks_file, array(), '2015-03-19' ); - wp_enqueue_script( 'shortcode-ui', plugin_dir_url( dirname( __FILE__ ) ) . 'js/build/shortcode-ui.js', array( 'jquery', 'backbone', 'mce-view', 'shortcode-ui-js-hooks' ) ); - wp_enqueue_style( 'shortcode-ui', plugin_dir_url( dirname( __FILE__ ) ) . 'css/shortcode-ui.css', array() ); - - wp_localize_script( 'shortcode-ui', ' shortcodeUIData', array( - 'shortcodes' => $shortcodes, - 'strings' => array( - 'media_frame_title' => __( 'Insert Post Element', 'shortcode-ui' ), - 'media_frame_menu_insert_label' => __( 'Insert Post Element', 'shortcode-ui' ), - 'media_frame_menu_update_label' => __( '%s Details', 'shortcode-ui' ), // Substituted in JS - 'media_frame_toolbar_insert_label' => __( 'Insert Element', 'shortcode-ui' ), - 'media_frame_toolbar_update_label' => __( 'Update', 'shortcode-ui' ), - 'media_frame_no_attributes_message' => __( 'There are no attributes to configure for this Post Element.', 'shortcode-ui' ), - 'mce_view_error' => __( 'Failed to load preview', 'shortcode-ui' ), - 'search_placeholder' => __( 'Search', 'shortcode-ui' ), - 'insert_content_label' => __( 'Insert Content', 'shortcode-ui' ), - ), - 'nonces' => array( - 'preview' => wp_create_nonce( 'shortcode-ui-preview' ), - 'thumbnailImage' => wp_create_nonce( 'shortcode-ui-get-thumbnail-image' ), - ), - ) ); - - // add templates to the footer, instead of where we're at now - add_action( 'admin_print_footer_scripts', 'shortcode_ui_action_admin_print_footer_scripts' ); - - /** - * Fires after shortcode UI assets have been enqueued. - * - * Will only fire once per page load. - */ - do_action( 'enqueue_shortcode_ui' ); -} - -/** - * Enqueue shortcode UI assets when the editor is enqueued. - */ -function shortcode_ui_action_wp_enqueue_editor() { - - shortcode_ui_enqueue(); - - /** - * Fires after shortcode UI assets have been loaded for the editor. - * - * Will fire every time the editor is loaded. - */ - do_action( 'shortcode_ui_loaded_editor' ); -} - -/** - * Output an "Add Post Element" button with the media buttons. - */ -function shortcode_ui_action_media_buttons( $editor_id ) { - printf( '', - esc_attr( $editor_id ), - esc_html__( 'Add Post Element', 'shortcode-ui' ) - ); -} - -/** - * Output required underscore.js templates in the footer - */ -function shortcode_ui_action_admin_print_footer_scripts() { - - echo shortcode_ui_get_view( 'media-frame' ); // WPCS: xss ok - echo shortcode_ui_get_view( 'list-item' ); // WPCS: xss ok - echo shortcode_ui_get_view( 'edit-form' ); // WPCS: xss ok - - /** - * Fires after base shortcode UI templates have been loaded. - * - * Allows custom shortcode UI field types to load their own templates. - */ - do_action( 'print_shortcode_ui_templates' ); -} - -/** - * Helper function for displaying a PHP template file. - * - * Template args array is extracted and passed to the template file. - * - * @param string $template full template file path. Or name of template file in inc/templates. - * @return string the template contents - */ -function shortcode_ui_get_view( $template ) { - - if ( ! file_exists( $template ) ) { - - $template_dir = plugin_dir_path( dirname( __FILE__ ) ) . 'inc/templates/'; - $template = $template_dir . $template . '.tpl.php'; - - if ( ! file_exists( $template ) ) { - return ''; - } - } - - ob_start(); - include $template; - - return ob_get_clean(); -} - -/** - * Sort labels alphabetically. - * - * @param array $a - * @param array $b - * @return int - */ -function shortcode_ui_compare_shortcodes_by_label( $a, $b ) { - return strcmp( $a['label'], $b['label'] ); -} - -/** - * Render a shortcode body for preview. - */ -function shortcode_ui_render_shortcode_for_preview( $shortcode, $post_id = null ) { - - if ( ! defined( 'SHORTCODE_UI_DOING_PREVIEW' ) ) { - define( 'SHORTCODE_UI_DOING_PREVIEW', true ); - } - - if ( ! current_user_can( 'edit_post', $post_id ) ) { - return esc_html__( "Something's rotten in the state of Denmark", 'shortcode-ui' ); - } - - if ( ! empty( $post_id ) ) { - // @codingStandardsIgnoreStart - global $post; - $post = get_post( $post_id ); - setup_postdata( $post ); - // @codingStandardsIgnoreEnd - } - - ob_start(); - /** - * Fires before shortcode is rendered in preview. - * - * @param string $shortcode Full shortcode including attributes - */ - do_action( 'shortcode_ui_before_do_shortcode', $shortcode ); - echo do_shortcode( $shortcode ); // WPCS: xss ok - /** - * Fires after shortcode is rendered in preview. - * - * @param string $shortcode Full shortcode including attributes - */ - do_action( 'shortcode_ui_after_do_shortcode', $shortcode ); - - return ob_get_clean(); -} - -/** - * Get a bunch of shortcodes to render in MCE preview. - */ -function shortcode_ui_handle_ajax_bulk_do_shortcode() { - - if ( is_array( $_POST['queries'] ) ) { - - $responses = array(); - - foreach ( $_POST['queries'] as $posted_query ) { - - // Don't sanitize shortcodes — can contain HTML kses doesn't allow (e.g. sourcecode shortcode) - if ( ! empty( $posted_query['shortcode'] ) ) { - $shortcode = stripslashes( $posted_query['shortcode'] ); - } else { - $shortcode = null; - } - if ( isset( $posted_query['post_id'] ) ) { - $post_id = intval( $posted_query['post_id'] ); - } else { - $post_id = null; - } - - $responses[ $posted_query['counter'] ] = array( - 'query' => $posted_query, - 'response' => shortcode_ui_render_shortcode_for_preview( $shortcode, $post_id ), - ); - } - - wp_send_json_success( $responses ); - exit; - } - -} - -/** - * Decode any encoded attributes. - * - * @param array $out The output array of shortcode attributes. - * @param array $pairs The supported attributes and their defaults. - * @param array $atts The user defined shortcode attributes. - * @return array $out The output array of shortcode attributes. - */ -function shortcode_ui_filter_shortcode_atts_decode_encoded( $out, $pairs, $atts ) { - - global $shortcode_ui_shortcodes; - - // Get current shortcode tag from the current filter - // by stripping `shortcode_atts_` from start of string. - $shortcode_tag = substr( current_filter(), 15 ); - - if ( ! isset( $shortcode_ui_shortcodes[ $shortcode_tag ] ) ) { - return $out; - } - - $fields = Shortcode_UI_Fields::get_instance()->get_fields(); - $args = $shortcode_ui_shortcodes[ $shortcode_tag ]; - - foreach ( $args['attrs'] as $attr ) { - - $default = isset( $fields[ $attr['type'] ]['encode'] ) ? $fields[ $attr['type'] ]['encode'] : false; - $encoded = isset( $attr['encode'] ) ? $attr['encode'] : $default; - - if ( $encoded && isset( $out[ $attr['attr'] ] ) ) { - $out[ $attr['attr'] ] = rawurldecode( $out[ $attr['attr'] ] ); - } - } - - return $out; - -} diff --git a/js/src/views/wip-shortcode.js b/js/src/views/wip-shortcode.js deleted file mode 100644 index b8267063..00000000 --- a/js/src/views/wip-shortcode.js +++ /dev/null @@ -1,39 +0,0 @@ - -var preview = Backbone.View.extend({ - - shortcode: null, - post_id: null, - - templateEmpty: '<%= notice %>', - - initialize: function( options ) { - this.post_id = options.post_id; - this.shortcode = options.shortcode; - }, - - render: function() {}, - - fetch: function() { - - var self = this, template; - - wp.ajax.post( 'do_shortcode', { - post_id: this.post_id, - shortcode: this.shortcode.formatShortcode(), - nonce: shortcodeUIData.nonces.preview, - }).done( function( response ) { - if ( '' === response ) { - template = _.template( this.templateEmpty ); - self.content = template( { notice: self.shortcodeModel.formatShortcode() } ); - } else { - self.content = response; - } - }).fail( function() { - self.content = '' + shortcodeUIData.strings.mce_view_error + ''; - } ).always( function() { - delete self.fetching; - self.render( null, true ); - } ); - } - -}); From 8ea5bf1551e4b4e88a3e6ba946b4b0e8f99aa871 Mon Sep 17 00:00:00 2001 From: Matth_eu Date: Wed, 2 Mar 2016 13:30:31 +0000 Subject: [PATCH 04/13] use rest_url --- inc/class-shortcode-ui.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/inc/class-shortcode-ui.php b/inc/class-shortcode-ui.php index 16beb69c..4fec330c 100644 --- a/inc/class-shortcode-ui.php +++ b/inc/class-shortcode-ui.php @@ -273,8 +273,8 @@ public function enqueue() { 'thumbnailImage' => wp_create_nonce( 'shortcode-ui-get-thumbnail-image' ), ), 'urls' => array( - 'preview' => home_url( '/wp-json/shortcode-ui/v1/preview' ), - 'bulkPreview' => home_url( '/wp-json/shortcode-ui/v1/preview/bulk' ), + 'preview' => rest_url( '/shortcode-ui/v1/preview' ), + 'bulkPreview' => rest_url( '/shortcode-ui/v1/preview/bulk' ), ), ) ); From 2ed8e06333e06ebdc7633b719b32da344df8ece1 Mon Sep 17 00:00:00 2001 From: Matth_eu Date: Wed, 2 Mar 2016 14:02:45 +0000 Subject: [PATCH 05/13] Remove registration of shortcode preview action --- inc/class-shortcode-ui.php | 1 - 1 file changed, 1 deletion(-) diff --git a/inc/class-shortcode-ui.php b/inc/class-shortcode-ui.php index 4fec330c..671e04ca 100644 --- a/inc/class-shortcode-ui.php +++ b/inc/class-shortcode-ui.php @@ -67,7 +67,6 @@ private function __construct() { private function setup_actions() { add_action( 'admin_enqueue_scripts', array( $this, 'action_admin_enqueue_scripts' ) ); add_action( 'wp_enqueue_editor', array( $this, 'action_wp_enqueue_editor' ) ); - add_action( 'wp_ajax_bulk_do_shortcode', array( $this, 'handle_ajax_bulk_do_shortcode' ) ); add_action( 'rest_api_init', array( $this, 'action_rest_api_init' ) ); add_filter( 'wp_editor_settings', array( $this, 'filter_wp_editor_settings' ), 10, 2 ); } From e90671fe17fc6352141e37b1cee16fb2be89f3c5 Mon Sep 17 00:00:00 2001 From: Matth_eu Date: Wed, 2 Mar 2016 14:24:48 +0000 Subject: [PATCH 06/13] Fix CI issues --- inc/class-shortcode-ui.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/inc/class-shortcode-ui.php b/inc/class-shortcode-ui.php index 671e04ca..117b8e80 100644 --- a/inc/class-shortcode-ui.php +++ b/inc/class-shortcode-ui.php @@ -76,8 +76,8 @@ public function action_rest_api_init() { register_rest_route( 'shortcode-ui/v1', 'preview', array( 'methods' => 'GET', 'callback' => array( $this, 'handle_shortcode_preview' ), - 'args' => array( - 'query' => array( + 'args' => array( + 'query' => array( 'sanitize_callback' => array( $this, 'sanitize_rest_arg_arg_query' ), ), ) @@ -86,8 +86,8 @@ public function action_rest_api_init() { register_rest_route( 'shortcode-ui/v1', 'preview/bulk', array( 'methods' => 'GET', 'callback' => array( $this, 'handle_shortcode_preview_bulk' ), - 'args' => array( - 'queries' => array( + 'args' => array( + 'queries' => array( 'sanitize_callback' => array( $this, 'sanitize_rest_arg_arg_queries' ), ), ), @@ -397,7 +397,7 @@ private function render_shortcode_for_preview( $shortcode, $post_id = null ) { * Get a preview for a single shortcode to render in MCE preview. */ public function handle_shortcode_preview( WP_REST_Request $request ) { - return $this->get_shortcode_preview( $request->get_param('query') ); + return $this->get_shortcode_preview( $request->get_param( 'query' ) ); } /** @@ -405,7 +405,7 @@ public function handle_shortcode_preview( WP_REST_Request $request ) { */ public function handle_shortcode_preview_bulk( WP_REST_Request $request ) { - $queries = $request->get_param('queries'); + $queries = $request->get_param( 'queries' ); $responses = array(); if ( is_array( $queries ) ) { From 8c4e48f21f46d6d0a96406dae5ff9c243ec4b3d3 Mon Sep 17 00:00:00 2001 From: Matth_eu Date: Wed, 2 Mar 2016 14:48:22 +0000 Subject: [PATCH 07/13] CS - comma on each line of array --- inc/class-shortcode-ui.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inc/class-shortcode-ui.php b/inc/class-shortcode-ui.php index 117b8e80..a68633d3 100644 --- a/inc/class-shortcode-ui.php +++ b/inc/class-shortcode-ui.php @@ -80,7 +80,7 @@ public function action_rest_api_init() { 'query' => array( 'sanitize_callback' => array( $this, 'sanitize_rest_arg_arg_query' ), ), - ) + ), ) ); register_rest_route( 'shortcode-ui/v1', 'preview/bulk', array( From 969921368840513c1a97129bff117a707132b398 Mon Sep 17 00:00:00 2001 From: Matth_eu Date: Thu, 3 Mar 2016 11:05:31 +0000 Subject: [PATCH 08/13] use permission callback on endpoints --- inc/class-shortcode-ui.php | 177 +++++++++++++-------- js-tests/build/specs.js | 28 ++-- js/build/shortcode-ui.js | 28 ++-- js/src/utils/fetcher.js | 19 +-- js/src/utils/shortcode-view-constructor.js | 9 +- 5 files changed, 150 insertions(+), 111 deletions(-) diff --git a/inc/class-shortcode-ui.php b/inc/class-shortcode-ui.php index a68633d3..58c378b3 100644 --- a/inc/class-shortcode-ui.php +++ b/inc/class-shortcode-ui.php @@ -71,30 +71,6 @@ private function setup_actions() { add_filter( 'wp_editor_settings', array( $this, 'filter_wp_editor_settings' ), 10, 2 ); } - public function action_rest_api_init() { - - register_rest_route( 'shortcode-ui/v1', 'preview', array( - 'methods' => 'GET', - 'callback' => array( $this, 'handle_shortcode_preview' ), - 'args' => array( - 'query' => array( - 'sanitize_callback' => array( $this, 'sanitize_rest_arg_arg_query' ), - ), - ), - ) ); - - register_rest_route( 'shortcode-ui/v1', 'preview/bulk', array( - 'methods' => 'GET', - 'callback' => array( $this, 'handle_shortcode_preview_bulk' ), - 'args' => array( - 'queries' => array( - 'sanitize_callback' => array( $this, 'sanitize_rest_arg_arg_queries' ), - ), - ), - ) ); - - } - /** * When a WP_Editor is initialized on a page, call the 'register_shortcode_ui' action. * @@ -363,10 +339,6 @@ private function render_shortcode_for_preview( $shortcode, $post_id = null ) { define( 'SHORTCODE_UI_DOING_PREVIEW', true ); } - if ( ! current_user_can( 'edit_post', $post_id ) ) { - return $shortcode; - } - if ( ! empty( $post_id ) ) { // @codingStandardsIgnoreStart global $post; @@ -394,63 +366,136 @@ private function render_shortcode_for_preview( $shortcode, $post_id = null ) { } /** - * Get a preview for a single shortcode to render in MCE preview. + * Register rest api endpoints. */ - public function handle_shortcode_preview( WP_REST_Request $request ) { - return $this->get_shortcode_preview( $request->get_param( 'query' ) ); + public function action_rest_api_init() { + + register_rest_route( 'shortcode-ui/v1', 'preview', array( + 'methods' => 'GET', + 'callback' => array( $this, 'rest_preview_callback' ), + 'permission_callback' => array( $this, 'rest_preview_permission_callback' ), + 'args' => array( + 'shortcode' => array( + 'sanitize_callback' => array( $this, 'rest_sanitize_shortcode' ), + ), + 'post_id' => array( + 'sanitize_callback' => array( $this, 'rest_sanitize_post_id' ), + ), + ), + ) ); + + register_rest_route( 'shortcode-ui/v1', 'preview/bulk', array( + 'methods' => 'GET', + 'callback' => array( $this, 'rest_preview_bulk_callback' ), + 'permission_callback' => array( $this, 'rest_preview_permission_callback' ), + 'args' => array( + 'queries' => array( + 'sanitize_callback' => array( $this, 'rest_sanitize_queries' ), + 'validate_callback' => array( $this, 'rest_validate_queries' ), + ), + 'post_id' => array( + 'sanitize_callback' => array( $this, 'rest_sanitize_post_id' ), + ), + ), + ) ); + } /** - * Get a bunch of shortcodes to render in MCE preview. + * Permission check for getting a shortcode preview. + * + * @param WP_REST_Request $request + * @return boolean */ - public function handle_shortcode_preview_bulk( WP_REST_Request $request ) { - - $queries = $request->get_param( 'queries' ); - $responses = array(); + public function rest_preview_permission_callback( WP_REST_Request $request ) { + return current_user_can( 'edit_post', $request->get_param( 'post_id' ) ); + } - if ( is_array( $queries ) ) { - foreach ( $queries as $posted_query ) { - $responses[ $posted_query['counter'] ] = array( - 'query' => $posted_query, - 'response' => $this->render_shortcode_for_preview( $posted_query['shortcode'], $posted_query['post_id'] ), - ); - } + /** + * Sanitize collection of shortcode queries. + * + * Used for bulk requests. + * + * @param array $queries Queries + * @return string Queries + */ + public function rest_sanitize_queries( $queries ) { + $clean_queries = array(); + foreach ( $queries as $query ) { + $clean_queries[] = array( + 'counter' => absint( $query['counter'] ), + 'shortcode' => $this->rest_sanitize_shortcode( $query['shortcode'] ), + ); } + return $clean_queries; + } - return array_filter( $responses ); + /** + * Validate collection of shortcodes. + * + * Used for bulk requests. + * + * @param array $queries Queries + * @return boolean + */ + public function rest_validate_queries( $shortcodes ) { + return is_array( $shortcodes ); + } + /** + * Sanitize rest request shortcode arg. + * + * @param string $shortcode Shortcode + * @return string Shortcode + */ + public function rest_sanitize_shortcode( $shortcode ) { + return stripslashes( $shortcode ); } - public function sanitize_rest_arg_arg_query( $dirty_args ) { + /** + * Sanitize Post ID. + * + * @param mixed $shortcode Post Id + * @return int Post Id + */ + public function rest_sanitize_post_id( $post_id ) { + return absint( $post_id ); + } - $clean_args = array( - 'shortcode' => null, - 'post_id' => null, - ); + /** + * Get a preview for a single shortcode to render in MCE preview. + */ + public function rest_preview_callback( WP_REST_Request $request ) { - // Don't sanitize shortcodes — can contain HTML kses doesn't allow (e.g. sourcecode shortcode) - if ( ! empty( $dirty_args['shortcode'] ) ) { - $clean_args['shortcode'] = stripslashes( $dirty_args['shortcode'] ); - } + $shortcode = $request->get_param( 'shortcode' ); + $post_id = $request->get_param( 'post_id' ); - if ( isset( $dirty_args['post_id'] ) ) { - $clean_args['post_id'] = intval( $dirty_args['post_id'] ); - } + return array( + 'shortcode' => $shortcode, + 'post_id' => $post_id, + 'preview' => $this->render_shortcode_for_preview( $shortcode, $post_id ), + ); + } - if ( isset( $dirty_args['nonce'] ) ) { - $clean_args['nonce'] = sanitize_text_field( $dirty_args['nonce'] ); - } + /** + * Get a bunch of shortcodes previews to render in MCE preview. + */ + public function rest_preview_bulk_callback( WP_REST_Request $request ) { - if ( isset( $dirty_args['counter'] ) ) { - $clean_args['counter'] = intval( $dirty_args['counter'] ); - } + $previews = array(); + $post_id = $request->get_param( 'post_id' ); - return $clean_args; + foreach ( $request->get_param( 'queries' ) as $query ) { + $previews[] = array( + 'shortcode' => $query['shortcode'], + 'post_id' => $post_id, + 'counter' => $query['counter'], + 'preview' => $this->render_shortcode_for_preview( $query['shortcode'], $post_id ), + ); + } - } + return array_filter( $previews ); - public function sanitize_rest_arg_arg_queries( $arg ) { - return array_map( array( $this, 'sanitize_rest_arg_arg_query' ), (array) $arg ); } /** diff --git a/js-tests/build/specs.js b/js-tests/build/specs.js index 94cb7bfe..db9cd1bd 100644 --- a/js-tests/build/specs.js +++ b/js-tests/build/specs.js @@ -699,15 +699,13 @@ var Fetcher = (function() { * } * @return {Deferred} */ - this.queueToFetch = function( query ) { + this.queueToFetch = function( shortcode ) { var fetchPromise = new $.Deferred(); - query.counter = ++fetcher.counter; - fetcher.queries.push({ promise: fetchPromise, - query: query, - counter: query.counter + shortcode: shortcode, + counter: ++fetcher.counter }); if ( ! fetcher.timeout ) { @@ -735,21 +733,24 @@ var Fetcher = (function() { var request = $.get( shortcodeUIData.urls.bulkPreview, { _wpnonce: shortcodeUIData.nonces.wp_rest, - queries: _.pluck( fetcher.queries, 'query' ) + post_id: $( '#post_ID' ).val(), + queries: _.map( fetcher.queries, function( query ) { + return { shortcode: query.shortcode, counter: query.counter }; + } ) } ); request.done( function( responses ) { - _.each( responses, function( result, index ) { + _.each( responses, function( result ) { var matchedQuery = _.findWhere( fetcher.queries, { - counter: parseInt( index ), + counter: result.counter, }); if ( matchedQuery ) { fetcher.queries = _.without( fetcher.queries, matchedQuery ); - matchedQuery.promise.resolve( result ); + matchedQuery.promise.resolve( result.preview ); } } ); @@ -800,8 +801,8 @@ var shortcodeViewConstructor = { this.shortcodeModel = this.getShortcodeModel( this.shortcode ); this.fetching = this.delayedFetch(); - this.fetching.done( function( queryResponse ) { - var response = queryResponse.response; + this.fetching.done( function( response ) { + if ( '' === response ) { var span = $('').addClass('shortcake-notice shortcake-empty').text( self.shortcodeModel.formatShortcode() ); var wrapper = $('
').html( span ); @@ -887,10 +888,7 @@ var shortcodeViewConstructor = { * @return {Promise} */ delayedFetch: function() { - return fetcher.queueToFetch({ - post_id: $( '#post_ID' ).val(), - shortcode: this.shortcodeModel.formatShortcode(), - }); + return fetcher.queueToFetch( this.shortcodeModel.formatShortcode() ); }, /** diff --git a/js/build/shortcode-ui.js b/js/build/shortcode-ui.js index 883a72ab..e709187f 100644 --- a/js/build/shortcode-ui.js +++ b/js/build/shortcode-ui.js @@ -331,15 +331,13 @@ var Fetcher = (function() { * } * @return {Deferred} */ - this.queueToFetch = function( query ) { + this.queueToFetch = function( shortcode ) { var fetchPromise = new $.Deferred(); - query.counter = ++fetcher.counter; - fetcher.queries.push({ promise: fetchPromise, - query: query, - counter: query.counter + shortcode: shortcode, + counter: ++fetcher.counter }); if ( ! fetcher.timeout ) { @@ -367,21 +365,24 @@ var Fetcher = (function() { var request = $.get( shortcodeUIData.urls.bulkPreview, { _wpnonce: shortcodeUIData.nonces.wp_rest, - queries: _.pluck( fetcher.queries, 'query' ) + post_id: $( '#post_ID' ).val(), + queries: _.map( fetcher.queries, function( query ) { + return { shortcode: query.shortcode, counter: query.counter }; + } ) } ); request.done( function( responses ) { - _.each( responses, function( result, index ) { + _.each( responses, function( result ) { var matchedQuery = _.findWhere( fetcher.queries, { - counter: parseInt( index ), + counter: result.counter, }); if ( matchedQuery ) { fetcher.queries = _.without( fetcher.queries, matchedQuery ); - matchedQuery.promise.resolve( result ); + matchedQuery.promise.resolve( result.preview ); } } ); @@ -432,8 +433,8 @@ var shortcodeViewConstructor = { this.shortcodeModel = this.getShortcodeModel( this.shortcode ); this.fetching = this.delayedFetch(); - this.fetching.done( function( queryResponse ) { - var response = queryResponse.response; + this.fetching.done( function( response ) { + if ( '' === response ) { var span = $('').addClass('shortcake-notice shortcake-empty').text( self.shortcodeModel.formatShortcode() ); var wrapper = $('
').html( span ); @@ -519,10 +520,7 @@ var shortcodeViewConstructor = { * @return {Promise} */ delayedFetch: function() { - return fetcher.queueToFetch({ - post_id: $( '#post_ID' ).val(), - shortcode: this.shortcodeModel.formatShortcode(), - }); + return fetcher.queueToFetch( this.shortcodeModel.formatShortcode() ); }, /** diff --git a/js/src/utils/fetcher.js b/js/src/utils/fetcher.js index 011cba54..62d2c6d5 100644 --- a/js/src/utils/fetcher.js +++ b/js/src/utils/fetcher.js @@ -47,15 +47,13 @@ var Fetcher = (function() { * } * @return {Deferred} */ - this.queueToFetch = function( query ) { + this.queueToFetch = function( shortcode ) { var fetchPromise = new $.Deferred(); - query.counter = ++fetcher.counter; - fetcher.queries.push({ promise: fetchPromise, - query: query, - counter: query.counter + shortcode: shortcode, + counter: ++fetcher.counter }); if ( ! fetcher.timeout ) { @@ -83,21 +81,24 @@ var Fetcher = (function() { var request = $.get( shortcodeUIData.urls.bulkPreview, { _wpnonce: shortcodeUIData.nonces.wp_rest, - queries: _.pluck( fetcher.queries, 'query' ) + post_id: $( '#post_ID' ).val(), + queries: _.map( fetcher.queries, function( query ) { + return { shortcode: query.shortcode, counter: query.counter }; + } ) } ); request.done( function( responses ) { - _.each( responses, function( result, index ) { + _.each( responses, function( result ) { var matchedQuery = _.findWhere( fetcher.queries, { - counter: parseInt( index ), + counter: result.counter, }); if ( matchedQuery ) { fetcher.queries = _.without( fetcher.queries, matchedQuery ); - matchedQuery.promise.resolve( result ); + matchedQuery.promise.resolve( result.preview ); } } ); diff --git a/js/src/utils/shortcode-view-constructor.js b/js/src/utils/shortcode-view-constructor.js index e9495a62..350d22ae 100644 --- a/js/src/utils/shortcode-view-constructor.js +++ b/js/src/utils/shortcode-view-constructor.js @@ -28,8 +28,8 @@ var shortcodeViewConstructor = { this.shortcodeModel = this.getShortcodeModel( this.shortcode ); this.fetching = this.delayedFetch(); - this.fetching.done( function( queryResponse ) { - var response = queryResponse.response; + this.fetching.done( function( response ) { + if ( '' === response ) { var span = $('').addClass('shortcake-notice shortcake-empty').text( self.shortcodeModel.formatShortcode() ); var wrapper = $('
').html( span ); @@ -115,10 +115,7 @@ var shortcodeViewConstructor = { * @return {Promise} */ delayedFetch: function() { - return fetcher.queueToFetch({ - post_id: $( '#post_ID' ).val(), - shortcode: this.shortcodeModel.formatShortcode(), - }); + return fetcher.queueToFetch( this.shortcodeModel.formatShortcode() ); }, /** From e6392c1a537ed9f851284c98c8c5b8a07702cc24 Mon Sep 17 00:00:00 2001 From: Matth_eu Date: Thu, 3 Mar 2016 11:14:58 +0000 Subject: [PATCH 09/13] Better error handling --- inc/class-shortcode-ui.php | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/inc/class-shortcode-ui.php b/inc/class-shortcode-ui.php index 58c378b3..d142a348 100644 --- a/inc/class-shortcode-ui.php +++ b/inc/class-shortcode-ui.php @@ -377,9 +377,11 @@ public function action_rest_api_init() { 'args' => array( 'shortcode' => array( 'sanitize_callback' => array( $this, 'rest_sanitize_shortcode' ), + 'required' => true, ), 'post_id' => array( 'sanitize_callback' => array( $this, 'rest_sanitize_post_id' ), + 'required' => true, ), ), ) ); @@ -408,7 +410,16 @@ public function action_rest_api_init() { * @return boolean */ public function rest_preview_permission_callback( WP_REST_Request $request ) { - return current_user_can( 'edit_post', $request->get_param( 'post_id' ) ); + + if ( empty( $request->get_param( 'post_id' ) ) ) { + return new WP_Error( 'rest_no_post_id', __( 'No Post ID.' ) ); + } + + if ( ! current_user_can( 'edit_post', $request->get_param( 'post_id' ) ) ) { + return new WP_Error( 'rest_no_edit_post_cap', __( 'You do not have permission to edit this Post.' ) ); + } + + return true; } /** From 0f4358e029e0f425ad78046748e8bfc24adb585b Mon Sep 17 00:00:00 2001 From: Matth_eu Date: Thu, 3 Mar 2016 11:18:27 +0000 Subject: [PATCH 10/13] Fix PHP 5.2 errors --- inc/class-shortcode-ui.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/inc/class-shortcode-ui.php b/inc/class-shortcode-ui.php index d142a348..58233765 100644 --- a/inc/class-shortcode-ui.php +++ b/inc/class-shortcode-ui.php @@ -411,11 +411,13 @@ public function action_rest_api_init() { */ public function rest_preview_permission_callback( WP_REST_Request $request ) { - if ( empty( $request->get_param( 'post_id' ) ) ) { + $post_id = $request->get_param( 'post_id' ); + + if ( empty( $post_id ) ) { return new WP_Error( 'rest_no_post_id', __( 'No Post ID.' ) ); } - if ( ! current_user_can( 'edit_post', $request->get_param( 'post_id' ) ) ) { + if ( ! current_user_can( 'edit_post', $post_id ) ) { return new WP_Error( 'rest_no_edit_post_cap', __( 'You do not have permission to edit this Post.' ) ); } From b4cbbce89d70f887b6eef6dfe6d3607947bb6c2d Mon Sep 17 00:00:00 2001 From: Matth_eu Date: Mon, 27 Jun 2016 17:51:11 +0200 Subject: [PATCH 11/13] PHPUnit tests for rest requests --- php-tests/test-shortcode-ui.php | 115 ++++++++++++++++++++++++++++++++ 1 file changed, 115 insertions(+) diff --git a/php-tests/test-shortcode-ui.php b/php-tests/test-shortcode-ui.php index cf896c8f..8265de1c 100644 --- a/php-tests/test-shortcode-ui.php +++ b/php-tests/test-shortcode-ui.php @@ -62,4 +62,119 @@ public function test_register_shortcode_malicious_html() { $this->assertEquals( 'banana()', $shortcodes['foo']['attrs'][0]['description'] ); } + public function action_rest_api_init() { + + } + + public function test_rest_preview_permission_callback() { + + add_shortcode( 'test', function() { return 'foo'; } ); + + $instance = Shortcode_UI::get_instance(); + $author_id = self::factory()->user->create( array( 'role' => 'author' ) ); + $author_id_2 = self::factory()->user->create( array( 'role' => 'author' ) ); + $post_id = self::factory()->post->create( array( 'post_author' => $author_id ) ); + + wp_set_current_user( $author_id ); + + $rest_request = new WP_REST_Request( 'GET', 'shortcode-ui/v1/preview', [ 'post_id' => $post_id ] ); + + $permission = $instance->rest_preview_permission_callback( $rest_request ); + + // Test that you cannot generate a shortcode preview without passing a post ID + $this->assertInstanceOf( 'WP_Error', $permission ); + + $rest_request->set_param( 'post_id', $post_id ); + $permission = $instance->rest_preview_permission_callback( $rest_request ); + + // Assert that the user who created a post, + // is able to preview a shortcode for that post. + $this->assertTrue( $permission ); + + wp_set_current_user( $author_id_2 ); + + // Assert that a user who did NOT create the post + // is NOT able to preview a shortcode for that post. + $permission = $instance->rest_preview_permission_callback( $rest_request ); + $this->assertInstanceOf( 'WP_Error', $permission ); + + } + + public function test_rest_sanitize_queries() { + + $queries = Shortcode_UI::get_instance()->rest_sanitize_queries( array( + array( + 'counter' => 'foo', + 'shortcode' => '\foo', + ) + ) ); + + $this->assertEquals( count( $queries ), 1 ); + $this->assertInternalType( 'array', $queries ); + $this->assertInternalType( 'array', $queries[0] ); + $this->assertEquals( $queries[0]['counter'], 0 ); + $this->assertEquals( $queries[0]['shortcode'], 'foo' ); + + } + + public function test_rest_validate_queries() { + $this->assertTrue( Shortcode_UI::get_instance()->rest_validate_queries( array() ) ); + $this->assertFalse( Shortcode_UI::get_instance()->rest_validate_queries( 'foo' ) ); + } + + public function test_rest_sanitize_post_id() { + $this->assertInternalType( 'int', Shortcode_UI::get_instance()->rest_sanitize_post_id( 'foo' ) ); + } + + public function test_rest_preview_callback() { + + add_shortcode( 'test', function() { return 'foo'; } ); + + $author_id = self::factory()->user->create( array( 'role' => 'author' ) ); + $post_id = self::factory()->post->create( array( 'post_author' => $author_id ) ); + + wp_set_current_user( $author_id ); + + $rest_request = new WP_REST_Request( 'GET', 'shortcode-ui/v1/preview' ); + $rest_request->set_param( 'post_id', $post_id ); + $rest_request->set_param( 'shortcode', '[test]' ); + + $response = Shortcode_UI::get_instance()->rest_preview_callback( $rest_request ); + + $this->assertEquals( $response['shortcode'], '[test]' ); + $this->assertEquals( $response['post_id'], $post_id ); + $this->assertEquals( $response['preview'], 'foo' ); + + } + + public function test_rest_preview_bulk_callback() { + + add_shortcode( 'test', function() { return 'foo'; } ); + + $author_id = self::factory()->user->create( array( 'role' => 'author' ) ); + $post_id = self::factory()->post->create( array( 'post_author' => $author_id ) ); + + wp_set_current_user( $author_id ); + + $queries = array( + array( + 'counter' => 1, + 'shortcode' => '[test]', + ) + ); + + $rest_request = new WP_REST_Request( 'GET', 'shortcode-ui/v1/preview/bulk' ); + $rest_request->set_param( 'post_id', $post_id ); + $rest_request->set_param( 'queries', $queries ); + + $response = Shortcode_UI::get_instance()->rest_preview_bulk_callback( $rest_request ); + + $this->assertInternalType( 'array', $response ); + $this->assertEquals( $response[0]['shortcode'], '[test]' ); + $this->assertEquals( $response[0]['post_id'], $post_id ); + $this->assertEquals( $response[0]['counter'], 1 ); + $this->assertEquals( $response[0]['preview'], 'foo' ); + + } + } From 22c10fa0a28a3fbf5881539cc6b39e36202465d5 Mon Sep 17 00:00:00 2001 From: Matth_eu Date: Mon, 27 Jun 2016 17:59:00 +0200 Subject: [PATCH 12/13] Make tests work on PHP 5.2 --- php-tests/test-shortcode-ui.php | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/php-tests/test-shortcode-ui.php b/php-tests/test-shortcode-ui.php index 8265de1c..4ef2d40f 100644 --- a/php-tests/test-shortcode-ui.php +++ b/php-tests/test-shortcode-ui.php @@ -2,6 +2,14 @@ class Test_Shortcode_UI extends WP_UnitTestCase { + public function setUp() { + add_shortcode( 'test', array( $this, 'return_foo' ) ); + } + + public function return_foo() { + return 'foo'; + } + public function test_plugin_loaded() { $this->assertTrue( function_exists( 'shortcode_ui_register_for_shortcode' ) ); } @@ -68,8 +76,6 @@ public function action_rest_api_init() { public function test_rest_preview_permission_callback() { - add_shortcode( 'test', function() { return 'foo'; } ); - $instance = Shortcode_UI::get_instance(); $author_id = self::factory()->user->create( array( 'role' => 'author' ) ); $author_id_2 = self::factory()->user->create( array( 'role' => 'author' ) ); @@ -106,7 +112,7 @@ public function test_rest_sanitize_queries() { array( 'counter' => 'foo', 'shortcode' => '\foo', - ) + ), ) ); $this->assertEquals( count( $queries ), 1 ); @@ -128,8 +134,6 @@ public function test_rest_sanitize_post_id() { public function test_rest_preview_callback() { - add_shortcode( 'test', function() { return 'foo'; } ); - $author_id = self::factory()->user->create( array( 'role' => 'author' ) ); $post_id = self::factory()->post->create( array( 'post_author' => $author_id ) ); @@ -149,8 +153,6 @@ public function test_rest_preview_callback() { public function test_rest_preview_bulk_callback() { - add_shortcode( 'test', function() { return 'foo'; } ); - $author_id = self::factory()->user->create( array( 'role' => 'author' ) ); $post_id = self::factory()->post->create( array( 'post_author' => $author_id ) ); @@ -160,7 +162,7 @@ public function test_rest_preview_bulk_callback() { array( 'counter' => 1, 'shortcode' => '[test]', - ) + ), ); $rest_request = new WP_REST_Request( 'GET', 'shortcode-ui/v1/preview/bulk' ); From 3dfbaa5abe2e010239a45b60372ebf2c43d4d251 Mon Sep 17 00:00:00 2001 From: Matth_eu Date: Tue, 28 Jun 2016 00:42:19 +0200 Subject: [PATCH 13/13] PHP 5.2 fix --- php-tests/test-shortcode-ui.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php-tests/test-shortcode-ui.php b/php-tests/test-shortcode-ui.php index 4ef2d40f..749147c1 100644 --- a/php-tests/test-shortcode-ui.php +++ b/php-tests/test-shortcode-ui.php @@ -83,7 +83,7 @@ public function test_rest_preview_permission_callback() { wp_set_current_user( $author_id ); - $rest_request = new WP_REST_Request( 'GET', 'shortcode-ui/v1/preview', [ 'post_id' => $post_id ] ); + $rest_request = new WP_REST_Request( 'GET', 'shortcode-ui/v1/preview' ); $permission = $instance->rest_preview_permission_callback( $rest_request );