function search_terms($taxonomy, array $options) { $options += ['hide_empty' => false, 'childless' => false, 'pad_counts' => true, 'level' => null]; $options['cache_domain'] = md5(serialize($options)); if ($raw_query = value($options, 'search', null)) { $raw_query = trim($raw_query); $query = preg_replace('@\\s+@smi', '%', trim($raw_query)); unset($options['search']); } else { $query = null; } if (value($options, 'level', null) === 0) { unset($options['level']); $options['parent'] = 0; } return escoped_filters(['terms_clauses' => function ($clauses) use($raw_query, $query, $options, $taxonomy) { global $wpdb; if (($level_and_above = value($options, 'level_and_above', null)) !== null) { $options['level'] = $level_and_above; } if (value($options, 'level', null)) { $join = $level_and_above ? " LEFT JOIN" : " INNER JOIN"; $clauses["join"] .= " {$join} {$wpdb->term_taxonomy} AS ttl0 ON ttl0.taxonomy = '{$taxonomy}' and ttl0.term_taxonomy_id = tt.parent "; for ($i = 1; $i < $options['level']; $i++) { $clauses["join"] .= "{$join} {$wpdb->term_taxonomy} AS ttl{$i} ON ttl{$i}.taxonomy = '{$taxonomy}' and ttl{$i}.term_taxonomy_id = ttl" . ($i - 1) . ".parent "; if ($level_and_above) { $roots[] = "ttl{$i}.parent"; } } if ($level_and_above) { $roots[] = "ttl0.parent"; $roots[] = "ttl" . ($i - 1) . ".parent"; $roots[] = "tt.parent"; } else { $roots = ["ttl" . ($options['level'] - 1) . ".parent"]; } $clauses["where"] .= " AND 0 IN (" . implode(",", $roots) . ")"; } if ($query) { $clauses = ['fields' => "{$clauses['fields']}, " . $wpdb->prepare('CASE WHEN t.slug like %s THEN %d WHEN t.name = %s THEN %d WHEN t.slug like %s THEN %d WHEN t.name like %s THEN %d WHEN t.slug like %s THEN %d WHEN t.name like %s THEN %d ELSE 0 END as score ', [$raw_query, 6, $raw_query, 5, "{$raw_query}%", 4, "{$raw_query}%", 3, "{$query}%", 2, "{$query}%", 1]), 'where' => $clauses['where'] . $wpdb->prepare(' AND ( (t.name LIKE %s) OR (t.slug LIKE %s) ) ', ["{$query}%", "%{$query}%"]), 'orderby' => 'ORDER BY score DESC, tt.count DESC, length(t.name) ASC, t.name '] + $clauses; } return $clauses; }], function () use($options, $taxonomy) { return get_terms($taxonomy, $options); }); }
public function setupRender(\WP_Post $post, array $box, \stdClass $taxonomy) { $labels = get_taxonomy_labels($taxonomy); $renderSettings = ['name' => 'tax_input[' . esc_attr($taxonomy->name) . ']', 'delimiter' => _x(',', 'tag delimiter'), 'options' => $this->get_options($post, $box, $taxonomy), 'items' => $this->get_items($post, $box, $taxonomy), 'disabled' => !current_user_can($taxonomy->cap->assign_terms)] + $this->settings; if (value($renderSettings, 'label') === true) { $renderSettings['label'] = $labels->{value($renderSettings, 'multiple', false) ? "singular_name" : "name"}; } $renderSettings = apply_filters('tf_setup_render', $renderSettings, $post, $box, $taxonomy); return apply_filters(sprintf('tf_%s_setup_render', $taxonomy->name), $renderSettings, $post, $box, $taxonomy); }
/** * Generates a taxonomy metabox function callback together with seletize * @since 0.1.0 * * @global array $defaultSettings Default settings applied to all TSNS fields * @global wpdb $wpdb WordPress database abstraction object. * * @param array $settings { * Settings to describe how the TSNS fields should work * * @type string $ajax_url url ajax target. Defaults to `ajaxurl` * @type array $selector_setup Selectize Setup * @type array $ajax_data Aditional data to be served by ajax. * By default, wp_ajax settings are assumed. * @type string $ajax_query_field field in ajax data for the query, which * is overwrited in runtime by current one. * * @type int|bool $terms_limit defines how much terms can be assigned to * the post. Define *false* for no limit. * * } * * @return function Returns a function which should be passed to 'meta_box_cb' * of {@link register_taxonomy()}'s $args * if no taxonomy is specified and the term ID exists. Returns * an array of the term ID and the term taxonomy ID the taxonomy * is specified and the pairing exists. */ function searchNSelectField($settings = []) { global $defaultSettings, $tsns_initiated; $settings += ['selector_setup' => [], 'ajax_url' => false, 'ajax_query_field' => 'query', 'terms_limit' => false]; return function (\WP_Post $post, array $box) use($settings) { $tax_name = $box['args']['taxonomy']; $taxonomy = get_taxonomy($tax_name); $user_can_assign_terms = current_user_can($taxonomy->cap->assign_terms); $comma = _x(',', 'tag delimiter'); $terms = wp_get_object_terms($post->ID, $tax_name); $labels = get_taxonomy_labels($taxonomy); $new_label = $labels->add_new_item; $preload = []; if ($preload_length = value($settings, 'preload', 10)) { $preload = get_terms($tax_name, ['number' => $preload_length, 'hide_empty' => false, 'orderby' => 'count']); } /** * Filters the selectize settings before its conversion to JSON * * @since 0.1.0 * * @param array $settings Original settings to passed to selectize.js * @param WP_Post $post The post currently being edited * @param object $taxonomy Taxonomy for the current metabox * @param array $settings Options this current fields */ $config = apply_filters('tsns_selector_setup', $settings['selector_setup'] + ['loadThrottle' => 100, 'valueField' => 'term_id', 'labelField' => 'name', 'searchField' => 'name', 'maxOptions' => 10, 'optionsTemplate' => '<div class="option"><%- option.name %></div>', 'createTemplate' => "<div class='create'>{$new_label}: <%- input %></div>", 'itemsTemplate' => '<div class="item"><%- item.name %></div>', 'maxItems' => $settings['terms_limit'], 'delimiter' => $comma, 'options' => $terms + $preload, 'items' => array_map(function ($term) { return $term->term_id; }, $terms), 'create' => $user_can_assign_terms], $post, $taxonomy, $settings); /** * Filters the selectize settings before its conversion to JSON specifically * to {taxonomy}, after filtered by {@link tsns_selector_setup} * * @since 0.1.0 * * @param array $settings Original settings to passed to selectize.js * @param WP_Post $post The post currently being edited * @param object $taxonomy Taxonomy for the current metabox * @param array $settings Options this current fields */ $config = apply_filters(sprintf('tsns_%s_selector_setup', $tax_name), $config, $post, $taxonomy, $settings); /** * Filter ajax data to be sent along with the query * * @since 0.1.0 * * @param array $ajax_data Original ajax data * @param WP_Post $post The post currently being edited * @param object $taxonomy Taxonomy for the current metabox * @param array $settings Options this current fields */ $ajax_data = apply_filters('tsns_ajax_data', value($settings, 'ajax_data', ['action' => "tsns_search", 'taxonomy' => $tax_name]), $post, $taxonomy, $settings); /** * Filter ajax data to be sent along with the query specifically to * {taxonomy}, after filtered by {@link tsns_setup_selector} * * @since 0.1.0 * * @param array $settings Original settings to passed to selectize.js * @param WP_Post $post The post currently being edited * @param object $taxonomy Taxonomy for the current metabox * @param array $settings Options this current fields */ $ajax_data = apply_filters(sprintf('tsns_%s_ajax_data', $tax_name), $ajax_data, $post, $taxonomy, $settings); if ($ajax_url = value($settings, 'ajax_url', false)) { $ajax_url = json_encode($ajax_url); } else { $ajax_url = 'ajaxurl'; } ?> <div class="selectize-taxonomy"> <textarea name="<?php echo "tax_input_tsns[{$tax_name}]"; ?> " rows="3" cols="20" class="tsns" id="tax-input-<?php echo $tax_name; ?> " <?php disabled(!$user_can_assign_terms); ?> ><?php echo str_replace(',', $comma . ' ', get_terms_to_edit($post->ID, $tax_name)); ?> </textarea> <script type="text/javascript"> (function($, _) { var $el = $("script:last").prev(); <?php if (value($settings, 'required')) { ?> $el.closest("form").submit(function(e){ if (!$el.val()) { e.preventDefault(); e.stopPropagation(); alert(<?php if (value($settings, 'required') === true) { echo 'Required field is empty'; } else { echo json_encode(value($settings, 'required')); } ?> ); return false; } }); <?php } ?> // Settings var options = <?php echo json_encode($config); ?> ; var ajaxData = <?php echo json_encode($ajax_data); ?> ; if (!options.maxItems) delete options.maxItems; // Templates var optionsTemplate = (options.optionsTemplate && _.template(options.optionsTemplate)) || null; var itemsTemplate = (options.itemsTemplate && _.template(options.itemsTemplate)) || null; var createTemplate = (options.createTemplate && _.template(options.createTemplate)) || null; options.create = options.create && function(input) { return { term_id: input, name: input } }; // Methods options = $.extend({ load: function(query, done) { ajaxData['query'] = query; $.ajax({ url: <?php echo $ajax_url; ?> , type: 'GET', dataType: 'json', data: ajaxData, error: function() { done(); }, success: function(res) { done(res); } }); }, render: { item: (itemsTemplate && function(item, escape) { return itemsTemplate({item:item, escape:escape}); }) || undefined, option: (optionsTemplate && function(option, escape) { return optionsTemplate({option: option, escape:escape}); }) || undefined, option_create: (createTemplate && function(query, serialize) { query.serialize = serialize; return createTemplate(query); }) || undefined } }, options); $el.selectize(options); })(jQuery, _); </script> </div> <?php }; }