commit bd0ea78f34d1a118064d945d48e3840239212b47 Author: Ruben Garcia Date: Tue Mar 14 20:07:56 2017 +0100 Initial commit diff --git a/cmb-field-ajax-search.php b/cmb-field-ajax-search.php new file mode 100644 index 0000000..3b71f1b --- /dev/null +++ b/cmb-field-ajax-search.php @@ -0,0 +1,249 @@ +setup_admin_scripts(); + $field_name = $field->_name(); + $default_limit = 1; + + // Current filter is cmb2_render_{$object_to_search}_ajax_search ( post, user or term ) + $object_to_search = str_replace( 'cmb2_render_', '', str_replace( '_ajax_search', '', current_filter() ) ); + + if( $field->args( 'multiple' ) == true ) { + $default_limit = -1; // 0 or -1 means unlimited + + ?>input( array( + 'type' => 'hidden', + 'name' => $field_name, + 'value' => $value, + 'desc' => false + ) ); + + $input_value = ( $value ? $this->object_text( $field_name, $value, $object_to_search ) : '' ); + } + + echo $field_type->input( array( + 'type' => 'text', + 'name' => $field_name . '_input', + 'id' => $field_name . '_input', + 'class' => 'cmb-ajax-search cmb-' . $object_to_search . '-ajax-search', + 'value' => $input_value, + 'desc' => false, + 'data-multiple' => $field->args( 'multiple' ) ? $field->args( 'multiple' ) : '0', + 'data-limit' => $field->args( 'limit' ) ? $field->args( 'limit' ) : $default_limit, + 'data-sortable' => $field->args( 'sortable' ) ? $field->args( 'sortable' ) : '0', + 'data-object-type' => $object_to_search, + 'data-query-args' => $field->args( 'query_args' ) ? htmlspecialchars( json_encode( $field->args( 'query_args' ) ), ENT_QUOTES, 'UTF-8' ) : '' + ) ); + + echo ''; + + $field_type->_desc( true, true ); + + } + + /** + * Optionally save the latitude/longitude values into two custom fields + */ + public function sanitize( $override_value, $value, $object_id, $field_args ) { + $fid = $field_args['id']; + + if($field_args['render_row_cb'][0]->data_to_save[$field_args['id']]) { + $value = $field_args['render_row_cb'][0]->data_to_save[$field_args['id']]; + } else { + $value = false; + } + + return $value; + } + + /** + * Enqueue scripts and styles + */ + public function setup_admin_scripts() { + + wp_register_script( 'jquery-autocomplete', plugins_url( 'js/jquery.autocomplete.min.js', __FILE__ ), array( 'jquery' ), self::VERSION ); + wp_register_script( 'cmb-ajax-search', plugins_url( 'js/ajax-search.js', __FILE__ ), array( 'jquery', 'jquery-autocomplete', 'jquery-ui-sortable' ), self::VERSION ); + + wp_localize_script( 'cmb-ajax-search', 'cmb_ajax_search', array( + 'ajaxurl' => admin_url( 'admin-ajax.php' ), + 'nonce' => wp_create_nonce( 'cmb_ajax_search_get_results' ) + ) ); + + wp_enqueue_script( 'cmb-ajax-search' ); + wp_enqueue_style( 'cmb-ajax-search', plugins_url( 'css/ajax-search.css', __FILE__ ), array(), self::VERSION ); + + } + + /** + * Ajax request : get results + */ + public function get_results() { + $nonce = $_POST['nonce']; + + if ( ! wp_verify_nonce( $nonce, 'cmb_ajax_search_get_results' ) ) { + // Wrong nonce + die( json_encode( array( + 'error' => __( 'Error : Unauthorized action' ) + ) ) ); + } else if ( ( ! isset( $_POST['field_id'] ) || empty( $_POST['field_id'] ) ) + || ( ! isset( $_POST['object_type'] ) || empty( $_POST['object_type'] ) ) ) { + // Wrong request parameters (field_id and object_type are mandatory) + die( json_encode( array( + 'error' => __( 'Error : Wrong request parameters' ) + ) ) ); + } else { + $query_args = json_decode( stripslashes( htmlspecialchars_decode( $_POST['query_args'] ) ), true ); + $data = array(); + $results = array(); + + switch( $_POST['object_type'] ) { + case 'post': + $query_args['s'] = $_POST['query']; + $query = new WP_Query( $query_args ); + $results = $query->posts; + break; + case 'user': + $query_args['search'] = '*' . $_POST['query'] . '*'; + $query = new WP_User_Query( $query_args ); + $results = $query->results; + break; + case 'term': + $query_args['search'] = $_POST['query']; + $query = new WP_Term_Query( $query_args ); + $results = $query->terms; + break; + } + + foreach ( $results as $result ) : + if( $_POST['object_type'] == 'term' ) { + $result_id = $result->term_id; + } else { + $result_id = $result->ID; + } + + $data[] = array( + 'id' => $result_id, + 'value' => $this->object_text( $_POST['field_id'], $result_id, $_POST['object_type'] ), + 'link' => $this->object_link( $_POST['field_id'], $result_id, $_POST['object_type'] ) + ); + endforeach; + + wp_send_json( $data ); + exit; + } + } + + public function object_text( $field_id, $object_id, $object_type ) { + $text = ''; + + if( $object_type == 'post' ) { + $text = get_the_title( $object_id ); + } else if( $object_type == 'user' ) { + $text = get_the_author_meta('display_name', $object_id); + } else if( $object_type == 'term' ) { + $term = get_term( $object_id ); + + $text = $term->name; + } + + $text = apply_filters( "cmb_{$field_id}_ajax_search_result_text", $text, $object_id, $object_type ); + + return $text; + } + + public function object_link( $field_id, $object_id, $object_type ) { + $link = '#'; + + if( $object_type == 'post' ) { + $link = get_edit_post_link( $object_id ); + } else if( $object_type == 'user' ) { + $link = get_edit_user_link( $object_id ); + } else if( $object_type == 'term' ) { + $link = get_edit_term_link( $object_id ); + } + + $link = apply_filters( "cmb_{$field_id}_ajax_search_result_link", $link, $object_id, $object_type ); + + return $link; + } + + } + + $cmb2_field_ajax_search = new CMB2_Field_Ajax_Search(); + +} + diff --git a/css/ajax-search.css b/css/ajax-search.css new file mode 100644 index 0000000..2de6421 --- /dev/null +++ b/css/ajax-search.css @@ -0,0 +1,27 @@ +.autocomplete-suggestions { border: 1px solid #DDD; background: #FFF; overflow: auto; box-sizing: border-box; } +.autocomplete-suggestion { padding: 5px 5px; white-space: nowrap; overflow: hidden; cursor: pointer; } +.autocomplete-no-suggestion { padding: 5px 5px; white-space: nowrap; overflow: hidden; } +.autocomplete-selected { background: #F0F0F0; } +.autocomplete-suggestions strong { font-weight: normal; color: #3399FF; } +.autocomplete-group { padding: 2px 5px; } +.autocomplete-group strong { display: block; border-bottom: 1px solid #000; } + +input.cmb-ajax-search { width: 30em; } +.cmb-ajax-search-results { width: 30em; padding: 0 1px; box-sizing: border-box; margin-bottom: 5px; } +.cmb-ajax-search-results li { margin: 0; border-bottom: 1px solid #f4f4f4; padding: 7px 5px; background: #fff; } +.cmb-ajax-search-results li:last-child { border-bottom: none; } +.cmb-ajax-search-results li span.hndl { font-size: 13px; line-height: 16px; color: #ccc; margin: 0 8px 0 0; height: 16px; cursor: s-resize; } +.cmb-ajax-search-results li span.hndl:before { content: '\2807'; } +.cmb-ajax-search-results li a.edit-link { color: #333; text-decoration: none; } +.cmb-ajax-search-results li a.edit-link:hover { color: #00a0d2; text-decoration: underline; } +.cmb-ajax-search-results li a.remover { float: right; cursor:pointer; color: #ccc; } +.cmb-ajax-search-results li a.remover span { height: 16px; line-height: 16px; font-size: 14px; } +.cmb-ajax-search-results li a.remover span.dashicons-dismiss { display: none; } +.cmb-ajax-search-results li a.remover:hover { color: #C00; } +.cmb-ajax-search-results li a.remover:hover span.dashicons-dismiss { display: inline-block; } +.cmb-ajax-search-results li a.remover:hover span.dashicons-no { display: none; } +.cmb-ajax-search-results .ui-state-highlight { background: #f4f4f4; } +.cmb-ajax-search-spinner { position: absolute; margin: 9px 0 0 -25px; width: 15px; display:none; } + +.columns-2 #postbox-container-1 .cmb-ajax-search-spinner { right: 25px; margin: -23px 0 0 0; } + diff --git a/example.gif b/example.gif new file mode 100644 index 0000000..dbcc613 Binary files /dev/null and b/example.gif differ diff --git a/js/ajax-search.js b/js/ajax-search.js new file mode 100644 index 0000000..32f17db --- /dev/null +++ b/js/ajax-search.js @@ -0,0 +1,99 @@ +(function( $ ) { + $('.cmb-ajax-search').each(function () { + var input_id = $(this).attr('id'); // Field id with '_input' sufix (the searchable field) + var field_id = $(this).attr('id').replace( new RegExp('_input$'), '' ); // Field id, the true one field + var object_type = $(this).attr('data-object-type'); + var query_args = $(this).attr('data-query-args'); + + $(this).autocomplete({ + serviceUrl: cmb_ajax_search.ajaxurl, + type: 'POST', + triggerSelectOnValidInput: false, + showNoSuggestionNotice: true, + params: { + action : 'cmb_ajax_search_get_results', + nonce : cmb_ajax_search.nonce, // nonce + field_id : field_id, // Field id for hook purposes + object_type : object_type, // post, user or term + query_args : query_args, // Query args passed to field + }, + transformResult: function( results ) { + var suggestions = $.parseJSON( results ); + + if( $('#' + field_id + '_results li').length ) { + var selected_vals = []; + var d = 0; + + $('#' + field_id + '_results input').each(function( index, element ) { + selected_vals.push( $(this).val() ); + }); + + // Remove already picked suggestions + $(suggestions).each(function( index, suggestion ) { + if( $.inArray( ( suggestion.id ).toString(), selected_vals ) > -1 ) { + suggestions.splice( index - d, 1 ); + d++; + } + }); + } + + return { suggestions: suggestions }; + }, + onSearchStart: function(){ + $(this).next('img.cmb-ajax-search-spinner').css( 'display', 'inline-block' ); + }, + onSearchComplete: function(){ + $(this).next('img.cmb-ajax-search-spinner').hide(); + }, + onSelect: function ( suggestion ) { + $(this).autocomplete('clearCache'); + + var field_name = $(this).attr('id').replace( new RegExp('_input$'), '' ); + var multiple = $(this).attr('data-multiple'); + var limit = parseInt( $(this).attr('data-limit') ); + var sortable = $(this).attr('data-sortable'); + + if( multiple == 1 ) { + // Multiple + $('#' + field_name + '_results' ).append( '
  • ' + + ( ( sortable == 1 ) ? '' : '' ) + + '' + + '' + suggestion.value + '' + + '' + + '
  • ' ); + + $(this).val( '' ); + + // Checks if there is the max allowed results, limit < 0 means unlimited + if( limit > 0 && limit == $('#' + field_name + '_results li').length ) { + $(this).prop( 'disabled', 'disabled' ); + } else { + $(this).focus(); + } + } else { + // Singular + $('input[name=' + field_name + ']').val( suggestion.id ).change(); + } + } + }); + + if( $(this).attr('data-sortable') == 1 ){ + $('#' + field_id + '_results').sortable({ + handle : '.hndl', + placeholder : 'ui-state-highlight', + forcePlaceholderSize : true + }); + } + }); + + $('.cmb-ajax-search-results').on( 'click', 'a.remover', function() { + $(this).parent('li').fadeOut( 400, function(){ + var field_id = $(this).parents('ul').attr('id').replace('_results', ''); + + $('#' + field_id).removeProp( 'disabled' ); + $('#' + field_id).autocomplete('clearCache'); + + $(this).remove(); + }); + }); +})(jQuery); \ No newline at end of file diff --git a/js/jquery.autocomplete.min.js b/js/jquery.autocomplete.min.js new file mode 100644 index 0000000..4536430 --- /dev/null +++ b/js/jquery.autocomplete.min.js @@ -0,0 +1,8 @@ +/** +* Ajax Autocomplete for jQuery, version 1.2.27 +* (c) 2014 Tomas Kirda +* +* Ajax Autocomplete for jQuery is freely distributable under the terms of an MIT-style license. +* For details, see the web site: https://github.com/devbridge/jQuery-Autocomplete +*/ +!function(a){"use strict";"function"==typeof define&&define.amd?define(["jquery"],a):a("object"==typeof exports&&"function"==typeof require?require("jquery"):jQuery)}(function(a){"use strict";function b(c,d){var e=a.noop,f=this,g={ajaxSettings:{},autoSelectFirst:!1,appendTo:document.body,serviceUrl:null,lookup:null,onSelect:null,width:"auto",minChars:1,maxHeight:300,deferRequestBy:0,params:{},formatResult:b.formatResult,delimiter:null,zIndex:9999,type:"GET",noCache:!1,onSearchStart:e,onSearchComplete:e,onSearchError:e,preserveInput:!1,containerClass:"autocomplete-suggestions",tabDisabled:!1,dataType:"text",currentRequest:null,triggerSelectOnValidInput:!0,preventBadQueries:!0,lookupFilter:function(a,b,c){return-1!==a.value.toLowerCase().indexOf(c)},paramName:"query",transformResult:function(b){return"string"==typeof b?a.parseJSON(b):b},showNoSuggestionNotice:!1,noSuggestionNotice:"No results",orientation:"bottom",forceFixPosition:!1};f.element=c,f.el=a(c),f.suggestions=[],f.badQueries=[],f.selectedIndex=-1,f.currentValue=f.element.value,f.intervalId=0,f.cachedResponse={},f.onChangeInterval=null,f.onChange=null,f.isLocal=!1,f.suggestionsContainer=null,f.noSuggestionsContainer=null,f.options=a.extend({},g,d),f.classes={selected:"autocomplete-selected",suggestion:"autocomplete-suggestion"},f.hint=null,f.hintValue="",f.selection=null,f.initialize(),f.setOptions(d)}var c=function(){return{escapeRegExChars:function(a){return a.replace(/[|\\{}()[\]^$+*?.]/g,"\\$&")},createNode:function(a){var b=document.createElement("div");return b.className=a,b.style.position="absolute",b.style.display="none",b}}}(),d={ESC:27,TAB:9,RETURN:13,LEFT:37,UP:38,RIGHT:39,DOWN:40};b.utils=c,a.Autocomplete=b,b.formatResult=function(a,b){if(!b)return a.value;var d="("+c.escapeRegExChars(b)+")";return a.value.replace(new RegExp(d,"gi"),"$1").replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/<(\/?strong)>/g,"<$1>")},b.prototype={killerFn:null,initialize:function(){var c,d=this,e="."+d.classes.suggestion,f=d.classes.selected,g=d.options;d.element.setAttribute("autocomplete","off"),d.killerFn=function(b){a(b.target).closest("."+d.options.containerClass).length||(d.killSuggestions(),d.disableKillerFn())},d.noSuggestionsContainer=a('
    ').html(this.options.noSuggestionNotice).get(0),d.suggestionsContainer=b.utils.createNode(g.containerClass),c=a(d.suggestionsContainer),c.appendTo(g.appendTo),"auto"!==g.width&&c.css("width",g.width),c.on("mouseover.autocomplete",e,function(){d.activate(a(this).data("index"))}),c.on("mouseout.autocomplete",function(){d.selectedIndex=-1,c.children("."+f).removeClass(f)}),c.on("click.autocomplete",e,function(){return d.select(a(this).data("index")),!1}),d.fixPositionCapture=function(){d.visible&&d.fixPosition()},a(window).on("resize.autocomplete",d.fixPositionCapture),d.el.on("keydown.autocomplete",function(a){d.onKeyPress(a)}),d.el.on("keyup.autocomplete",function(a){d.onKeyUp(a)}),d.el.on("blur.autocomplete",function(){d.onBlur()}),d.el.on("focus.autocomplete",function(){d.onFocus()}),d.el.on("change.autocomplete",function(a){d.onKeyUp(a)}),d.el.on("input.autocomplete",function(a){d.onKeyUp(a)})},onFocus:function(){var a=this;a.fixPosition(),a.el.val().length>=a.options.minChars&&a.onValueChange()},onBlur:function(){this.enableKillerFn()},abortAjax:function(){var a=this;a.currentRequest&&(a.currentRequest.abort(),a.currentRequest=null)},setOptions:function(b){var c=this,d=c.options;a.extend(d,b),c.isLocal=a.isArray(d.lookup),c.isLocal&&(d.lookup=c.verifySuggestionsFormat(d.lookup)),d.orientation=c.validateOrientation(d.orientation,"bottom"),a(c.suggestionsContainer).css({"max-height":d.maxHeight+"px",width:d.width+"px","z-index":d.zIndex})},clearCache:function(){this.cachedResponse={},this.badQueries=[]},clear:function(){this.clearCache(),this.currentValue="",this.suggestions=[]},disable:function(){var a=this;a.disabled=!0,clearInterval(a.onChangeInterval),a.abortAjax()},enable:function(){this.disabled=!1},fixPosition:function(){var b=this,c=a(b.suggestionsContainer),d=c.parent().get(0);if(d===document.body||b.options.forceFixPosition){var e=b.options.orientation,f=c.outerHeight(),g=b.el.outerHeight(),h=b.el.offset(),i={top:h.top,left:h.left};if("auto"===e){var j=a(window).height(),k=a(window).scrollTop(),l=-k+h.top-f,m=k+j-(h.top+g+f);e=Math.max(l,m)===l?"top":"bottom"}if("top"===e?i.top+=-f:i.top+=g,d!==document.body){var n,o=c.css("opacity");b.visible||c.css("opacity",0).show(),n=c.offsetParent().offset(),i.top-=n.top,i.left-=n.left,b.visible||c.css("opacity",o).hide()}"auto"===b.options.width&&(i.width=b.el.outerWidth()+"px"),c.css(i)}},enableKillerFn:function(){var b=this;a(document).on("click.autocomplete",b.killerFn)},disableKillerFn:function(){var b=this;a(document).off("click.autocomplete",b.killerFn)},killSuggestions:function(){var a=this;a.stopKillSuggestions(),a.intervalId=window.setInterval(function(){a.visible&&(a.options.preserveInput||a.el.val(a.currentValue),a.hide()),a.stopKillSuggestions()},50)},stopKillSuggestions:function(){window.clearInterval(this.intervalId)},isCursorAtEnd:function(){var a,b=this,c=b.el.val().length,d=b.element.selectionStart;return"number"==typeof d?d===c:document.selection?(a=document.selection.createRange(),a.moveStart("character",-c),c===a.text.length):!0},onKeyPress:function(a){var b=this;if(!b.disabled&&!b.visible&&a.which===d.DOWN&&b.currentValue)return void b.suggest();if(!b.disabled&&b.visible){switch(a.which){case d.ESC:b.el.val(b.currentValue),b.hide();break;case d.RIGHT:if(b.hint&&b.options.onHint&&b.isCursorAtEnd()){b.selectHint();break}return;case d.TAB:if(b.hint&&b.options.onHint)return void b.selectHint();if(-1===b.selectedIndex)return void b.hide();if(b.select(b.selectedIndex),b.options.tabDisabled===!1)return;break;case d.RETURN:if(-1===b.selectedIndex)return void b.hide();b.select(b.selectedIndex);break;case d.UP:b.moveUp();break;case d.DOWN:b.moveDown();break;default:return}a.stopImmediatePropagation(),a.preventDefault()}},onKeyUp:function(a){var b=this;if(!b.disabled){switch(a.which){case d.UP:case d.DOWN:return}clearInterval(b.onChangeInterval),b.currentValue!==b.el.val()&&(b.findBestHint(),b.options.deferRequestBy>0?b.onChangeInterval=setInterval(function(){b.onValueChange()},b.options.deferRequestBy):b.onValueChange())}},onValueChange:function(){var b=this,c=b.options,d=b.el.val(),e=b.getQuery(d);return b.selection&&b.currentValue!==e&&(b.selection=null,(c.onInvalidateSelection||a.noop).call(b.element)),clearInterval(b.onChangeInterval),b.currentValue=d,b.selectedIndex=-1,c.triggerSelectOnValidInput&&b.isExactMatch(e)?void b.select(0):void(e.lengthh&&(c.suggestions=c.suggestions.slice(0,h)),c},getSuggestions:function(b){var c,d,e,f,g=this,h=g.options,i=h.serviceUrl;if(h.params[h.paramName]=b,d=h.ignoreParams?null:h.params,h.onSearchStart.call(g.element,h.params)!==!1){if(a.isFunction(h.lookup))return void h.lookup(b,function(a){g.suggestions=a.suggestions,g.suggest(),h.onSearchComplete.call(g.element,b,a.suggestions)});g.isLocal?c=g.getSuggestionsLocal(b):(a.isFunction(i)&&(i=i.call(g.element,b)),e=i+"?"+a.param(d||{}),c=g.cachedResponse[e]),c&&a.isArray(c.suggestions)?(g.suggestions=c.suggestions,g.suggest(),h.onSearchComplete.call(g.element,b,c.suggestions)):g.isBadQuery(b)?h.onSearchComplete.call(g.element,b,[]):(g.abortAjax(),f={url:i,data:d,type:h.type,dataType:h.dataType},a.extend(f,h.ajaxSettings),g.currentRequest=a.ajax(f).done(function(a){var c;g.currentRequest=null,c=h.transformResult(a,b),g.processResponse(c,b,e),h.onSearchComplete.call(g.element,b,c.suggestions)}).fail(function(a,c,d){h.onSearchError.call(g.element,b,a,c,d)}))}},isBadQuery:function(a){if(!this.options.preventBadQueries)return!1;for(var b=this.badQueries,c=b.length;c--;)if(0===a.indexOf(b[c]))return!0;return!1},hide:function(){var b=this,c=a(b.suggestionsContainer);a.isFunction(b.options.onHide)&&b.visible&&b.options.onHide.call(b.element,c),b.visible=!1,b.selectedIndex=-1,clearInterval(b.onChangeInterval),a(b.suggestionsContainer).hide(),b.signalHint(null)},suggest:function(){if(!this.suggestions.length)return void(this.options.showNoSuggestionNotice?this.noSuggestions():this.hide());var b,c=this,d=c.options,e=d.groupBy,f=d.formatResult,g=c.getQuery(c.currentValue),h=c.classes.suggestion,i=c.classes.selected,j=a(c.suggestionsContainer),k=a(c.noSuggestionsContainer),l=d.beforeRender,m="",n=function(a,c){var d=a.data[e];return b===d?"":(b=d,'
    '+b+"
    ")};return d.triggerSelectOnValidInput&&c.isExactMatch(g)?void c.select(0):(a.each(c.suggestions,function(a,b){e&&(m+=n(b,g,a)),m+='
    '+f(b,g,a)+"
    "}),this.adjustContainerWidth(),k.detach(),j.html(m),a.isFunction(l)&&l.call(c.element,j,c.suggestions),c.fixPosition(),j.show(),d.autoSelectFirst&&(c.selectedIndex=0,j.scrollTop(0),j.children("."+h).first().addClass(i)),c.visible=!0,void c.findBestHint())},noSuggestions:function(){var b=this,c=a(b.suggestionsContainer),d=a(b.noSuggestionsContainer);this.adjustContainerWidth(),d.detach(),c.empty(),c.append(d),b.fixPosition(),c.show(),b.visible=!0},adjustContainerWidth:function(){var b,c=this,d=c.options,e=a(c.suggestionsContainer);"auto"===d.width&&(b=c.el.outerWidth(),e.css("width",b>0?b:300))},findBestHint:function(){var b=this,c=b.el.val().toLowerCase(),d=null;c&&(a.each(b.suggestions,function(a,b){var e=0===b.value.toLowerCase().indexOf(c);return e&&(d=b),!e}),b.signalHint(d))},signalHint:function(b){var c="",d=this;b&&(c=d.currentValue+b.value.substr(d.currentValue.length)),d.hintValue!==c&&(d.hintValue=c,d.hint=b,(this.options.onHint||a.noop)(c))},verifySuggestionsFormat:function(b){return b.length&&"string"==typeof b[0]?a.map(b,function(a){return{value:a,data:null}}):b},validateOrientation:function(b,c){return b=a.trim(b||"").toLowerCase(),-1===a.inArray(b,["auto","bottom","top"])&&(b=c),b},processResponse:function(a,b,c){var d=this,e=d.options;a.suggestions=d.verifySuggestionsFormat(a.suggestions),e.noCache||(d.cachedResponse[c]=a,e.preventBadQueries&&!a.suggestions.length&&d.badQueries.push(b)),b===d.getQuery(d.currentValue)&&(d.suggestions=a.suggestions,d.suggest())},activate:function(b){var c,d=this,e=d.classes.selected,f=a(d.suggestionsContainer),g=f.find("."+d.classes.suggestion);return f.find("."+e).removeClass(e),d.selectedIndex=b,-1!==d.selectedIndex&&g.length>d.selectedIndex?(c=g.get(d.selectedIndex),a(c).addClass(e),c):null},selectHint:function(){var b=this,c=a.inArray(b.hint,b.suggestions);b.select(c)},select:function(a){var b=this;b.hide(),b.onSelect(a),b.disableKillerFn()},moveUp:function(){var b=this;if(-1!==b.selectedIndex)return 0===b.selectedIndex?(a(b.suggestionsContainer).children().first().removeClass(b.classes.selected),b.selectedIndex=-1,b.el.val(b.currentValue),void b.findBestHint()):void b.adjustScroll(b.selectedIndex-1)},moveDown:function(){var a=this;a.selectedIndex!==a.suggestions.length-1&&a.adjustScroll(a.selectedIndex+1)},adjustScroll:function(b){var c=this,d=c.activate(b);if(d){var e,f,g,h=a(d).outerHeight();e=d.offsetTop,f=a(c.suggestionsContainer).scrollTop(),g=f+c.options.maxHeight-h,f>e?a(c.suggestionsContainer).scrollTop(e):e>g&&a(c.suggestionsContainer).scrollTop(e-c.options.maxHeight+h),c.options.preserveInput||c.el.val(c.getValue(c.suggestions[b].value)),c.signalHint(null)}},onSelect:function(b){var c=this,d=c.options.onSelect,e=c.suggestions[b];c.currentValue=c.getValue(e.value),c.currentValue===c.el.val()||c.options.preserveInput||c.el.val(c.currentValue),c.signalHint(null),c.suggestions=[],c.selection=e,a.isFunction(d)&&d.call(c.element,e)},getValue:function(a){var b,c,d=this,e=d.options.delimiter;return e?(b=d.currentValue,c=b.split(e),1===c.length?a:b.substr(0,b.length-c[c.length-1].length)+a):a},dispose:function(){var b=this;b.el.off(".autocomplete").removeData("autocomplete"),b.disableKillerFn(),a(window).off("resize.autocomplete",b.fixPositionCapture),a(b.suggestionsContainer).remove()}},a.fn.autocomplete=a.fn.devbridgeAutocomplete=function(c,d){var e="autocomplete";return arguments.length?this.each(function(){var f=a(this),g=f.data(e);"string"==typeof c?g&&"function"==typeof g[c]&&g[c](d):(g&&g.dispose&&g.dispose(),g=new b(this,c),f.data(e,g))}):this.first().data(e)}}); \ No newline at end of file diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..3a8c593 --- /dev/null +++ b/readme.md @@ -0,0 +1,162 @@ +CMB2 Field Type: Ajax Search +================== + +Custom fields for [CMB2](https://github.com/WebDevStudios/CMB2) to attach posts, users or terms to each others. + +Once activated, this plugin adds three new field types `post_ajax_search`, `user_ajax_search` and `term_ajax_search`. + +This plugin is an update of [CMB2 Field Type: Post Search Ajax](https://github.com/alexis-magina/cmb2-field-post-search-ajax) by [Magina](http://magina.fr/) with support to attach posts, users or terms. + +## Installation + +You can install this field type as you would a WordPress plugin: + +- Download the plugin +- Place the plugin folder in your /wp-content/plugins/ directory +- Activate the plugin in the Plugin dashboard + +## Parameters + +Options : +- multiple (bool, default = false) : Turn field into a multiple attached objects +- limit (int, default = -1 : single selection) : Limit the number of posts that can be selected (-1 for unlimited) +- sortable (bool, default = false) : Allow selected items to be sort (only if multiple = true) +- query_args (array) : Query arguments to pass on each request + +Query args: +- query_args accepts same parameters as [WP_Query](https://codex.wordpress.org/Class_Reference/WP_Query) for `post_ajax_search` +- query_args accepts same parameters as [WP_User_Query](https://codex.wordpress.org/Class_Reference/WP_User_Query) for `user_ajax_search` +- query_args accepts same parameters as [WP_Term_Query](https://developer.wordpress.org/reference/classes/wp_term_query/) for `term_ajax_search` + +## Examples + +```php +add_action( 'cmb2_admin_init', 'cmb2_ajax_search_metabox' ); +function cmb2_ajax_search_metabox() { + + $prefix = 'your_prefix_demo_'; + + $cmb_demo = new_cmb2_box( array( + 'id' => $prefix . 'metabox', + 'title' => __( 'Attached posts Metabox', 'cmb2' ), + 'object_types' => array( 'page', 'post' ), // Post type + ) ); + + // Single post + $cmb_demo->add_field( array( + 'name' => __( 'Attached post', 'cmb2' ), + 'desc' => __( 'Field description (optional)', 'cmb2' ), + 'id' => $prefix . 'post', + 'type' => 'post_ajax_search', + 'query_args' => array( + 'post_type' => array( 'post' ), + 'posts_per_page' => -1 + ) + ) ); + + // Multiple posts + $cmb_demo->add_field( array( + 'name' => __( 'Multiple posts', 'cmb2' ), + 'desc' => __( 'Field description (optional)', 'cmb2' ), + 'id' => $prefix . 'posts', + 'type' => 'post_ajax_search', + 'multiple' => true, + 'limit' => 10, + 'query_args' => array( + 'post_type' => array( 'post', 'page' ), + 'post_status' => array( 'publish', 'pending' ) + ) + ) ); + + // Single user + $cmb_demo->add_field( array( + 'name' => __( 'Attached user', 'cmb2' ), + 'desc' => __( 'Field description (optional)', 'cmb2' ), + 'id' => $prefix . 'user', + 'type' => 'post_ajax_search', + 'query_args' => array( + 'role' => array( 'Subscriber' ), + 'search_columns' => array( 'user_login', 'user_email' ) + ) + ) ); + + // Multiple users + $cmb_demo->add_field( array( + 'name' => __( 'Multiple users', 'cmb2' ), + 'desc' => __( 'Field description (optional)', 'cmb2' ), + 'id' => $prefix . 'users', + 'type' => 'post_ajax_search', + 'multiple' => true, + 'limit' => 5, + 'query_args' => array( + 'role__not_in' => array( 'Administrator', 'Editor' ), + ) + ) ); + + // Single term + $cmb_demo->add_field( array( + 'name' => __( 'Attached term', 'cmb2' ), + 'desc' => __( 'Field description (optional)', 'cmb2' ), + 'id' => $prefix . 'term', + 'type' => 'post_ajax_search', + 'query_args' => array( + 'taxonomy' => 'category', + 'childless' => true + ) + ) ); + + // Multiple terms + $cmb_demo->add_field( array( + 'name' => __( 'Multiple terms', 'cmb2' ), + 'desc' => __( 'Field description (optional)', 'cmb2' ), + 'id' => $prefix . 'terms', + 'type' => 'post_ajax_search', + 'multiple' => true, + 'limit' => -1, + 'query_args' => array( + 'taxonomy' => 'post_tag', + 'hide_empty' => false + ) + ) ); + +} +``` + +## Customize results output + +You can use `cmb_{$field_id}_ajax_search_result_text` to customize the text returned from ajax searches and `cmb_{$field_id}_ajax_search_result_link` to customize the link, check next example: + +```php +add_filter( 'cmb_your_prefix_demo_posts_ajax_search_result_text', 'cmb2_ajax_search_custom_field_text', 10, 3 ); +function cmb2_ajax_search_custom_field_text( $text, $object_id, $object_type ) { + $text = sprintf( '#%s - %s', $object_id, $text ); // #123 - Post title + + return $text; +} + +add_filter( 'cmb_your_prefix_demo_posts_ajax_search_result_link', 'cmb2_ajax_search_custom_field_link', 10, 3 ); +function cmb2_ajax_search_custom_field_link( $link, $object_id, $object_type ) { + if( $object_id == 123 ) { + $link = '#'; + } + + return $link; +} +``` + +## Retrieve the field value + +If multiple == false will return the ID of attached object: +`get_post_meta( get_the_ID(), 'your_field_id', true );` + +If multiple == true will return an array of IDs of attached object: +`get_post_meta( get_the_ID(), 'your_field_id', false );` + +## Screenshot + +![example](example.gif) + +## Changelog + +### 1.0.0 +* Initial commit