1: <?php
2: namespace elasticsearch;
3:
4: /**
5: * This class provides numerous helper methods for working with facet information returned from elastic search results.
6: *
7: * @license http://opensource.org/licenses/MIT
8: * @author Paris Holley <[email protected]>
9: * @version 2.0.0
10: **/
11: class Faceting{
12: /**
13: * A convenient method that aggregates the results of all the other methods in the class. Example of output:
14: *
15: * <code>
16: * array(
17: * // the keys are names of fields and/or taxonomies
18: * 'taxonomy' => array(
19: * 'available' => array(
20: * 'taxonomy1' => array(
21: * 'count' => 10,
22: * 'slug' => 'taxonomy1',
23: * 'name' => 'Taxonomy One',
24: * 'font' => 24
25: * )
26: * ),
27: * 'selected' => array(
28: * 'taxonomy2' => array(
29: * 'slug' => 'taxonomy2',
30: * 'name' => 'Taxonomy Two'
31: * )
32: * ),
33: * 'total' => 10
34: * ),
35: * 'rating' => array(
36: * 'available' => array(
37: * '10-20' => array(
38: * 'count' => 4,
39: * 'slug' => '10-20',
40: * 'to' => 20,
41: * 'from' => 10
42: * )
43: * ),
44: * 'total' => 4
45: * )
46: * )
47: * </code>
48: *
49: * @param string $minFont The minimum font size to use for display in a tag cloud (defaults to : 12)
50: * @param string $maxFont The maximum font size to use for display in a tag cloud (defaults to : 24)
51: *
52: * @return array An associative array where the keys represent the data point with a list of selected and/or available options.
53: **/
54: static function all($minFont = 12, $maxFont = 24){
55: $options = array();
56:
57: foreach(Config::taxonomies() as $tax){
58: $options[$tax] = self::taxonomy($tax);
59: }
60:
61: $numeric = Config::option('numeric');
62:
63: foreach(Config::fields() as $field){
64: if(isset($numeric[$field])){
65: $options[$field] = self::range($field);
66: }
67: }
68:
69: foreach($options as $name => &$field){
70: foreach($field['available'] as &$available){
71: $available['font'] = self::cloud($field['available'], $available, $minFont, $maxFont);
72: }
73: }
74:
75: return $options;
76: }
77:
78: /**
79: * Analyse query parameters for range slugs and determine which facets are selected vs. which are available for the given field. Example of output:
80: *
81: * <code>
82: * array(
83: * 'available' => array(
84: * '10-20' => array(
85: * 'count' => 4,
86: * 'slug' => '10-20',
87: * 'to' => 20,
88: * 'from' => 10
89: * )
90: * ),
91: * 'selected' => array(
92: * '-20' => array(
93: * 'slug' => '-20',
94: * 'to' => 20
95: * )
96: * ),
97: * 'total' => 4
98: * )
99: * </code>
100: *
101: * @param string $field The field to determine range facet information about
102: *
103: * @return array An associative array based on example provided
104: **/
105: static function range($field){
106: global $wp_query;
107:
108: $facets = $wp_query->facets;
109:
110: $result = array(
111: 'selected' => array(),
112: 'available' => array(),
113: 'total' => 0
114: );
115:
116: $ranges = Config::ranges($field);
117:
118: if($ranges){
119: foreach($ranges as $slug => $range){
120: $split = explode('-', $slug);
121:
122: $item = array(
123: 'slug' => $slug,
124: 'count' => $facets[$field][$slug],
125: 'to' => $split[1],
126: 'from' => $split[0]
127: );
128:
129: if(isset($_GET[$field]) && in_array($slug, $_GET[$field]['and'])){
130: $result['selected'][$slug] = $item;
131: }else if($item['count'] > 0){
132: $result['available'][$slug] = $item;
133: $result['total'] += $item['count'];
134: }
135: }
136: }
137:
138: return $result;
139: }
140:
141: /**
142: * Analyse query parameters for taxonomoy slugs and determine which facets are selected vs. which are available for the given field. Example of output:
143: *
144: * <code>
145: * array(
146: * 'available' => array(
147: * 'taxonomy1' => array(
148: * 'count' => 10,
149: * 'slug' => 'taxonomy1',
150: * 'name' => 'Taxonomy One',
151: * 'font' => 24
152: * )
153: * ),
154: * 'selected' => array(
155: * 'taxonomy2' => array(
156: * 'slug' => 'taxonomy2',
157: * 'name' => 'Taxonomy Two'
158: * )
159: * ),
160: * 'total' => 10
161: * )
162: * </code>
163: *
164: * @param string $field The taxonomy type to retrieve facet information about
165: *
166: * @return array An associative array based on example provided
167: **/
168: static function taxonomy($tax){
169: global $wp_query;
170:
171: $facets = $wp_query->facets;
172:
173: $taxonomy = array(
174: 'selected' => array(),
175: 'available' => array(),
176: 'total' => 0
177: );
178:
179: if(isset($facets[$tax])){
180: foreach(get_terms($tax) as $term){
181: $item = array(
182: 'name' => $term->name ?: $term->slug,
183: 'slug' => $term->slug
184: );
185:
186: if(isset($_GET[$tax]) && in_array($term->slug, $_GET[$tax]['and'])){
187: $taxonomy['selected'][$term->slug] = $item;
188: }else if(isset($facets[$tax][$term->slug])){
189: $count = $item['count'] = $facets[$tax][$term->slug];
190:
191: if($count > 0){
192: $taxonomy['available'][$term->slug] = $item;
193: $taxonomy['total'] += $item['count'];
194: }
195: }
196: }
197: }
198:
199: return $taxonomy;
200: }
201:
202: /**
203: * Will calculate a font size based on the total number of results for the given item in a collection of items. Example of output:
204: *
205: * <code>
206: * array(
207: * 'available' => array(
208: * 'taxonomy1' => array(
209: * 'count' => 10,
210: * 'slug' => 'taxonomy1',
211: * 'name' => 'Taxonomy One',
212: * 'font' => 24
213: * )
214: * ),
215: * 'selected' => array(
216: * 'taxonomy2' => array(
217: * 'slug' => 'taxonomy2',
218: * 'name' => 'Taxonomy Two'
219: * )
220: * ),
221: * 'total' => 10
222: * )
223: * </code>
224: *
225: * @param array $items An array of arrays that contain a key called 'count'
226: * @param array $item An item out of the array that you wish to calculate a font size
227: * @param string $minFont The minimum font size to use for display in a tag cloud (defaults to : 12)
228: * @param string $maxFont The maximum font size to use for display in a tag cloud (defaults to : 24)
229: *
230: * @return integer The calculated font size
231: **/
232: static function cloud($items, $item, $min = 12, $max = 24){
233: $maxTotal = 1;
234:
235: foreach($items as $itm){
236: if(log($itm['count']) > $maxTotal){
237: $maxTotal = log($itm['count']);
238: }
239: }
240:
241: return floor((log($item['count']) / $maxTotal) * ($max - $min) + $min);
242: }
243:
244: /**
245: * Modifies the provided URL by appending query parameters for faceted searching.
246: *
247: * @param string $url The URL of the page that supports F.E.S
248: * @param string $type The data point you wish to enable faceting for (ie: a field name or taxonomy name)
249: * @param string $value The value/slug that was provided by another method call in this class
250: * @param string $operation Whether the facet should query using 'and' or 'or' (defaults to and)
251: *
252: * @return string The URL modified to support faceting
253: **/
254: static function urlAdd($url, $type, $value, $operation = 'and'){
255: $filter = $_GET;
256:
257: $op = $operation;
258:
259: if(isset($filter[$type])){
260: $op = array_keys($filter[$type]);
261: $op = $op[0];
262: }
263:
264: $filter[$type][$op][] = $value;
265:
266: $url = new \Purl\Url($url);
267: $url->query->setData($filter);
268:
269: return $url->getUrl();
270: }
271:
272: /**
273: * Modifies the provided URL by removing query parameters that control faceting.
274: *
275: * @param string $url The URL of the page that supports F.E.S
276: * @param string $type The data point you wish to remove faceting for (ie: a field name or taxonomy name)
277: * @param string $value The value/slug that was provided in the URL (query parameters)
278: *
279: * @return string The URL modified to remove faceting for the provided data point
280: **/
281: static function urlRemove($url, $type, $value){
282: $filter = $_GET;
283:
284: $operation = isset($filter[$type]['and']) ? 'and' : 'or';
285:
286: if(isset($filter[$type][$operation])){
287: $index = array_search($value, $filter[$type][$operation]);
288:
289: if($index !== false){
290: unset($filter[$type][$operation][$index]);
291:
292: if(count($filter[$type][$operation]) == 0){
293: unset($filter[$type][$operation]);
294: }
295:
296: if(count($filter[$type]) == 0){
297: unset($filter[$type]);
298: }
299: }
300: }
301:
302: $url = new \Purl\Url($url);
303: $url->query->setData($filter);
304:
305: return $url->getUrl();
306: }
307: }
308:
309: ?>
310: