So erstellen Sie ein AJAX-basiertes Live-Produktsuch-Widget für WooCommerce
German (Deutsch) translation by Władysław Łucyszyn (you can also view the original English article)
AJAX (Asynchronous Javascript and XML) ist eine Möglichkeit, eine Webseite mit einem Server zu kommunizieren und ihren Inhalt zu aktualisieren, ohne die Seite neu zu laden. Mit WooCommerce können wir mit AJAX Produkte direkt in den Warenkorb legen, Produkte im laufenden Betrieb anpassen, Produktlisten filtern und vieles mehr.
In diesem Tutorial erstellen wir ein Produkt-Plugin für die "live search" mit einem Produktkategoriefilter und einer Keyword-Eingabe. Alles natürlich mit AJAX.
Unser Plugin gibt uns ein benutzerdefiniertes Widget, das dann überall im WooCommerce Store platziert werden kann. Es sieht folgendermaßen aus (die Ästhetik ändert sich je nach verwendetem WordPress-Thema):



1. Erstellen Sie den Plugin-Ordner
Beginnen Sie mit der Erstellung eines Ordners namens "Produktsuche" und der darin enthaltenen PHP-Hauptdatei "product-search.php". Öffnen Sie die Datei und fügen Sie den folgenden Header-Kommentar hinzu, wobei Sie die relevanten Details in Ihre eigenen ändern:
1 |
/*
|
2 |
Plugin Name: Woocommerce AJAX product search
|
3 |
Plugin URI: https://www.enovathemes.com
|
4 |
Description: Ajax product search for WooCommerce
|
5 |
Author: Enovathemes
|
6 |
Version: 1.0
|
7 |
Author URI: https://enovathemes.com
|
8 |
*/
|
9 |
|
10 |
if ( ! defined( 'ABSPATH' ) ) { |
11 |
exit; // Exit if accessed directly |
12 |
}
|
Hier beschreiben wir, was unser Plugin ist und was es tut. Ich werde die Plugin-Entwicklung nicht im Detail behandeln, da dies den Rahmen dieses Tutorials sprengt. Wenn Sie jedoch noch nicht mit der Plugin-Entwicklung vertraut sind, empfehle ich dringend, einen Blick auf diesen Anfängerkurs zu werfen:
2. Planen Sie unsere Plugin-Entwicklung
Hier ist unser Plan: Wir haben eine Sucheingabe mit einem ausgewählten Element, um die Produktkategorie zu definieren. All dies wird in ein Widget gepackt. Benutzer können nach einem Schlüsselwort innerhalb einer bestimmten Produktkategorie suchen.
Immer wenn der Benutzer ein Produktschlüsselwort oder eine Produkt-SKU eingibt, werden wir eine AJAX-Anfrage stellen, um Produkte abzufragen, die der Kategorie entsprechen (falls definiert) und das angegebene Schlüsselwort im Titel, Inhalt oder der angegebenen SKU enthalten. Dem Benutzer wird eine Liste mit Suchergebnissen angezeigt.
Unser nächster Schritt besteht darin, den Plugin-Stil und die Skriptdateien in die Warteschlange zu stellen.
3. Plugin-Dateien in die Warteschlange stellen
Fügen Sie nach dem Plugin-Intro den folgenden Code hinzu:
1 |
function search_plugin_scripts_styles(){ |
2 |
if (class_exists("Woocommerce")) { |
3 |
|
4 |
wp_enqueue_style( 'search-style', plugins_url('/css/style.css', __FILE__ ), array(), '1.0.0' ); |
5 |
wp_register_script( 'search-main', plugins_url('/js/main.js', __FILE__ ), array('jquery'), '', true); |
6 |
wp_localize_script( |
7 |
'search-main', |
8 |
'opt', |
9 |
array( |
10 |
'ajaxUrl' => admin_url('admin-ajax.php'), |
11 |
'noResults' => esc_html__( 'No products found', 'textdomain' ), |
12 |
)
|
13 |
);
|
14 |
}
|
15 |
}
|
16 |
add_action( 'wp_enqueue_scripts', 'search_plugin_scripts_styles' ); |
Stellen Sie sicher, dass Sie entsprechende Ordner für Stile und Skripte (CSS- und JS-Ordner) und die entsprechenden Dateien (style.css und main.js) erstellen.
Für die Datei main.js müssen einige Parameter mit der Funktion wp_localize_script übergeben werden. Diese Parameter geben uns die AJAX-URL und den Text "no results", sodass wir sie nicht fest in unser Skript codieren müssen.
4. Holen Sie sich die Taxonomie der Produktkategorie mit Hierarchie
Als nächstes müssen wir alle Produktkategorien mit Hierarchie sammeln und zwischenspeichern. Dies wird für die Optionen zur Kategorieauswahl verwendet.
Diese Aufgabe besteht aus 4 Schritten:
- Holen Sie sich Produktkategorie Taxonomie mit Hierarchie
- Listen Sie die Taxonomie der Produktkategorien mit der Hierarchie als Auswahloptionen auf
- Zwischenspeichern Sie die Ergebnisse der Produktkategorie-Taxonomie
- Löschen Sie vorübergehende Produktkategorien (Cache) beim Bearbeiten von Begriffen und beim Speichern nach dem Speichern
Holen Sie sich Taxonomie
Hier habe ich eine rekursive Funktion erstellt, die die angegebenen Taxonomiebegriffe mit der Eltern-Kind-Beziehung sammelt:
1 |
function get_taxonomy_hierarchy( $taxonomy, $parent = 0, $exclude = 0) { |
2 |
$taxonomy = is_array( $taxonomy ) ? array_shift( $taxonomy ) : $taxonomy; |
3 |
$terms = get_terms( $taxonomy, array( 'parent' => $parent, 'hide_empty' => false, 'exclude' => $exclude) ); |
4 |
|
5 |
$children = array(); |
6 |
foreach ( $terms as $term ){ |
7 |
$term->children = get_taxonomy_hierarchy( $taxonomy, $term->term_id, $exclude); |
8 |
$children[ $term->term_id ] = $term; |
9 |
}
|
10 |
return $children; |
11 |
}
|
Produktkategorien als Auswahloptionen auflisten
Als nächstes müssen wir die gesammelten Begriffe mit einer anderen rekursiven Funktion auflisten. Es erstellt die auf option und optgroup basierende HTML-Struktur:
1 |
function list_taxonomy_hierarchy_no_instance( $taxonomies) { |
2 |
?>
|
3 |
<?php foreach ( $taxonomies as $taxonomy ) { ?> |
4 |
<?php $children = $taxonomy->children; ?> |
5 |
<option value="<?php echo $taxonomy->term_id; ?>"><?php echo $taxonomy->name; ?></option> |
6 |
<?php if (is_array($children) && !empty($children)): ?> |
7 |
<optgroup>
|
8 |
<?php list_taxonomy_hierarchy_no_instance($children); ?> |
9 |
</optgroup>
|
10 |
<?php endif ?> |
11 |
<?php } ?> |
12 |
|
13 |
<?php
|
14 |
}
|
Zwischenspeichern der Ergebnisse der Produktkategorie
Abgefragte Ergebnisse müssen zwischengespeichert werden, um den Filterrenderprozess nicht zu verlangsamen. Hier müssen wir also einen Übergang für Produktkategorien erstellen. Ich werde die Transients-API nicht im Detail beschreiben, aber wenn Sie mit dem Thema noch nicht vertraut sind, empfehle ich dringend, diese erstaunlichen Einführungs-Tutorials zu lesen:
-
ThemenentwicklungErste Schritte mit der WordPress Transients API, Teil 1Tom McFarlin -
PluginsErste Schritte mit der WordPress Transient API, Teil 2Tom McFarlin
Im Moment ist hier die Produktkategorie vorübergehend:
1 |
function get_product_categories_hierarchy() { |
2 |
|
3 |
if ( false === ( $categories = get_transient( 'product-categories-hierarchy' ) ) ) { |
4 |
|
5 |
$categories = get_taxonomy_hierarchy( 'product_cat', 0, 0); |
6 |
|
7 |
// do not set an empty transient - should help catch private or empty accounts.
|
8 |
if ( ! empty( $categories ) ) { |
9 |
$categories = base64_encode( serialize( $categories ) ); |
10 |
set_transient( 'product-categories-hierarchy', $categories, apply_filters( 'null_categories_cache_time', 0 ) ); |
11 |
}
|
12 |
}
|
13 |
|
14 |
if ( ! empty( $categories ) ) { |
15 |
|
16 |
return unserialize( base64_decode( $categories ) ); |
17 |
|
18 |
} else { |
19 |
|
20 |
return new WP_Error( 'no_categories', esc_html__( 'No categories.', 'textdomain' ) ); |
21 |
|
22 |
}
|
23 |
}
|
Löschen Sie vorübergehende Produktkategorien (Cache) beim Bearbeiten von Begriffen und beim Speichern nach dem Speichern
Schließlich müssen wir den Übergang löschen, wenn ein Benutzer eine Produktkategorie aktualisiert oder erstellt oder das Produkt selbst aktualisiert / erstellt.
1 |
function edit_product_term($term_id, $tt_id, $taxonomy) { |
2 |
$term = get_term($term_id,$taxonomy); |
3 |
if (!is_wp_error($term) && is_object($term)) { |
4 |
$taxonomy = $term->taxonomy; |
5 |
if ($taxonomy == "product_cat") { |
6 |
delete_transient( 'product-categories-hierarchy' ); |
7 |
}
|
8 |
}
|
9 |
}
|
10 |
|
11 |
function delete_product_term($term_id, $tt_id, $taxonomy, $deleted_term) { |
12 |
if (!is_wp_error($deleted_term) && is_object($deleted_term)) { |
13 |
$taxonomy = $deleted_term->taxonomy; |
14 |
if ($taxonomy == "product_cat") { |
15 |
delete_transient( 'product-categories-hierarchy' ); |
16 |
}
|
17 |
}
|
18 |
}
|
19 |
add_action( 'create_term', 'edit_product_term', 99, 3 ); |
20 |
add_action( 'edit_term', 'edit_product_term', 99, 3 ); |
21 |
add_action( 'delete_term', 'delete_product_term', 99, 4 ); |
22 |
|
23 |
add_action( 'save_post', 'save_post_action', 99, 3); |
24 |
function save_post_action( $post_id ){ |
25 |
|
26 |
if( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) return; |
27 |
if (!current_user_can( 'edit_page', $post_id ) ) return; |
28 |
|
29 |
$post_info = get_post($post_id); |
30 |
|
31 |
if (!is_wp_error($post_info) && is_object($post_info)) { |
32 |
$content = $post_info->post_content; |
33 |
$post_type = $post_info->post_type; |
34 |
|
35 |
if ($post_type == "product"){ |
36 |
delete_transient( 'enovathemes-product-categories' ); |
37 |
}
|
38 |
}
|
39 |
|
40 |
}
|
Wir werden Aktionen für create_term, edit_term, delete_term und save_post hinzufügen
5. Erstellen Sie das Widget
Jetzt ist es Zeit, das Widget selbst zu erstellen. Ich werde den Widget-Erstellungsprozess nicht im Detail beschreiben, aber wenn Sie sich auf dem Laufenden halten müssen, empfehle ich dieses Tutorial:
Fügen Sie vorerst den folgenden Code hinzu, um das Widget zu erstellen:
1 |
add_action('widgets_init', 'register_product_search_widget'); |
2 |
function register_product_search_widget(){ |
3 |
register_widget( 'Enovathemes_Addons_WP_Product_Search' ); |
4 |
}
|
5 |
|
6 |
class Enovathemes_Addons_WP_Product_Search extends WP_Widget { |
7 |
|
8 |
public function __construct() { |
9 |
parent::__construct( |
10 |
'product_search_widget', |
11 |
esc_html__('* Product ajax search', 'textdomain'), |
12 |
array( 'description' => esc_html__('Product ajax search', 'textdomain')) |
13 |
);
|
14 |
}
|
15 |
|
16 |
public function widget( $args, $instance) { |
17 |
|
18 |
wp_enqueue_script('search-main'); |
19 |
|
20 |
extract($args); |
21 |
|
22 |
$title = apply_filters( 'widget_title', $instance['title'] ); |
23 |
|
24 |
echo $before_widget; |
25 |
|
26 |
if ( ! empty( $title ) ){echo $before_title . $title . $after_title;} |
27 |
|
28 |
?>
|
29 |
|
30 |
<div class="product-search"> |
31 |
<form name="product-search" method="POST"> |
32 |
<?php $categories = get_product_categories_hierarchy(); ?> |
33 |
<?php if ($categories): ?> |
34 |
<select name="category" class="category"> |
35 |
<option class="default" value=""><?php echo esc_html__( 'Select a category', 'textdomain' ); ?></option> |
36 |
<?php list_taxonomy_hierarchy_no_instance( $categories); ?> |
37 |
</select>
|
38 |
<?php endif ?> |
39 |
<div class="search-wrapper"> |
40 |
<input type="search" name="search" class="search" placeholder="<?php echo esc_html__( 'Search for product...', 'textdomain' ); ?>" value=""> |
41 |
<?php echo file_get_contents(plugins_url( 'images/loading.svg', __FILE__ )); ?> |
42 |
</div>
|
43 |
</form>
|
44 |
<div class="search-results"></div> |
45 |
</div>
|
46 |
|
47 |
<?php echo $after_widget; |
48 |
}
|
49 |
|
50 |
public function form( $instance ) { |
51 |
|
52 |
$defaults = array( |
53 |
'title' => esc_html__('Product search', 'textdomain'), |
54 |
);
|
55 |
|
56 |
$instance = wp_parse_args((array) $instance, $defaults); |
57 |
|
58 |
?>
|
59 |
|
60 |
<div id="<?php echo esc_attr($this->get_field_id( 'widget_id' )); ?>"> |
61 |
|
62 |
<p>
|
63 |
<label for="<?php echo $this->get_field_id( 'title' ); ?>"><?php echo esc_html__( 'Title:', 'textdomain' ); ?></label> |
64 |
<input class="widefat <?php echo $this->get_field_id( 'title' ); ?>" name="<?php echo $this->get_field_name( 'title' ); ?>" type="text" value="<?php echo esc_attr( $instance['title'] ); ?>" /> |
65 |
</p>
|
66 |
|
67 |
</div>
|
68 |
|
69 |
<?php
|
70 |
}
|
71 |
|
72 |
public function update( $new_instance, $old_instance ) { |
73 |
$instance = $old_instance; |
74 |
$instance['title'] = strip_tags( $new_instance['title'] ); |
75 |
return $instance; |
76 |
}
|
77 |
|
78 |
}
|
Unser Widget hat keine Optionen, aber Sie können einen Titel eingeben. Es ist ein einfaches Formular mit einem Suchfeld und einer Kategorieauswahl. Und für die Kategorieauswahl verwenden wir die zuvor erstellte Funktion:
get_product_categories_hierarchy und list_taxonomy_hierarchy_no_instance. Außerdem benötigen wir eine SVG-Datei, um das Laden bei der AJAX-Abfrage zu kennzeichnen.
Wenn Sie zunächst zu Darstellung > Widgets gehen, wird ein neues Widget angezeigt, sodass Sie es dem Widget-Bereich hinzufügen und im Front-End Folgendes sehen können:



Sieht schrecklich aus! Fügen wir einige Stile hinzu.
6. Fügen Sie einige Stile hinzu
Öffnen Sie die Datei style.css und fügen Sie Folgendes hinzu:
1 |
.product-search { |
2 |
position: relative; |
3 |
padding: 24px; |
4 |
border-radius: 4px; |
5 |
box-shadow:0px 0px 24px 0px rgba(0, 0, 0, 0.08); |
6 |
border:1px solid #e0e0e0; |
7 |
background: #f5f5f5; |
8 |
}
|
9 |
|
10 |
.search-results { |
11 |
display: none; |
12 |
position: absolute; |
13 |
width: 200%; |
14 |
background: #ffffff; |
15 |
padding:12px 24px; |
16 |
border: 1px solid #e0e0e0; |
17 |
z-index: 15; |
18 |
transform: translateY(-1px); |
19 |
}
|
20 |
|
21 |
.search-results.active { |
22 |
display: block; |
23 |
}
|
24 |
|
25 |
.search-results ul { |
26 |
list-style: none; |
27 |
margin:0 !important; |
28 |
padding: 0 !important; |
29 |
}
|
30 |
|
31 |
.search-results ul li { |
32 |
display: block; |
33 |
padding: 12px 0; |
34 |
position: relative; |
35 |
border-bottom: 1px dashed #e0e0e0; |
36 |
}
|
37 |
|
38 |
.search-results ul li:last-child { |
39 |
border-bottom: none; |
40 |
}
|
41 |
|
42 |
.search-results ul li a { |
43 |
display: table; |
44 |
width: 100%; |
45 |
}
|
46 |
|
47 |
.search-results ul li a > * { |
48 |
display: table-cell; |
49 |
vertical-align: top; |
50 |
}
|
51 |
|
52 |
.search-results .product-image { |
53 |
width: 72px; |
54 |
max-width: 72px; |
55 |
}
|
56 |
|
57 |
.product-data { |
58 |
padding-left: 24px; |
59 |
}
|
60 |
|
61 |
.search-results h3 { |
62 |
display: block; |
63 |
}
|
64 |
|
65 |
.product-data div:not(.product-categories) { |
66 |
display: inline-block; |
67 |
vertical-align: middle; |
68 |
}
|
69 |
|
70 |
.product-data .product-price { |
71 |
position: absolute; |
72 |
top: 12px; |
73 |
right: 0; |
74 |
}
|
75 |
|
76 |
.product-data .product-stock { |
77 |
padding: 4px 8px; |
78 |
background: #eeeeee; |
79 |
border-radius: 4px; |
80 |
position: absolute; |
81 |
bottom: 12px; |
82 |
right: 0; |
83 |
}
|
84 |
|
85 |
.product-categories > span { |
86 |
display: inline-block; |
87 |
margin-right: 4px; |
88 |
}
|
89 |
|
90 |
.product-categories > span:after { |
91 |
content: ","; |
92 |
}
|
93 |
|
94 |
.product-categories > span:last-child:after { |
95 |
content: ""; |
96 |
}
|
97 |
|
98 |
.product-categories > span:last-child { |
99 |
margin-right:0; |
100 |
}
|
101 |
|
102 |
.product-search select { |
103 |
width: 100% !important; |
104 |
min-height: 40px !important; |
105 |
margin-bottom: 16px; |
106 |
}
|
107 |
|
108 |
.product-search select, |
109 |
.product-search input { |
110 |
background: #ffffff; |
111 |
border:1px solid #e0e0e0; |
112 |
}
|
113 |
|
114 |
.search-wrapper { |
115 |
position: relative; |
116 |
}
|
117 |
|
118 |
.search-wrapper input { |
119 |
padding-right: 35px !important; |
120 |
}
|
121 |
|
122 |
.search-wrapper svg { |
123 |
position: absolute; |
124 |
top: 10px; |
125 |
right: 10px; |
126 |
width: 20px; |
127 |
height: 20px; |
128 |
fill:#bdbdbd; |
129 |
animation:loading 500ms 0ms infinite normal linear; |
130 |
transform-origin: center; |
131 |
opacity: 0; |
132 |
}
|
133 |
|
134 |
.search-wrapper.loading svg { |
135 |
opacity:1; |
136 |
}
|
137 |
|
138 |
@keyframes loading { |
139 |
from {transform: rotate(0deg);} |
140 |
to {transform: rotate(360deg);} |
141 |
}
|
Aktualisieren Sie nun den Browser (vergessen Sie nicht den Browser-Cache) und Ihr Widget sollte viel besser aussehen:



Im Moment macht es überhaupt nichts, also wenden wir einige Funktionen an.
7. Suchfunktionen hinzufügen
Öffnen Sie die Datei main.js. Hier erstellen wir unsere Kernsuchfunktion.
Die Idee ist einfach: Wir werden Ereignis-Listener hinzufügen, um die Eingabe-Eingabe (Eingabe) zu suchen und die Feldänderung auszuwählen. Immer wenn eines dieser Ereignisse ausgelöst wird, werden wir eine AJAX-Anfrage stellen, um das Schlüsselwort zu senden, Produkte basierend auf dem Schlüsselwort abzufragen und die angegebenen Ergebnisse auszugeben.
Fügen Sie der Datei main.js den folgenden Code hinzu:
1 |
(function($){ |
2 |
|
3 |
"use strict"; |
4 |
$('form[name="product-search"]').each(function(){ |
5 |
|
6 |
var form = $(this), |
7 |
search = form.find('.search'), |
8 |
category = form.find('.category'), |
9 |
currentQuery = '', |
10 |
timeout = false; |
11 |
|
12 |
category.on('change',function(){ |
13 |
currentQuery = ''; |
14 |
var query = search.val(); |
15 |
productSearch(form,query,currentQuery,timeout); |
16 |
});
|
17 |
|
18 |
search.keyup(function(){ |
19 |
var query = $(this).val(); |
20 |
productSearch(form,query,currentQuery,timeout); |
21 |
});
|
22 |
|
23 |
});
|
24 |
|
25 |
})(jQuery); |
Hier haben wir einige erforderliche Variablen definiert und der ausgewählten Suche Ereignis-Listener hinzugefügt. Wie Sie sehen können, lösen beide Ereignisse dieselbe Funktion productSearch aus, die mehrere Parameter hat:
- form
- query
- currentQuery
- timeout;
productSearch-Funktion
Wir haben diese Funktion noch nicht, daher funktioniert die Suche vorerst nicht. Erstellen wir also diese Funktion. Fügen Sie den folgenden Code direkt vor dem vorherigen hinzu.
1 |
function productSearch(form,query,currentQuery,timeout){ |
2 |
|
3 |
var search = form.find('.search'), |
4 |
category = form.find('.category'); |
5 |
|
6 |
form.next('.search-results').html('').removeClass('active'); |
7 |
|
8 |
query = query.trim(); |
9 |
|
10 |
if (query.length >= 3) { |
11 |
|
12 |
if (timeout) { |
13 |
clearTimeout(timeout); |
14 |
}
|
15 |
|
16 |
form.next('.search-results').removeClass('empty'); |
17 |
|
18 |
search.parent().addClass('loading'); |
19 |
if (query != currentQuery) { |
20 |
timeout = setTimeout(function() { |
21 |
|
22 |
$.ajax({ |
23 |
url:opt.ajaxUrl, |
24 |
type: 'post', |
25 |
data: { action: 'search_product', keyword: query, category: category.val() }, |
26 |
success: function(data) { |
27 |
currentQuery = query; |
28 |
search.parent().removeClass('loading'); |
29 |
|
30 |
if (!form.next('.search-results').hasClass('empty')) { |
31 |
|
32 |
if (data.length) { |
33 |
form.next('.search-results').html('<ul>'+data+'</ul>').addClass('active'); |
34 |
} else { |
35 |
form.next('.search-results').html(opt.noResults).addClass('active'); |
36 |
}
|
37 |
|
38 |
}
|
39 |
|
40 |
clearTimeout(timeout); |
41 |
timeout = false; |
42 |
|
43 |
|
44 |
}
|
45 |
});
|
46 |
|
47 |
}, 500); |
48 |
}
|
49 |
} else { |
50 |
|
51 |
search.parent().removeClass('loading'); |
52 |
form.next('.search-results').empty().removeClass('active').addClass('empty'); |
53 |
|
54 |
clearTimeout(timeout); |
55 |
timeout = false; |
56 |
|
57 |
}
|
58 |
}
|
In dieser Funktion stellen wir zunächst sicher, dass unser Keyword mindestens 3 Zeichen enthält und keine Leerzeichen enthält
Wenn unsere Keyword-Länge mehr oder weniger 3 Zeichen beträgt, fügen wir die Ladeklasse dem übergeordneten Suchfeld-Wrapper hinzu. Dies ist erforderlich, um die CSS-Animation auszuführen, während wir unsere AJAX-Anforderung stellen.
Und hier müssen wir überprüfen, ob das eingegebene Keyword nicht dem aktuellen Keyword entspricht, um doppelte AJAX-Anforderungen für dasselbe Keyword zu vermeiden. Als nächstes setzen wir das Timeout auf 500 ms und stellen eine AJAX-Anfrage. Mit der Anfrage übergeben wir das Schlüsselwort, die Kategorie und die AJAX-Anforderungsaktion search_product.
Da wir noch keine search_product-Aktion haben, wird beim Erstellen des AJAX ein interner Serverfehler angezeigt. Lassen Sie uns nun diese Aktion erstellen.
search_product Aktion
Öffnen Sie die Hauptdatei product-search.php und fügen Sie ganz unten den folgenden Code hinzu:
1 |
function search_product() { |
2 |
|
3 |
global $wpdb, $woocommerce; |
4 |
|
5 |
if (isset($_POST['keyword']) && !empty($_POST['keyword'])) { |
6 |
|
7 |
$keyword = $_POST['keyword']; |
8 |
|
9 |
if (isset($_POST['category']) && !empty($_POST['category'])) { |
10 |
|
11 |
$category = $_POST['category']; |
12 |
|
13 |
$querystr = "SELECT DISTINCT * FROM $wpdb->posts AS p |
14 |
LEFT JOIN $wpdb->term_relationships AS r ON (p.ID = r.object_id) |
15 |
INNER JOIN $wpdb->term_taxonomy AS x ON (r.term_taxonomy_id = x.term_taxonomy_id) |
16 |
INNER JOIN $wpdb->terms AS t ON (r.term_taxonomy_id = t.term_id) |
17 |
WHERE p.post_type IN ('product')
|
18 |
AND p.post_status = 'publish'
|
19 |
AND x.taxonomy = 'product_cat'
|
20 |
AND (
|
21 |
(x.term_id = {$category}) |
22 |
OR
|
23 |
(x.parent = {$category}) |
24 |
)
|
25 |
AND (
|
26 |
(p.ID IN (SELECT post_id FROM $wpdb->postmeta WHERE meta_key = '_sku' AND meta_value LIKE '%{$keyword}%')) |
27 |
OR
|
28 |
(p.post_content LIKE '%{$keyword}%') |
29 |
OR
|
30 |
(p.post_title LIKE '%{$keyword}%') |
31 |
)
|
32 |
ORDER BY t.name ASC, p.post_date DESC;"; |
33 |
|
34 |
} else { |
35 |
$querystr = "SELECT DISTINCT $wpdb->posts.* |
36 |
FROM $wpdb->posts, $wpdb->postmeta |
37 |
WHERE $wpdb->posts.ID = $wpdb->postmeta.post_id |
38 |
AND (
|
39 |
($wpdb->postmeta.meta_key = '_sku' AND $wpdb->postmeta.meta_value LIKE '%{$keyword}%') |
40 |
OR
|
41 |
($wpdb->posts.post_content LIKE '%{$keyword}%') |
42 |
OR
|
43 |
($wpdb->posts.post_title LIKE '%{$keyword}%') |
44 |
)
|
45 |
AND $wpdb->posts.post_status = 'publish' |
46 |
AND $wpdb->posts.post_type = 'product' |
47 |
ORDER BY $wpdb->posts.post_date DESC"; |
48 |
}
|
49 |
|
50 |
$query_results = $wpdb->get_results($querystr); |
51 |
|
52 |
if (!empty($query_results)) { |
53 |
|
54 |
$output = ''; |
55 |
|
56 |
foreach ($query_results as $result) { |
57 |
|
58 |
$price = get_post_meta($result->ID,'_regular_price'); |
59 |
$price_sale = get_post_meta($result->ID,'_sale_price'); |
60 |
$currency = get_woocommerce_currency_symbol(); |
61 |
|
62 |
$sku = get_post_meta($result->ID,'_sku'); |
63 |
$stock = get_post_meta($result->ID,'_stock_status'); |
64 |
|
65 |
$categories = wp_get_post_terms($result->ID, 'product_cat'); |
66 |
|
67 |
$output .= '<li>'; |
68 |
$output .= '<a href="'.get_post_permalink($result->ID).'">'; |
69 |
$output .= '<div class="product-image">'; |
70 |
$output .= '<img src="'.esc_url(get_the_post_thumbnail_url($result->ID,'thumbnail')).'">'; |
71 |
$output .= '</div>'; |
72 |
$output .= '<div class="product-data">'; |
73 |
$output .= '<h3>'.$result->post_title.'</h3>'; |
74 |
if (!empty($price)) { |
75 |
$output .= '<div class="product-price">'; |
76 |
$output .= '<span class="regular-price">'.$price[0].'</span>'; |
77 |
if (!empty($price_sale)) { |
78 |
$output .= '<span class="sale-price">'.$price_sale[0].'</span>'; |
79 |
}
|
80 |
$output .= $currency; |
81 |
$output .= '</div>'; |
82 |
}
|
83 |
if (!empty($categories)) { |
84 |
$output .= '<div class="product-categories">'; |
85 |
foreach ($categories as $category) { |
86 |
if ($category->parent) { |
87 |
$parent = get_term_by('id',$category->parent,'product_cat'); |
88 |
$output .= '<span>'.$parent->name.'</span>'; |
89 |
}
|
90 |
$output .= '<span>'.$category->name.'</span>'; |
91 |
}
|
92 |
$output .= '</div>'; |
93 |
}
|
94 |
if (!empty($sku)) { |
95 |
$output .= '<div class="product-sku">'.esc_html__( 'SKU:', 'textdomain' ).' '.$sku[0].'</div>'; |
96 |
}
|
97 |
|
98 |
if (!empty($stock)) { |
99 |
$output .= '<div class="product-stock">'.$stock[0].'</div>'; |
100 |
}
|
101 |
|
102 |
$output .= '</div>'; |
103 |
$output .= '</a>'; |
104 |
$output .= '</li>'; |
105 |
}
|
106 |
|
107 |
if (!empty($output)) { |
108 |
echo $output; |
109 |
}
|
110 |
}
|
111 |
}
|
112 |
|
113 |
die(); |
114 |
}
|
115 |
add_action( 'wp_ajax_search_product', 'search_product' ); |
116 |
add_action( 'wp_ajax_nopriv_search_product', 'search_product' ); |
Achten Sie vorerst auf den Teil add_action des Codes. Sehen Sie die Aktionsnamen mit den Präfixen wp_ajax_ und wp_ajax_nopriv_? Wir müssen dieselben Aktionsnamen verwenden, die wir in der Datei main.js angegeben haben - search_product.
Nun zum Aktionskern
Hier verwenden wir die Abfragemethode $wpdb, um den Abfrageprozess zu beschleunigen. Ich bin kein MySQL-Guru, daher können die Profis es meiner Meinung nach optimieren, aber für unsere Aufgabe ist es gut genug und funktioniert wie erwartet.
Hier prüfen wir zuerst, ob eine Kategorie angegeben wurde, und fragen dann die Ergebnisse unter dieser bestimmten Kategorie ab. Wenn keine Kategorie angegeben ist, führen wir eine regelmäßige Produktabfrage durch, die das Schlüsselwort im Titel oder den Inhalt enthält oder mit der SKU übereinstimmt. Und wenn wir die Ergebnisse haben, erstellen wir die Ausgabe basierend auf den abgefragten Ergebnissen.
Nun zurück zu main.js. Wenn unsere AJAX-Anfrage erfolgreich ist, geben wir die Ausgabedaten in der Liste zurück und hängen sie an das leere div der Suchergebnisse an. Alles was bleibt ist, das Timeout zu löschen.



Das ist es! Eine effektive und leistungsstarke Produkt-AJAX-Suche. Wenn Sie jetzt zum Front-End gehen, laden Sie die Seite neu (vergessen Sie nicht das Browser-Caching). Sie können nach Produkten suchen und das Widget in Aktion sehen.
Abschluss
Sie können dieses Plugin in Ihren kommerziellen und nichtkommerziellen Projekten verwenden. Ich hoffe es gefällt dir und wenn du irgendwelche Ideen hast, können Sie sie gerne in den Kommentaren schreiben. Sie können das Plugin von GitHub herunterladen. Und hier ist die Plugin-Demo. Danke fürs Lesen!







