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

Fehlerbehebungen

Error 403 Permission denied

Meist bekommt man diese Meldung nachm Update oder nach installation eines größeren Plugins zum Beispiel WooCommerce.

grafik.png

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

Fehlerbehebungen

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.

grafik.png

Lösung:

Um genau zu sehen was Phase ist nehmen wir das Plugin WP Cron

Addon - WP Control

Und wie wir sehen ist eine Ursache die cURL Timeout Geschichte.

grafik.png


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

grafik.png

Fertig:

Wie man sieht keine Fehler mehr und die letzten Ausführungszeiten passen jetzt auch:

grafik.png

Installation

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;

Installation

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

Installation

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.

grafik.png

Und Preise im Shop anzeigen Steuern eingeschlossen
Preise Während Bestell Warenkorb und Bezahlvorgangs (Kasse) anzeigen Steuern eingeschlossen.

grafik.png

Dann Auf der Seite Allgemein bei Einstellungen

grafik.png

Dort unter Voreingestellter Ort für Kunden : Land Region des Stores

grafik.png

fertig

Installation

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.

grafik.png

Plugins

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 ;-)

Auswahl_1357.png

Auswahl_1358.png

Und schon gibts ein Feld beim Artikel

Auswahl_1359.png

Plugins

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

grafik.png

Dort kann man oben eon neues Form erstellen

grafik.png

Unten weiter stehen schon bestehende Forms.
Ein Form ist für einen Artikel gedacht, ein Form kann natürlich mehrere Felder haben

grafik.png

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.

grafik.png

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.

grafik.png

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

grafik.png

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

grafik.png

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.

grafik.png

grafik.png

Zum Schluss das ganze noch speichern.

grafik.png

Fertig:

grafik.png

Plugins

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.

Bedienung:

Nach der installtion hat man links im Menü Snipptes und alle Snippets.
Es gibt schon ein paar Demo Snipptes die aber deaktiviert sind.

grafik.png

Über Neu hinzufügen können wir ein neues Snippet einfügen

grafik.png

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.

grafik.png

Unten weiter kann noch eine Beschreibung angeben werden.
Dann auf Speichern und aktivieren klicken.

grafik.png

Nun sollte das Snippet beim Artikel genau das tun, was es soll:

Wenn man nicht eingeloggt ist bekommt man diese Meldung:

grafik.png

Wenn man eingeloggt ist, diese wenn gekauft

grafik.png

und wenn man es noch nicht besitzt

grafik.png

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.

grafik.png

Plugins

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  :

grafik.png

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 

Plugins

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

grafik.png

Wer das Englische nicht mag kann diese ja in Deutsch umbenennen.
und schon steht der Firmenname mit drin.

grafik.png

Plugins

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

grafik.png

Hier kann man die Sequenz und Prefixe einstellen

Uns interessiert nur dies, denn wir wollen einfach Order Nummern fortlaufend

grafik.png

Möchte man vorhandene Order Nummern umbenennen

Runter scrollen bis Renumerate Order Tools

grafik.png

Auf renumerate klicken

grafik.png

Das Ergebnis, alle order Nummern, Nummeriert

grafik.png

Alles zurücksetzten:

Erstmal alle Bestellungen löschen und den Papierkorb auch leeren:

grafik.png

grafik.png

Nun in die Plugineinstellungen auf Settings gehen

grafik.png

Ganz nach unten Scrollen

reset Section Settings anklicken und speichern anklicken

grafik.png

Nun kann wieder von vorne begonnen werden mit Bestell Nr 1

grafik.png

Plugins

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

grafik.png


grafik.png

Dann speichern.

Nun kann das Rechnungsdesign angepasst werden, dazu auf den Link klicken

grafik.png

Das Hauptmenü, an der linken Seite, können alle Bereiche definiert werden

grafik.png

in der Rechnungsfußzeile ist das einzige was ich anpassen würde. Da müssen die Sachen aus der Rechung rein, wie Steuernummer etc.

grafik.png

zum Beispiel so:

grafik.png

Dann sieht die Vorschau so aus:

grafik.png

Nun veröffentlichen.

Plugins

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

grafik.png

Nun den Emailsender wählen.
Es werden viele Anbieter ünterstützt

grafik.png

ich wähle hier anderer SMTP-Server aus

 

grafik.png

Nun die Daten eingeben

 

grafik.png

grafik.png

Speichern und fortfahren

Alles so lassen

grafik.png

Diesen schritt überspringen

grafik.png

Wir nutzen die Kostenlose Version, auch hier überspringen.
Wer natürlich einen Schlüssel hat , eingeben und auf verbinden klicken

grafik.png

 

 

Plugins

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

grafik.png

Alles so lassen außer man ist Kleinunternehmer

grafik.png

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

grafik.png

Nun Auf Tutorial starten klicken

grafik.png

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

grafik.png

Dort wählen wir folgende Tabellen mit Empty aus

grafik.png

Nun runter scrollen und auf empty drop klicken

grafik.png

Wurden geleert

grafik.png

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

grafik.png

Dann bei Rechnungen und Lieferscheine auf den Stift klicken

grafik.png

Hier steht in der Vorschau was die nächste Nummer wäre. Was aber falsch ist da wir ja alles weggeschmissen haben

grafik.png

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.

grafik.png

Dann auf speichern klicken.

grafik.png

Plugins

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:

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

Plugin Webseite: https://de.wordpress.org/plugins/wp-crontrol/

Bedienung :

Unter Ereignisse kann der Status eingesehen werden oder  Zeitpläne können eingesehen werden

grafik.png

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.

grafik.png

Wir klicken bei Weitere information bei cURL Fehler drauf.

Fehlerdiagnose :

Unser Problem ist :

cURL error 28: Operation timed out after 3000 milliseconds with 0 bytes received

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

Addon - Code Snippet

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;
});

Plugins

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.

grafik.png

Nun können wir entscheiden was wir möchten

grafik.png

Der rest ist Selbserklärend

Plugins

Addon - Redis Cache

Beschreibung:

Ein Plugin das benötigt wird um Redis zu verwenden

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

 

grafik.png

Wenn der Redis Server erreichbar ist alles funktioniert, sieht das ganze so aus

grafik.png

Code Snippets

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:

grafik.png

Wenn man eingeloggt ist, diese wenn gekauft

grafik.png

und wenn man es noch nicht besitzt

grafik.png

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.

 

 

 

Code Snippets

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>';
    }
});

 

Code Snippets

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>';
    }
});

Code Snippets

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;
});

 

Code Snippets

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

grafik.png

grafik.png

Hier in type="url" name="url_3112976778"

url_3112976778 ist der Wert der uns später interessiert.

grafik.png

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:

grafik.png

Code Snippets

✅ Snippet - Mengenfeld gezielt ausblenden, über Productid oder Kategorie ausblenden - DEFEKT

Beschreibung:

Mengenfeld gezielt ausblenden, über Productid oder Kategorie ausblenden.

Snippet:

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>';
        }
    }
}

Code Snippets

Snippet - Verlinkte Produkte auf Produktseite anzeigen

Beschreibung:

Unter Produktbeschreibung Verlinkte Produkte anzeigen.

So ohne Snippet:

image.png

So mit Snippet

image.png

Welche Produkte werden angezeigt?
Die, die verlinkt werden:

image.png

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>';
    }
}