From 00935df91eb727fcd881b31bcc65dc0ae9ffa69f Mon Sep 17 00:00:00 2001 From: dashaluna Date: Tue, 31 May 2016 17:51:53 +0100 Subject: [PATCH 01/11] Initial code for User Select field --- inc/fields/class-field-user-select.php | 167 +++++++++++++ js/build/shortcode-ui.js | 219 +++++++++++++++++- .../views/edit-attribute-field-user-select.js | 194 ++++++++++++++++ js/src/views/edit-shortcode-form.js | 3 +- shortcode-ui.php | 4 +- 5 files changed, 574 insertions(+), 13 deletions(-) create mode 100644 inc/fields/class-field-user-select.php create mode 100644 js/src/views/edit-attribute-field-user-select.js diff --git a/inc/fields/class-field-user-select.php b/inc/fields/class-field-user-select.php new file mode 100644 index 00000000..6e18f52b --- /dev/null +++ b/inc/fields/class-field-user-select.php @@ -0,0 +1,167 @@ + array( + 'template' => 'shortcode-ui-field-user-select', + 'view' => 'editAttributeFieldUserSelect', + ), + ); + + /** + * Setup the instance. + * + * @return Shortcode_UI_Field_User_Select + */ + public static function get_instance() { + + if ( ! isset( self::$instance ) ) { + self::$instance = new self; + self::$instance->setup_actions(); + } + return self::$instance; + } + + /** + * Add the required actions and filters. + */ + private function setup_actions() { + + add_filter( 'shortcode_ui_fields', array( $this, 'filter_shortcode_ui_fields' ) ); + add_action( 'enqueue_shortcode_ui', array( $this, 'action_enqueue_shortcode_ui' ) ); + add_action( 'wp_ajax_shortcode_ui_user_field', array( $this, 'action_wp_ajax_shortcode_ui_user_field' ) ); + add_action( 'shortcode_ui_loaded_editor', array( $this, 'action_shortcode_ui_loaded_editor' ) ); + } + + /** + * Add our field to the shortcode fields. + * + * @param $fields + * + * @return array + */ + public function filter_shortcode_ui_fields( $fields ) { + + return array_merge( $fields, $this->fields ); + } + + /** + * Add Select2 for our UI. + */ + public function action_enqueue_shortcode_ui() { + + $plugin_dir = dirname( dirname( __FILE__ ) ); + + wp_enqueue_script( 'select2', plugins_url( 'lib/select2/select2.min.js', $plugin_dir ), array( 'jquery', 'jquery-ui-sortable' ), '3.5.2' ); + wp_enqueue_style( 'select2', plugins_url( 'lib/select2/select2.css', $plugin_dir ), null, '3.5.2' ); + + wp_localize_script( 'shortcode-ui', 'shortcodeUiUserFieldData', array( + 'nonce' => wp_create_nonce( 'shortcode_ui_field_user_select' ), + ) ); + } + + /** + * Output styles and templates used by user select field. + */ + public function action_shortcode_ui_loaded_editor() { + ?> + + + + + + post_fields + * Supports passing page number and search query string. + * + * @return null + */ + public function action_wp_ajax_shortcode_ui_user_field() { + + $nonce = isset( $_GET['nonce'] ) ? sanitize_text_field( $_GET['nonce'] ) : null; + $requested_shortcode = isset( $_GET['shortcode'] ) ? sanitize_text_field( $_GET['shortcode'] ) : null; + $requested_attr = isset( $_GET['attr'] ) ? sanitize_text_field( $_GET['attr'] ) : null; + $response = array( 'users' => array(), 'found_users' => 0, 'users_per_page' => 0 ); + + if ( ! wp_verify_nonce( $nonce, 'shortcode_ui_field_user_select' ) ) { + wp_send_json_error( $response ); + } + + $shortcodes = Shortcode_UI::get_instance()->get_shortcodes(); + + // Shortcode not found. + if ( ! isset( $shortcodes[ $requested_shortcode ] ) ) { + wp_send_json_error( $response ); + } + + $shortcode = $shortcodes[ $requested_shortcode ]; + + // Supports WP_User_Query query args. + foreach ( $shortcode['attrs'] as $attr ) { + if ( $attr['attr'] === $requested_attr && isset( $attr['query'] ) ) { + $query_args = $attr['query']; + } + } + + // Hardcoded user query args. + $query_args['search_columns'] = array( 'ID', 'user_login', 'user_nicename', 'user_email' ); + + if ( isset( $_GET['page'] ) ) { + $query_args['paged'] = sanitize_text_field( $_GET['page'] ); + } + + if ( ! empty( $_GET['s'] ) ) { + $query_args['search'] = sanitize_text_field( $_GET['s'] ); + } + + $query = new WP_User_Query( $query_args ); + + foreach ( $query->get_results() as $user ) { + array_push( $response['users'], array( + 'id' => $user->ID, + 'text' => html_entity_decode( $user->display_name ), + ) ); + } + + $response['found_users'] = $query->get_total(); + $response['users_per_page'] = $query->query_vars['number']; + + wp_send_json_success( $response ); + } +} diff --git a/js/build/shortcode-ui.js b/js/build/shortcode-ui.js index 66e7f002..6f1f7cb7 100644 --- a/js/build/shortcode-ui.js +++ b/js/build/shortcode-ui.js @@ -281,7 +281,7 @@ $(document).ready(function(){ }); }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"./collections/shortcodes.js":2,"./utils/shortcode-view-constructor.js":9,"./utils/sui.js":10,"./views/media-frame.js":19}],8:[function(require,module,exports){ +},{"./collections/shortcodes.js":2,"./utils/shortcode-view-constructor.js":9,"./utils/sui.js":10,"./views/media-frame.js":20}],8:[function(require,module,exports){ (function (global){ var $ = (typeof window !== "undefined" ? window['jQuery'] : typeof global !== "undefined" ? global['jQuery'] : null); var _ = (typeof window !== "undefined" ? window['_'] : typeof global !== "undefined" ? global['_'] : null); @@ -1049,7 +1049,7 @@ sui.views.editAttributeFieldColor = editAttributeField.extend({ }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"./../utils/sui.js":10,"./edit-attribute-field.js":15}],13:[function(require,module,exports){ +},{"./../utils/sui.js":10,"./edit-attribute-field.js":16}],13:[function(require,module,exports){ ( function( $ ) { var sui = window.Shortcode_UI; @@ -1443,6 +1443,202 @@ sui.views.editAttributeFieldColor = editAttributeField.extend({ } )( jQuery ); },{}],15:[function(require,module,exports){ +( function( $ ) { + + var sui = window.Shortcode_UI; + + // Cached Data. + var userSelectCache = {}; + + sui.views.editAttributeFieldUserSelect = sui.views.editAttributeField.extend( { + + events: { + 'change .shortcode-ui-user-select': 'inputChanged', + }, + + inputChanged: function(e) { + this.setValue( e.val ); + this.triggerCallbacks(); + }, + + render: function() { + + var self = this, + defaults = { multiple: false }; + + for ( var arg in defaults ) { + if ( ! this.model.get( arg ) ) { + this.model.set( arg, defaults[ arg ] ); + } + } + + var data = this.model.toJSON(); + data.id = 'shortcode-ui-' + this.model.get( 'attr' ) + '-' + this.model.cid; + + this.$el.html( this.template( data ) ); + + var ajaxData = { + action : 'shortcode_ui_user_field', + nonce : shortcodeUiUserFieldData.nonce, + shortcode : this.shortcode.get( 'shortcode_tag'), + attr : this.model.get( 'attr' ) + }; + + var $field = this.$el.find( '.shortcode-ui-user-select' ); + + $field.select2({ + + placeholder: "Search", + multiple: this.model.get( 'multiple' ), + ajax: { + url: ajaxurl, + dataType: 'json', + quietMillis: 250, + data: function (term, page) { + ajaxData.s = term; + ajaxData.page = page; + return ajaxData; + }, + results: function ( response, page ) { + + if ( ! response.success ) { + return { results: {}, more: false }; + } + + // Cache data for quicker rendering later. + userSelectCache = $.extend( userSelectCache, response.data.users ); + + var more = ( page * response.data.users_per_page ) < response.data.found_users; // whether or not there are more results available + return { results: response.data.users, more: more }; + + }, + }, + + /** + * Initialize Callback + * Used to set render the initial value. + * Has to make a request to get the title for the current ID. + */ + initSelection: function(element, callback) { + + var ids, parsedData = [], cached; + + // Convert stored value to array of IDs (int). + ids = $(element) + .val() + .split(',') + .map( function (str) { return str.trim(); } ) + .map( function (str) { return parseInt( str ); } ); + + if ( ids.length < 1 ) { + return; + } + + // Check if there is already cached data. + for ( var i = 0; i < ids.length; i++ ) { + cached = _.find( userSelectCache, _.matches( { id: ids[i] } ) ); + if ( cached ) { + parsedData.push( cached ); + } + } + + // If not multiple - return single value if we have one. + if ( parsedData.length && ! self.model.get( 'multiple' ) ) { + callback( parsedData[0] ); + return; + } + + var uncachedIds = _.difference( ids, _.pluck( parsedData, 'id' ) ); + + if ( ! uncachedIds.length ) { + + callback( parsedData ); + + } else { + + var initAjaxData = jQuery.extend( true, {}, ajaxData ); + initAjaxData.action = 'shortcode_ui_user_field'; + initAjaxData.post__in = uncachedIds; + + $.get( ajaxurl, initAjaxData ).done( function( response ) { + + if ( ! response.success ) { + return { results: {}, more: false }; + } + + userSelectCache = $.extend( userSelectCache, response.data.users ); + + // If not multi-select, expects single object, not array of objects. + if ( ! self.model.get( 'multiple' ) ) { + callback( response.data.users[0] ); + return; + } + + // Append new data to cached data. + // Sort by original order. + parsedData = parsedData + .concat( response.data.users ) + .sort(function (a, b) { + if ( ids.indexOf( a.id ) > ids.indexOf( b.id ) ) return 1; + if ( ids.indexOf( a.id ) < ids.indexOf( b.id ) ) return -1; + return 0; + }); + + callback( parsedData ); + return; + + } ); + + } + + }, + + } ); + + // Make multiple values sortable. + if ( this.model.get( 'multiple' ) ) { + $field.select2('container').find('ul.select2-choices').sortable({ + containment: 'parent', + start: function() { $('.shortcode-ui-user-select').select2('onSortStart'); }, + update: function() { $('.shortcode-ui-user-select').select2('onSortEnd'); } + }); + } + + return this; + + } + + } ); + + /** + * Extending SUI Media Controller to hide Select2 UI Drop-Down when menu + * changes in Meida modal + * 1. going back/forth between different shortcakes (refresh) + * 2. changing the menu in left column (deactivate) + * 3. @TODO closing the modal. + */ + var mediaController = sui.controllers.MediaController; + sui.controllers.MediaController = mediaController.extend({ + + refresh: function(){ + mediaController.prototype.refresh.apply( this, arguments ); + this.destroySelect2UI(); + }, + + //doesn't need to call parent as it already an "abstract" method in parent to provide callback + deactivate: function() { + this.destroySelect2UI(); + }, + + destroySelect2UI: function() { + $('.shortcode-ui-user-select.select2-container').select2( "close" ); + } + + }); + +} )( jQuery ); + +},{}],16:[function(require,module,exports){ (function (global){ var Backbone = (typeof window !== "undefined" ? window['Backbone'] : typeof global !== "undefined" ? global['Backbone'] : null), sui = require('./../utils/sui.js'), @@ -1585,7 +1781,7 @@ sui.views.editAttributeField = editAttributeField; module.exports = editAttributeField; }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"./../utils/sui.js":10}],16:[function(require,module,exports){ +},{"./../utils/sui.js":10}],17:[function(require,module,exports){ (function (global){ var wp = (typeof window !== "undefined" ? window['wp'] : typeof global !== "undefined" ? global['wp'] : null), sui = require('./../utils/sui.js'), @@ -1597,7 +1793,8 @@ backbone = (typeof window !== "undefined" ? window['Backbone'] : typeof global ! editAttributeFieldAttachment = require('./edit-attribute-field-attachment.js'), editAttributeFieldPostSelect = require('./edit-attribute-field-post-select.js'), editAttributeFieldTermSelect = require('./edit-attribute-field-term-select.js'), - editAttributeFieldColor = require('./edit-attribute-field-color.js'); + editAttributeFieldUserSelect = require('./edit-attribute-field-user-select.js'), + editAttributeFieldColor = require('./edit-attribute-field-color.js'); /** @@ -1670,7 +1867,7 @@ var EditShortcodeForm = wp.Backbone.View.extend({ module.exports = EditShortcodeForm; }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"./../utils/sui.js":10,"./edit-attribute-field-attachment.js":11,"./edit-attribute-field-color.js":12,"./edit-attribute-field-post-select.js":13,"./edit-attribute-field-term-select.js":14,"./edit-attribute-field.js":15}],17:[function(require,module,exports){ +},{"./../utils/sui.js":10,"./edit-attribute-field-attachment.js":11,"./edit-attribute-field-color.js":12,"./edit-attribute-field-post-select.js":13,"./edit-attribute-field-term-select.js":14,"./edit-attribute-field-user-select.js":15,"./edit-attribute-field.js":16}],18:[function(require,module,exports){ (function (global){ var wp = (typeof window !== "undefined" ? window['wp'] : typeof global !== "undefined" ? global['wp'] : null), $ = (typeof window !== "undefined" ? window['jQuery'] : typeof global !== "undefined" ? global['jQuery'] : null); @@ -1704,7 +1901,7 @@ var insertShortcodeListItem = wp.Backbone.View.extend({ module.exports = insertShortcodeListItem; }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{}],18:[function(require,module,exports){ +},{}],19:[function(require,module,exports){ (function (global){ var wp = (typeof window !== "undefined" ? window['wp'] : typeof global !== "undefined" ? global['wp'] : null); var Backbone = (typeof window !== "undefined" ? window['Backbone'] : typeof global !== "undefined" ? global['Backbone'] : null); @@ -1751,7 +1948,7 @@ var insertShortcodeList = wp.Backbone.View.extend({ module.exports = insertShortcodeList; }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"./../collections/shortcodes.js":2,"./insert-shortcode-list-item.js":17}],19:[function(require,module,exports){ +},{"./../collections/shortcodes.js":2,"./insert-shortcode-list-item.js":18}],20:[function(require,module,exports){ (function (global){ var wp = (typeof window !== "undefined" ? window['wp'] : typeof global !== "undefined" ? global['wp'] : null), $ = (typeof window !== "undefined" ? window['jQuery'] : typeof global !== "undefined" ? global['jQuery'] : null), @@ -1875,7 +2072,7 @@ var mediaFrame = postMediaFrame.extend( { module.exports = mediaFrame; }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"./../controllers/media-controller.js":3,"./media-toolbar":20,"./shortcode-ui":22}],20:[function(require,module,exports){ +},{"./../controllers/media-controller.js":3,"./media-toolbar":21,"./shortcode-ui":23}],21:[function(require,module,exports){ (function (global){ var wp = (typeof window !== "undefined" ? window['wp'] : typeof global !== "undefined" ? global['wp'] : null); @@ -1907,7 +2104,7 @@ var Toolbar = wp.media.view.Toolbar.extend({ module.exports = Toolbar; }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{}],21:[function(require,module,exports){ +},{}],22:[function(require,module,exports){ (function (global){ var wp = (typeof window !== "undefined" ? window['wp'] : typeof global !== "undefined" ? global['wp'] : null); sui = require('./../utils/sui.js'); @@ -1955,7 +2152,7 @@ sui.views.SearchShortcode = SearchShortcode; module.exports = SearchShortcode; }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"./../utils/sui.js":10}],22:[function(require,module,exports){ +},{"./../utils/sui.js":10}],23:[function(require,module,exports){ (function (global){ var Backbone = (typeof window !== "undefined" ? window['Backbone'] : typeof global !== "undefined" ? global['Backbone'] : null), insertShortcodeList = require('./insert-shortcode-list.js'), @@ -2060,4 +2257,4 @@ var Shortcode_UI = Backbone.View.extend({ module.exports = Shortcode_UI; }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"./../utils/sui.js":10,"./edit-shortcode-form.js":16,"./insert-shortcode-list.js":18,"./media-toolbar.js":20,"./search-shortcode.js":21}]},{},[7]); +},{"./../utils/sui.js":10,"./edit-shortcode-form.js":17,"./insert-shortcode-list.js":19,"./media-toolbar.js":21,"./search-shortcode.js":22}]},{},[7]); diff --git a/js/src/views/edit-attribute-field-user-select.js b/js/src/views/edit-attribute-field-user-select.js new file mode 100644 index 00000000..ff761d12 --- /dev/null +++ b/js/src/views/edit-attribute-field-user-select.js @@ -0,0 +1,194 @@ +( function( $ ) { + + var sui = window.Shortcode_UI; + + // Cached Data. + var userSelectCache = {}; + + sui.views.editAttributeFieldUserSelect = sui.views.editAttributeField.extend( { + + events: { + 'change .shortcode-ui-user-select': 'inputChanged', + }, + + inputChanged: function(e) { + this.setValue( e.val ); + this.triggerCallbacks(); + }, + + render: function() { + + var self = this, + defaults = { multiple: false }; + + for ( var arg in defaults ) { + if ( ! this.model.get( arg ) ) { + this.model.set( arg, defaults[ arg ] ); + } + } + + var data = this.model.toJSON(); + data.id = 'shortcode-ui-' + this.model.get( 'attr' ) + '-' + this.model.cid; + + this.$el.html( this.template( data ) ); + + var ajaxData = { + action : 'shortcode_ui_user_field', + nonce : shortcodeUiUserFieldData.nonce, + shortcode : this.shortcode.get( 'shortcode_tag'), + attr : this.model.get( 'attr' ) + }; + + var $field = this.$el.find( '.shortcode-ui-user-select' ); + + $field.select2({ + + placeholder: "Search", + multiple: this.model.get( 'multiple' ), + ajax: { + url: ajaxurl, + dataType: 'json', + quietMillis: 250, + data: function (term, page) { + ajaxData.s = term; + ajaxData.page = page; + return ajaxData; + }, + results: function ( response, page ) { + + if ( ! response.success ) { + return { results: {}, more: false }; + } + + // Cache data for quicker rendering later. + userSelectCache = $.extend( userSelectCache, response.data.users ); + + var more = ( page * response.data.users_per_page ) < response.data.found_users; // whether or not there are more results available + return { results: response.data.users, more: more }; + + }, + }, + + /** + * Initialize Callback + * Used to set render the initial value. + * Has to make a request to get the title for the current ID. + */ + initSelection: function(element, callback) { + + var ids, parsedData = [], cached; + + // Convert stored value to array of IDs (int). + ids = $(element) + .val() + .split(',') + .map( function (str) { return str.trim(); } ) + .map( function (str) { return parseInt( str ); } ); + + if ( ids.length < 1 ) { + return; + } + + // Check if there is already cached data. + for ( var i = 0; i < ids.length; i++ ) { + cached = _.find( userSelectCache, _.matches( { id: ids[i] } ) ); + if ( cached ) { + parsedData.push( cached ); + } + } + + // If not multiple - return single value if we have one. + if ( parsedData.length && ! self.model.get( 'multiple' ) ) { + callback( parsedData[0] ); + return; + } + + var uncachedIds = _.difference( ids, _.pluck( parsedData, 'id' ) ); + + if ( ! uncachedIds.length ) { + + callback( parsedData ); + + } else { + + var initAjaxData = jQuery.extend( true, {}, ajaxData ); + initAjaxData.action = 'shortcode_ui_user_field'; + initAjaxData.post__in = uncachedIds; + + $.get( ajaxurl, initAjaxData ).done( function( response ) { + + if ( ! response.success ) { + return { results: {}, more: false }; + } + + userSelectCache = $.extend( userSelectCache, response.data.users ); + + // If not multi-select, expects single object, not array of objects. + if ( ! self.model.get( 'multiple' ) ) { + callback( response.data.users[0] ); + return; + } + + // Append new data to cached data. + // Sort by original order. + parsedData = parsedData + .concat( response.data.users ) + .sort(function (a, b) { + if ( ids.indexOf( a.id ) > ids.indexOf( b.id ) ) return 1; + if ( ids.indexOf( a.id ) < ids.indexOf( b.id ) ) return -1; + return 0; + }); + + callback( parsedData ); + return; + + } ); + + } + + }, + + } ); + + // Make multiple values sortable. + if ( this.model.get( 'multiple' ) ) { + $field.select2('container').find('ul.select2-choices').sortable({ + containment: 'parent', + start: function() { $('.shortcode-ui-user-select').select2('onSortStart'); }, + update: function() { $('.shortcode-ui-user-select').select2('onSortEnd'); } + }); + } + + return this; + + } + + } ); + + /** + * Extending SUI Media Controller to hide Select2 UI Drop-Down when menu + * changes in Meida modal + * 1. going back/forth between different shortcakes (refresh) + * 2. changing the menu in left column (deactivate) + * 3. @TODO closing the modal. + */ + var mediaController = sui.controllers.MediaController; + sui.controllers.MediaController = mediaController.extend({ + + refresh: function(){ + mediaController.prototype.refresh.apply( this, arguments ); + this.destroySelect2UI(); + }, + + //doesn't need to call parent as it already an "abstract" method in parent to provide callback + deactivate: function() { + this.destroySelect2UI(); + }, + + destroySelect2UI: function() { + $('.shortcode-ui-user-select.select2-container').select2( "close" ); + } + + }); + +} )( jQuery ); diff --git a/js/src/views/edit-shortcode-form.js b/js/src/views/edit-shortcode-form.js index 8292f849..952f918b 100644 --- a/js/src/views/edit-shortcode-form.js +++ b/js/src/views/edit-shortcode-form.js @@ -8,7 +8,8 @@ backbone = require('backbone'), editAttributeFieldAttachment = require( 'sui-views/edit-attribute-field-attachment' ), editAttributeFieldPostSelect = require( 'sui-views/edit-attribute-field-post-select' ), editAttributeFieldTermSelect = require( 'sui-views/edit-attribute-field-term-select' ), - editAttributeFieldColor = require( 'sui-views/edit-attribute-field-color' ); + editAttributeFieldUserSelect = require( 'sui-views/edit-attribute-field-user-select' ), + editAttributeFieldColor = require( 'sui-views/edit-attribute-field-color' ); /** diff --git a/shortcode-ui.php b/shortcode-ui.php index 0492a2d5..0cea695e 100644 --- a/shortcode-ui.php +++ b/shortcode-ui.php @@ -19,7 +19,7 @@ * GNU General Public License for more details. */ -define( 'SHORTCODE_UI_VERSION', '0.7.1-alpha' ); +define( 'SHORTCODE_UI_VERSION', '0.7.2-alpha' ); require_once dirname( __FILE__ ) . '/inc/class-shortcode-ui.php'; require_once dirname( __FILE__ ) . '/inc/fields/class-shortcode-ui-fields.php'; @@ -27,6 +27,7 @@ require_once dirname( __FILE__ ) . '/inc/fields/class-field-color.php'; require_once dirname( __FILE__ ) . '/inc/fields/class-field-post-select.php'; require_once dirname( __FILE__ ) . '/inc/fields/class-field-term-select.php'; +require_once dirname( __FILE__ ) . '/inc/fields/class-field-user-select.php'; add_action( 'init', 'shortcode_ui_load_textdomain' ); @@ -44,6 +45,7 @@ function shortcode_ui_init() { $color_field = Shortcake_Field_Color::get_instance(); $post_field = Shortcode_UI_Field_Post_Select::get_instance(); $term_field = Shortcode_UI_Field_Term_Select::get_instance(); + $user_field = Shortcode_UI_Field_User_Select::get_instance(); } /** From 71c0d26dec3ac5ee49e5a55ce91fdb31ff944b2c Mon Sep 17 00:00:00 2001 From: dashaluna Date: Wed, 1 Jun 2016 14:37:51 +0100 Subject: [PATCH 02/11] Add 'number' query arg set to 10 by default - needed for pagination and WP_User_Query doesn't set default. Move default user shortcode args, so they can be overwritten by values in shorcode setup --- inc/fields/class-field-user-select.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/inc/fields/class-field-user-select.php b/inc/fields/class-field-user-select.php index 6e18f52b..2bba61ae 100644 --- a/inc/fields/class-field-user-select.php +++ b/inc/fields/class-field-user-select.php @@ -130,7 +130,11 @@ public function action_wp_ajax_shortcode_ui_user_field() { wp_send_json_error( $response ); } - $shortcode = $shortcodes[ $requested_shortcode ]; + $shortcode = $shortcodes[ $requested_shortcode ]; + + // Defaults user query args. + $query_args['search_columns'] = array( 'ID', 'user_login', 'user_nicename', 'user_email' ); + $query_args['number'] = 10; // Supports WP_User_Query query args. foreach ( $shortcode['attrs'] as $attr ) { @@ -139,9 +143,6 @@ public function action_wp_ajax_shortcode_ui_user_field() { } } - // Hardcoded user query args. - $query_args['search_columns'] = array( 'ID', 'user_login', 'user_nicename', 'user_email' ); - if ( isset( $_GET['page'] ) ) { $query_args['paged'] = sanitize_text_field( $_GET['page'] ); } From 55e502d6594ca208bfd8438ff32030065ac8cf74 Mon Sep 17 00:00:00 2001 From: dashaluna Date: Wed, 1 Jun 2016 14:39:12 +0100 Subject: [PATCH 03/11] Add * to search string, so it converts to % in SQL query and searchers for partial match --- inc/fields/class-field-user-select.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inc/fields/class-field-user-select.php b/inc/fields/class-field-user-select.php index 2bba61ae..ee73f42f 100644 --- a/inc/fields/class-field-user-select.php +++ b/inc/fields/class-field-user-select.php @@ -148,7 +148,7 @@ public function action_wp_ajax_shortcode_ui_user_field() { } if ( ! empty( $_GET['s'] ) ) { - $query_args['search'] = sanitize_text_field( $_GET['s'] ); + $query_args['search'] = '*' . sanitize_text_field( $_GET['s'] ) . '*'; } $query = new WP_User_Query( $query_args ); From d5967a3e0d1900791955db13fe63d1df2da74d1f Mon Sep 17 00:00:00 2001 From: dashaluna Date: Wed, 1 Jun 2016 15:04:25 +0100 Subject: [PATCH 04/11] Updated readme with new minor version, contributor name and description of an update --- README.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f5f9ec8b..1fd85319 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ # Shortcake (Shortcode UI) # -**Contributors:** fusionengineering, mattheu, danielbachhuber, zebulonj, goldenapples, jitendraharpalani, sanchothefat, bfintal, davisshaver, garyj, mte90, fredserva, khromov, bronsonquick +**Contributors:** fusionengineering, mattheu, danielbachhuber, zebulonj, goldenapples, jitendraharpalani, sanchothefat, bfintal, davisshaver, garyj, mte90, fredserva, khromov, bronsonquick, dashaluna **Tags:** shortcodes **Requires at least:** 4.1 **Tested up to:** 4.4 -**Stable tag:** 0.6.3 +**Stable tag:** 0.6.4 **License:** GPLv2 or later **License URI:** http://www.gnu.org/licenses/gpl-2.0.html @@ -60,6 +60,9 @@ We've removed the compatibility shim for the magical `content` attribute. If you ## Changelog ## +### 0.6.4 (June 1, 2016) ### +* Introduced a `user_select` input type for user selection. + ### 0.6.3 (May 19, 2016) ### * Introduced a `term_select` input type for taxonomy selection. From a077c94b48f5b693f92386e694bb916a23a24c1b Mon Sep 17 00:00:00 2001 From: Matth_eu Date: Wed, 1 Jun 2016 16:32:12 +0100 Subject: [PATCH 05/11] Fix init selection for user select --- inc/fields/class-field-user-select.php | 6 ++++++ js/build/shortcode-ui.js | 2 +- js/src/views/edit-attribute-field-user-select.js | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/inc/fields/class-field-user-select.php b/inc/fields/class-field-user-select.php index ee73f42f..ca3e71f2 100644 --- a/inc/fields/class-field-user-select.php +++ b/inc/fields/class-field-user-select.php @@ -136,6 +136,12 @@ public function action_wp_ajax_shortcode_ui_user_field() { $query_args['search_columns'] = array( 'ID', 'user_login', 'user_nicename', 'user_email' ); $query_args['number'] = 10; + // Include selected users. + if ( isset( $_GET['include'] ) ) { + $query_args['include'] = is_array( $_GET['include'] ) ? $_GET['include'] : explode( ',', $_GET['include'] ); + $query_args['include'] = array_map( 'absint', $query_args['include'] ); + } + // Supports WP_User_Query query args. foreach ( $shortcode['attrs'] as $attr ) { if ( $attr['attr'] === $requested_attr && isset( $attr['query'] ) ) { diff --git a/js/build/shortcode-ui.js b/js/build/shortcode-ui.js index 1cbeb4ca..3f302056 100644 --- a/js/build/shortcode-ui.js +++ b/js/build/shortcode-ui.js @@ -1558,7 +1558,7 @@ sui.views.editAttributeFieldColor = editAttributeField.extend({ var initAjaxData = jQuery.extend( true, {}, ajaxData ); initAjaxData.action = 'shortcode_ui_user_field'; - initAjaxData.post__in = uncachedIds; + initAjaxData.include = uncachedIds; $.get( ajaxurl, initAjaxData ).done( function( response ) { diff --git a/js/src/views/edit-attribute-field-user-select.js b/js/src/views/edit-attribute-field-user-select.js index ff761d12..ff74bc98 100644 --- a/js/src/views/edit-attribute-field-user-select.js +++ b/js/src/views/edit-attribute-field-user-select.js @@ -113,7 +113,7 @@ var initAjaxData = jQuery.extend( true, {}, ajaxData ); initAjaxData.action = 'shortcode_ui_user_field'; - initAjaxData.post__in = uncachedIds; + initAjaxData.include = uncachedIds; $.get( ajaxurl, initAjaxData ).done( function( response ) { From e2b9c7a9c47bcd6de50734361b4489e3b053a03b Mon Sep 17 00:00:00 2001 From: Matth_eu Date: Wed, 1 Jun 2016 16:34:07 +0100 Subject: [PATCH 06/11] Add users field to dev --- dev.php | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/dev.php b/dev.php index f3d66bec..1488c887 100644 --- a/dev.php +++ b/dev.php @@ -193,6 +193,12 @@ function shortcode_ui_dev_advanced_example() { 'taxonomy' => 'post_tag', 'multiple' => true, ), + array( + 'label' => __( 'User Select', 'shortcode-ui-example' ), + 'attr' => 'users', + 'type' => 'user_select', + 'multiple' => true, + ), array( 'label' => esc_html__( 'Background Color', 'shortcode-ui-example' ), 'attr' => 'background-color', @@ -285,8 +291,16 @@ function shortcode_ui_dev_shortcode( $attr, $content, $shortcode_tag ) { 'source' => '', 'attachment' => 0, 'page' => null, + 'users' => '', ), $attr, $shortcode_tag ); + $attr['users'] = array_map( + function( $user_id ) { + $data = get_userdata( $user_id ); + return $data->display_name; + }, + array_filter( array_map( 'absint', explode( ',', $attr['users'] ) ) ) + ); // Shortcode callbacks must return content, hence, output buffering here. ob_start(); ?> @@ -295,6 +309,9 @@ function shortcode_ui_dev_shortcode( $attr, $content, $shortcode_tag ) {


+ +
+

Date: Thu, 2 Jun 2016 16:05:14 +0100 Subject: [PATCH 07/11] Fix version numbers --- README.md | 12 ++++++------ shortcode-ui.php | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 1fd85319..af2c6f8b 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,11 @@ # Shortcake (Shortcode UI) # **Contributors:** fusionengineering, mattheu, danielbachhuber, zebulonj, goldenapples, jitendraharpalani, sanchothefat, bfintal, davisshaver, garyj, mte90, fredserva, khromov, bronsonquick, dashaluna -**Tags:** shortcodes -**Requires at least:** 4.1 -**Tested up to:** 4.4 -**Stable tag:** 0.6.4 -**License:** GPLv2 or later -**License URI:** http://www.gnu.org/licenses/gpl-2.0.html +**Tags:** shortcodes +**Requires at least:** 4.1 +**Tested up to:** 4.4 +**Stable tag:** 0.6.3 +**License:** GPLv2 or later +**License URI:** http://www.gnu.org/licenses/gpl-2.0.html Shortcake makes using WordPress shortcodes a piece of cake. diff --git a/shortcode-ui.php b/shortcode-ui.php index 0cea695e..d97b87ad 100644 --- a/shortcode-ui.php +++ b/shortcode-ui.php @@ -19,7 +19,7 @@ * GNU General Public License for more details. */ -define( 'SHORTCODE_UI_VERSION', '0.7.2-alpha' ); +define( 'SHORTCODE_UI_VERSION', '0.7.0-alpha' ); require_once dirname( __FILE__ ) . '/inc/class-shortcode-ui.php'; require_once dirname( __FILE__ ) . '/inc/fields/class-shortcode-ui-fields.php'; From a9098e8255a649f273f533bba20c7d8abb0df8e5 Mon Sep 17 00:00:00 2001 From: dashaluna Date: Fri, 3 Jun 2016 11:17:02 +0100 Subject: [PATCH 08/11] Move all extractions at the top of the function. wp_unslash vars before sanitization --- inc/fields/class-field-user-select.php | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/inc/fields/class-field-user-select.php b/inc/fields/class-field-user-select.php index ca3e71f2..684ecf07 100644 --- a/inc/fields/class-field-user-select.php +++ b/inc/fields/class-field-user-select.php @@ -114,9 +114,12 @@ public function action_shortcode_ui_loaded_editor() { */ public function action_wp_ajax_shortcode_ui_user_field() { - $nonce = isset( $_GET['nonce'] ) ? sanitize_text_field( $_GET['nonce'] ) : null; - $requested_shortcode = isset( $_GET['shortcode'] ) ? sanitize_text_field( $_GET['shortcode'] ) : null; - $requested_attr = isset( $_GET['attr'] ) ? sanitize_text_field( $_GET['attr'] ) : null; + $nonce = isset( $_GET['nonce'] ) ? sanitize_text_field( wp_unslash( $_GET['nonce'] ) ) : null; + $requested_shortcode = isset( $_GET['shortcode'] ) ? sanitize_text_field( wp_unslash( $_GET['shortcode'] ) ) : null; + $requested_attr = isset( $_GET['attr'] ) ? sanitize_text_field( wp_unslash( $_GET['attr'] ) ) : null; + $include = isset( $_GET['include'] ) ? sanitize_text_field( wp_unslash( $_GET['include'] ) ) : null; + $page = isset( $_GET['page'] ) ? sanitize_text_field( wp_unslash( $_GET['page'] ) ) : null; + $search_str = isset( $_GET['s'] ) ? sanitize_text_field( wp_unslash( $_GET['s'] ) ) : null; $response = array( 'users' => array(), 'found_users' => 0, 'users_per_page' => 0 ); if ( ! wp_verify_nonce( $nonce, 'shortcode_ui_field_user_select' ) ) { @@ -137,8 +140,8 @@ public function action_wp_ajax_shortcode_ui_user_field() { $query_args['number'] = 10; // Include selected users. - if ( isset( $_GET['include'] ) ) { - $query_args['include'] = is_array( $_GET['include'] ) ? $_GET['include'] : explode( ',', $_GET['include'] ); + if ( $include ) { + $query_args['include'] = is_array( $include ) ? $include : explode( ',', $include ); $query_args['include'] = array_map( 'absint', $query_args['include'] ); } @@ -149,12 +152,12 @@ public function action_wp_ajax_shortcode_ui_user_field() { } } - if ( isset( $_GET['page'] ) ) { - $query_args['paged'] = sanitize_text_field( $_GET['page'] ); + if ( $page ) { + $query_args['paged'] = $page; } - if ( ! empty( $_GET['s'] ) ) { - $query_args['search'] = '*' . sanitize_text_field( $_GET['s'] ) . '*'; + if ( $search_str ) { + $query_args['search'] = '*' . $search_str . '*'; } $query = new WP_User_Query( $query_args ); From 9e816a1b594dbf20c8f9878eaae2d8b68bc58eee Mon Sep 17 00:00:00 2001 From: dashaluna Date: Fri, 3 Jun 2016 13:41:50 +0100 Subject: [PATCH 09/11] Add registration of select2 js and style outside of select fields. Enqueue in select fields using handle --- inc/class-shortcode-ui.php | 3 +++ inc/fields/class-field-post-select.php | 6 ++---- inc/fields/class-field-term-select.php | 5 ++--- inc/fields/class-field-user-select.php | 6 ++---- 4 files changed, 9 insertions(+), 11 deletions(-) diff --git a/inc/class-shortcode-ui.php b/inc/class-shortcode-ui.php index 54bc03c7..77671a3f 100644 --- a/inc/class-shortcode-ui.php +++ b/inc/class-shortcode-ui.php @@ -195,6 +195,9 @@ public function get_shortcode( $shortcode_tag ) { */ public function action_admin_enqueue_scripts( $editor_supports ) { add_editor_style( trailingslashit( $this->plugin_url ) . 'css/shortcode-ui-editor-styles.css' ); + + wp_register_script( 'select2', trailingslashit( $this->plugin_url ) . 'lib/select2/select2.min.js', array( 'jquery', 'jquery-ui-sortable' ), '3.5.2' ); + wp_register_style( 'select2', trailingslashit( $this->plugin_url ) . 'lib/select2/select2.css', null, '3.5.2' ); } /** diff --git a/inc/fields/class-field-post-select.php b/inc/fields/class-field-post-select.php index 6f5d3934..3032725b 100644 --- a/inc/fields/class-field-post-select.php +++ b/inc/fields/class-field-post-select.php @@ -38,10 +38,8 @@ public function filter_shortcode_ui_fields( $fields ) { public function action_enqueue_shortcode_ui() { - $plugin_dir = dirname( dirname( __FILE__ ) ); - - wp_enqueue_script( 'select2', plugins_url( 'lib/select2/select2.min.js', $plugin_dir ) , array( 'jquery', 'jquery-ui-sortable' ), '3.5.2' ); - wp_enqueue_style( 'select2', plugins_url( 'lib/select2/select2.css', $plugin_dir ), null, '3.5.2' ); + wp_enqueue_script( 'select2' ); + wp_enqueue_style( 'select2' ); wp_localize_script( 'shortcode-ui', 'shortcodeUiPostFieldData', array( 'nonce' => wp_create_nonce( 'shortcode_ui_field_post_select' ), diff --git a/inc/fields/class-field-term-select.php b/inc/fields/class-field-term-select.php index 1f1e5b4d..63c382a8 100644 --- a/inc/fields/class-field-term-select.php +++ b/inc/fields/class-field-term-select.php @@ -51,10 +51,9 @@ public function filter_shortcode_ui_fields( $fields ) { * Add Select2 for our UI. */ public function action_enqueue_shortcode_ui() { - $plugin_dir = dirname( dirname( __FILE__ ) ); - wp_enqueue_script( 'select2', plugins_url( 'lib/select2/select2.min.js', $plugin_dir ), array( 'jquery', 'jquery-ui-sortable' ), '3.5.2' ); - wp_enqueue_style( 'select2', plugins_url( 'lib/select2/select2.css', $plugin_dir ), null, '3.5.2' ); + wp_enqueue_script( 'select2' ); + wp_enqueue_style( 'select2' ); wp_localize_script( 'shortcode-ui', 'shortcodeUiTermFieldData', array( 'nonce' => wp_create_nonce( 'shortcode_ui_field_term_select' ), diff --git a/inc/fields/class-field-user-select.php b/inc/fields/class-field-user-select.php index 684ecf07..eb21aa84 100644 --- a/inc/fields/class-field-user-select.php +++ b/inc/fields/class-field-user-select.php @@ -57,10 +57,8 @@ public function filter_shortcode_ui_fields( $fields ) { */ public function action_enqueue_shortcode_ui() { - $plugin_dir = dirname( dirname( __FILE__ ) ); - - wp_enqueue_script( 'select2', plugins_url( 'lib/select2/select2.min.js', $plugin_dir ), array( 'jquery', 'jquery-ui-sortable' ), '3.5.2' ); - wp_enqueue_style( 'select2', plugins_url( 'lib/select2/select2.css', $plugin_dir ), null, '3.5.2' ); + wp_enqueue_script( 'select2' ); + wp_enqueue_style( 'select2' ); wp_localize_script( 'shortcode-ui', 'shortcodeUiUserFieldData', array( 'nonce' => wp_create_nonce( 'shortcode_ui_field_user_select' ), From c9a1365eb65bc9ef6ffc2f74b691d5bc4099f66c Mon Sep 17 00:00:00 2001 From: dashaluna Date: Fri, 3 Jun 2016 15:16:27 +0100 Subject: [PATCH 10/11] Fix sanitisation of include, it's an array. Oops --- inc/fields/class-field-user-select.php | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/inc/fields/class-field-user-select.php b/inc/fields/class-field-user-select.php index eb21aa84..c3fbab95 100644 --- a/inc/fields/class-field-user-select.php +++ b/inc/fields/class-field-user-select.php @@ -115,11 +115,16 @@ public function action_wp_ajax_shortcode_ui_user_field() { $nonce = isset( $_GET['nonce'] ) ? sanitize_text_field( wp_unslash( $_GET['nonce'] ) ) : null; $requested_shortcode = isset( $_GET['shortcode'] ) ? sanitize_text_field( wp_unslash( $_GET['shortcode'] ) ) : null; $requested_attr = isset( $_GET['attr'] ) ? sanitize_text_field( wp_unslash( $_GET['attr'] ) ) : null; - $include = isset( $_GET['include'] ) ? sanitize_text_field( wp_unslash( $_GET['include'] ) ) : null; $page = isset( $_GET['page'] ) ? sanitize_text_field( wp_unslash( $_GET['page'] ) ) : null; $search_str = isset( $_GET['s'] ) ? sanitize_text_field( wp_unslash( $_GET['s'] ) ) : null; $response = array( 'users' => array(), 'found_users' => 0, 'users_per_page' => 0 ); + if ( isset( $_GET['include'] ) ) { + // Make sure include is always an array & sanitize its values. + $include = is_array( $_GET['include'] ) ? $_GET['include'] : explode( ',', $_GET['include'] ); + $include = array_map( 'absint', stripslashes_deep( $include ) ); + } + if ( ! wp_verify_nonce( $nonce, 'shortcode_ui_field_user_select' ) ) { wp_send_json_error( $response ); } @@ -137,10 +142,9 @@ public function action_wp_ajax_shortcode_ui_user_field() { $query_args['search_columns'] = array( 'ID', 'user_login', 'user_nicename', 'user_email' ); $query_args['number'] = 10; - // Include selected users. + // Include selected users to be displayed. if ( $include ) { - $query_args['include'] = is_array( $include ) ? $include : explode( ',', $include ); - $query_args['include'] = array_map( 'absint', $query_args['include'] ); + $query_args['include'] = $include; } // Supports WP_User_Query query args. From 0b9e7c9379701786eeda1135dc44824ca06448db Mon Sep 17 00:00:00 2001 From: dashaluna Date: Fri, 3 Jun 2016 16:02:46 +0100 Subject: [PATCH 11/11] Declare default value for , so if statement don't do warning if it's not set --- inc/fields/class-field-user-select.php | 1 + 1 file changed, 1 insertion(+) diff --git a/inc/fields/class-field-user-select.php b/inc/fields/class-field-user-select.php index c3fbab95..779fb8fd 100644 --- a/inc/fields/class-field-user-select.php +++ b/inc/fields/class-field-user-select.php @@ -119,6 +119,7 @@ public function action_wp_ajax_shortcode_ui_user_field() { $search_str = isset( $_GET['s'] ) ? sanitize_text_field( wp_unslash( $_GET['s'] ) ) : null; $response = array( 'users' => array(), 'found_users' => 0, 'users_per_page' => 0 ); + $include = null; if ( isset( $_GET['include'] ) ) { // Make sure include is always an array & sanitize its values. $include = is_array( $_GET['include'] ) ? $_GET['include'] : explode( ',', $_GET['include'] );