Advanced Woo Search - Version 1.01

Version Description

  • Fix problem with result block layout
Download this release

Release Info

Developer Mihail Barinov
Plugin Icon 128x128 Advanced Woo Search
Version 1.01
Comparing to
See all releases

Version 1.01

advanced-woo-search.php ADDED
@@ -0,0 +1,577 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ Plugin Name: Advanced Woo Search
5
+ Description: Advance ajax WooCommerce product search.
6
+ Version: 1.01
7
+ Author: ILLID
8
+ Text Domain: aws
9
+ */
10
+
11
+
12
+ if ( ! defined( 'ABSPATH' ) ) {
13
+ exit;
14
+ }
15
+
16
+
17
+ define( 'AWS_DIR', dirname( __FILE__ ) );
18
+ define( 'AWS_URL', plugins_url( '', __FILE__ ) );
19
+
20
+
21
+ if ( ! class_exists( 'AWS_Main' ) ) :
22
+
23
+ /**
24
+ * Main plugin class
25
+ *
26
+ * @class AWS_Main
27
+ */
28
+ final class AWS_Main {
29
+
30
+ /**
31
+ * @var AWS_Main The single instance of the class
32
+ */
33
+ protected static $_instance = null;
34
+
35
+ /**
36
+ * @var AWS_Main Array of all plugin data $data
37
+ */
38
+ private $data = array();
39
+
40
+ /**
41
+ * Main AWS_Main Instance
42
+ *
43
+ * Ensures only one instance of AWS_Main is loaded or can be loaded.
44
+ *
45
+ * @static
46
+ * @return AWS_Main - Main instance
47
+ */
48
+ public static function instance() {
49
+ if ( is_null( self::$_instance ) ) {
50
+ self::$_instance = new self();
51
+ }
52
+ return self::$_instance;
53
+ }
54
+
55
+ /**
56
+ * Constructor
57
+ */
58
+ public function __construct() {
59
+
60
+ $this->data['settings'] = get_option( 'aws_settings' );
61
+
62
+ add_filter( 'widget_text', 'do_shortcode' );
63
+
64
+ add_shortcode( 'aws_search_form', array( $this, 'markup' ) );
65
+
66
+ add_action( 'wp_enqueue_scripts', array( $this, 'load_scripts' ) );
67
+
68
+ add_action( 'wp_ajax_aws_action', array( $this, 'action_callback' ) );
69
+ add_action('wp_ajax_nopriv_aws_action', array( $this, 'action_callback' ) );
70
+
71
+ add_filter( 'plugin_action_links', array( $this, 'add_settings_link' ), 10, 2 );
72
+
73
+ //load_plugin_textdomain( 'aws', false, dirname( plugin_basename( __FILE__ ) ). '/languages/' );
74
+
75
+ $this->includes();
76
+
77
+ }
78
+
79
+ /**
80
+ * Include required core files used in admin and on the frontend.
81
+ */
82
+ public function includes() {
83
+ include_once( 'includes/class-aws-admin.php' );
84
+ include_once( 'includes/widget.php' );
85
+ }
86
+
87
+ /*
88
+ * Generate search box markup
89
+ */
90
+ public function markup( $args = array() ) {
91
+
92
+ $placeholder = $this->get_settings( 'search_field_text' );
93
+ $min_chars = $this->get_settings( 'min_chars' );
94
+ $show_loader = $this->get_settings( 'show_loader' );
95
+
96
+ $params_string = '';
97
+
98
+ $params = array(
99
+ 'data-url' => admin_url('admin-ajax.php'),
100
+ 'data-siteurl' => site_url(),
101
+ 'data-show-loader' => $show_loader,
102
+ 'data-min-chars' => $min_chars,
103
+ );
104
+
105
+ foreach( $params as $key => $value ) {
106
+ $params_string .= $key . '="' . $value . '"';
107
+ }
108
+
109
+ $markup = '';
110
+ $markup .= '<div class="aws-container" ' . $params_string . '>';
111
+ $markup .= '<form class="aws-search-form" action="' . site_url() . '" method="get" role="search" >';
112
+ $markup .= '<input type="text" name="s" value="' . get_search_query() . '" class="aws-search-field" placeholder="' . $placeholder . '" autocomplete="off" />';
113
+ $markup .= '<div class="aws-search-result" style="display: none;"></div>';
114
+ $markup .= '</form>';
115
+ $markup .= '</div>';
116
+
117
+ return apply_filters( 'aws_searchbox_markup', $markup );
118
+
119
+ }
120
+
121
+ /*
122
+ * Load assets for search form
123
+ */
124
+ public function load_scripts() {
125
+ wp_enqueue_style( 'aws-style', AWS_URL . '/assets/css/common.css' );
126
+ wp_enqueue_script( 'aws-script', AWS_URL . '/assets/js/common.js', array('jquery'), '1.0', true );
127
+ }
128
+
129
+ /*
130
+ * Get array of included to search result posts ids
131
+ */
132
+ private function get_posts_ids( $sql ) {
133
+
134
+ global $wpdb;
135
+
136
+ $posts_ids = array();
137
+
138
+ $search_results = $wpdb->get_results( $sql );
139
+
140
+
141
+ if ( !empty( $search_results ) && !is_wp_error( $search_results ) && is_array( $search_results ) ) {
142
+ foreach ( $search_results as $search_result ) {
143
+ $posts_ids[] = intval( $search_result->ID );
144
+ }
145
+ }
146
+
147
+ unset( $search_results );
148
+
149
+ return $posts_ids;
150
+
151
+ }
152
+
153
+ /*
154
+ * AJAX call action callback
155
+ */
156
+ public function action_callback() {
157
+
158
+ global $wpdb;
159
+
160
+ $show_cats = $this->get_settings( 'show_cats' );
161
+ $show_tags = $this->get_settings( 'show_tags' );
162
+ $exact_match = $this->get_settings( 'exact_match' );
163
+ $results_num = $this->get_settings( 'results_num' );
164
+ $search_in = $this->get_settings( 'search_in' );
165
+
166
+ $search_in_arr = explode( ',', $this->get_settings( 'search_in' ) );
167
+
168
+ // Search in title if all options is disabled
169
+ if ( ! $search_in ) {
170
+ $search_in_arr = array( 'title' );
171
+ }
172
+
173
+ $categories_array = array();
174
+ $tags_array = array();
175
+ $query = array();
176
+
177
+
178
+ $s = esc_attr( $_POST['keyword'] );
179
+ $s = stripslashes( $s );
180
+ $s = str_replace( array( "\r", "\n" ), '', $s );
181
+
182
+ $this->data['s'] = $s;
183
+ $this->data['search_terms'] = array();
184
+ $this->data['search_in'] = $search_in_arr;
185
+
186
+ if ( $exact_match === 'true' ) {
187
+ $this->data['search_terms'] = array( $s );
188
+ } else {
189
+ $this->data['search_terms'] = array_unique( explode( ' ', $s ) );
190
+
191
+ if ( count( $this->data['search_terms'] ) > 0 ) {
192
+ if ( count( $this->data['search_terms'] ) > 9 ) {
193
+ $this->data['search_terms'] = array( $s );
194
+ }
195
+ } else {
196
+ $this->data['search_terms'] = array( $s );
197
+ }
198
+
199
+ }
200
+
201
+
202
+ // Generate search query
203
+
204
+ $query['search'] = '';
205
+ $query['relevance'] = '';
206
+
207
+ $temp_search_array = array();
208
+ $relevance_array = array();
209
+ $new_relevance_array = array();
210
+
211
+ foreach ( $this->data['search_terms'] as $search_term ) {
212
+
213
+ $like = '%' . $wpdb->esc_like( $search_term ) . '%';
214
+
215
+ $search_in_array = array();
216
+
217
+ foreach ( $search_in_arr as $search_in_term ) {
218
+
219
+ switch ( $search_in_term ) {
220
+
221
+ case 'title':
222
+ $search_in_array[] = $wpdb->prepare( '( posts.post_title LIKE %s )', $like );
223
+ $relevance_array['title'][] = $wpdb->prepare( "( case when ( post_title LIKE %s ) then 10 else 0 end )", $like );
224
+ break;
225
+
226
+ case 'content':
227
+ $search_in_array[] = $wpdb->prepare( '( posts.post_content LIKE %s )', $like );
228
+ $relevance_array['content'][] = $wpdb->prepare( "( case when ( post_content LIKE %s ) then 7 else 0 end )", $like );
229
+ break;
230
+
231
+ case 'excerpt':
232
+ $search_in_array[] = $wpdb->prepare( '( posts.post_excerpt LIKE %s )', $like );
233
+ $relevance_array['content'][] = $wpdb->prepare( "( case when ( post_excerpt LIKE %s ) then 7 else 0 end )", $like );
234
+ break;
235
+
236
+ case 'sku':
237
+ $search_in_array[] = $wpdb->prepare( '( postmeta.meta_value LIKE %s )', $like );
238
+ break;
239
+
240
+ }
241
+
242
+ }
243
+
244
+ $temp_search_array[] = sprintf( ' ( %s ) ', implode( ' OR ', $search_in_array ) );
245
+
246
+ }
247
+
248
+ $query['search'] .= sprintf( ' AND ( %s )', implode( ' OR ', $temp_search_array ) );
249
+
250
+ // Sort 'relevance' queries in the array by search priority
251
+ foreach ( $search_in_arr as $search_in_item ) {
252
+ if ( isset( $relevance_array[$search_in_item] ) ) {
253
+ $new_relevance_array[$search_in_item] = implode( ' + ', $relevance_array[$search_in_item] );
254
+ }
255
+ }
256
+
257
+ $query['relevance'] .= sprintf( ' ( %s ) ', implode( ' + ', $new_relevance_array ) );
258
+
259
+
260
+ $sql = "SELECT
261
+ ID,
262
+ {$query['relevance']} as relevance
263
+ FROM
264
+ $wpdb->posts AS posts,
265
+ $wpdb->postmeta AS postmeta
266
+ WHERE
267
+ posts.post_type = 'product'
268
+ AND posts.post_status = 'publish'
269
+ AND posts.ID = postmeta.post_id
270
+ AND postmeta.meta_key = '_sku'
271
+ {$query['search']}
272
+ ORDER BY
273
+ relevance DESC,
274
+ posts.post_date DESC
275
+ LIMIT 0, {$results_num}
276
+ ";
277
+
278
+
279
+ $posts_ids = $this->get_posts_ids( $sql );
280
+
281
+ $products_array = $this->get_products( $posts_ids );
282
+
283
+
284
+ if ( $show_cats === 'true' ) {
285
+ $categories_array = $this->get_taxonomies( $this->data['s'], 'product_cat' );
286
+ }
287
+
288
+ if ( $show_tags === 'true' ) {
289
+ $tags_array = $this->get_taxonomies( $this->data['s'], 'product_tag' );
290
+ }
291
+
292
+ echo json_encode( array(
293
+ 'cats' => $categories_array,
294
+ 'tags' => $tags_array,
295
+ 'products' => $products_array
296
+ ) );
297
+
298
+ die;
299
+
300
+ }
301
+
302
+ /*
303
+ * Get products info
304
+ */
305
+ private function get_products( $posts_ids ) {
306
+
307
+ $products_array = array();
308
+
309
+ if ( count( $posts_ids ) > 0 ) {
310
+
311
+ $show_excerpt = $this->get_settings( 'show_excerpt' );
312
+ $excerpt_source = $this->get_settings( 'desc_source' );
313
+ $excerpt_length = $this->get_settings( 'excerpt_length' );
314
+ $mark_search_words = $this->get_settings( 'mark_words' );
315
+ $show_price = $this->get_settings( 'show_price' );
316
+ $show_sale = $this->get_settings( 'show_sale' );
317
+ $show_image = $this->get_settings( 'show_image' );
318
+
319
+ foreach ( $posts_ids as $post_id ) {
320
+
321
+ $product = new WC_product( $post_id );
322
+
323
+ $post_data = $product->get_post_data();
324
+
325
+ $title = $product->get_title();
326
+
327
+ $excerpt = '';
328
+ $price = '';
329
+ $on_sale = '';
330
+ $image = '';
331
+
332
+ if ( $show_excerpt === 'true' ) {
333
+ $excerpt = ( $excerpt_source === 'excerpt' && $post_data->post_excerpt ) ? $post_data->post_excerpt : $post_data->post_content;
334
+ $excerpt = wp_trim_words( $excerpt, $excerpt_length, '...' );
335
+ }
336
+
337
+ if ( $mark_search_words === 'true' ) {
338
+
339
+ $marked_content = $this->mark_search_words( $title, $excerpt );
340
+
341
+ $title = $marked_content['title'];
342
+ $excerpt = $marked_content['excerpt'];
343
+
344
+ }
345
+
346
+ if ( $show_price === 'true' ) {
347
+ $price = $product->get_price_html();
348
+ }
349
+
350
+ if ( $show_sale === 'true' ) {
351
+ $on_sale = $product->is_on_sale();
352
+ }
353
+
354
+ if ( $show_image === 'true' ) {
355
+ $image_id = $product->get_image_id();
356
+ $image_attributes = wp_get_attachment_image_src( $image_id );
357
+ $image = $image_attributes[0];
358
+ }
359
+
360
+ $categories = $product->get_categories( ',' );
361
+
362
+ $tags = $product->get_tags( ',' );
363
+
364
+ $new_result = array(
365
+ 'title' => $title,
366
+ 'excerpt' => $excerpt,
367
+ 'link' => get_permalink( $post_id ),
368
+ 'image' => $image,
369
+ 'price' => $price,
370
+ 'categories' => $categories,
371
+ 'tags' => $tags,
372
+ 'on_sale' => $on_sale
373
+ );
374
+
375
+ $products_array[] = $new_result;
376
+ }
377
+
378
+ }
379
+
380
+ return $products_array;
381
+
382
+ }
383
+
384
+ /*
385
+ * Mark search words
386
+ */
387
+ private function mark_search_words( $title, $excerpt ) {
388
+
389
+ $show_excerpt = $this->get_settings( 'show_excerpt' );
390
+
391
+ $pattern = array();
392
+
393
+ foreach( $this->data['search_terms'] as $search_in ) {
394
+ $pattern[] = '(' . $search_in . ')+';
395
+ }
396
+
397
+ usort( $pattern, array( $this, 'sort_by_length' ) );
398
+ $pattern = implode( '|', $pattern );
399
+ $pattern = sprintf( '/%s/i', $pattern );
400
+
401
+ if ( in_array( 'title', $this->data['search_in'] ) ) {
402
+ $title = preg_replace($pattern, '<strong>${0}</strong>', $title);
403
+ }
404
+
405
+ if ( $show_excerpt === 'true' && in_array( 'content', $this->data['search_in'] ) ) {
406
+ $excerpt = preg_replace( $pattern, '<strong>${0}</strong>', $excerpt );
407
+ }
408
+
409
+ return array(
410
+ 'title' => $title,
411
+ 'excerpt' => $excerpt
412
+ );
413
+
414
+ }
415
+
416
+ /*
417
+ * Sort array by its values length
418
+ */
419
+ private function sort_by_length( $a, $b ) {
420
+ return strlen( $b ) - strlen( $a );
421
+ }
422
+
423
+ /*
424
+ * Check if the terms are suitable for searching
425
+ */
426
+ private function parse_search_terms( $terms ) {
427
+
428
+ $strtolower = function_exists( 'mb_strtolower' ) ? 'mb_strtolower' : 'strtolower';
429
+ $checked = array();
430
+
431
+ $stopwords = $this->get_search_stopwords();
432
+
433
+ foreach ( $terms as $term ) {
434
+
435
+ // Avoid single A-Z.
436
+ if ( ! $term || ( 1 === strlen( $term ) && preg_match( '/^[a-z]$/i', $term ) ) )
437
+ continue;
438
+
439
+ if ( in_array( call_user_func( $strtolower, $term ), $stopwords, true ) )
440
+ continue;
441
+
442
+ $checked[] = $term;
443
+ }
444
+
445
+ return $checked;
446
+
447
+ }
448
+
449
+ /*
450
+ * Get array of stopwords
451
+ */
452
+ private function get_search_stopwords() {
453
+
454
+ $stopwords = array( 'about','an','are','as','at','be','by','com','for','from','how','in','is','it','of','on','or','that','the','this','to','was','what','when','where','who','will','with','www' );
455
+
456
+ return $stopwords;
457
+
458
+ }
459
+
460
+ /*
461
+ * Query product taxonomies
462
+ */
463
+ private function get_taxonomies( $s, $taxonomy ) {
464
+
465
+ global $wpdb;
466
+
467
+ $result_array = array();
468
+ $excludes = '';
469
+
470
+ $sql = "
471
+ SELECT
472
+ distinct($wpdb->terms.name),
473
+ $wpdb->terms.term_id,
474
+ $wpdb->term_taxonomy.taxonomy,
475
+ $wpdb->term_taxonomy.count
476
+ FROM
477
+ $wpdb->terms
478
+ , $wpdb->term_taxonomy
479
+ WHERE
480
+ name LIKE '%{$s}%'
481
+ AND $wpdb->term_taxonomy.taxonomy = '{$taxonomy}'
482
+ AND $wpdb->term_taxonomy.term_id = $wpdb->terms.term_id
483
+ $excludes
484
+ LIMIT 0, 10";
485
+
486
+ $search_results = $wpdb->get_results( $sql );
487
+
488
+ if ( ! empty( $search_results ) && !is_wp_error( $search_results ) ) {
489
+
490
+ foreach ( $search_results as $result ) {
491
+
492
+ $term = get_term( $result->term_id, $result->taxonomy );
493
+
494
+ if ( $term != null && !is_wp_error( $term ) ) {
495
+ $term_link = get_term_link( $term );
496
+ } else {
497
+ $term_link = '';
498
+ }
499
+
500
+ $new_result = array(
501
+ 'name' => $result->name,
502
+ 'count' => $result->count,
503
+ 'link' => $term_link
504
+ );
505
+
506
+ $result_array[] = $new_result;
507
+
508
+ }
509
+
510
+ }
511
+
512
+ return $result_array;
513
+
514
+ }
515
+
516
+ /*
517
+ * Get plugin settings
518
+ */
519
+ public function get_settings( $name ) {
520
+ $plugin_options = $this->data['settings'];
521
+ return $plugin_options[ $name ];
522
+ }
523
+
524
+ /*
525
+ * Add settings link to plugins
526
+ */
527
+ public function add_settings_link( $links, $file ) {
528
+ $plugin_base = plugin_basename( __FILE__ );
529
+
530
+ if ( $file == $plugin_base ) {
531
+ $setting_link = '<a href="' . admin_url('admin.php?page=aws-options') . '">'.__( 'Settings', 'aws' ).'</a>';
532
+ array_unshift( $links, $setting_link );
533
+ }
534
+
535
+ return $links;
536
+ }
537
+
538
+ }
539
+
540
+ endif;
541
+
542
+ /**
543
+ * Returns the main instance of AWS_Main
544
+ *
545
+ * @return AWS_Main
546
+ */
547
+ function AWS() {
548
+ return AWS_Main::instance();
549
+ }
550
+
551
+
552
+ /*
553
+ * Check if WooCommerce is active
554
+ */
555
+ if ( in_array( 'woocommerce/woocommerce.php', apply_filters( 'active_plugins', get_option( 'active_plugins' ) ) ) ) {
556
+ add_action( 'woocommerce_loaded', 'aws_init' );
557
+ } else {
558
+ add_action( 'admin_notices', 'aws_install_woocommerce_admin_notice' );
559
+ }
560
+
561
+ /*
562
+ * Error notice if WooCommerce plugin is not active
563
+ */
564
+ function aws_install_woocommerce_admin_notice() {
565
+ ?>
566
+ <div class="error">
567
+ <p><?php _e( 'Advanced Woo Search plugin is enabled but not effective. It requires WooCommerce in order to work.', 'aws' ); ?></p>
568
+ </div>
569
+ <?php
570
+ }
571
+
572
+ /*
573
+ * Init AWS plugin
574
+ */
575
+ function aws_init() {
576
+ AWS();
577
+ }
assets/css/admin.css ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .sortable-container {
2
+ width: 200px;
3
+ padding: 0;
4
+ float: left;
5
+ margin-right: 10px;
6
+ }
7
+
8
+ .sortable-title {
9
+ padding: 10px 0;
10
+ margin-right: 10px;
11
+ font-size: 13px;
12
+ }
13
+
14
+ .sti-sortable {
15
+ border: 1px solid #C7C4C4;
16
+ background: #DEDEDE;
17
+ list-style-type: none;
18
+ margin: 0;
19
+ padding: 5px;
20
+ margin-right: 10px;
21
+ height: 180px;
22
+ }
23
+
24
+ .sti-sortable li.sti-btn,
25
+ .sti-sortable li.highlight,
26
+ .sti-sortable li#excerpt {
27
+ display: inline-block;
28
+ float: left;
29
+ width: 100%;
30
+ height: auto;
31
+ margin: 0 3px 3px 0;
32
+ cursor: pointer;
33
+ background: #F1F1F1;
34
+ border: 1px solid #C7C4C4;
35
+ text-align: center;
36
+ padding: 8px 0;
37
+ }
38
+
39
+ .sti-sortable li.highlight {
40
+ background: #fff;
41
+ width: 100%;
42
+ height: 36px;
43
+ padding: 0;
44
+ border: 1px dotted #ccc;
45
+ }
assets/css/common.css ADDED
@@ -0,0 +1,195 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .aws-container .aws-search-form {
2
+ position: relative;
3
+ width: 100%;
4
+ }
5
+
6
+ .aws-container .aws-search-form * {
7
+ -moz-box-sizing: border-box;
8
+ -webkit-box-sizing: border-box;
9
+ box-sizing: border-box;
10
+ -moz-hyphens: manual;
11
+ -webkit-hyphens: manual;
12
+ hyphens: manual;
13
+ border-radius: 0 !important;
14
+ }
15
+
16
+ .aws-container .aws-search-form:after {
17
+ display: none;
18
+ position: absolute;
19
+ content: '';
20
+ background: url('../img/loader-1.GIF') no-repeat 50% 50%;
21
+ width: 20px;
22
+ height: 20px;
23
+ right: 10px;
24
+ top: 50%;
25
+ margin-top: -10px;
26
+ z-index: 999;
27
+ }
28
+
29
+ .aws-container .aws-search-form.processing:after {
30
+ display: block;
31
+ }
32
+
33
+ .aws-container .aws-search-field {
34
+ color: #313131;
35
+ padding: 6px;
36
+ line-height: 30px;
37
+ display: block;
38
+ font-size: 12px;
39
+ position: relative;
40
+ z-index: 2;
41
+ background: rgb(247, 247, 247);
42
+ -webkit-appearance: none;
43
+ }
44
+
45
+ .aws-container .aws-search-field:focus {
46
+ background-color: #fff;
47
+ }
48
+
49
+ .aws-search-result {
50
+ position: absolute;
51
+ z-index: 999;
52
+ z-index: 9999;
53
+ background: #fff;
54
+ width: 100%;
55
+ margin-top: -1px;
56
+ border: 1px solid #ccc;
57
+ font-size: 12px;
58
+ line-height: 16px;
59
+ }
60
+
61
+ .aws-search-result ul {
62
+ list-style: none;
63
+ padding: 0;
64
+ margin: 0 !important;
65
+
66
+ max-height: 300px;
67
+ overflow-y: scroll;
68
+ }
69
+
70
+ .aws-search-result ul li {
71
+ list-style: none;
72
+ border-bottom: 1px solid #ccc;
73
+ overflow: hidden;
74
+ margin: 0 !important;
75
+ position: relative;
76
+ }
77
+
78
+ .aws-search-result ul li:last-child {
79
+ border-bottom: 0;
80
+ }
81
+
82
+
83
+ .aws-search-result .aws_result_link {
84
+ display: block;
85
+ cursor: pointer;
86
+ padding: 10px 8px;
87
+ width: 100%;
88
+ height: 100%;
89
+ overflow: hidden;
90
+ text-decoration: none;
91
+ border: 0;
92
+ }
93
+ .aws-search-result .aws_result_link:hover {
94
+ background: #f5f5f5;
95
+ }
96
+
97
+
98
+ .aws-search-result .aws_result_content {
99
+ overflow: hidden;
100
+ display: block;
101
+ }
102
+
103
+ .aws-search-result .aws_result_title {
104
+ display: block;
105
+ font-weight: normal;
106
+ margin-bottom: 3px;
107
+ color: #21759b;
108
+ }
109
+
110
+ .aws-search-result .aws_result_cat .aws_result_title,
111
+ .aws-search-result .aws_result_tag .aws_result_title {
112
+ margin-bottom: 2px;
113
+ }
114
+
115
+ .aws-search-result .aws_result_excerpt {
116
+ display: block;
117
+ color: #222;
118
+ }
119
+
120
+ .aws-search-result .aws_result_price {
121
+ display: block;
122
+ padding: 2px 0;
123
+ color: #222;
124
+ }
125
+
126
+ .aws-search-result .aws_result_price del,
127
+ .aws-search-result .aws_result_price ins {
128
+ background: none;
129
+ padding: 0 12px 0 0;
130
+ opacity: 1;
131
+ }
132
+
133
+ .aws-search-result .aws_result_cats {
134
+ display: block;
135
+ float: left;
136
+ margin-right: 20px;
137
+ }
138
+
139
+ .aws-search-result .aws_result_image {
140
+ display: block;
141
+ height: 100%;
142
+ float: left;
143
+ padding-right: 10px;
144
+ }
145
+ .aws-search-result .aws_result_image img {
146
+ width: 50px;
147
+ height: 50px;
148
+ box-shadow: none;
149
+ }
150
+
151
+ .aws-search-result .aws_result_sale {
152
+ display: block;
153
+ height: 42px;
154
+ overflow: hidden;
155
+ position: absolute;
156
+ right: 0px;
157
+ top: 0px;
158
+ width: 47px;
159
+ }
160
+
161
+ .aws-search-result .aws_onsale {
162
+ background: #77a464 none repeat scroll 0 0;
163
+ color: #fff;
164
+ display: block;
165
+ float: right;
166
+ height: 20px;
167
+ padding-top: 2px;
168
+ position: relative;
169
+ right: -25px;
170
+ text-align: center;
171
+ top: 3px;
172
+ transform: rotate(45deg);
173
+ width: 77px;
174
+ }
175
+
176
+ .aws-search-result .aws_no_result {
177
+ line-height: 40px;
178
+ padding: 0 6px;
179
+ cursor: auto;
180
+ }
181
+
182
+ .aws-search-result .aws_search_more {
183
+
184
+ }
185
+ .aws-search-result .aws_search_more a {
186
+ line-height: 40px;
187
+ display: block;
188
+ text-decoration: none;
189
+ border: 0;
190
+ text-align: center;
191
+ color: #21759b;
192
+ }
193
+ .aws-search-result .aws_search_more a:hover {
194
+ background: #f5f5f5;
195
+ }
assets/img/loader-1.GIF ADDED
Binary file
assets/js/common.js ADDED
@@ -0,0 +1,278 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ (function($){
2
+ "use strict";
3
+
4
+ var selector = '.aws-container';
5
+ var instance = 0;
6
+ var pluginPfx = 'aws_opts';
7
+
8
+ $.fn.aws_search = function( options ) {
9
+
10
+
11
+ instance++;
12
+
13
+
14
+ var self = $(this),
15
+ $searchForm = self.find('.aws-search-form'),
16
+ $searchField = self.find('.aws-search-field'),
17
+ haveResults = false,
18
+ requests = Array(),
19
+ searchFor = '',
20
+ cachedResponse = new Array();
21
+
22
+
23
+ var ajaxUrl = ( self.data('url') !== undefined ) ? self.data('url') : false;
24
+ //var siteUrl = ( self.data('siteurl') !== undefined ) ? self.data('siteurl') : false;
25
+
26
+
27
+ self.data( pluginPfx, {
28
+ minChars : ( self.data('min-chars') !== undefined ) ? self.data('min-chars') : 1,
29
+ showLoader: ( self.data('show-loader') !== undefined ) ? self.data('show-loader') : true,
30
+ instance: instance,
31
+ resultBlock: '#aws-search-result-' + instance
32
+ });
33
+
34
+
35
+ var d = self.data(pluginPfx);
36
+
37
+
38
+ var methods = {
39
+
40
+ init: function() {
41
+
42
+ $('body').append('<div id="aws-search-result-' + instance + '" class="aws-search-result" style="display: none;"></div>');
43
+
44
+ methods.resultLayout();
45
+
46
+ },
47
+
48
+ onKeyup: function(e) {
49
+
50
+ searchFor = $searchField.val();
51
+ searchFor = searchFor.trim();
52
+ searchFor = searchFor.replace( /[`~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi, '' );
53
+ searchFor = searchFor.replace( /\s\s+/g, ' ' );
54
+
55
+ for ( var i = 0; i < requests.length; i++ ) {
56
+ requests[i].abort();
57
+ }
58
+
59
+ if ( searchFor === '' ) {
60
+ $(d.resultBlock).html('');
61
+ return;
62
+ }
63
+
64
+ if ( typeof cachedResponse[searchFor] != 'undefined') {
65
+ methods.showResults( cachedResponse[searchFor] );
66
+ return;
67
+ }
68
+
69
+ if ( searchFor.length < d.minChars ) {
70
+ $(d.resultBlock).html('');
71
+ return;
72
+ }
73
+
74
+ if ( d.showLoader ) {
75
+ $searchForm.addClass('processing');
76
+ }
77
+
78
+ var data = {
79
+ action: 'aws_action',
80
+ keyword : searchFor,
81
+ page: 0
82
+ };
83
+
84
+ requests.push(
85
+
86
+ $.ajax({
87
+ type: 'POST',
88
+ url: ajaxUrl,
89
+ data: data,
90
+ success: function( response ) {
91
+
92
+ var response = $.parseJSON( response );
93
+
94
+ cachedResponse[searchFor] = response;
95
+
96
+ methods.showResults( response );
97
+
98
+ $(d.resultBlock).show();
99
+
100
+ },
101
+ error: function (data, dummy) {
102
+ }
103
+ })
104
+
105
+ );
106
+
107
+ },
108
+
109
+ showResults: function( response ) {
110
+
111
+ var html = '<ul>';
112
+
113
+
114
+ if ( response.cats.length > 0 ) {
115
+
116
+ $.each(response.cats, function (i, result) {
117
+
118
+ html += '<li class="aws_result_item aws_result_cat">';
119
+ html += '<a class="aws_result_link" href="' + result.link + '" >';
120
+ html += '<span class="aws_result_content">';
121
+ html += '<span class="aws_result_title">';
122
+ html += result.name + '(' + result.count + ')';
123
+ html += '</span>';
124
+ html += '</span>';
125
+ html += '</a>';
126
+ html += '</li>';
127
+
128
+ });
129
+
130
+ }
131
+
132
+ if ( response.tags.length > 0 ) {
133
+
134
+ $.each(response.tags, function (i, result) {
135
+
136
+ html += '<li class="aws_result_item aws_result_tag">';
137
+ html += '<a class="aws_result_link" href="' + result.link + '" >';
138
+ html += '<span class="aws_result_content">';
139
+ html += '<span class="aws_result_title">';
140
+ html += result.name + '(' + result.count + ')';
141
+ html += '</span>';
142
+ html += '</span>';
143
+ html += '</a>';
144
+ html += '</li>';
145
+
146
+ });
147
+
148
+ }
149
+
150
+ if ( response.products.length > 0 ) {
151
+
152
+ $.each(response.products, function (i, result) {
153
+
154
+ html += '<li class="aws_result_item">';
155
+ html += '<a class="aws_result_link" href="' + result.link + '" >';
156
+
157
+ if ( result.image ) {
158
+ html += '<span class="aws_result_image">';
159
+ html += '<img src="' + result.image + '">';
160
+ html += '</span>';
161
+ }
162
+
163
+ html += '<span class="aws_result_content">';
164
+ html += '<span class="aws_result_title">' + result.title + '</span>';
165
+
166
+ if ( result.excerpt ) {
167
+ html += '<span class="aws_result_excerpt">' + result.excerpt + '</span>';
168
+ }
169
+
170
+ if ( result.price ) {
171
+ html += '<span class="aws_result_price">' + result.price + '</span>';
172
+ }
173
+
174
+ html += '</span>';
175
+
176
+ if ( result.on_sale ) {
177
+ html += '<span class="aws_result_sale">';
178
+ html += '<span class="aws_onsale">Sale!</span>';
179
+ html += '</span>';
180
+ }
181
+
182
+ html += '</a>';
183
+ html += '</li>';
184
+
185
+ });
186
+
187
+ //html += '<li class="aws_result_item aws_search_more"><a href="' + opts.siteUrl + '/?s=' + searchFor + '&post_type=product">View all</a></li>';
188
+ //html += '<li class="aws_result_item"><a href="#">Next Page</a></li>';
189
+
190
+ }
191
+
192
+ if ( response.cats.length <= 0 && response.tags.length <= 0 && response.products.length <= 0 ) {
193
+ html += '<li class="aws_result_item aws_no_result">Nothing found</li>';
194
+ }
195
+
196
+
197
+ html += '</ul>';
198
+
199
+ $searchForm.removeClass('processing');
200
+ $(d.resultBlock).html( html );
201
+
202
+ $(d.resultBlock).show();
203
+
204
+ },
205
+
206
+ onFocus: function( event ) {
207
+ if ( searchFor !== '' ) {
208
+ $(d.resultBlock).show();
209
+ }
210
+ },
211
+
212
+ hideResults: function( event ) {
213
+ if ( ! $(event.target).closest( ".aws-container" ).length ) {
214
+ $(d.resultBlock).hide();
215
+ }
216
+ },
217
+
218
+ resultLayout: function () {
219
+ var offset = self.offset();
220
+
221
+ if ( offset ) {
222
+
223
+ var width = self.outerWidth();
224
+ var top = offset.top + $(self).innerHeight();
225
+ var left = offset.left;
226
+
227
+ $( d.resultBlock ).css({
228
+ width : width,
229
+ top : top,
230
+ left: left
231
+ });
232
+
233
+ }
234
+
235
+ }
236
+
237
+ };
238
+
239
+
240
+ if ( $searchForm.length > 0 ) {
241
+ methods.init.call(this);
242
+ }
243
+
244
+
245
+ $searchField.on( 'keyup', function(e) {
246
+ methods.onKeyup(e);
247
+ });
248
+
249
+
250
+ $searchField.on( 'focus', function (e) {
251
+ methods.onFocus(e);
252
+ });
253
+
254
+
255
+ $(document).on( 'click', function (e) {
256
+ methods.hideResults(e);
257
+ });
258
+
259
+
260
+ $(window).on( 'resize', function(e) {
261
+ methods.resultLayout();
262
+ });
263
+
264
+
265
+ };
266
+
267
+
268
+ // Call plugin method
269
+ $(document).ready(function() {
270
+
271
+ $(selector).each( function() {
272
+ $(this).aws_search();
273
+ });
274
+
275
+ });
276
+
277
+
278
+ })( jQuery );
includes/class-aws-admin.php ADDED
@@ -0,0 +1,406 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ if ( ! defined( 'ABSPATH' ) ) {
4
+ exit;
5
+ }
6
+
7
+
8
+ if ( ! class_exists( 'AWS_Admin' ) ) :
9
+
10
+ /**
11
+ * Class for plugin admin panel
12
+ */
13
+ class AWS_Admin {
14
+
15
+ /*
16
+ * Name of the plugin settings page
17
+ */
18
+ var $page_name = 'aws-options';
19
+
20
+ /*
21
+ * Constructor
22
+ */
23
+ public function __construct() {
24
+ add_action( 'admin_menu', array( &$this, 'add_admin_page' ) );
25
+ add_action( 'admin_init', array( &$this, 'register_settings' ) );
26
+
27
+ if ( ! get_option( 'aws_settings' ) ) {
28
+ $this->initialize_settings();
29
+ }
30
+
31
+ add_action( 'admin_enqueue_scripts', array( &$this, 'admin_enqueue_scripts' ) );
32
+ }
33
+
34
+ /**
35
+ * Add options page
36
+ */
37
+ public function add_admin_page() {
38
+ add_menu_page( __( 'Adv. Woo Search', 'aws' ), __( 'Adv. Woo Search', 'aws' ), 'manage_options', 'aws-options', array( &$this, 'display_admin_page' ), 'dashicons-search' );
39
+ //add_submenu_page( 'aws-options', 'Analytics', 'Analytics', 'manage_options', 'aws-analytics', array( &$this, 'display_admin_page' ) );
40
+ }
41
+
42
+ /**
43
+ * Generate and display options page
44
+ */
45
+ public function display_admin_page() {
46
+
47
+ $options = $this->options_array();
48
+
49
+ $actual_link = "http://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]";
50
+
51
+ $tabs = array(
52
+ 'general' => __( 'General', 'aws' ),
53
+ //'query' => __( 'Query', 'aws' ),
54
+ //'view' => __( 'View', 'aws' )
55
+ );
56
+
57
+ $current_tab = empty( $_GET['tab'] ) ? 'general' : sanitize_title( $_GET['tab'] );
58
+
59
+ $tabs_html = '';
60
+
61
+ foreach ( $tabs as $name => $label ) {
62
+ $tabs_html .= '<a href="' . admin_url( 'admin.php?page=aws-options&tab=' . $name ) . '" class="nav-tab ' . ( $current_tab == $name ? 'nav-tab-active' : '' ) . '">' . $label . '</a>';
63
+ }
64
+
65
+ $tabs_html = '<h2 class="nav-tab-wrapper woo-nav-tab-wrapper">'.$tabs_html.'</h2>';
66
+
67
+ if( isset( $_POST["Submit"] ) ) {
68
+ $update_settings = $this->get_settings();
69
+
70
+ foreach ( $options[$current_tab] as $values ) {
71
+
72
+ if ( $values['type'] === 'heading' ) {
73
+ continue;
74
+ }
75
+
76
+ if ( $values['type'] === 'checkbox' ) {
77
+
78
+ $checkbox_array = array();
79
+
80
+ foreach ( $values['choices'] as $key => $value ) {
81
+ $new_value = isset( $_POST[ $values['id'] ][$key] ) ? '1' : '0';
82
+ $checkbox_array[$key] = $new_value;
83
+ }
84
+
85
+ $update_settings[ $values['id'] ] = $checkbox_array;
86
+
87
+ continue;
88
+ }
89
+
90
+ $new_value = isset( $_POST[ $values['id'] ] ) ? $_POST[ $values['id'] ] : '';
91
+ $update_settings[ $values['id'] ] = $new_value;
92
+
93
+ if ( isset( $values['sub_option'] ) ) {
94
+ $new_value = isset( $_POST[ $values['sub_option']['id'] ] ) ? $_POST[ $values['sub_option']['id'] ] : '';
95
+ $update_settings[ $values['sub_option']['id'] ] = $new_value;
96
+ }
97
+ }
98
+
99
+ update_option( 'aws_settings', $update_settings );
100
+ }
101
+
102
+ echo '<div class="wrap">';
103
+
104
+ echo $tabs_html;
105
+
106
+ echo '<form action="' . $actual_link . '" name="aws_form" id="aws_form" method="post">';
107
+
108
+ echo '<table class="form-table">';
109
+ echo '<tbody>';
110
+
111
+ switch ($current_tab) {
112
+ case('query'):
113
+ $this->generate_options( $options['query'] );
114
+ break;
115
+ case('view'):
116
+ $this->generate_options( $options['view'] );
117
+ break;
118
+ default:
119
+ $this->generate_options( $options['general'] );
120
+ }
121
+
122
+ echo '</tbody>';
123
+ echo '</table>';
124
+
125
+ echo '<p class="submit"><input name="Submit" type="submit" class="button-primary" value="Save Changes" /></p>';
126
+
127
+ echo '</form>';
128
+
129
+ echo '</div>';
130
+
131
+ }
132
+
133
+ /**
134
+ * Generate options
135
+ */
136
+ public function generate_options( $options ) {
137
+
138
+ $plugin_options = get_option( 'aws_settings' );
139
+
140
+ if ( empty( $options ) ) {
141
+ return;
142
+ }
143
+
144
+ foreach ( $options as $k => $value ) {
145
+ switch ( $value['type'] ) {
146
+
147
+ case 'text': ?>
148
+ <tr valign="top">
149
+ <th scope="row"><?php echo $value['name']; ?></th>
150
+ <td>
151
+ <input type="text" name="<?php echo $value['id']; ?>" class="regular-text" value="<?php echo stripslashes( $plugin_options[ $value['id'] ] ); ?>">
152
+ <br><span class="description"><?php echo $value['desc']; ?></span>
153
+ </td>
154
+ </tr>
155
+ <?php break;
156
+
157
+ case 'image': ?>
158
+ <tr valign="top">
159
+ <th scope="row"><?php echo $value['name']; ?></th>
160
+ <td>
161
+ <input type="text" name="<?php echo $value['id']; ?>" class="regular-text" value="<?php echo stripslashes( $plugin_options[ $value['id'] ] ); ?>">
162
+ <br><span class="description"><?php echo $value['desc']; ?></span>
163
+ <img style="display: block;max-width: 100px;margin-top: 20px;" src="<?php echo stripslashes( $plugin_options[ $value['id'] ] ); ?>">
164
+ </td>
165
+ </tr>
166
+ <?php break;
167
+
168
+ case 'number': ?>
169
+ <tr valign="top">
170
+ <th scope="row"><?php echo $value['name']; ?></th>
171
+ <td>
172
+ <input type="number" name="<?php echo $value['id']; ?>" class="regular-text" value="<?php echo stripslashes( $plugin_options[ $value['id'] ] ); ?>">
173
+ <br><span class="description"><?php echo $value['desc']; ?></span>
174
+ </td>
175
+ </tr>
176
+ <?php break;
177
+
178
+ case 'textarea': ?>
179
+ <tr valign="top">
180
+ <th scope="row"><?php echo $value['name']; ?></th>
181
+ <td>
182
+ <textarea id="<?php echo $value['id']; ?>" name="<?php echo $value['id']; ?>" cols="45" rows="3"><?php print stripslashes( $plugin_options[ $value['id'] ] ); ?></textarea>
183
+ <br><span class="description"><?php echo $value['desc']; ?></span>
184
+ </td>
185
+ </tr>
186
+ <?php break;
187
+
188
+ case 'checkbox': ?>
189
+ <tr valign="top">
190
+ <th scope="row"><?php echo $value['name']; ?></th>
191
+ <td>
192
+ <?php $checkbox_options = $plugin_options[ $value['id'] ]; ?>
193
+ <?php foreach ( $value['choices'] as $val => $label ) { ?>
194
+ <input type="checkbox" name="<?php echo $value['id'] . '[' . $val . ']'; ?>" id="<?php echo $value['id'] . '_' . $val; ?>" value="1" <?php checked( $checkbox_options[$val], '1' ); ?>> <label for="<?php echo $value['id'] . '_' . $val; ?>"><?php echo $label; ?></label><br>
195
+ <?php } ?>
196
+ <br><span class="description"><?php echo $value['desc']; ?></span>
197
+ </td>
198
+ </tr>
199
+ <?php break;
200
+
201
+ case 'radio': ?>
202
+ <tr valign="top">
203
+ <th scope="row"><?php echo $value['name']; ?></th>
204
+ <td>
205
+ <?php foreach ( $value['choices'] as $val => $label ) { ?>
206
+ <input class="radio" type="radio" name="<?php echo $value['id']; ?>" id="<?php echo $value['id'].$val; ?>" value="<?php echo $val; ?>" <?php checked( $plugin_options[ $value['id'] ], $val ); ?>> <label for="<?php echo $value['id'].$val; ?>"><?php echo $label; ?></label><br>
207
+ <?php } ?>
208
+ <br><span class="description"><?php echo $value['desc']; ?></span>
209
+ </td>
210
+ </tr>
211
+ <?php break;
212
+
213
+ case 'select': ?>
214
+ <tr valign="top">
215
+ <th scope="row"><?php echo $value['name']; ?></th>
216
+ <td>
217
+ <select name="<?php echo $value['id']; ?>">
218
+ <?php foreach ( $value['choices'] as $val => $label ) { ?>
219
+ <option value="<?php echo $val; ?>" <?php selected( $plugin_options[ $value['id'] ], $val ); ?>><?php echo $label; ?></option>
220
+ <?php } ?>
221
+ </select>
222
+ <br><span class="description"><?php echo $value['desc']; ?></span>
223
+ </td>
224
+ </tr>
225
+ <?php break;
226
+
227
+ case 'select_advanced': ?>
228
+ <tr valign="top">
229
+ <th scope="row"><?php echo $value['name']; ?></th>
230
+ <td>
231
+ <select name="<?php echo $value['id'].'[]'; ?>" multiple class="chosen-select">
232
+ <?php $values = $plugin_options[ $value['id'] ]; ?>
233
+ <?php foreach ( $value['choices'] as $val => $label ) { ?>
234
+ <?php $selected = in_array( $val, $values ) ? ' selected="selected" ' : ''; ?>
235
+ <option value="<?php echo $val; ?>"<?php echo $selected; ?>><?php echo $label; ?></option>
236
+ <?php } ?>
237
+ </select>
238
+ <br><span class="description"><?php echo $value['desc']; ?></span>
239
+
240
+ <?php if ( $value['sub_option'] ): ?>
241
+ <?php $sub_options = $value['sub_option']; ?>
242
+ <br><br>
243
+ <p>
244
+ <label for="<?php echo $sub_options['id']; ?>">
245
+ <input type="checkbox" value="1" id="<?php echo $sub_options['id']; ?>" name="<?php echo $sub_options['id']; ?>" <?php checked( $plugin_options[ $sub_options['id'] ], '1' ); ?>>
246
+ <?php echo $sub_options['desc']; ?>
247
+ </label>
248
+ </p>
249
+ <?php endif; ?>
250
+
251
+ </td>
252
+ </tr>
253
+ <?php break;
254
+
255
+ case 'sortable': ?>
256
+ <tr valign="top">
257
+ <th scope="row"><?php echo $value['name']; ?></th>
258
+ <td>
259
+
260
+ <script>
261
+ jQuery(document).ready(function() {
262
+
263
+ jQuery( "#sti-sortable1, #sti-sortable2" ).sortable({
264
+ connectWith: ".connectedSortable",
265
+ placeholder: "highlight",
266
+ update: function(event, ui){
267
+ var serviceList = '';
268
+ jQuery("#sti-sortable2 li").each(function(){
269
+
270
+ serviceList = serviceList + ',' + jQuery(this).attr('id');
271
+
272
+ });
273
+ var serviceListOut = serviceList.substring(1);
274
+ jQuery('#<?php echo $value['id']; ?>').attr('value', serviceListOut);
275
+ }
276
+ }).disableSelection();
277
+
278
+ });
279
+ </script>
280
+
281
+ <span class="description"><?php echo $value['desc']; ?></span><br><br>
282
+
283
+ <?php
284
+ $all_buttons = $value['choices'];
285
+ $active_buttons = explode( ',', $plugin_options[ $value['id'] ] );
286
+ $inactive_buttons = array_diff($all_buttons, $active_buttons);
287
+ ?>
288
+
289
+ <div class="sortable-container">
290
+
291
+ <div class="sortable-title"><?php _e( 'Available fields', 'aws' ) ?></div>
292
+
293
+ <ul id="sti-sortable1" class="sti-sortable connectedSortable">
294
+ <?php
295
+ if ( count( $inactive_buttons ) > 0 ) {
296
+ foreach ($inactive_buttons as $button) {
297
+ echo '<li id="' . $button . '" class="sti-btn sti-' . $button . '-btn">' . $button . '</li>';
298
+ }
299
+ }
300
+ ?>
301
+ </ul>
302
+
303
+ </div>
304
+
305
+ <div class="sortable-container">
306
+
307
+ <div class="sortable-title"><?php _e( 'Drag&drop to enable', 'aws' ) ?></div>
308
+
309
+ <ul id="sti-sortable2" class="sti-sortable connectedSortable">
310
+ <?php
311
+ if ( count( $active_buttons ) > 0 ) {
312
+ foreach ($active_buttons as $button) {
313
+ if ( ! $button ) continue;
314
+ echo '<li id="' . $button . '" class="sti-btn sti-' . $button . '-btn">' . $button . '</li>';
315
+ }
316
+ }
317
+ ?>
318
+ </ul>
319
+
320
+ </div>
321
+
322
+ <input type="hidden" id="<?php echo $value['id']; ?>" name="<?php echo $value['id']; ?>" value="<?php echo $plugin_options[ $value['id'] ]; ?>" />
323
+
324
+ </td>
325
+ </tr>
326
+ <?php break;
327
+
328
+ case 'heading': ?>
329
+ <tr valign="top">
330
+ <th scope="row"><h3><?php echo $value['name']; ?></h3></th>
331
+ </tr>
332
+ <?php break;
333
+ }
334
+ }
335
+
336
+ }
337
+
338
+ /*
339
+ * Options array that generate settings page
340
+ */
341
+ public function options_array() {
342
+
343
+ require_once AWS_DIR .'/includes/options.php';
344
+
345
+ return $options;
346
+ }
347
+
348
+ /*
349
+ * Register plugin settings
350
+ */
351
+ public function register_settings() {
352
+ register_setting( 'aws_settings', 'aws_settings' );
353
+ }
354
+
355
+ /*
356
+ * Get plugin settings
357
+ */
358
+ public function get_settings() {
359
+ $plugin_options = get_option( 'aws_settings' );
360
+ return $plugin_options;
361
+ }
362
+
363
+ /**
364
+ * Initialize settings to their default values
365
+ */
366
+ public function initialize_settings() {
367
+ $options = $this->options_array();
368
+ $default_settings = array();
369
+
370
+ foreach ( $options as $section ) {
371
+ foreach ($section as $values) {
372
+
373
+ if ( $values['type'] === 'heading' ) {
374
+ continue;
375
+ }
376
+
377
+ $default_settings[$values['id']] = $values['value'];
378
+
379
+ if (isset( $values['sub_option'])) {
380
+ $default_settings[$values['sub_option']['id']] = $values['sub_option']['value'];
381
+ }
382
+ }
383
+ }
384
+
385
+ update_option( 'aws_settings', $default_settings );
386
+ }
387
+
388
+ /*
389
+ * Enqueue admin scripts and styles
390
+ */
391
+ public function admin_enqueue_scripts() {
392
+
393
+ if ( isset( $_GET['page'] ) && $_GET['page'] == 'aws-options' ) {
394
+ wp_enqueue_style( 'plugin-admin-style', AWS_URL . '/assets/css/admin.css' );
395
+ wp_enqueue_script( 'jquery' );
396
+ wp_enqueue_script( 'jquery-ui-sortable' );
397
+ }
398
+
399
+ }
400
+
401
+ }
402
+
403
+ endif;
404
+
405
+
406
+ new AWS_Admin();
includes/options.php ADDED
@@ -0,0 +1,169 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Array of plugin options
4
+ */
5
+
6
+ $options = array();
7
+
8
+ $options['general'][] = array(
9
+ "name" => __( "Text for search field", "aws" ),
10
+ "desc" => __( "Text for search field placeholder.", "aws" ),
11
+ "id" => "search_field_text",
12
+ "value" => "Search",
13
+ "type" => "text"
14
+ );
15
+
16
+ $options['general'][] = array(
17
+ "name" => __( "Minimum number of characters", "aws" ),
18
+ "desc" => __( "Minimum number of characters required to run ajax search.", "aws" ),
19
+ "id" => "min_chars",
20
+ "value" => 1,
21
+ "type" => "number"
22
+ );
23
+
24
+ $options['general'][] = array(
25
+ "name" => __( "Show loader", "aws" ),
26
+ "desc" => __( "Show loader animation while searching.", "aws" ),
27
+ "id" => "show_loader",
28
+ "value" => 'true',
29
+ "type" => "radio",
30
+ 'choices' => array(
31
+ 'true' => 'On',
32
+ 'false' => 'Off'
33
+ )
34
+ );
35
+
36
+ $options['general'][] = array(
37
+ "name" => __( "Show image", "aws" ),
38
+ "desc" => __( "Show product image for each search result.", "aws" ),
39
+ "id" => "show_image",
40
+ "value" => 'true',
41
+ "type" => "radio",
42
+ 'choices' => array(
43
+ 'true' => 'On',
44
+ 'false' => 'Off'
45
+ )
46
+ );
47
+
48
+ $options['general'][] = array(
49
+ "name" => __( "Show description", "aws" ),
50
+ "desc" => __( "Show product description for each search result.", "aws" ),
51
+ "id" => "show_excerpt",
52
+ "value" => 'true',
53
+ "type" => "radio",
54
+ 'choices' => array(
55
+ 'true' => 'On',
56
+ 'false' => 'Off'
57
+ )
58
+ );
59
+
60
+ $options['general'][] = array(
61
+ "name" => __( "Description source", "aws" ),
62
+ "desc" => __( "From where to take product description.<br>If first source is empty data will be taken from other sources.", "aws" ),
63
+ "id" => "desc_source",
64
+ "value" => 'content',
65
+ "type" => "radio",
66
+ 'choices' => array(
67
+ 'content' => __( 'Content', 'aws' ),
68
+ 'excerpt' => __( 'Excerpt', 'aws' ),
69
+ )
70
+ );
71
+
72
+ $options['general'][] = array(
73
+ "name" => __( "Description length", "aws" ),
74
+ "desc" => __( "Maximal allowed number of words for product description.", "aws" ),
75
+ "id" => "excerpt_length",
76
+ "value" => 10,
77
+ "type" => "number"
78
+ );
79
+
80
+ $options['general'][] = array(
81
+ "name" => __( "Show price", "aws" ),
82
+ "desc" => __( "Show product price for each search result.", "aws" ),
83
+ "id" => "show_price",
84
+ "value" => 'true',
85
+ "type" => "radio",
86
+ 'choices' => array(
87
+ 'true' => 'On',
88
+ 'false' => 'Off'
89
+ )
90
+ );
91
+
92
+ $options['general'][] = array(
93
+ "name" => __( "Mark words", "aws" ),
94
+ "desc" => __( "Mark searching words in the result.", "aws" ),
95
+ "id" => "mark_words",
96
+ "value" => 'true',
97
+ "type" => "radio",
98
+ 'choices' => array(
99
+ 'true' => 'On',
100
+ 'false' => 'Off'
101
+ )
102
+ );
103
+
104
+ $options['general'][] = array(
105
+ "name" => __( "Show categories", "aws" ),
106
+ "desc" => __( "Include categories in search result.", "aws" ),
107
+ "id" => "show_cats",
108
+ "value" => 'false',
109
+ "type" => "radio",
110
+ 'choices' => array(
111
+ 'true' => 'On',
112
+ 'false' => 'Off'
113
+ )
114
+ );
115
+
116
+ $options['general'][] = array(
117
+ "name" => __( "Show tags", "aws" ),
118
+ "desc" => __( "Include tags in search result.", "aws" ),
119
+ "id" => "show_tags",
120
+ "value" => 'false',
121
+ "type" => "radio",
122
+ 'choices' => array(
123
+ 'true' => 'On',
124
+ 'false' => 'Off'
125
+ )
126
+ );
127
+
128
+ $options['general'][] = array(
129
+ "name" => __( "Show sale badge", "aws" ),
130
+ "desc" => __( "Show sale badge for products in search results.", "aws" ),
131
+ "id" => "show_sale",
132
+ "value" => 'true',
133
+ "type" => "radio",
134
+ 'choices' => array(
135
+ 'true' => 'On',
136
+ 'false' => 'Off'
137
+ )
138
+ );
139
+
140
+ // Query tab
141
+
142
+ $options['general'][] = array(
143
+ "name" => __( "Max number of results", "aws" ),
144
+ "desc" => __( "Maximum number of displayed search results.", "aws" ),
145
+ "id" => "results_num",
146
+ "value" => 10,
147
+ "type" => "number"
148
+ );
149
+
150
+ $options['general'][] = array(
151
+ "name" => __( "Exact match", "aws" ),
152
+ "desc" => __( "Search only for fully matching string. Not divide string into words.", "aws" ),
153
+ "id" => "exact_match",
154
+ "value" => 'false',
155
+ "type" => "radio",
156
+ 'choices' => array(
157
+ 'true' => 'On',
158
+ 'false' => 'Off'
159
+ )
160
+ );
161
+
162
+ $options['general'][] = array(
163
+ "name" => __( "Search in", "aws" ),
164
+ "desc" => __( "Source of searching. Set the source of searching by drag&drop needed fields to the right area.", "aws" ),
165
+ "id" => "search_in",
166
+ "value" => "title,content,sku,excerpt",
167
+ "choices" => array( "title", "content", "sku", "excerpt" ),
168
+ "type" => "sortable"
169
+ );
includes/widget.php ADDED
@@ -0,0 +1,69 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * Initialized plugins widget
4
+ */
5
+
6
+ add_action( 'widgets_init', create_function( '', 'return register_widget("AWS_Widget");' ) );
7
+
8
+
9
+ class AWS_Widget extends WP_Widget {
10
+
11
+ /*
12
+ * Constructor
13
+ */
14
+ function __construct() {
15
+ $widget_ops = array( 'description' => __('Advanced WooCommerce search widget', 'aws' ) );
16
+ $control_ops = array( 'width' => 400 );
17
+ parent::__construct( false, __( '&raquo; AWS Widget', 'aws' ), $widget_ops, $control_ops );
18
+ }
19
+
20
+ /*
21
+ * Display widget
22
+ */
23
+ function widget( $args, $instance ) {
24
+ extract( $args );
25
+ $title = apply_filters('widget_title', $instance['title'] );
26
+
27
+ echo $before_widget;
28
+ echo $before_title;
29
+ echo $title;
30
+ echo $after_title;
31
+
32
+ // Generate search form markup
33
+ echo AWS()->markup();
34
+
35
+ echo $after_widget;
36
+ }
37
+
38
+ /*
39
+ * Update widget settings
40
+ */
41
+ function update( $new_instance, $old_instance ) {
42
+ $instance = $old_instance;
43
+ $params = array( 'title' );
44
+ foreach ( $params as $k ) {
45
+ $instance[$k] = strip_tags( $new_instance[$k] );
46
+ }
47
+ return $instance;
48
+ }
49
+
50
+ /*
51
+ * Widget settings form
52
+ */
53
+ function form( $instance ) {
54
+ global $shortname;
55
+ $defaults = array(
56
+ 'title' => __( 'Search...', 'aws' )
57
+ );
58
+ $instance = wp_parse_args( (array) $instance, $defaults );
59
+ ?>
60
+
61
+ <p>
62
+ <label for="<?php echo esc_attr( $this->get_field_id('title') ); ?>"><?php _e( 'Title:', 'aws' ); ?></label>
63
+ <input type="text" class="widefat" id="<?php echo esc_attr( $this->get_field_id('title') ); ?>" name="<?php echo esc_attr( $this->get_field_name('title') ); ?>" value="<?php echo esc_attr( $instance['title'] ); ?>">
64
+ </p>
65
+
66
+ <?php
67
+ }
68
+ }
69
+ ?>
readme.txt ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ === Advanced Woo Search ===
2
+ Contributors: Mihail Barinov
3
+ Donate link: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=GSE37FC4Y7CEY
4
+ Tags: widget, plugin, woocommerce, search, product search, woocommerce search, ajax search, live search, custom search, ajax, shortcode, better search, relevance search, relevant search, search by sku, search plugin, shop, store, wordpress search, wp ajax search, wp search, wp search plugin, sidebar, ecommerce, merketing, products, category search, instant-search, search highlight, woocommerce advanced search, woocommerce live search, WooCommerce Plugin, woocommerce product search
5
+ Requires at least: 4.0
6
+ Tested up to: 4.4.2
7
+ Stable tag: 1.01
8
+ License: GPLv2 or later
9
+ License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
+
11
+ Advanced AJAX search plugin for WooCommerce.
12
+
13
+ == Description ==
14
+
15
+ Advanced Woo Search - powerful live search plugin for WooCommerce. Just start typing and you will immediately see the products that you search
16
+
17
+ = Main Features =
18
+
19
+ * **Products search** - Search across all your WooCommerce products
20
+ * **Settings page** - User-friendly settings page with lot of options
21
+ * **Search in** - Search in product title, content, excerpt and sku. Or just in some of them
22
+ * **Shortcode** - Use shortcode to place search box anywhere you want
23
+ * **Product image** - Each search result contains product image
24
+ * **Product price** - Each search result contains product price
25
+ * **Terms search** - Search for product categories and tags
26
+ * **Smart ordering** - Search results ordered by the priority of source where they were found
27
+ * **Fast** - Nothing extra. Just what you need for proper work
28
+
29
+ == Installation ==
30
+
31
+ 1. Upload advanced-woo-search to the /wp-content/plugins/ directory
32
+ 2. Activate the plugin through the 'Plugins' menu in WordPress
33
+ 3. Place the plugin shortcode [aws_search_form] into your template or post-page or just use build-in widget
34
+
35
+ == Frequently Asked Questions ==
36
+
37
+ = How to insert search form? =
38
+
39
+ You can use build-in widget to place plugins search form to your sidebar.
40
+
41
+ Or just use shortcode for displaying form inside your post/page:
42
+
43
+ `[aws_search_form]`
44
+
45
+ Or insert this function inside php file ( often it used to insert form inside page templates files ):
46
+
47
+ `echo do_shortcode( '[aws_search_form]' );`
48
+
49
+ == Screenshots ==
50
+
51
+ 1. Front-end view
52
+ 2. Plugin settings page
53
+
54
+ == Changelog ==
55
+
56
+ = 1.01 =
57
+ * Fix problem with result block layout
58
+
59
+ = 1.00 =
60
+ * First Release