Category Archives: WooCommerce

Nach dem vollen Namen suchen in WordPress geht nicht! Doch! Ooooh!

Wieder ein Problem, von dem man gar nicht denkt, daß es eins ist, bis man sich mal intensiver damit beschäftigt:

Kundin will die Benutzersuche erweitert haben. Standardmäßig kann man nur nach eMail-Adresse, Benutzernamen und WebSite-URL suchen, aber nicht nach Vorname, Nachname, Ort, PLZ oder Vor- + Nachnamen. Wieso das denn?

Das liegt vermutlich an der Struktur, wie die User in der Datenbank gespeichert sind. Die stehen in 2 Tabellen: wp_users und wp_usermeta.

In der wp_users steht nicht viel drin, aber wir haben die Spalten user_nicename, user_email und user_url. Das sind unsere Suchmöglichkeiten.
Die ganzen anderen Dinge stehen in der anderen Tabelle, der wp_usermeta, und die ist mit der wp_users über die ID verbunden:

 wp_posts.ID = wp_postmeta.user_id

Und hier haben wir jetzt plötzlich die interessanten Sachen: billing_first_name, billing_last_name und billing_city.

Also brauchen wir eine Suchfunktion danach. Ich hab bissl rumgegoogelt und das hier gefunden:

add_action( ‚pre_user_query‘, function( $uqi ) {
global $wpdb;
$search = “;
if ( isset( $uqi->query_vars[’search‘] ) )
$search = trim( $uqi->query_vars[’search‘] );if ( $search ) {
$search = trim($search, ‚*‘);
$the_search = ‚%‘.$search.’%‘;$search_meta = $wpdb->prepare(“
ID IN ( SELECT user_id FROM {$wpdb->usermeta}
WHERE ( ( meta_key=’first_name‘ OR meta_key=’last_name‘ )
AND {$wpdb->usermeta}.meta_value LIKE ‚%s‘ )
)“, $the_search);$uqi->query_where = str_replace(
‚WHERE 1=1 AND (‚,
„WHERE 1=1 AND (“ . $search_meta . “ OR „,
$uqi->query_where );
}
});

Aha aha!

EIgentlich dachte ich, man müßte eine Art SELECT user_id from wp_usermeta WHERE meta_key LIKE ‚billing_last_name‘ AND meta_value LIKE ‚%Suchbegriff%‘ machen, und dann die gefundene(n) User-ID(s) returnen oder sonstwie übergeben.

Aber der Autor des Snippets macht das anders: Er erweitert die Query erweitern, bevor sie ausgeführt wird, mit pre_user_query, und schreibt sich seine eigene WHERE-Bedingung, mit der er nachher die originale ($uqi->query_where) ersetzt. Toll. Ich kapiere seine syntaktischen Merkwürdigkeiten zwar nicht ganz, aber ich mach das jetzt auch so…und dann erweitere ich die eine Zeile noch mit der Stadt:

WHERE ( ( meta_key=’first_name‘ OR meta_key=’last_name‘ OR meta_key=’billing_city‘ )

Funktioniert.

Ich kann nach Heinz Becker in Bexbach suchen. ‚Heinz‘ findet alle Heinze, ‚Becker‘ alle Beckers, ‚Bexbach‘ alle, die in Bexbach wohnen. Oder auch die Bexbach heißen.

Äh…Moment…’Heinz Becker‘ findet gar nix. Nochmal die Query ansehen. Ja klar. Grmpf.
Die würde nur was finden, wenn Vorname, Nachname oder Stadt ‚Heinz Becker‘ heißen…tun sie aber nicht. Was nu?

Eigentlich müßte man 2 Abfragen machen, alle Heinze bei Vornamen, alle Beckers bei Nachnamen, und dann die User-ID ausgeben, die in beiden Abfragen enthalten ist.
Zuerst Vornamen namen suchen, ergibt ein Array der User-IDs aller Heinze. Danach dasselbe mit den Nachnamen, ergibt alle Beckers. Jetzt habe ich 2 Arrays.

Mit der schönen Funktion array_intersect kann ich rausfinden, ob es Elemente gibt, die in beiden Arrays vorhanden sind. Also da wo Vorname=Heinz und Nachname=Becker die gleiche user_id ergeben.

Klappt 🙂

Jetzt außendrum noch eine Abfrage, ob der Suchbegriff ein Leerzeichen enthält, damit eine einfache Suche weiterhin funktioniert.

Also so:

if (stristr($search, “ „)) {$search_exp = explode(“ „, $search);

// 1. Query: Vorname
$query1 = „SELECT * FROM wp_usermeta
WHERE meta_key = ‚first_name‘
AND meta_value LIKE ‚%“.$search_exp[0].“%'“;
$results1 = $wpdb->get_results($query1);
$vorname_ids = array();
foreach ($results1 as $key1 => $value1) {
$vorname_ids[] = $value1->user_id;
}

// 2. Query: Nachname
$query2 = „SELECT * FROM wp_usermeta
WHERE meta_key = ‚last_name‘
AND meta_value LIKE ‚%“.$search_exp[1].“%'“;
$results2 = $wpdb->get_results($query2);
$nachname_ids = array();
foreach ($results2 as $key2 => $value2) {
$nachname_ids[] = $value2->user_id;
}

$fullname_ids = array_intersect($vorname_ids, $nachname_ids);
$fullname_ids = implode(„,“, $fullname_ids);

$search_meta = $wpdb->prepare(“
ID IN (‚%s‘)“, $fullname_ids);

$uqi->query_where = str_replace(
‚WHERE 1=1 AND (‚,
„WHERE 1=1 AND (“ . $search_meta . “ OR „,
$uqi->query_where );
}

Klappt.

Vollständiger Code:

add_action( ‚pre_user_query‘, function( $uqi ) {
global $wpdb;

$search = “;
if ( isset( $uqi->query_vars[’search‘] ) )
$search = trim( $uqi->query_vars[’search‘] );

if ( $search ) {
$search = trim($search, ‚*‘);

if (stristr($search, “ „)) {

$search_exp = explode(“ „, $search);

// 1. Query: Vorname
$query1 = „SELECT * FROM wp_usermeta
WHERE meta_key = ‚first_name‘
AND meta_value LIKE ‚%“.$search_exp[0].“%'“;
$results1 = $wpdb->get_results($query1);
$vorname_ids = array();
foreach ($results1 as $key1 => $value1) {
$vorname_ids[] = $value1->user_id;
}

// 2. Query: Nachname
$query2 = „SELECT * FROM wp_usermeta
WHERE meta_key = ‚last_name‘
AND meta_value LIKE ‚%“.$search_exp[1].“%'“;
$results2 = $wpdb->get_results($query2);
$nachname_ids = array();
foreach ($results2 as $key2 => $value2) {
$nachname_ids[] = $value2->user_id;
}

$fullname_ids = array_intersect($vorname_ids, $nachname_ids);
$fullname_ids = implode(„,“, $fullname_ids);

$search_meta = $wpdb->prepare(“
ID IN (‚%s‘)“, $fullname_ids);

$uqi->query_where = str_replace(
‚WHERE 1=1 AND (‚,
„WHERE 1=1 AND (“ . $search_meta . “ OR „,
$uqi->query_where );
}
else {
$the_search = ‚%‘.$search.’%‘;

$search_meta = $wpdb->prepare(“
ID IN ( SELECT user_id FROM {$wpdb->usermeta}
WHERE ( ( meta_key=’first_name‘ OR meta_key=’last_name‘ OR meta_key=’billing_city‘ )
AND {$wpdb->usermeta}.meta_value LIKE ‚%s‘ )
)“, $the_search);

$uqi->query_where = str_replace(
‚WHERE 1=1 AND (‚,
„WHERE 1=1 AND (“ . $search_meta . “ OR „,
$uqi->query_where );
}
}
});

WordPress schneller machen 2023 – #1: Google PageSpeed und WP Rocket

Hallo Zielgruppe.

Vor Jahren habe ich mal 2 Beiträge geschrieben, wie man WordPress schneller macht: #1: JavaScripts in den Footer und #2: Performance-Bremsen ermitteln.

Das war damals so mein Wissensstand für WordPress. Mittlerweile habe ich mich mit der Performance-Optimierung von WooCommerce-Shops befaßt, und da hat sich eine andere Vorgehensweise als sinnvoll herausgestellt: (Achtung…das kostet Geld!)

Zuerst auf Google Pagespeed Insights gehen und die betreffende WebSite testen.

Da kommen jetzt alle möglichen Dinge zum Vorschein, zuerst wird die Mobilansicht angezeigt, aber man kann auch auf Desktop umschalten.

Das Interessante sind die Empfehlungen, die unten stehen.

Z.B. könnte da stehen „Reduziere nicht verwendete CSS„. Daneben ein Pfeil zum rausklappen.

Mit einiger Wahrscheinlichkeit steht etwas mit WP-Rocket dabei, z.B. „Aktiviere das Entfernen von nicht verwendetem CSS-Code in WP Rocket, um dieses Problem zu beheben. Die Funktion verringert die Seitengröße, indem sie sämtlichen CSS-Code und alle Stylesheets entfernt, die nicht verwendet werden, und nur den für einzelne Seiten verwendeten CSS-Code beibehält.

Und genau das müssen wir jetzt machen. Hierhin gehen und WP-Rocket installieren. Kostet 59$ im Jahr, aber es gibt eine 14-tägige Money-Back-Garantie.
Dann einfach den Schalter finden, den Google Pagespeed Insights uns verraten hat, und einschalten.

Ich kann aus eigener Erfahrung sagen, daß man auf diese Art die größten Performance-Bremsen sehr einfach beseitigen kann. Manchmal wundert man sich ungläubig und reibt sich die Augen, wenn man sieht, was es tatsächlich gebracht hat 🙂

Aber klar, das kostet Geld, und nicht jeder kann/möchte das bezahlen.

Im nächsten Artikel stelle ich deshalb eine andere Methode vor, die nichts kostet, aber etwas mehr Arbeit bedeutet…

YITH WooCommerce Custom Order Status funktioniert nicht unter PHP8? Doch!

Ich sollte wieder mehr Beiträge schreiben. Gelegentlich liest das jemand und kann damit sogar was anfangen 🙂

Also gut…was gibt’s heute?

Nach Umstellung auf PHP8 funktioniert das YITH WooCommerce Custom Order Status-Plugin nicht mehr?

Das ist ganz einfach zu beheben. Gut wenn man ein Error-Logfile hat oder Fehler direkt angezeigt bekommt, denn da steht dann etwa das hier:

Deprecated: Array and string offset access syntax with curly braces is deprecated in /wp-content/plugins/yith-woocommerce-custom-order-status/plugin-fw/lib/yit-plugin-gradients.php line 443

Das bedeutet, daß es ab PHP8 verboten ist, ArrayElemente mit geschweiften Klammern anzusprechen, und das ist hier der Fall:

Das hier:

$base[‚R‘] = hexdec( $color{0} . $color{1} );
$base[‚G‘] = hexdec( $color{2} . $color{3} );
$base[‚B‘] = hexdec( $color{4} . $color{5} );

muß ersetzt werden durch das hier:

$base[‚R‘] = hexdec( $color[0] . $color[1] );
$base[‚G‘] = hexdec( $color[2] . $color[3] );
$base[‚B‘] = hexdec( $color[4] . $color[5] );

 

WooCommerce: Produkt im Warenkorb bearbeiten

Ich habe mich gerade damit rumgeschlagen, ein Produkt im Warenkorb zu bearbeiten.

Bei normalen Produkten ist das eigentlich nur die Anzahl, die geändert werden soll, und das kann man im Warenkorb selbst machen.

Bei Produkten mit Custom Attributes ist das schon schwieriger. Wenn z.B.  eine Bestellung auf mehrere Lieferadressen aufgeteilt werden soll, und von 5 Stück für Bruchmühlbach-Miesau jetzt 2 davon nach Thaleischweiler-Fröschen gehen sollen und nur 3 nach Bruchmühlbach-Miesau. Ich habe dafür mehrere Input-Felder erstellt und rechne die Gesamtanzahl mit JavaScript aus. Das klappt auch alles. Nur…wie editiert man das?

Eine Anfrage bei WooCommerce ergab, daß es diese Funktion nicht gibt. Und irgendwie scheint sie auch niemand außer mir zu vermissen. Was tun?

Selber machen 🙂

Meine Idee war, Löschen und Hinzufügen zu einer Bearbeiten-funktion zu kombinieren.

1.) Meine Warenkorb-Seite liegt (als WooCommerce-Template) in /wp-content/themes/mytheme/woocommerce/cart/cart.php. Es ist eine Kopie des Original-Woo-Templates. Ich gucke rein und sehe, daß die Löschfunktion mit esc_url(wc_g
et_cart_remove_url( $cart_item_key )…
gelöst wird. Ich baue daneben eine Edit-Funktion mit esc_url( $product_permalink ).“?edit_item=“.esc_attr( $cart_item[‚key‘] )… und übergebe den key. Unterhalb der Löschfunktion erstelle ich etwas in der Art:


echo apply_filters( 'woocommerce_cart_item_remove_link', sprintf('Bearbeiten',
esc_url( $product_permalink )."?edit_item=".esc_attr( $cart_item['key'] ),
__( 'Edit this item', 'woocommerce' ),
esc_attr( $product_id ),
esc_attr( $_product->get_sku() )
), $cart_item_key );

Der Link sieht so aus:


produkt/permalink/?edit_item=cc4dfe235de18d17fd11c3953d4a47d0

2.) Die Variable $edit_item steht für das Warenkorb-Item, das entfernt werden soll. Leider ist es mir nicht gelungen, den Key mit $_GET oder $_POST zu übergeben, deshalb verwende ich eine Session-Variable, die ich nach getanre Arbeit wieder lösche.

In der functions.php erstelle ich eine Funktion, die ddie Session-Variable erstellt:


function gw_edit_cart_item() {
$keytoremove = $_GET['edit_item'];
$_SESSION['keytoremove'] = $keytoremove;
}
add_action('woocommerce_after_single_product_summary', 'gw_edit_cart_item');

3.) So, erstellt. Jetzt brauche ich noch eine Funktion, die beim In-den-Warenkorb-legen des neuen Produktes das alte löscht. Und danach die Session-Variable. Ich mach das mit einer weiteren Funktion in der functions.php:


function gw_validate_add_cart_item( $passed, $product_id, $quantity, $variation_id = '', $variations= '' ) {
GLOBAL $woocommerce;
if ( isset ($_SESSION['keytoremove']) ) {
$keytoremove=$_SESSION['keytoremove'];
$passed = true;
$woocommerce->cart->remove_cart_item($keytoremove);
wc_add_notice( __( 'Produkt wurde aus dem Warenkorb entfernt', 'textdomain' ), 'notice' );
unset ($_SESSION["keytoremove"]);
}
return $passed;
}
add_filter( 'woocommerce_add_to_cart_validation', 'gw_validate_add_cart_item', 10, 5 );

 

4.) Jetzt sehe ich beim Produkt-Bearbeiten 2 Notices oben stehen:

„Produkt X wurde in den Warenkorb gelegt“
und
„Produkt wurde aus dem Warenkorb entfernt“

Das kann man sicher noch schöner machen…aber es funktioniert und macht genau das was es soll.

Freue mich über Anregungen und Ideen 🙂