Wordpress
WordPress ist ein freies Content-Management-System. Es wurde ab 2003 von Matthew Mullenweg als Software für Weblogs programmiert und wird als Open-Source-Projekt permanent weiterentwickelt.
- Fehlerbehebungen
- Error 403 Permission denied
- cURL error 28: Operation timed out after 3000 milliseconds und Aktionsplaner: 90 überfällige Aktionen gefunden;
- Installation
- installation via Docker
- redis zu wordpress docker hinzufügen
- Einstellungen Brutto Preise also inklusive MwSt anzeigen
- Kundenkonto erstellen unter mein Konto und beim bezahlen
- Plugins
- Addon - Flexible Product Fields
- Addon - Product Addons for Woocommerce – Product Options with Custom Fields
- Addon - Code Snippet
- Addon - WooCommerce Product Dependencies
- Addon - Checkout Field Editor (Checkout Manager)
- Addon - Custom Order Numbers for WooCommerce
- Addon - WooCommerce E-Invoicing Customizer
- Addon - WP Mail SMTP by WPForms – The Most Popular SMTP and Email Log Plugin
- Addon - Germanized Pro für WooCommerce
- Addon - WP Control
- Addon - WP-DBManager
- Addon - Redis Cache
- Code Snippets
- Snippet - Prüfe ob Kunde Artikel im Besitz
- Snippet - Wenn Kunde Produkt aus kategorie in Besitz hat ist dieses nicht mehr kaufbar
- Snippet - Wenn Kunde ein explicites Produkt in Besitz hat ist dieses nicht mehr kaufbar
- Snippet - Umleitung externer DNS name auf internen Docker instance - service Namen
- Snippet - Artikel als neue Position im Warenkorb mit Textfeld aus Acowebs Product Addons
- ✅ Snippet - Mengenfeld gezielt ausblenden, über Productid oder Kategorie ausblenden - DEFEKT
- Snippet - Verlinkte Produkte auf Produktseite anzeigen
Fehlerbehebungen
Error 403 Permission denied
Meist bekommt man diese Meldung nachm Update oder nach installation eines größeren Plugins zum Beispiel WooCommerce.
Was tun.
Lösung 1:
Meistens ist es ne kaputte .htaccess Datei oder sgoar einer nicht vorhandenen .htaccess datei.
Hier wie die Standard .htaccess von Wordpress ausieht
cURL error 28: Operation timed out after 3000 milliseconds und Aktionsplaner: 90 überfällige Aktionen gefunden;
Beschreibung:
Wenn WP Cron nicht richtig läuft funktionieren hintergund Dienste nicht.
Hier ist das Problem des timeouts bezüglich Caddy.
Es schadet aber trotzdem nicht ein höheres Timeout in die php.ini reinzupacken.
Lösung:
Um genau zu sehen was Phase ist nehmen wir das Plugin WP Cron
Und wie wir sehen ist eine Ursache die cURL Timeout Geschichte.
Das liegt am Caddy
Hier bauen wir mit den Code Snippet ein Workaround das URL richtig umgeleitet wird auf den internen Docker Service namen.
in diesem Fall ist unser interner Servic name Wordpress
Codesnippet:
add_filter('cron_request', function($cron_request) {
// Ersetze die externe HTTPS-Adresse durch den internen HTTP-Service-Namen
$cron_request['url'] = str_replace('https://deine-externe-domain.de', 'http://wordpress', $cron_request['url']);
return $cron_request;
});
Hier im Snippet Editor Screenshot
Fertig:
Wie man sieht keine Fehler mehr und die letzten Ausführungszeiten passen jetzt auch:
Installation
installation via Docker
Beschreibung:
Docker installation mit mariadb caddy und Wordpress natürlich
Installation
Projektverzeichnis anlegen
mkdir /root/wordpress
Dort drin eine .env Datei anlegen
nano /root/wordpress/.env
Inhalt
# MariaDB Einstellungen
MYSQL_ROOT_PASSWORD=rootpassword
MYSQL_DATABASE=wordpress
MYSQL_USER=wordpress
MYSQL_PASSWORD=wordpresspass
# Domain/Hostname für Caddy
CADDY_HOST=shop.example.com
Die docker compose Datei
nano /root/wordpress/docker-compose.yml
Inhalt
version: '3.8'
services:
mariadb:
image: mariadb:latest
restart: always
volumes:
- ./data/mariadb:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
MYSQL_DATABASE: ${MYSQL_DATABASE}
MYSQL_USER: ${MYSQL_USER}
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
wordpress:
image: wordpress:latest
restart: always
depends_on:
- mariadb
environment:
WORDPRESS_DB_HOST: mariadb:3306
WORDPRESS_DB_USER: ${MYSQL_USER}
WORDPRESS_DB_PASSWORD: ${MYSQL_PASSWORD}
WORDPRESS_DB_NAME: ${MYSQL_DATABASE}
volumes:
- ./data/wordpress:/var/www/html
- ./php.ini:/usr/local/etc/php/conf.d/custom.ini
caddy:
image: caddy:latest
restart: always
ports:
- "80:80"
- "443:443"
command: caddy reverse-proxy --from ${CADDY_HOST} --to wordpress:80
volumes:
- ./data/caddy/data:/data
- ./data/caddy/config:/config
nun noch die php.ini anlegen für 512MB uploads
nano /root/wordpress/php.ini
Inhalt
upload_max_filesize = 512M
post_max_size = 2048M
nun den Container starten
docker-compose up -d
Nun noch die ufw Firewall regeln anpassen.
Da hier der Docker container sowieso von außen erreichbar sein soll, brauchen wir hier keine Anspassung für docker.
Aber ssh soll nur auf der lokalen Netzwerkkarte zur Verfügung stehen
ufw allow in on enp6s18 to any port 22
ufw enable
Cron Jobs richtig zum Laufen bringen Caddy Fehler:
Code Snippet hinzufügen über Plugin für die WP Cron Dienste um folgenden Fehler zu vermeiden
Sie Seite Fehler: cURL error 28: Operation timed out after 3000 milliseconds und Aktionsplaner: 90 überfällige Aktionen gefunden;
redis zu wordpress docker hinzufügen
Beschreibung:
Sollte die Wordpress instanz ziemlich langsam laufen, kann man einen Redis Service mit zwischen packen.
Unsere docker-compose Datei baut auf der ersten auf.
Dann muss noch das Redis Cache Plugin installiert werden
Einrichtung:
Docker-compose:
Die eigentlichen Änderungen
Einen Redis Service hinzufügen.
...
redis:
image: redis:alpine
restart: always
...
im Wordpress service eine environment variable hinzufügen WP_REDIS_HOST: redis
und depends on -redis hinzufügen
...
depends_on:
- mariadb
- redis
environment:
WORDPRESS_DB_HOST: mariadb:3306
WORDPRESS_DB_USER: ${MYSQL_USER}
WORDPRESS_DB_PASSWORD: ${MYSQL_PASSWORD}
WORDPRESS_DB_NAME: ${MYSQL_DATABASE}
WP_REDIS_HOST: redis
...
Hier nochmals unsere komplette docker compose Datei
version: '3.8'
services:
mariadb:
image: mariadb:latest
restart: always
volumes:
- ./data/mariadb:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
MYSQL_DATABASE: ${MYSQL_DATABASE}
MYSQL_USER: ${MYSQL_USER}
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
redis:
image: redis:alpine
restart: always
wordpress:
image: wordpress:latest
restart: always
depends_on:
- mariadb
- redis
environment:
WORDPRESS_DB_HOST: mariadb:3306
WORDPRESS_DB_USER: ${MYSQL_USER}
WORDPRESS_DB_PASSWORD: ${MYSQL_PASSWORD}
WORDPRESS_DB_NAME: ${MYSQL_DATABASE}
WP_REDIS_HOST: redis
volumes:
- ./data/wordpress:/var/www/html
- ./php.ini:/usr/local/etc/php/conf.d/custom.ini
caddy:
image: caddy:latest
restart: always
ports:
- "80:80"
- "443:443"
command: caddy reverse-proxy --from ${CADDY_HOST} --to wordpress:80
volumes:
- ./data/caddy/data:/data
- ./data/caddy/config:/config
Wordpressplugin aktivieren
Siehe Artikel Wordpress Redis Plugin : Addon - Redis Cache
Einstellungen Brutto Preise also inklusive MwSt anzeigen
Beschreibung:
Standardmäßig sind die Artikelpreise Netto Preise + Steuer.
Um dies zu ändern, in die Woocomerce Einstellungen gehen
Automated tax deaktivieren, dann speichern und nun kann Preise inklusive Steuern angegeben werden.
Und Preise im Shop anzeigen Steuern eingeschlossen
Preise Während Bestell Warenkorb und Bezahlvorgangs (Kasse) anzeigen Steuern eingeschlossen.
Dann Auf der Seite Allgemein bei Einstellungen
Dort unter Voreingestellter Ort für Kunden : Land Region des Stores
fertig
Kundenkonto erstellen unter mein Konto und beim bezahlen
Beschreibung:
Damit Kunden die Möglichkeit haben, Ihre Bestellungen zu speichern.
müssen wir einstellen, das in Mein konto und beim Bezahlen die möglichkeit besteht ein kundenkonto anzulegen.
Dazu gehen wir unter Einstellungen -> Konten und Datenschutz
Wir möchten nicht das Gäste kaufen können, da sonst die Käufe nicht in der Historie gespeichert sind. Also Haken raus.
Durch Eingabe der Emailadresse wird dann automatisch ein Kundenkonto erstellt, da Gast Bestellung nicht möglich sind
Anmeldung während des Bezahlvorgangs rein, damit vorhandene Kunden sich anmelden können. Haken rein
Kunden Konto Erstellung erlauben haken rein bei
Beim bezahlen
Auf der Seite mein Konto
sonst wird kein Kundenkonto durch Emailadresse erstellt.
Link zur Einrichtung des Passworts zusenden haken rein.
Plugins
Addon - Flexible Product Fields
Beschreibung:
Ein Plugin um einen Artikel mit weiteren Feldern auszustatten
Woocommerce Plugin Seite :
https://de.wordpress.org/plugins/flexible-product-fields/
Mit diesem Addon kann man weitere Felder zum Produkt hinzufügen.
konfigurierbar unter Plugins einstellungen.
Dort kann die Eigenschaft an Produkt oder eine Kategorie gepackt werden.
produkt auswählen und dann Feldeigenschaft whälen und Feld Namen geben fertig ;-)
Und schon gibts ein Feld beim Artikel
Addon - Product Addons for Woocommerce – Product Options with Custom Fields
Beschreibung:
Ein weiteres Plugin was zusätzliche Felder zu einem Produkt hinzufügen kann.
bei diesem ist der Vorteil man kann es über ganze Kategorien packen, bei dem vorherigen musste man jedes Produkt einzeln aufführen, und die Beschreibung sieht auch besser aus
https://de.wordpress.org/plugins/woo-custom-product-addons/
Einrichtung:
Unter Plugin auf create Forms klicken
Dort kann man oben eon neues Form erstellen
Unten weiter stehen schon bestehende Forms.
Ein Form ist für einen Artikel gedacht, ein Form kann natürlich mehrere Felder haben
Hier gehen wir in die Details eines Forms, das ist das gleiche als wenn wir ein neues erstellen würden.
Oben der Title zusätzliche Domain, dieser taucht nirgends auf, sondern dient der Beschreibung bzw Namen des Form.
Rechts haben wir weitere Felder die wir ren einziehen können wenn wir noch weitere Felder anlegen wollen.
Wir klicken hier unsere vorhandendes Feld an, gibts noch keins und wir ziehen ein Feld rein kommts auf selbe hinaus.
Nun habn wir auf der rechten Seite die Feldeigenschaften.
Das Label, das ist auch das was dann beim Artikel erscheint.
Enabled / Disabled, sprich soll das Feld aktiv sein.
Required, ist der Haken gesetzt muss das Feld ausgefüllt sein, sonst kann der Artikel nicht in den Warenkorb gepackt werden.
In der Feldbeschreibung, kann kann man auch nochmals ausfüllen was das Feld macht, ich habs aber ins Label mit reingepackt
Nun unter condition wenn man mehrere Felder hat, kann man sich weitere Felder erst anzeigen lassen, wenn die vorherigen schon befüllt sind. So kann man eine Art Assistent bauen, die Felder ploppen nach und nach je auswahl auf. oder Sogar andere Auswahlen.
Zum Beispiel bei CPU AMD oder intel.
Bei Intel würden im zweiten Drop Down menü dann die Intel bzw bei AMD die AMD CPUs gelistet werden
Zum Schluss kann über das Zahnrad bestimmt werden, für Welche Produkte oder Produkt Kategorien.
Dies ist ein zusatzartikel für jeweils eine bestimmte Produktkategorie.
Zum Schluss das ganze noch speichern.
Fertig:
Addon - Code Snippet
Beschreibung:
Einige Funktionen oder Änderungen lassen sich durch kleine Code Snipptes in der function.php realisieren.
Allerdings ist das manuelle bearbeiten meist umständlich.
Vorallem wenn ein Code Snippet Fehlerhaft ist, funktioniert unter Umständen das ganze Wordpress nicht mehr.
Hier ein Plugin mit dem man solche Snippets verwalten kann.
Download Link : https://de.wordpress.org/plugins/code-snippets/
Bedienung:
Nach der installtion hat man links im Menü Snipptes und alle Snippets.
Es gibt schon ein paar Demo Snipptes die aber deaktiviert sind.
Über Neu hinzufügen können wir ein neues Snippet einfügen
hier ein Snippet was prüft ob der Kunde den Artiekl in der vergangenheit schon mal gekauft hat.
Dieses wird im Produkt dargestellt
add_action('woocommerce_before_single_product', function() {
if (!is_user_logged_in()) {
echo '<div style="padding:10px;background:#ffeeba;border-left:5px solid #f0ad4e;margin-bottom:15px;">
🔒 Du bist nicht eingeloggt. Eine Besitzprüfung ist nicht möglich.
</div>';
return;
}
global $product;
$user_id = get_current_user_id();
$product_id = $product->get_id();
$owns_product = wc_customer_bought_product('', $user_id, $product_id);
if ($owns_product) {
echo '<div style="padding:10px;background:#d4edda;border-left:5px solid #28a745;margin-bottom:15px;">
✅ Du besitzt dieses Produkt bereits.
</div>';
} else {
echo '<div style="padding:10px;background:#f8d7da;border-left:5px solid #dc3545;margin-bottom:15px;">
❌ Du besitzt dieses Produkt nicht.
</div>';
}
});
Titel Ausfüllen den Quelltext reinpacken.
Unten weiter kann noch eine Beschreibung angeben werden.
Dann auf Speichern und aktivieren klicken.
Nun sollte das Snippet beim Artikel genau das tun, was es soll:
Wenn man nicht eingeloggt ist bekommt man diese Meldung:
Wenn man eingeloggt ist, diese wenn gekauft
und wenn man es noch nicht besitzt
Man kann sich überlegen ob man sich die Ausgabe, das man es nicht besitzt spart. In dem Man dieses wieder auskommentiert bzw. den else block entfernt.
Dort steht es nun in der Liste.
Addon - WooCommerce Product Dependencies
Beschreibung:
EIn Plugin das Abhängigkeiten zu anderen Produkten hat.
bedeuet ein Benutzer muss ein Produkt im Warenkorb oder in der Vergangenheit gekauft haben, damit er den Artikel in den Warenkorb packen kann.
https://wordpress.org/plugins/woocommerce-product-dependencies/
Allerdings hat die version 2.0.1 einen Bug bei gekauften Produkten.
habe Ihn mit einem Workaround gefixt. Siehe weiter unten bei BUG
Bedienung:
Nach der Installation gibt es nichts weiter einzustellen.
unter Produkt gibt es einen neuen Menüpunkt Dependencies
Dort kann man einstellen ob die Abhängigkeit von einem einzelnen Produkt sein soll, oder eine Kategorie.
Dann der Abhängigkeitstyp / Dependency type :
- Ownership: Obs schon gekauft sein muss
- Purchase : Ob im Warenkorb sein muss
- Either: Beides, muss im Warenkorb oder schon mal gekauft worden sein.
Eins von beiden muss zutreffen, also eine oder Bedingung
BUG:
Lösung:
Die Funktion
....
// Check ownership.
if ( in_array( $dependency_type, array( self::DEPENDENCY_TYPE_OWNERSHIP, self::DEPENDENCY_TYPE_EITHER ) ) ) {
if ( is_user_logged_in() ) {
$current_user = wp_get_current_user();
if ( 'category_ids' === $dependency_selection_type ) {
$tied_product_ids = $this->get_product_ids_in_categories( $tied_category_ids );
...
dies muss stehen belieben, die funktion ghet bis hier:
$result = $ownership_dependency_result || $purchase_dependency_result;
Ersetzen durch
// Check ownership (vereinfachte Prüfung).
if ( in_array( $dependency_type, array( self::DEPENDENCY_TYPE_OWNERSHIP, self::DEPENDENCY_TYPE_EITHER ) ) ) {
if ( is_user_logged_in() ) {
$current_user = wp_get_current_user();
// Hole ggf. Produkt-IDs aus Kategorie
if ( 'category_ids' === $dependency_selection_type ) {
$tied_product_ids = $this->get_product_ids_in_categories( $tied_category_ids );
} else {
$tied_product_ids = $tied_ids;
}
foreach ( $tied_product_ids as $tied_id ) {
if ( wc_customer_bought_product( '', $current_user->ID, $tied_id ) ) {
$ownership_dependency_result = true;
break;
}
}
// Kombinieren mit Kaufabhängigkeit falls nötig
if ( $ownership_dependency_result && self::DEPENDENCY_TYPE_EITHER === $dependency_type ) {
$purchase_dependency_result = true;
}
}
}
//hier endet die funktion und die datei geht normal weiter
Dann sieht das ganze so aus:
....
// Check ownership (vereinfachte Prüfung).
if ( in_array( $dependency_type, array( self::DEPENDENCY_TYPE_OWNERSHIP, self::DEPENDENCY_TYPE_EITHER ) ) ) {
if ( is_user_logged_in() ) {
$current_user = wp_get_current_user();
// Hole ggf. Produkt-IDs aus Kategorie
if ( 'category_ids' === $dependency_selection_type ) {
$tied_product_ids = $this->get_product_ids_in_categories( $tied_category_ids );
} else {
$tied_product_ids = $tied_ids;
}
foreach ( $tied_product_ids as $tied_id ) {
if ( wc_customer_bought_product( '', $current_user->ID, $tied_id ) ) {
$ownership_dependency_result = true;
break;
}
}
// Kombinieren mit Kaufabhängigkeit falls nötig
if ( $ownership_dependency_result && self::DEPENDENCY_TYPE_EITHER === $dependency_type ) {
$purchase_dependency_result = true;
}
}
}
//hier endet die funktion und die datei geht normal weiter
$result = $ownership_dependency_result || $purchase_dependency_result;
// Show notice.
if ( false === $result ) {
...
Hier einmal die woocommerce-product-dependencies.php zum download bzw
gleich die ganze Plugin Zip woocommerce-product-dependencies-2.0.1-original-ownership-logic-fix.zip
Addon - Checkout Field Editor (Checkout Manager)
Beschreibung:
Check Out Filed manager.
Damit können zusätzliche Felder zu den Kundendaten erfasst werden.
Download : https://wordpress.org/plugins/woo-checkout-field-editor-pro/
Einrichtung:
Im Plugin Manager auf Settings klicken.
Dann unter Block check out und Adresses, findet man alle Einstellungen / Felder für die Adressen.
Die Reihenfolge lässt sich auch ändern
Wer das Englische nicht mag kann diese ja in Deutsch umbenennen.
und schon steht der Firmenname mit drin.
Addon - Custom Order Numbers for WooCommerce
Beschreibung:
Order Nummern anpassen zurück setzten Plugin.
https://wordpress.org/plugins/custom-order-numbers-for-woocommerce/
Bedienung:
unter Einstellungen -> Custom Order Numbers for WooCommerce
order number Format
Hier kann man die Sequenz und Prefixe einstellen
Uns interessiert nur dies, denn wir wollen einfach Order Nummern fortlaufend
Möchte man vorhandene Order Nummern umbenennen
Runter scrollen bis Renumerate Order Tools
Auf renumerate klicken
Das Ergebnis, alle order Nummern, Nummeriert
Alles zurücksetzten:
Erstmal alle Bestellungen löschen und den Papierkorb auch leeren:
Nun in die Plugineinstellungen auf Settings gehen
Ganz nach unten Scrollen
reset Section Settings anklicken und speichern anklicken
Nun kann wieder von vorne begonnen werden mit Bestell Nr 1
Addon - WooCommerce E-Invoicing Customizer
Beschreibung:
Ein Plugin für Zugpferd,xrechung etc.
Allerings ist der Germanized besser, auch wenn er Jährlich Geld kostet.
Eine Super investition
Zugpferd Rechung und Rechnungen im Kundenkonto.
Kasse DSGVO Konform etc.
Siehe hier:
Addon - Germanized Pro für WooCommerce
Einrichtung:
nach der installtion landet man automatisch in den Einstellungen.
Erstmal die grundlegenden Sachen
Dann speichern.
Nun kann das Rechnungsdesign angepasst werden, dazu auf den Link klicken
Das Hauptmenü, an der linken Seite, können alle Bereiche definiert werden
in der Rechnungsfußzeile ist das einzige was ich anpassen würde. Da müssen die Sachen aus der Rechung rein, wie Steuernummer etc.
zum Beispiel so:
Dann sieht die Vorschau so aus:
Nun veröffentlichen.
Addon - WP Mail SMTP by WPForms – The Most Popular SMTP and Email Log Plugin
Beschreibung:
Ein SMTP-Server zum versenden von Email aus Wordpress heraus.
Einrichtung:
nach der Installation kommt der Setup Assitant
Nun den Emailsender wählen.
Es werden viele Anbieter ünterstützt
ich wähle hier anderer SMTP-Server aus
Nun die Daten eingeben
Speichern und fortfahren
Alles so lassen
Diesen schritt überspringen
Wir nutzen die Kostenlose Version, auch hier überspringen.
Wer natürlich einen Schlüssel hat , eingeben und auf verbinden klicken
Addon - Germanized Pro für WooCommerce
Beschreibung:
Plugin das den Shop Germany rechtskomform macht, mit E-Rechnung etc.
Für E Rechungen braucht man kostenpflichtig, Abo.
Aber lohnt sich ;-)
https://de.wordpress.org/plugins/woocommerce-germanized/
Einrichtung:
So lassen und weiter
Alles so lassen außer man ist Kleinunternehmer
Wer DHL integration braucht ist auch hier mit dem kostenlosen plugin bedient,
ich brauche allerdings kein versand, habe nur digitale Produkte.
Aber trotzdem cool DHL
Nun Auf Tutorial starten klicken
Rechnungsnummern und alle Rechnungen zurück setzten:
(dadurch gehen alle vorhandenen bzw. ausgewählten Rechnungen verloren)
Dazu müssen wir Tabellen und Verzeichnis leeren.
Um die Tabellen zu leeren, nehmen wir das WP Database plugin : Addon - WP-DBManager
Nun gehen wir dort auf Emtpy Tables
Dort wählen wir folgende Tabellen mit Empty aus
{prefix}_storeabill_documents{prefix}_storeabill_documentmeta{prefix}_storeabill_document_items{prefix}_storeabill_document_itemmeta{prefix}_storeabill_document_notices{prefix}_storeabill_document_noticemeta{prefix}_storeabill_document_attachments{prefix}_storeabill_document_attachmentmeta
Nun runter scrollen und auf empty drop klicken
Wurden geleert
Nun müssen wir noch die PDF wegräumen
wir gehen in den storebill ordner rein
root@shop:~/wordpress/data/wordpress/wp-content/uploads/storeabill-2b9e42fc8f# ls
2025 fonts index.php tmp
root@shop:~/wordpress/data/wordpress/wp-content/uploads/storeabill-2b9e42fc8f#
Hier sehen wir die Jahre, in diesem Fall 2025, sollten bei euch noch mehrere Jahre sein. Alle Jahre löschen
Die Ordner tmp fonts und die index.php Datei NICHT löschen.
rm -r 2025
Nun den Nummernkreis zurücksetzten.
Nun Auf Einstellungen gehen
Dann bei Rechnungen und Lieferscheine auf den Stift klicken
Hier steht in der Vorschau was die nächste Nummer wäre. Was aber falsch ist da wir ja alles weggeschmissen haben
Nun den Haken bei letzte Nummer anpassen rein und den Wert auf 0 ändern
Nun steht in der Vorschau wieder die 1 als nächste Fortlaufende Nummer.
Unser Prefix ist hier die 101. So kommt dann 1011 zu Stande.
Addon - WP Control
Beschreibung:
WP Crontrol ermöglicht es Ihnen, die geplanten Cron-Ereignisse auf Ihrer WordPress-Website oder in Ihrem WooCommerce-Shop zu verwalten. Über die Administrationsseiten können Sie:
-
Alle geplanten Cron-Ereignisse samt ihrer Parameter, Zeitpläne, Callback-Funktionen und dem nächsten Ausführungszeitpunkt anzeigen.
-
Cron-Ereignisse bearbeiten, löschen, pausieren, fortsetzen und sofort ausführen.
-
Neue Cron-Ereignisse hinzufügen.
-
Cron-Ereignisse per Massenverarbeitung löschen.
-
Individuelle Cron-Zeitpläne hinzufügen und entfernen.
-
Cron-Ereignislisten als CSV-Datei exportieren und herunterladen.
WP Crontrol berücksichtigt Zeitzonen, warnt Sie vor Ereignissen, die keine Aktionen enthalten oder ihren Zeitplan verfehlt haben, und zeigt Ihnen eine hilfreiche Warnmeldung an, falls Probleme mit Ihrem Cron-System festgestellt werden.
Nutzung
-
Gehen Sie im Menü zu Werkzeuge → Cron-Ereignisse, um Cron-Ereignisse zu verwalten.
-
Gehen Sie im Menü zu Einstellungen → Cron-Zeitpläne, um Cron-Zeitpläne zu verwalten.
Plugin Webseite: https://de.wordpress.org/plugins/wp-crontrol/
Bedienung :
Unter Ereignisse kann der Status eingesehen werden oder Zeitpläne können eingesehen werden
Ereignisse :
Hier kann man sehr schön sehen, das irgendwas mit dem cron system nicht stimmt.
Aber sonst, wenn alles läuft sieht man hier die Ereignisse.
Wir klicken bei Weitere information bei cURL Fehler drauf.
Fehlerdiagnose :
Unser Problem ist :
This means there is a network connectivity problem preventing your server from performing "loopback" requests to itself.
3000 Milliskeunden sind 3 Sekunden.
Wenn unsere Seite nicht schnell genug läuft gibts ein Timeout.
In der php.ini den Timeout einstellen auf 30 Sekunden
default_socket_timeout = 30
Sollte das auch nicht gehen, leiten wir die URL um wegen dem Caddy namen. Dann funktioniert die Auflösung nicht richtig.
Das machen wir mit dem Plugin Code Snippte
Snippt,
http://wordpress is der name in der docker-compose Datei.
Sollte dein DIenst anders heißen hier abändern genauso wie die externe url
add_filter('cron_request', function($cron_request) {
// Ersetze die externe HTTPS-Adresse durch den internen HTTP-Service-Namen
$cron_request['url'] = str_replace('https://deine-externe-domain.de', 'http://wordpress', $cron_request['url']);
return $cron_request;
});
Addon - WP-DBManager
Beschreibung:
So ne Art abgespecktes phpmyadmin für Wordpress.
URL : https://de.wordpress.org/plugins/wp-dbmanager/
Bedienung:
Nach der Installation gibt es links im Menü einen neuen Punkt der Datenbank.
Nun können wir entscheiden was wir möchten
Der rest ist Selbserklärend
Addon - Redis Cache
Beschreibung:
Ein Plugin das benötigt wird um Redis zu verwenden
Link : https://wordpress.org/plugins/redis-cache/
Einrichtung:
bevor das Plugin aktiviert wird. Muss noch die config.php angepasst werden.
Hier wird die env Variable vom Wordpress ausgelesen die wir im docker compose File gesetzt haben
define( 'WP_REDIS_HOST', getenv('WP_REDIS_HOST') ?: 'redis' );
wer kein docker nutzt einfach nur den server definieren sollte er local laufen dann einfach localhost oder 127.0.0.1 verwenden, ansonsten den hostnamen
define( 'WP_REDIS_HOST', '<hostname oder ip von redisserver' );
da wir ein docker haben können wir übers Dateisystem dies ändern, alle anderen varianten via ftp
nano /root/wordpress/data/wordpress/wp-config.php
Inhalt, nach den Datenbank Einträgen einfügen:
.../** Database hostname */
define( 'DB_HOST', getenv_docker('WORDPRESS_DB_HOST', 'mysql') );
/** Database charset to use in creating database tables. */
define( 'DB_CHARSET', getenv_docker('WORDPRESS_DB_CHARSET', 'utf8') );
/** The database collate type. Don't change this if in doubt. */
define( 'DB_COLLATE', getenv_docker('WORDPRESS_DB_COLLATE', '') );
/** Hier die define hin für redis*/
define( 'WP_REDIS_HOST', getenv('WP_REDIS_HOST') ?: 'redis' );
Addon installieren aktivieren
Nach der Aktivierung kommt der Assistent.
Hier den Cache einschalten
Wenn der Redis Server erreichbar ist alles funktioniert, sieht das ganze so aus
Code Snippets
Snippet - Prüfe ob Kunde Artikel im Besitz
Beschreibung:
Prüfe ob Kunde Artikel im Besitz, und gebe das beim Artikel aus.
Code:
add_action('woocommerce_before_single_product', function() {
if (!is_user_logged_in()) {
echo '<div style="padding:10px;background:#ffeeba;border-left:5px solid #f0ad4e;margin-bottom:15px;">
🔒 Du bist nicht eingeloggt. Eine Besitzprüfung ist nicht möglich.
</div>';
return;
}
global $product;
$user_id = get_current_user_id();
$product_id = $product->get_id();
$owns_product = wc_customer_bought_product('', $user_id, $product_id);
if ($owns_product) {
echo '<div style="padding:10px;background:#d4edda;border-left:5px solid #28a745;margin-bottom:15px;">
✅ Du besitzt dieses Produkt bereits.
</div>';
} else {
echo '<div style="padding:10px;background:#f8d7da;border-left:5px solid #dc3545;margin-bottom:15px;">
❌ Du besitzt dieses Produkt nicht.
</div>';
}
});
Ausführung:
Wenn man nicht eingeloggt ist bekommt man diese Meldung:
Wenn man eingeloggt ist, diese wenn gekauft
und wenn man es noch nicht besitzt
Man kann sich überlegen ob man sich die Ausgabe, das man es nicht besitzt spart. In dem Man dieses wieder auskommentiert bzw. den else block entfernt. Genauso wie die Prüfung ob eingeloggt, kann man auch entfernen wenn es nervt oder man nicht haben will.
Snippet - Wenn Kunde Produkt aus kategorie in Besitz hat ist dieses nicht mehr kaufbar
Beschreibung:
Wenn ein Kunde ein Produkt aus einer Kategorie im Besitz hat, sprich schon mal gekauft hat, kann er diesen Artikel nicht nochmals erwerben. Die menge Beschreibungsfelder etc. und in den Warenkorb werden via CSS ausgeblendet.
Auch hier kann wieder entschieden werden, welche Sachen angezeigt werden sollen.
Was nicht gebraucht wird, löschen oder auskommentieren.
Code:
// Besitzprüfung + Hinweis + optional Kauf verhindern
add_action('woocommerce_before_single_product', function() {
if (!is_user_logged_in()) {
echo '<div style="padding:10px;background:#ffeeba;border-left:5px solid #f0ad4e;margin-bottom:15px;">
🔒 Du bist nicht eingeloggt. Eine Besitzprüfung ist nicht möglich.
</div>';
return;
}
global $product;
$user_id = get_current_user_id();
$product_id = $product->get_id();
$owns_product = wc_customer_bought_product('', $user_id, $product_id);
$has_category = has_term('Homepagevorlagen', 'product_cat', $product_id);
if ($owns_product) {
echo '<div style="padding:10px;background:#d4edda;border-left:5px solid #28a745;margin-bottom:15px;">
✅ Du besitzt dieses Produkt bereits.
</div>';
if ($has_category) {
echo '<div style="padding:10px;background:#fff3cd;border-left:5px solid #ffeeba;margin-bottom:15px;">
🛑 Du besitzt dieses Produkt bereits und es gehört zur Kategorie „Homepagevorlagen“. Ein erneuter Kauf ist nicht möglich.
</div>';
// Dynamisch CSS einfügen, um Kaufbereich auszublenden
add_action('wp_head', function() {
echo '<style>
body.woocommerce.single-product .cart,
body.woocommerce.single-product .quantity,
body.woocommerce.single-product form.cart {
display: none !important;
}
</style>';
});
}
} else {
echo '<div style="padding:10px;background:#f8d7da;border-left:5px solid #dc3545;margin-bottom:15px;">
❌ Du besitzt dieses Produkt nicht.
</div>';
}
});
Snippet - Wenn Kunde ein explicites Produkt in Besitz hat ist dieses nicht mehr kaufbar
Beschreibung:
Wenn ein Kunde ein bestimmtes Produkt im Besitz hat, sprich schon mal gekauft hat, kann er diesen Artikel nicht nochmals erwerben. Die menge Beschreibungsfelder etc. und in den Warenkorb werden via CSS ausgeblendet.
Auch hier kann wieder entschieden werden, welche Sachen angezeigt werden sollen.
Was nicht gebraucht wird, löschen oder auskommentieren. Unter target_product_id die id des produktes eintragen
Code:
add_action('woocommerce_before_single_product', function() {
if (!is_user_logged_in()) {
echo '<div style="padding:10px;background:#ffeeba;border-left:5px solid #f0ad4e;margin-bottom:15px;">
🔒 Du bist nicht eingeloggt. Eine Besitzprüfung ist nicht möglich.
</div>';
return;
}
global $product;
$user_id = get_current_user_id();
$product_id = $product->get_id();
$owns_product = wc_customer_bought_product('', $user_id, $product_id);
// Hier deine Ziel-Produkt-ID eintragen
$target_product_id = 1234;
if ($owns_product) {
echo '<div style="padding:10px;background:#d4edda;border-left:5px solid #28a745;margin-bottom:15px;">
✅ Du besitzt dieses Produkt bereits.
</div>';
if ($product_id == $target_product_id) {
echo '<div style="padding:10px;background:#fff3cd;border-left:5px solid #ffeeba;margin-bottom:15px;">
🛑 Du besitzt dieses Produkt bereits. Ein erneuter Kauf ist nicht möglich.
</div>';
// Kaufbereich via CSS ausblenden
add_action('wp_head', function() {
echo '<style>
body.woocommerce.single-product .cart,
body.woocommerce.single-product .quantity,
body.woocommerce.single-product form.cart {
display: none !important;
}
</style>';
});
}
} else {
echo '<div style="padding:10px;background:#f8d7da;border-left:5px solid #dc3545;margin-bottom:15px;">
❌ Du besitzt dieses Produkt nicht.
</div>';
}
});
Snippet - Umleitung externer DNS name auf internen Docker instance - service Namen
Beschreibung:
Damit der WP Cron Dienst in Verbindung mit Caddy im Docker funktioniert, müssen der Externe DNS Name auf den internen Namen umgeleitet werden. Hier heißt der Service Name wordpress, dieser ist in der Docker compose Datei zu finden.
Code:
add_filter('cron_request', function($cron_request) {
// Ersetze die externe HTTPS-Adresse durch den internen HTTP-Service-Namen
$cron_request['url'] = str_replace('https://deine-externe-domain.de', 'http://wordpress', $cron_request['url']);
return $cron_request;
});
Snippet - Artikel als neue Position im Warenkorb mit Textfeld aus Acowebs Product Addons
Beschreibung:
Es gibt Artikel die mehrmal in den Warenkorb gelegt werden sollen, aber nicht gestapelt sondern als einzelne Position immer aufgelistet werden sollen, da sie Custom fields beinhalten.
Hier aus dem Plugin Acowebs Product Addons, für Benutzerdefinierte Felder.
Herausfinden des Feldnamens:
Die Artikelseite Aufrufen. Rechtklcik in das Textfeld und auf untersuchen klicken
Hier in type="url" name="url_3112976778"
url_3112976778 ist der Wert der uns später interessiert.
Snippet
In dem Beispiel haben wir url_3112976778 gelassen damit man weiß wo es rein muss
Diese beiden Werte in der POST setzen
$cart_item_data['addon-domain'] = sanitize_text_field($_POST['url_3112976778']);
$cart_item_data['unique_key'] = md5($_POST['url_3112976778'] . microtime());
add_filter('woocommerce_add_cart_item_data', 'force_unique_addon_domain_items', 10, 2);
function force_unique_addon_domain_items($cart_item_data, $product_id) {
if (!empty($_POST['url_3112976778'])) {
$cart_item_data['addon-domain'] = sanitize_text_field($_POST['url_3112976778']);
$cart_item_data['unique_key'] = md5($_POST['url_3112976778'] . microtime());
}
return $cart_item_data;
}
/*add_filter('woocommerce_get_item_data', 'show_domain_in_cart', 10, 2);
function show_domain_in_cart($item_data, $cart_item) {
if (isset($cart_item['addon-domain'])) {
$item_data[] = array(
'key' => 'Domain',
'value' => esc_html($cart_item['addon-domain']),
);
}
return $item_data;
}*/
add_action('woocommerce_add_order_item_meta', 'store_domain_in_order_meta', 10, 3);
function store_domain_in_order_meta($item_id, $values, $cart_item_key) {
if (isset($values['addon-domain'])) {
wc_add_order_item_meta($item_id, 'Domain', $values['addon-domain']);
}
}
Ergebnis:
✅ Snippet - Mengenfeld gezielt ausblenden, über Productid oder Kategorie ausblenden - DEFEKT
Beschreibung:
Mengenfeld gezielt ausblenden, über Productid oder Kategorie ausblenden.
Snippet:
-
n
$product_ids = array(42, 99);→ deine Produkt-IDs eintragen -
In
$category_slugs = array('zusatzartikel', 'einzeldomain');→ die Namen deiner Kategorien eintragen - Titelform ist der Slug
add_action('wp_head', 'hide_quantity_field_conditionally');
function hide_quantity_field_conditionally() {
// === KONFIGURATION ===
// Aktivieren oder deaktivieren
$check_by_product_id = true;
$check_by_category = true;
// Produkt-IDs (nur wenn $check_by_product_id = true)
$product_ids = array(42, 99); // <-- hier deine Produkt-IDs eintragen
// Kategorie-Slugs (nur wenn $check_by_category = true)
$category_slugs = array('zusatzartikel', 'einzeldomain'); // <-- Slugs deiner Kategorien
// === PRODUKTSEITE ===
if (is_product()) {
global $product;
$hide = false;
if ($check_by_product_id && in_array($product->get_id(), $product_ids)) {
$hide = true;
}
if ($check_by_category && has_term($category_slugs, 'product_cat', $product->get_id())) {
$hide = true;
}
if ($hide) {
echo '<style>
.woocommerce div.product form.cart .quantity {
display: none !important;
}
</style>';
}
}
// === WARENKORB ===
if (is_cart()) {
$hide = false;
foreach (WC()->cart->get_cart() as $cart_item) {
$product = $cart_item['data'];
if (
($check_by_product_id && in_array($product->get_id(), $product_ids)) ||
($check_by_category && has_term($category_slugs, 'product_cat', $product->get_id()))
) {
$hide = true;
break;
}
}
if ($hide) {
echo '<style>
.woocommerce-cart table.cart td.product-quantity .quantity {
display: none !important;
}
</style>';
}
}
}
Snippet - Verlinkte Produkte auf Produktseite anzeigen
Beschreibung:
Unter Produktbeschreibung Verlinkte Produkte anzeigen.
So ohne Snippet:
So mit Snippet
Welche Produkte werden angezeigt?
Die, die verlinkt werden:
Installation:
Code Snippet in die function.php oder über Snippet Manager Plugin
add_action('woocommerce_after_single_product_summary', 'show_crosssells_on_product_page', 16);
function show_crosssells_on_product_page() {
global $product;
$crosssell_ids = $product->get_cross_sell_ids();
if (!empty($crosssell_ids)) {
echo '<section class="cross-sells"><h2>Das könnte dich auch interessieren</h2>';
$args = array(
'post_type' => 'product',
'posts_per_page' => 4,
'post__in' => $crosssell_ids,
'orderby' => 'post__in'
);
woocommerce_product_loop_start();
$products = new WP_Query($args);
while ($products->have_posts()) {
$products->the_post();
wc_get_template_part('content', 'product');
}
woocommerce_product_loop_end();
wp_reset_postdata();
echo '</section>';
}
}