Laden

NützlichesNützliches

Hilfreiche Lösungen

Bei der täglichen Arbeit mit WordPress, Joomla, Typo3 und Co, treten in Abständen immer wieder die gleichen Probleme auf. Nachfolgend notiere ich die wichtigsten und gebe gleich die passende Lösung dafür.

Diese Lösung muss nicht immer sauber sein, dies bedeutet das es auch bessere Lösungen für das jeweilige Problem geben kann. Hierbei ist jedoch immer eine Gesamtbetrachtung nötig. Bei den hier präsentierten Lösungen war der entsprechende Lösungsansatz autonom.

Die Verwendung der hier vorgestellten Lösungen, geschieht natürlich auf eigene Gefahr. Ich rate dringend dazu, eine vorherige Sicherung anzulegen.

WordPress

Nachfolgend nützliche Erweiterungen für die wp-config.php Datei.

define('WP_HOME','https://ihredomain.de'); //WordPress-Adresse (Backend)
define('WP_SITEURL','https://ihredomain.de'); //Webseiten-Adresse (Startseite)

define('WP_POST_REVISIONS', 5); //Anzahl maximal gespeicherter Revisionen
define('WP_POST_REVISIONS', false); //Revisionen werden nicht gespeichert
define('AUTOSAVE_INTERVAL', 30); //Alle 30 Sekunden wird automatisch gespeichert (Standard 60)
define('EMPTY_TRASH_DAYS', 60); //Alle 60 Tage wir der Papierkorb geleert
define('EMPTY_TRASH_DAYS', 0); //Der Papierkorb wird sofort geleert

define('WP_CACHE', true); //Den internen Cache von WordPress aktivieren
define('WP_MEMORY_LIMIT', '128M'); //Hauptspeicher in MByte festlegen, der für WordPress zur Verfügung steht
define('WP_MEMORY_LIMIT', '8M'); //Upload-Limit auf zum Beispiel 8, 16, 32, 64, 128 MB erhöhen

define( 'WP_EMOICONS', false ); //Emojis deaktivieren
define( 'IMAGE_EDIT_OVERWRITE', true ); //Überschreibt vorhandene gleiche Bilder

define('DISALLOW_FILE_EDIT', TRUE); //Editieren der Dateien im Editor verhindern
define('FORCE_SSL_LOGIN', true); //SSL-Login erzwingen

define('AUTOMATIC_UPDATER_DISABLED', true); //Automatische Updates deaktivieren
define( 'WP_AUTO_UPDATE_CORE', false ); //Deaktivieren aller automatischen WordPress-Updates

Mit folgenden Code Snippet, der in der function.php des Themes eingefügt werden muss, entfernt man die Angaben zum entsprechenden Meta Generator.

/* Comment Feed entfernen */
add_filter( 'feed_links_show_comments_feed', '__return_false' );

/* Generator entfernen */
remove_action('wp_head', 'wp_generator');

In einigen Fällen kann es hilfreich sein, wenn anstatt einer Fehlerseite, eine direkte Weiterleitung zur Startseite erfolgen soll. Aus SEO Sicht ist dies eher nicht zu empfehlen, dennoch ist die Lösung für dieses Szenario recht einfach.

Lösung: Man erstellt sich im Theme Ordner eine eigene 404.php Datei und fügt den nachfolgenden Code ein. Zur Sicherheit sollte die (sofern vorhanden) original 404.php gesichert werden, falls man diese päter doch noch verwenden möchte.

header("HTTP/1.1 301 Moved Permanently"); 
header("Location:".get_bloginfo('url')); 
exit();

Eine generelle .htaccess Lösung ist unter Server/Hoster zu finden.

Ein Menülink lässt sich in WordPress nur mit bestimmten Elementen verlinken bzw. mit externen Seiten. Wenn ein Menülink z.B. ein Modal öffnen soll, ist dies meist komplizierter. Abhilfe schafft hier ein jQuery Skript.

Lösung: Man tauscht hier lediglich die ID des gewünschten Menülinks und definiert den Code, der beim Klick auf diesen Menüpunkt ausgeführt werden soll.

jQuery(document).ready(function(){
    jQuery("#menu-item-50").bind( "click", function() {
        //Hier der gewünschte Code
    });
});

Nicht erst seit der DSGVO bietet es sich an, Web Schriftarten selbst zu hosten. Je nachdem welches Theme verwendet wird, geht dies mal einfacher, mal schwerer, da die Schriften unterschiedlichen eingebunden sind.

Abhilfe schafft hier ein Plugin, das automatisch die verwendeten Schriftarten erkennt und lokal auf dem Server abspeichert.

Lösung: https://wordpress.org/plugins/selfhost-google-fonts/

Bietet das verwendete Theme keine Möglichkeiten, den Bild Titel darzustellen, lässt sich mit ein wenig PHP, dieser Umstand ändern. Dies funktioniert in dem hier beschriebenen Fall auch nur, wenn die ID des Bildes bzw. Anhangs zuvor abgefragt wird.

Lösung:

$attachment_title = get_the_title($attach_id)

In manchen Fällen ist es sinnvoll bestimmte Beiträge zwar auf der Blog Seite anzuzeigen, jedoch nicht im Archiv.

Lösung: Zuerst sollten die betreffenden Beiträge einer bestimmten Kategorie zugeordnet werden. Mit dem nachfolgenden Skript wird dann diese Kategorie aus dem Archiv entfernt. Die ID in dem Skript muss dann durch die erstellte Kategorie ID ersetzt werden.

function exclude_stuff($query) {
if ( $query->is_date) {
$query->set('cat', '-6');
}
return $query;
}
add_filter('pre_get_posts', 'exclude_stuff');

In manchen Fällen ist es ratsam eigne Custom Post Types zu erstellen. Hierbei handelt es sich um eine Erweiterung für Inhalte, wobei diese Inhalte nicht auf eine bestimmte Art hin festgelegt sind. Das nachfolgende Code Snippet erstellt einen Custom Post Type für Ansprechpartner und sorgt zugleich dazu, dass hier ein eigener Kategoriebaum zu erstellt wird.

function ansprechpartner_post_type() {
$labels = array(
'name' => 'Ansprechpartner Einträge',
'singular_name' => 'Ansprechpartner',
'menu_name' => 'Ansprechpartner',
'parent_item_colon' => '',
'all_items' => 'Alle Einträge',
'view_item' => 'Eintrag ansehen',
'add_new_item' => 'Neuer Eintrag',
'add_new' => 'Hinzufügen',
'edit_item' => 'Eintrag bearbeiten',
'update_item' => 'Update Eintrag',
'search_items' => '',
'not_found' => '',
'not_found_in_trash' => '',
);
$rewrite = array(
'slug' => 'neuer_ansprechpartner',
'with_front' => true,
'pages' => true,
'feeds' => true,
);
$args = array(
'labels' => $labels,
'supports' => array( 'title', 'editor', 'excerpt', 'thumbnail', 'comments', 'trackbacks', ),
'taxonomies' => array('post_tag'),
'hierarchical' => true,
'public' => true,
'show_ui' => true,
'show_in_menu' => true,
'show_in_nav_menus' => true,
'show_in_admin_bar' => true,
'menu_position' => 5,
'can_export' => false,
'has_archive' => true,
'exclude_from_search' => false,
'publicly_queryable' => true,
'rewrite' => $rewrite,
'capability_type' => 'page',
);
register_post_type( 'neuer_ansprechpartner', $args );
}
add_action( 'init', 'ansprechpartner_post_type', 0 );

add_action( 'init', 'ansprechpartner_post_type_custom_taxonomy', 0 );
function ansprechpartner_post_type_custom_taxonomy() {
  $labels = array(
    'name' => _x( 'Abteilungen', 'taxonomy general name' ),
    'singular_name' => _x( 'Abteilung', 'taxonomy singular name' ),
    'search_items' =>  __( 'Abteilung suchen' ),
    'all_items' => __( 'Alle Abteilungen' ),
    'parent_item' => __( 'Kategorie' ),
    'parent_item_colon' => __( 'Parent Type:' ),
    'edit_item' => __( 'Abteilung bearbeiten' ), 
    'update_item' => __( 'Aktualisieren' ),
    'add_new_item' => __( 'Neu hinzufügen' ),
    'new_item_name' => __( 'New Type Name' ),
    'menu_name' => __( 'Abteilungen' ),
  ); 	
  register_taxonomy('abteilungen',array('neuer_ansprechpartner'), array(
    'hierarchical' => true,
    'labels' => $labels,
    'show_ui' => true,
    'show_admin_column' => true,
    'query_var' => true,
    'rewrite' => array( 'slug' => 'abteilung' ),
  ));
}

Von Haus aus können SVG Dateien nicht in die Mediathek geladen werden. Dies geschieht aus Sicherheitsgründen und soll vor manipulierten SVG Dateien schützen. Wurde diese Datei von einem selbst erstellt, ist das Risiko sicher gering.

Lösung: Die einfachste Variante ist das verwenden eines Plugins, das den Upload ermöglicht. Befindet sich die Datei einmal in der Mediathek, kann das Plugin natürlich auch wieder deinstalliert werden. Gute Erfahrungen habe ich mit SVG Support gemacht.

Aus SEO Sicht kann es ratsam sein, bestimmte Unterseiten statisch anzulegen. So lassen sich auf dieser statischen Unterseite alle Skripte entfernen, die nicht benötigt werden, sowie das für diese Seite verwendete Keyword, für sämtliche Bilder, etc. verwenden. Generell sollte einem natürlich bewusst sein, dass diese statische Seite bei zukünftigen Änderungen schwieriger zu bearbeiten ist, da hier direkt im Quelltext gearbeitet werden muss.

Lösung: Auch hier gibt es verschiedene Plugins, wie u.a. WP2Static. In meinem Fall funktioniert keines der beworbenen Plugins, wobei dies auch an der Zusammensetzung der verwendeten Plugins gelegen haben könnte.  Die Verwendung von HTTrack funktionierte hingegen problemlos. Hier ließ ich nur die Unterseite tracken, die statisch umgewandelt werden sollte. Im Nachgang fügte ich alle benötigten CSS und Skripte in einen Ordner und wandelte die erzeugte index.html in eine php Datei um. Im Quelltext muss diese Datei wie folgt aufgebaut sein:

<?php
/*
 * Template Name: Gewünschter Template Name
 */
?>

Anschließend wird diese php Datei und der Dateien Ordner, in das Hauptverzeichnis des verwendeten Themes eingefügt. Erstellt man nun in WordPress eine neue Unterseite, wird in der Template Auswahlliste, die hinzugefügte PHP Datei angezeigt. Damit greift diese Unterseite dann genau auf diese php Datei zu. Diese kann dann noch beliebig modifiziert werden.

Angezeigte Fehler in WordPress sollte man schnellstmöglich beheben, da andernfalls irgendwann genau diese Fehler zu größeren Problemen führen. Beeinträchtigen diese Fehler jedoch das Frontend so sehr, dass eine kurzzeitige Lösung her muss, lassen sich die Fehler (meistens) mit folgenden Code, der in der wp-config hinterlegt werden muß.

ini_set('display_errors','Off');
ini_set('error_reporting', E_ALL );
define('WP_DEBUG', false);
define('WP_DEBUG_DISPLAY', false);

In den meisten Fällen reicht bereits der erste Code:

ini_set('display_errors','Off');

Die folgende Fehlermeldung „Fehler: Cookies sind gesperrt oder werden von Deinem Browser nicht unterstützt. Du musst Cookies aktivieren, um WordPress verwenden zu können.“ lässt sich mit einigen wenigen Anpassungen, meist schnell beheben.

Lösung: Sofern die wp-config.php fehlerfrei ist, können folgenden Ergänzungen darin, das Problem lösen.

define('WP_HOME','http://www.beispielseite.de');
define('WP_SITEURL','http://www.beispielseite.de');
define('COOKIE_DOMAIN','http://www.beispielseite.de');

Und abermals ein Fehler der in Kombination mit einer PHP Umstellung vorkommen kann. Dieser tritt jedoch nicht explizit nur bei WordPress auf, auch Joomla und Drupal sind hiervon betroffen. Generell ist hier eine fehlende Initialisierung eines Arrays Ursprung dieses Fehlers.

Lösung: Nachfolgend mehrere Variante und dessen Lösungen.

$data[] = '<script type="text/javascript">' . NL;

ändern in

$data = [];
$data[] = '<script type="text/javascript">' . NL;

Alternativ auch

$data = array();
$data[] = '<script type="text/javascript">' . NL;

Fehlt die Definition für

$section_style         = '';

muß diese geändert werden in

$section_style         = [];

Tritt der Fehler in dieser Kombination auf

self::$arrMetaBoxes[] = $box;

muss auch hier die Variable definiert werden

self::$arrMetaBoxes = [];
self::$arrMetaBoxes[] = $box;

Die Kombination aus veralteten Theme und einer PHP Umstellung, kann folgende Fehlermeldung zu Tage führen:

Strict Standards: Declaration of TGM_Bulk_Installer_Skin::before() should be compatible with Bulk_Upgrader_Skin::before($title = '') in /wp-content/themes/xxx/inc/class-tgm-plugin-activation.php on line 1893
Strict Standards: Declaration of TGM_Bulk_Installer_Skin::after() should be compatible with Bulk_Upgrader_Skin::after($title = '') in /wp-content/themes/xxx/inc/class-tgm-plugin-activation.php on line 1893


Lösung:
Hierzu müssen zwei Codezeilen geändert werden, die Zeilennummer kann dabei jedoch abweichen, hier sollte man die Suchfunktion verwenden.

In Zeile 1977 ändert man den Code

public function before() {

in

public function before( $title = '' ) {

Und in Zeile 1999:

public function after() {

in

public function after( $title = '' ) {

Tritt der Fehler 500 auf, wird dieser Fehler im Browser direkt angezeigt, jedoch ist auch eine komplett weiße WordPress Seite möglich. In beiden Fällen ist ein Login ins Backend nicht mehr möglich. Tritt der Fehler kurz nach einer PHP Umstellung auf, kann die nachstehende Lösung hilfreich sein.

Lösung: Meist sind es Plugins, die aufgrund der PHP Umstellung einen Fehler produzieren, der über eine einfache Fehlermeldung hinaus geht und somit das gesamte System stört.

Im ersten Schritt sollte man den Ordner /plugins/ umbenennen, um den Fehler einzugrenzen. Hierzu muss mit einem FTP Programm Zugriff auf dem Server erfolgen. Ist dies der Grund sollte man die Plugins nach der Reihe durchgehen, um nach dem Ausschlusskriterium das fehlerhafte Plugin zu lokalisieren.

Liegt dieses Problem vor, ist oftmals ein Plugin Konflikt der Grund. In der Regel deutet auch ein Fehler in der Konsole auf eventuelle gründe hin. Kandidaten sind hierfür gerne das Übersetzungsplugin WPML in der Kombination mit dem SEO Plugin YOAST.

Lösung: Aktualisiert man beide Plugins, dürfte auch der Fehler verschwinden und der Editor ist wieder nutzbar.

Der Grund kann vielfältig sein, die Lösung dafür ist hingegen recht einfach.

Lösung: Mit einem FTP Programm verschafft man sich Zugang ins Hauptverzeichnis der WordPress Installation auf dem Server. Hier sollte sich die Datei .maintenance befinden. Wird diese nun gelöscht, sollte auch das System wieder fehlerfrei funktionieren.

Verwendet man html Code im Elementor und nutzt gleichzeitig das Plugin Wordfence, kann es zu Problemen bei speichern kommen.

Lösung: Wenn man Wordfence kurzzeitig deaktiviert, funktioniert auch das Speichern wieder.

In WordPress lassen sich die Seiten bereits in einer Hierarchie anlegen, was der Übersichtlichkeit aber auch dem URL Aufbau entgegenkommen kann. Soll die übergeordnete Webseite jedoch nicht mit Inhalt gefüllt werden und direkt auf das Kindelement verweisen, muss ein wenig gecodet werden.

Lösung: Hierzu erstellt man idealerweise in einem Child-Theme, damit bei einem Update des Themes diese Datei nicht überschrieben wird, eine leere php Datei (z.B. blank.php). Abschließend fügt man den nachfolgenden Code ein.

<?php
/*
 * Template Name: Parent Menu
 * Description: Redirects empty parent page to first child page
 */

$child_page = get_pages( "child_of=" . $post->ID . "&sort_column=menu_order" );
if ( $child_page ) {
    $parent_page = $child_page[0];
    wp_redirect( get_permalink( $parent_page->ID ) );
}

Im letzten Schritt muss im Backend auf der gewünschten übergeordneten Seite, das Template geändert werden. Im genannten Fall auf „Parent Menu“.

Wird im WordPress Backend die Widget Funktion nicht angezeigt unterstützt aller Voraussicht nach das Theme diese nicht. Dies bedeutet wiederrum nicht, dass man es dem jeweiligen Theme nicht doch beibringen kann.

Lösung: Hierzu wird folgender Code in die functions.php eingefügt.

function ourWidgetsInit(){
  register_sidebar( array (
    'name' => 'Sidebar',
    'id' => 'sidebar1'
  ));
}
add_action('widgets_init', 'ourWidgetsInit');

Es gibt zahlreiche Tipps wie man seine WordPress Webseite sicherer machen kann. Regelmäßige Updates, komplizierte Passwörter, Dateirechte richtig einstellen, Sicherungen, sind nur ein kleiner Teil dieser Liste. Nachfolgend eine Liste von Möglichkeiten, die seltener genannt werden.

Automatische CORE-Updates aktivieren

define( 'WP_AUTO_UPDATE_CORE', true );

Dateiänderungen über Backend-Editor verhindern

define('DISALLOW_FILE_EDIT', true);

Benutzernamen verbergen (wird in der functions.php eingefügt)

add_action('template_redirect', 'bwp_template_redirect');
function bwp_template_redirect()
{
  if (is_author())
  {
    wp_redirect( home_url() ); exit;
  }
}

wp-includes Änderungen verhindert (wird in der .htaccess eingefügt)

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^wp-admin/includes/ - [F,L]
RewriteRule !^wp-includes/ - [S=3]
RewriteRule ^wp-includes/[^/]+\.php$ - [F,L]
RewriteRule ^wp-includes/js/tinymce/langs/.+\.php - [F,L]
RewriteRule ^wp-includes/theme-compat/ - [F,L]
</IfModule>

readme.html und license.txt schützen

<Files readme.html>
order allow,deny
deny from all
</Files>

<Files license.txt>
order allow,deny
deny from all
</Files>

Hinter WP-VCD steckt eine Malware, die sich in verschiedenen WordPress Dateien einnistet. Wird diese nicht vollständig entfernt, kann sich der Code immer wieder neu ausführen.

Verwendetet man sogenannten Nulled Premium Plugins oder Themes, dabei handelt es sich um modifizierte Dateien die im Internet frei zu finden sind und im Gegensatz zur originalen Hersteller Seite kostenlos zur Verfügung stehen. Der Nachteil ist jedoch, dass diese meist auch Schadcode erhalten, der sobald die Dateien auf dem Server aktiviert wurde, große Teile der Webseite beschädigen können.

Lösung: Generell gilt es zu überlegen, ob man Programme aus unbekannten Quellen laden möchte. Ist dies bereits geschehen, sollte man folgende Punkte beachten.

1.) Die gesamte Webseite sichern.

2.) Folgende Dateien löschen:

/wp-includes/wp-vcd.php
/wp-includes/class.wp.php
/wp-includes/wp-cd.php
/wp-includes/wp-feed.php
/wp-includes/wp-tmp.php
/wp-includes/class.theme-modules.php
/wp-includes/class.plugin-modules.php

3.) Den Quellcode in folgender Datei säubern:

/wp-includes/class.wp.php
/wp-content/themes/_verwendetesTheme/functions.php

4.) Den Server nach dem Ursprung durchsuchen, in dem man folgenden Dateien ausfindig macht:

class.theme-modules.php
class.plugin-modules.php

Ein einfachsten findet man die Dateien, in dem man per Shell auf den Webserver zugreift und mit dem nachfolgenden Befehl, alle Dateien auf dem Server danach durchsuchen lässt und anschließend entfernt.

find / -name gesuchteDatei.php

Der Fall dürfte zwar nur sehr selten auftreten, völlig abwegig ist dieser aber nicht: Man kommt nicht mehr ins Backend von WordPress.

Lösung: Sofern noch Zugang zur Datenbank besteht, idealerweise über phpMyAdmin, lässt sich ein neuer Admin Zugang schnell einrichten. Hierzu verwendet man einfach die nachfolgenden SQL Befehle. Zuvor muß noch das Wort ‚databasename‘, durch den tatsächlichen Datenbanknamen abgeändert werden.

INSERT INTO `databasename`.`wp_users` (`ID`, `user_login`, `user_pass`, `user_nicename`, `user_email`, `user_url`, `user_registered`, `user_activation_key`, `user_status`, `display_name`) VALUES ('4', 'demo', MD5('demo'), 'Your Name', 'test@yourdomain.de', 'http://www.test.de/', '2011-06-07 00:00:00', '', '0', 'Your Name');
 
INSERT INTO `databasename`.`wp_usermeta` (`umeta_id`, `user_id`, `meta_key`, `meta_value`) VALUES (NULL, '4', 'wp_capabilities', 'a:1:{s:13:"administrator";s:1:"1";}');
 
INSERT INTO `databasename`.`wp_usermeta` (`umeta_id`, `user_id`, `meta_key`, `meta_value`) VALUES (NULL, '4', 'wp_user_level', '10');

Anschließend kann man sich mit dem Benutzername und Passwort ‚demo‘ einloggen. Diese Zugangsdaten sollten natürlich schnellstmöglich geändert werden!

Um den nervigen und zugleich überflüssigen Kommentar aus dem Quelltext zu entfernen, fügt man einfach den folgenden Code in die functions.php ein:

if (defined('WPSEO_VERSION')) {
 add_action('wp_head',function() { ob_start(function($o) {
 return preg_replace('/^\n?\n?$/mi','',$o);
 }); },~PHP_INT_MAX);
}

Leider kommt es vor, dass beim Aufruf der von Yoast generierten XMP Sitemap diese endlos lädt, aber nie dargestellt wird.

Lösung: Klickt man unter Einstellungen -> Permalinks einmal auf Speichern, lässt sich das Problem damit oftmals beheben.

Die sogenannte Acceptance Box in Contact Form 7, dient als Checkbox innerhalb des Formulars. Von Haus aus wird diese beim nicht anklicken, trotz Pflichtfeld, mit einer Fehlermeldung bedacht.

Lösung: Mit der nachfolgenden Anweisung, die innerhalb des Tabs Additional Settings eingefügt wird, folgt die Behebung dieses Problems.

acceptance_as_validation: on

Sofern die empfangenen E-Mails, die über Contact Form 7 versendet werden, mit hoher Priorität angezeigt werden sollen, lässt sich unter „Additional Headers“ folgender Eintrag vornehmen:

X-Priority: 1
X-MSMail-Priority: High

Bisher fehlt immer noch eine Plugin eigene Lösung, um das Formular zweispaltig umzubauen. Die folgenden Anpassungen ermöglichen eine händische Lösung.

Anpassungen im Formular selbst:

<div class="wps-form">
    <!-- Zeile 1 -->
    <div class="wps-form-row">
        <!-- Spalte 1 -->
        <div class="wps-form-column">
            [text* your-name placeholder "Name*"]
        </div>
        <!-- Spalte 2 -->
        <div class="wps-form-column">
            [email* your-email placeholder "E-Mail*"]
        </div>
    </div>
    <!-- Ende der Zeile 1 -->
</div>

Ergänzungen für die CSS Datei:

.wps-form {
    width: 100%;
    margin: 0 auto;
}
.wps-form-row {
    display: flex;
    flex-direction: column;
    width: 100%;
}
.wps-form-row .wpcf7-form-control {
    width: 100%;
}
.wps-form-column {
    flex: 1;
    padding: 0.5rem 0;
    width: 100%;
}
@media only screen and ( min-width: 48em ) { 
    .wps-form-row {
        flex-direction: row;
    }
    .wps-form-column {
        padding: 0.5rem 1rem;
    }
}

Wenn Contact Form 7 beim Senden einer Nachricht eine Fehlermeldung ausgibt, dass die E-Mail nicht verschickt werden konnte, liegt es eventuell an einem Fehler mit Google reCAPTCHA ver 3. In Firefox lässt sich mit der Konsole eventuell dann auch ein API Fehler feststellen.

Lösung: Im Allgemeinen liegt es an einem falsch hinterlegten Domain Namen. Unter google.com/recaptcha muß die Einstellung der Domain z.B. cms-geek.de lauten. Wenn man hingegen ein www oder sogar ein https:// voranstellt, wird ein Fehler ausgelöst, der sich dann zeigt, wenn versucht wird das Kontaktformular abzusenden.

Leider bietet das Plugin von Haus aus keine eigene Länderliste an, außer man erstellt sich diese von Hand, was aufwendig und zudem viel Ressourcen beim Laden frisst.

Lösung: Zuerst wird das Plugin Listo benötigt, was trotz Meldung auch mit der aktuellen WordPress Version läuft. Ist dieses installiert und aktiviert, lässt sich ein entsprechendes Feld in Contact Form 7 erstellen.

[select land data:countries default:60]

Der Wert default:60 steht für Deutschland.

Dieser Fehler tritt gern bei älteren Versionen des Plugins auf, wenn hingegen auf eine aktuelle PHP Version gesetzt wird. Beides verträgt sich nicht und sorgt unter Umständen für eine komplett weiße Webseite.

Lösung: Im Plugin Ordner sucht bearbeitet man folgende Datei revslider/includes/framework/base-admin.class.php

Man sucht nun die folgende Codezeile:

private static $arrMetaBoxes = '';

und ersetzt diese durch:

private static $arrMetaBoxes = array();

Anschließend sollte man den Webseiten Cache und Browser Cache einmal löschen.

Folgendes Script scrollt automatisch nach dem letzten Slide unterhalb des Sliders zum nachfolgenden Content. Die ID des Sliders (hier: revapi1) muss entsprechend angepasst werden.

Lösung:

// Scroll-Geschwindigkeit in ms
var scrollTime = 500;
 
// Zeit bevor das Scrollen beginnt in ms
var scrollDelay = 2000;
 
var api = revapi1.on('revolution.slide.onchange', function(e, data) {
 
    if(data.slideIndex === api.revmaxslide()) {
 
        setTimeout(function() {
 
            var bounds = api[0].getBoundingClientRect();
            jQuery('html, body').animate({
                scrollTop: window.pageYOffset + bounds.top + bounds.height
            }, scrollTime);
 
        }, scrollDelay);
    }
});

Wär auf Slides außerhalb des Plugins zugreifen möchte, finden unter der folgenden Webseite des Plugin Entwicklers, eine genaue Anleitung:

https://www.themepunch.com/faq/change-slides-from-external-hyperlinksider/

In einigen Fällen kann es recht sinnvoll sein, dass sich ein Element außerhalb des Sliders, je nach angezeigten Slide anders verhält. In dem nachfolgenden Fall geht es darum, das Element farblich anzupassen.

Im gewünschten Slide fügt man unter Link & SEO, im Feld Custom Fields den folgenden Wert ein:

data-color="light"

Anschließend folgt ein kurzer CSS Code, bei dem sr- dem ganzen vorangestellt wird.

body.sr-light {background-color: #fff;}

Zu guter Letzt muss dann noch folgender JavaScript Code hinterlegt werden:

var api = revapi1.on('revolution.slide.onchange', function(e, data) {
 
  jQuery('body').removeClass('sr-light').addClass(
    'sr-' + api.find('li').eq(data.slideIndex - 1).attr('data-color')
  );
});

revapi1 muss hierbei, durch den API Namen des verwendeten Sliders ersetzt werden.

Durch diese Anpassungen wird im body eine Klasse mit dem Namen sr-light sichtbar, wenn der Slide angezeigt wird.

Zu guter Letzt muss jetzt das gewünschte Element angepasst werden, was z.B. mit dem nachfolgenden Code möglich ist:

body.sr-light .entry-content {color: #fff;}

Im Zusammenhang mit einer PHP Umstellung zu 7.1 oder 7.2 kann es vorkommen, dass der All-in-One Event Calendar mit folgender Fehlermeldung den Dienst quittiert: CSS-Kompilierung schlug fehl, da nicht genügend freier Speicher verfügbar war (mindestens 24M wird benötigt). Dein Kalender wird ohne CSS nicht angezeigt werden oder richtig funktionieren.

Lösung: Zum einen sollte geprüft werden, ob eventuell wirklich ein Problem mit dem Memory Limit des Servers besteht. Ist dies der Fall, kann mit einer php.ini Datei, die Erhöhung des Limits erzeugt werden (mehr dazu unter Server & Hoster).
Ist dieses Problem behoben, sollte man im Plugin selbst unter „Veranstaltungen“ > „Theme-Optionen“, auf „Optionen speichern“ klicken, den Webseiten Cache (falls vorhanden) und den Browser Cache leeren.

Aktuell fehlt es Elementor noch an einer Funktion, dass man mehreren Boxen nebeneinander dieselbe Höhe geben kann bzw. das sich an der höchsten Box orientiert wird.

Lösung: Mit etwas CSS kann man dieses Problem jedoch beheben. Zuerst muss innerhalb einer Section eine weitere Section erstellt werden. Diese kann dann z.B. drei oder vier Spalten besitzen. in jeder Spalte positioniert man dann den gewünschten Content. Der inneren Section muss dann die CSS Klasse zugewiesen werden.

.equal-height-content {
    height: 100%;
    display: flex;
}

Möchte man von einer Unterseite auf eine andere Unterseite die mit Tabs ausgestattet ist, einen bestimmten Tab öffnen lassen, lässt sich dies mit dem nachfolgenden Skript realisieren.

Lösung: Die entsprechende Unterseite muss dann z.B. mit /tab#2 aufgerufen werden.

<script type="text/javascript">
jQuery(document).ready(function ($) {
    //get the hash tag
    //hash exist
    setTimeout(function () {
        var current = window.location.href
        var current = current.split('#tab')
        if (current.length > 1) {
            showAndScrollToTab($, current)
        }
    }, 200);
    // change the browser url according to selected tab
    $('.elementor-tab-title[data-tab]').click(function () {
        var current_location = window.location.href;
        current_location = current_location.split('#')
        window.location = current_location[0] + '#tab' + $(this).attr('data-tab')
    })
    // activate tab also from anchor link in the same page
    $('a').on('click', function () {
        var anchorUrl = $(this).attr('href')
        var anchor = anchorUrl.split('#tab')
        if (anchor.length > 1) {
            showAndScrollToTab($, anchor)
        }
    })
})

function showAndScrollToTab($, current) {
    $('.elementor-tab-content').removeClass('elementor-active').css('display','none')
  $('.elementor-tab-content[data-tab="' + current[1] + '"]').addClass('elementor-active').css('display','block')
    $('.elementor-tab-content').hide();
    $('.elementor-tab-content[data-tab="'+current[1]+'"]').show();
    // scroll to
    var headerHeight = $('#header').height()  // put here your header id to get its height.
    $([document.documentElement, document.body]).animate({
        scrollTop: $('.elementor-tab-title[data-tab="' + current[1] + '"]').closest('.elementor-widget-wrap').offset().top - headerHeight
    }, 2000)
}
</script>

Das Caching Plugin WP Rocket erzeugt einen automatischen Eintrag am Ende des Webseiten Quelltextes. Dieser lässt sich jedoch auch mit wenig Aufwand entfernen.

Lösung: Hierzu wird einfach in der wp-config.php Datei, der nachfolgende Eintrag hinzugefügt.

define('WP_ROCKET_WHITE_LABEL_FOOTPRINT', true);

Die meisten Caching Plugins bieten die Funktion zum Zusammenfassen von CSS und JavaScript Dateien, um damit eine Reduzierung der Dateien zu erreichen und somit die Ladegeschwindigkeit zu reduzieren. Vor allem bei der Zusammenfassung von JavaScript Dateien kommt es (je nach Menge der verwendeten JavaScript Dateien) oftmals zu Fehlern in der Darstellung.

Lösung: Ein guter Weg ist es, alle verwendeten JavaScript Dateien zur Ausnahme hinzuzufügen und im zweiten Schritt, diese einzeln wieder aus der Ausnahme zu nehmen, um festzustellen welche Datei bzw. Dateien eventuell zu den Fehlern führen. Um eine einfache Zusammenfassung alle JavaScript Dateien zu bekommen, lässt sich über das kostenlose Crawler Programm Xenu’s Link Sleuth, eine Liste exportieren.

Als WordPress Plugin Entwickler erhält man Zugang zum Repository, von wo aus das Plugin in das WordPress Verzeichnis ausgegeben wird. Im ersten Moment stellt sich jedoch die Frage, wie man seine Datei in das Repository übertragen kann.

Lösung: Das kostenlose TortoiseSVN ermöglicht genau dieses. Gibt man hier seine Repository URL ein, erhält man Zugriff zu seinem Verzeichnis. Erstmalig müssen auch die WordPress.com Zugangsdaten hinterlegt werden.

Woocommerce

Standartmäßig wird die Produktübersichtsseite von Woocommerce im Meta Title als „Produkte Archiv“ dargestellt.

Lösung: Wär das SEO Plugin Yoast im Einsatz hat, kann dort unter der Rubrik „Titel & Metas“, die Darstellung von Archive von Artikeltypen entsprechend anpassen.

Die Bezeichnung der Versandmethode wird im Warenkorb, sowie Checkout und in den E-Mails vor den Versandkosten dargestellt. Sofern es nur eine Versandmethode gibt, ist diese vorgestellte Bezeichnung eventuell überflüssig.

Lösung: Mit dem folgen Code Snippet, der in der function.php des Themes eingefügt werden muss, wird diese Bezeichnung entfernt.

add_filter( 'woocommerce_cart_shipping_method_full_label', 'bbloomer_remove_shipping_label', 10, 2 );

function bbloomer_remove_shipping_label($label, $method) {
$new_label = preg_replace( '/^.+:/', '', $label );
return $new_label;
}

Möchte ein Kunden im Warenkorb die Mengenanzahl noch einmal korrigieren, muss die Änderung anschließend durch den Button „Warenkorb aktualisieren“ übernommen werden.

Das kostenlose Plugin WooCommerce AJAX Cart bietet hier eine automatische Lösung, so das ein manuelle bestätigen des Buttons vermieden wird.

Leider fehlen bis heute standartmäßig in Woocommerce noch einige Funktionen, die bei anderen Shopsystemen als Standard dazugehören. Durch die Skalierbarkeit des Systems, lassen sich jedoch Wege finden, diese Änderungen nachträglich vorzunehmen.

Der nachfolgende Code sorgt für mehrere Dinge gleichzeitig. Zum einen lässt sich damit auf der Mein Konto Loginseite, sowie auf der Bestellübersichtsseite, eine Registrierung für den Kunden umsetzen. Zudem werden innerhalb der Registrierung noch zwei Extrafelder erzeugt, die zum einen auch für den Admin im Backend sichtbar und auch bei jeder Bestellemail dem Admin mit angezeigt werden. Der Code muss in der function.php des verwendeten Themes, am besten am Ende der Datei, angefügt werden.

  
// Extrafelder definieren
function woo_get_account_fields() {
      return apply_filters( 'woo_account_fields', array(
        'user_extrafeld1' => array(
          'type'        => 'text',
          'label'       => __( 'Extrafeld1', 'woocommerce' ),
          'placeholder' => __( '', 'woocommerce' ),
          'required'    => true,
          'sanitize'    => 'wc_clean',
          'description'       => 'Beschreibung Beispieltext',
          'hide_in_account'      => false,
          'hide_in_admin'        => false,
          'hide_in_checkout'     => false,
          'hide_in_registration' => false,
        ),
      
        'user_extrafeld2' => array(
          'type'        => 'text',
          'label'       => __( 'Extrafeld2', 'woocommerce' ),
          'placeholder' => __( '', 'woocommerce' ),
          'required'    => true,
          'sanitize' => 'wc_clean',
          'description'       => 'Beschreibung Beispieltext',
          'hide_in_account'      => false,
          'hide_in_admin'        => false,
          'hide_in_checkout'     => false,
          'hide_in_registration' => false,
        ),
      ) );
  }


  function woo_print_user_frontend_fields() {
      $fields            = woo_get_account_fields();
      $is_user_logged_in = is_user_logged_in();
   
      foreach ( $fields as $key => $field_args ) {
          $value = null;
   
          if ( $is_user_logged_in && ! empty( $field_args['hide_in_account'] ) ) {
              continue;
          }
   
          if ( ! $is_user_logged_in && ! empty( $field_args['hide_in_registration'] ) ) {
              continue;
          }
   
          if ( $is_user_logged_in ) {
              $user_id = woo_get_edit_user_id();
              $value   = woo_get_userdata( $user_id, $key );
          }
   
          $value = isset( $field_args['value'] ) ? $field_args['value'] : $value;
   
          woocommerce_form_field( $key, $field_args, $value );
      }
  }
  add_action( 'woocommerce_register_form', 'woo_print_user_frontend_fields', 10 );
  add_action( 'woocommerce_edit_account_form', 'woo_print_user_frontend_fields', 10 );


  function woo_checkout_fields( $checkout_fields ) {
      $fields = woo_get_account_fields();
   
      foreach ( $fields as $key => $field_args ) {
          if ( ! empty( $field_args['hide_in_checkout'] ) ) {
              continue;
          }
   
          $checkout_fields['account'][ $key ] = $field_args;
      }
   
      return $checkout_fields;
  }
  add_filter( 'woocommerce_checkout_fields', 'woo_checkout_fields', 10, 1 );


  function woo_print_user_admin_fields() {
      $fields = woo_get_account_fields();
      ?>
        <table class="form-table" id="woo-additional-information">
          <tbody>
          <?php foreach ( $fields as $key => $field_args ) { ?>
              <?php
              if ( ! empty( $field_args['hide_in_admin'] ) ) {
                  continue;
              }
   
              $user_id = woo_get_edit_user_id();
              $value   = woo_get_userdata( $user_id, $key );
              ?>
              <tr>
                  <th>
                      <label for="<?php echo $key; ?>"><?php echo $field_args['label']; ?></label>
                  </th>
                  <td>
                      <?php $field_args['label'] = false; ?>
                      <?php woocommerce_form_field( $key, $field_args, $value ); ?>
                  </td>
              </tr>
          <?php } ?>
          </tbody>
      </table>
      <?php
  }
  add_action( 'show_user_profile', 'woo_print_user_admin_fields', 30 );
  add_action( 'edit_user_profile', 'woo_print_user_admin_fields', 30 );


  function woo_get_edit_user_id() {
      return isset( $_GET['user_id'] ) ? (int) $_GET['user_id'] : get_current_user_id();
  }


  function woo_save_account_fields( $customer_id ) {
      $fields = woo_get_account_fields();
      $sanitized_data = array();
   
      foreach ( $fields as $key => $field_args ) {
          if ( ! woo_is_field_visible( $field_args ) ) {
              continue;
          }
   
          $sanitize = isset( $field_args['sanitize'] ) ? $field_args['sanitize'] : 'wc_clean';
          $value    = isset( $_POST[ $key ] ) ? call_user_func( $sanitize, $_POST[ $key ] ) : '';
   
          update_user_meta( $customer_id, $key, $value );
      }
   
      if ( ! empty( $sanitized_data ) ) {
          $sanitized_data['ID'] = $customer_id;
          wp_update_user( $sanitized_data );
      }
  }
  add_action( 'woocommerce_created_customer', 'woo_save_account_fields' );
  add_action( 'personal_options_update', 'woo_save_account_fields' );
  add_action( 'edit_user_profile_update', 'woo_save_account_fields' );
  add_action( 'woocommerce_save_account_details', 'woo_save_account_fields' );


  function woo_is_field_visible( $field_args ) {
      $visible = true;
      $action = filter_input( INPUT_POST, 'action' );
   
      if ( is_admin() && ! empty( $field_args['hide_in_admin'] ) ) {
          $visible = false;
      } elseif ( ( is_account_page() || $action === 'save_account_details' ) && is_user_logged_in() && ! empty( $field_args['hide_in_account'] ) ) {
          $visible = false;
      } elseif ( ( is_account_page() || $action === 'save_account_details' ) && ! is_user_logged_in() && ! empty( $field_args['hide_in_registration'] ) ) {
          $visible = false;
      } elseif ( is_checkout() && ! empty( $field_args['hide_in_checkout'] ) ) {
          $visible = false;
      }
   
      return $visible;
  }


  function woo_is_userdata( $key ) {
      $userdata = array(
          'user_pass',
          'user_login',
          'user_nicename',
          'user_email',
          'display_name',
          'nickname',
          'first_name',
          'last_name',
          'description',
          'rich_editing',
          'user_registered',
          'role',
          'jabber',
          'aim',
          'yim',
          'show_admin_bar_front',
    'user_extrafeld1',
    'user_extrafeld2',
      );
   
      return in_array( $key, $userdata );
  }


  function woo_validate_user_frontend_fields( $errors ) {
      $fields = woo_get_account_fields();
   
      foreach ( $fields as $key => $field_args ) {
          if ( empty( $field_args['required'] ) ) {
              continue;
          }
   
          if ( ! isset( $_POST['register'] ) && ! empty( $field_args['hide_in_account'] ) ) {
              continue;
          }
   
          if ( isset( $_POST['register'] ) && ! empty( $field_args['hide_in_registration'] ) ) {
              continue;
          }
   
          if ( empty( $_POST[ $key ] ) ) {
              $message = sprintf( __( '%s muss angegeben werden.', 'woo' ), '<strong>' . $field_args['label'] . '</strong>' );
              $errors->add( $key, $message );
          }
      }
   
      return $errors;
  }
  add_filter( 'woocommerce_registration_errors', 'woo_validate_user_frontend_fields', 10 );
  add_filter( 'woocommerce_save_account_details_errors', 'woo_validate_user_frontend_fields', 10 );


  function woo_add_post_data_to_account_fields( $fields ) {
      if ( empty( $_POST ) ) {
          return $fields;
      }
   
      foreach ( $fields as $key => $field_args ) {
          if ( empty( $_POST[ $key ] ) ) {
              $fields[ $key ]['value'] = '';
              continue;
          }
   
          $fields[ $key ]['value'] = $_POST[ $key ];
      }
   
      return $fields;
  }
  add_filter( 'woo_account_fields', 'woo_add_post_data_to_account_fields', 10, 1 );


  function woo_get_userdata( $user_id, $key ) {
      if ( ! woo_is_userdata( $key ) ) {
          return get_user_meta( $user_id, $key );
      }
   
      $userdata = get_userdata( $user_id );
   
      if ( ! $userdata || ! isset( $userdata->{$key} ) ) {
          return '';
      }
   
      return $userdata->{$key};
  }
  add_filter( 'default_checkout_billing_country', 'change_default_checkout_country' );
  add_filter( 'default_checkout_billing_state', 'change_default_checkout_state' );


  function change_default_checkout_country() {
    return 'DE';
  }
  function change_default_checkout_state() {
    return 'DE';
  }


  add_action( 'woocommerce_register_form_start', 'woo_add_name_woo_account_registration' );
  function woo_add_name_woo_account_registration() {
      ?>
   
      <p class="form-row form-row-first">
      <label for="reg_billing_first_name"><?php _e( 'First name', 'woocommerce' ); ?> <span class="required">*</span></label>
      <input type="text" class="input-text" name="billing_first_name" id="reg_billing_first_name" value="<?php if ( ! empty( $_POST['billing_first_name'] ) ) esc_attr_e( $_POST['billing_first_name'] ); ?>" />
      </p>
   
      <p class="form-row form-row-last">
      <label for="reg_billing_last_name"><?php _e( 'Last name', 'woocommerce' ); ?> <span class="required">*</span></label>
      <input type="text" class="input-text" name="billing_last_name" id="reg_billing_last_name" value="<?php if ( ! empty( $_POST['billing_last_name'] ) ) esc_attr_e( $_POST['billing_last_name'] ); ?>" />
      </p>
    <?php
      $countries_obj   = new WC_Countries();
      $countries   = $countries_obj->get_allowed_countries();
      woocommerce_form_field('billing_country', array(
      'type'       => 'select',
      'class'      => array( 'chzn-drop' ),
      'label'      => __('Land'),
      'placeholder'    => __(''),
      'options'    => $countries,
      'required' => 1
      )
    );?>
    
    <p class="form-row">
      <label for="reg_billing_address_1"><?php _e( 'Straße & Hausnummer', 'woocommerce' ); ?> <span class="required">*</span></label>
      <input type="text" class="input-text" name="billing_address_1" id="reg_billing_address_1" value="<?php if ( ! empty( $_POST['billing_address_1'] ) ) esc_attr_e( $_POST['billing_address_1'] ); ?>" />
      </p>
    
    <p class="form-row">
      <label for="reg_billing_postcode"><?php _e( 'Postleitzahl', 'woocommerce' ); ?> <span class="required">*</span></label>
      <input type="text" class="input-text" name="billing_postcode" id="reg_billing_postcode" value="<?php if ( ! empty( $_POST['billing_postcode'] ) ) esc_attr_e( $_POST['billing_postcode'] ); ?>" />
      </p>
    
    <p class="form-row">
      <label for="reg_billing_city"><?php _e( 'Ort / Stadt', 'woocommerce' ); ?> <span class="required">*</span></label>
      <input type="text" class="input-text" name="billing_city" id="reg_billing_city" value="<?php if ( ! empty( $_POST['billing_city'] ) ) esc_attr_e( $_POST['billing_city'] ); ?>" />
      </p>
    
    <p class="form-row">
      <label for="reg_billing_phone"><?php _e( 'Telefon', 'woocommerce' ); ?> <span class="required">*</span></label>
      <input type="text" class="input-text" name="billing_phone" id="reg_billing_phone" value="<?php if ( ! empty( $_POST['billing_phone'] ) ) esc_attr_e( $_POST['billing_phone'] ); ?>" />
      </p>
   
      <div class="clear"></div>
   
      <?php
  }
   

  add_filter( 'woocommerce_registration_errors', 'woo_validate_name_fields', 10, 3 );
  function woo_validate_name_fields( $errors, $username, $email ) {
      if ( isset( $_POST['billing_first_name'] ) && empty( $_POST['billing_first_name'] ) ) {
          $errors->add( 'billing_first_name_error', __( 'Vorname muss angegeben werden.', 'woocommerce' ) );
      }
      if ( isset( $_POST['billing_last_name'] ) && empty( $_POST['billing_last_name'] ) ) {
          $errors->add( 'billing_last_name_error', __( 'Nachname muss angegeben werden.', 'woocommerce' ) );
      }
    
     if ( isset( $_POST['billing_country'] ) && empty( $_POST['billing_country'] ) ) {
          $errors->add( 'billing_country_error', __( 'Land muss angegeben werden.', 'woocommerce' ) );
      }
    
     if ( isset( $_POST['billing_address_1'] ) && empty( $_POST['billing_address_1'] ) ) {
          $errors->add( 'billing_address_1_name_error', __( 'Straße & Hausnummer muss angegeben werden.', 'woocommerce' ) );
      }
    
     if ( isset( $_POST['billing_postcode'] ) && empty( $_POST['billing_postcode'] ) ) {
          $errors->add( 'billing_postcode_name_error', __( 'Postleitzahl muss angegeben werden.', 'woocommerce' ) );
      }
    
     if ( isset( $_POST['billing_city'] ) && empty( $_POST['billing_city'] ) ) {
          $errors->add( 'billing_city_name_error', __( 'Ort / Stadt muss angegeben werden.', 'woocommerce' ) );
      }
    
     if ( isset( $_POST['billing_phone'] ) && empty( $_POST['billing_phone'] ) ) {
          $errors->add( 'billing_phone_error', __( 'Telefon muss angegeben werden.', 'woocommerce' ) );
      }
    
      return $errors;
  }


  add_action( 'woocommerce_created_customer', 'woo_save_name_fields' );
  function woo_save_name_fields( $customer_id ) {
      if ( isset( $_POST['billing_first_name'] ) ) {
          update_user_meta( $customer_id, 'billing_first_name', sanitize_text_field( $_POST['billing_first_name'] ) );
          update_user_meta( $customer_id, 'first_name', sanitize_text_field($_POST['billing_first_name']) );
      }
      if ( isset( $_POST['billing_last_name'] ) ) {
          update_user_meta( $customer_id, 'billing_last_name', sanitize_text_field( $_POST['billing_last_name'] ) );
          update_user_meta( $customer_id, 'last_name', sanitize_text_field($_POST['billing_last_name']) );
      }
    if ( isset( $_POST['billing_country'] ) ) {
          update_user_meta( $customer_id, 'billing_country', sanitize_text_field( $_POST['billing_country'] ) );
      }
    if ( isset( $_POST['billing_address_1'] ) ) {
          update_user_meta( $customer_id, 'billing_address_1', sanitize_text_field( $_POST['billing_address_1'] ) );
      }
    if ( isset( $_POST['billing_postcode'] ) ) {
          update_user_meta( $customer_id, 'billing_postcode', sanitize_text_field( $_POST['billing_postcode'] ) );
      }
    if ( isset( $_POST['billing_city'] ) ) {
          update_user_meta( $customer_id, 'billing_city', sanitize_text_field( $_POST['billing_city'] ) );
      }
    if ( isset( $_POST['billing_phone'] ) ) {
          update_user_meta( $customer_id, 'billing_phone', sanitize_text_field( $_POST['billing_phone'] ) );
      }
   
  }


  function woo_add_customer_to_email_subject( $subject, $order ) {
    $subject = $order->billing_first_name . ' ' . $order->billing_last_name . ' - ' . $order->get_order_number() . ' - ' . $order->get_date_created()->format ('d.m.Y');
    return $subject;
  }
  add_filter( 'woocommerce_email_subject_new_order', 'woo_add_customer_to_email_subject', 1, 2 );


  add_filter('woocommerce_email_order_meta_keys', 'my_woocommerce_email_order_meta_keys');
  function my_woocommerce_email_order_meta_keys( $keys ) {
      $keys['Extrafeld111'] = '_user_extrafeld1';
      return $keys;    
  }


  add_filter( 'woocommerce_email_order_meta_fields', 'woocommerce_email_order_meta_fields_func', 10, 3 );
  function woocommerce_email_order_meta_fields_func( $fields, $sent_to_admin, $order ) {
    $fields['user_extrafeld1'] = array(
      'label' => __( 'Extrafeld1', 'woocommerce' ),
      'value' => wptexturize( get_post_meta( $order->id, 'user_extrafeld1', true ) )
    );
    $fields['user_extrafeld2'] = array(
      'label' => __( 'Extrafeld2', 'woocommerce' ),
      'value' => wptexturize( get_post_meta( $order->id, 'user_extrafeld2', true ) )
    );
    return $fields;
  }


  add_action( 'woocommerce_email_order_details', 'woo_add_transaction_id', 10, 4);
  function woo_add_transaction_id( $order, $sent_to_admin, $plain_text, $email ){
      $_output = null;
      
      if ($sent_to_admin) {
          $_user = $order->get_user();
          
          if($_user) {
              $_userId = $_user->ID;
              $_extrafeld1 = get_user_meta( $_userId, 'user_extrafeld1', true );
              $_extrafeld2 = get_user_meta( $_userId, 'user_extrafeld2', true ); 
              
              if($_extrafeld1 != '')
                  $_output = 'Extrafeld: ' . $_extrafeld1;
                  
              if($_extrafeld2 != '')
                  $_output .= '<br />Extrafeld: ' . $_extrafeld2;
          }
      }
      
      echo $_output;
  }

Von Haus aus sendet WordPress alle E-Mails, auch die verschiedenen Woocommerce Varianten, per Skript. Hier wird vor allem beim Betreiben eines Online-Shops deutlich, dass manche E-Mail Anbieter Probleme haben, diese E-Mails zuzustellen. Das Resultat sind Bestellbestätigungen, etc. die beim Kunden nie ankommen und an den Shop Betreiber als Mailer Demon Nachricht zurückkommen.

Lösung: Das kostenlose Plugin Post SMTP leistet hier Abhilfe. Damit werden die eigenen Mailaccount Daten in WordPress hinterlegt, so dass die E-Mails in Zukunft nicht mehr per eigenen Skript, sondern über den Mail Anbieter versendet werden. Die Fehlerquote sinkt damit auf ein Minimum.

Bindet man PayPal in seinem Shop als Zahlungsanbieter mit ein, sollte innerhalb von PayPal selbst, der Rückkehrlink zur Webseite ebenfalls hinterlegt werden. Dies sorgt dafür das nach erfolgter Bezahlung, der Nutzer von der PayPal Webseite zurück zum eigenen Shop geleitet wird. Hier erhält der Nutzer dann noch eine Bestellübersicht.

Lösung: Der Link https://www.eigenewebseite.de/checkout/order-received/ führt zur Bestellzusammenfassung, sofern man die Übersetzung bzw. Bezeichnung der Seite im WordPress Backend nicht geändert hat.

Da die Ansprache im englischen nicht zwischen Du und Sie unterscheidet, ist in den Grundeinstellungen des Shops auch die Du Variante voreingestellt. Nun möchte nicht jeder seine Kunde mit Du ansprechen.

Lösung: Im WordPress Backend findet man unter Einstellungen > Allgemein > Sprache der Website > Deutsch (Sie), die passende Einstellung. Leider werden nicht immer alle Woocommerce Elemente auch in Sie Form übersetzt.

In diesem Fall muß man die Sprachdatei von Hand anpassen. Hierzu eignet sich das kostenlose Programm Poedit, in der sich die Sprachdatei bearbeiten lässt. Diese befindet sich unter/wp-content/languages/plugins/woocommerce-de_DE.po

Die Dankes- bzw. Bestellbestätigungsseite lässt sich auf unterschiedliche Weise anpassen, sofern man gänzlich auf Plugins verzichten möchte.

1. Variante: Per Weiterleitung zu einer eigenen Unterseite

add_action( 'template_redirect', 'woo_custom_redirect_after_purchase' );
function woo_custom_redirect_after_purchase() {
  global $wp;
  if ( is_checkout() && !empty( $wp->query_vars['order-received'] ) ) {
    wp_redirect( 'https://www.zurgewuenschtenseite.de' );
    exit;
  }
}

2. Variante: Anpassen der Woocommerce Seite

// Ändern der Überschrift

add_filter( 'the_title', 'woo_title_order_received', 10, 2 );
function woo_title_order_received( $title, $id ) {
  if ( function_exists( 'is_order_received_page' ) && 
       is_order_received_page() && get_the_ID() === $id ) {
    $title = "Vielen Dank für Ihre Bestellung und alles andere";
  }
  return $title;
}
// Ändern der zweite Überschrift

add_filter('woocommerce_thankyou_order_received_text', 'woo_change_order_received_text', 10, 2 );

function woo_change_order_received_text( $str, $order ) {
    $new_str = 'Dies steht nun in der zweiten Zeile';
    return $new_str;
}
// Weiterleiten zu einer eigenen Unterseite bei einem bestimmten Produkt (Grundlage ist die Produkt ID)

add_action( 'woocommerce_thankyou', 'redirect_product_based', 1 ); 
function redirect_product_based ( $order_id ){
            $order = wc_get_order( $order_id );
            foreach( $order->get_items() as $item ) {
                if ( $item['product_id'] == 643 ) {
                     wp_redirect( 'https://www.weiterleitungzurunterseite' );
                
                }
            }        
}

Diese Woocommerce Fehlermeldung ist etwas irreführend, da sie in unterschiedlichen Zusammenhängen auftreten kann.

Lösung: Wenn man sich sicher ist, dass die Versandklassen und Methoden richtig eingestellt und aktiviert wurden, sollte einmal die eingesetzten Plugins testen. Oftmals kann es passieren, dass sich Shipping Plugins gegenseitig stören.

Woocommerce bietet dank WordPress die Möglichkeit verschiedene Nutzergruppen zu erstellen. Der Standartbenutzer als Wocommerce Kunde ist Customer. Nun lässt sich z.B. eine weitere Benutzergruppe mit denselben Rechten erstellen, die dann z.B. als Wiederverkäufer tätig sind. Soll diese bestimmte Nutzergruppe eine zusätzliche Zahlungsmöglichkeit besitzen, die „normale“ Kunden nicht sehen können, lässt sich das wie folgt lösen.

Lösung: Folgendes Skript wird in der function.php des Theme am Ende eingefügt.

function customer_disable_manager( $available_gateways ) 
{global $woocommerce;
if ( isset( $available_gateways['hierdiezahlungsart'] ) && current_user_can('customer') ) {
   unset( $available_gateways['hierdiezahlungsart'] );
}
return $available_gateways;
}
add_filter( 'woocommerce_available_payment_gateways','customer_disable_manager' );

Wenn auf der Checkout Seite die Bereiche Zahlungsart und Artikelübersicht endlos Laden, liegt ein größerer Fehler vor. Leider ist dieser Fehler nie eindeutig, da es durchaus auch ein Konflikt mit einem anderen Skript geben kann.

Lösung: Sofern nicht unbedingt benötigt, sollte man einmal überprüfen, ob ein abschalten des Geo-Lokalisierung in Woocommerce Abhilfe schafft.

In Woocommerce fehlt standartmäßig eine Anzeige des gesparten Preises, wenn ein Aktionspreis hinterlegt wurde. Mit dem nachfolgenden Code der in der functions.php hinterlegt wird, lässt sich der gesparte preis, samt Prozentsatz in der Kategorieansicht, sowie den Produktdetails anzeigen.

function ts_you_save() {
  
  global $product;
  
   if( $product->is_type('simple') || $product->is_type('external') || $product->is_type('grouped') ) {
      
     	$regular_price 	= get_post_meta( $product->get_id(), '_regular_price', true ); 
        $sale_price 	= get_post_meta( $product->get_id(), '_sale_price', true );
     
     	if( !empty($sale_price) ) {
  
              $amount_saved = $regular_price - $sale_price;
              $currency_symbol = get_woocommerce_currency_symbol();

              $percentage = round( ( ( $regular_price - $sale_price ) / $regular_price ) * 100 );
              ?>
              <p class="you_save_price">Du sparst <?php echo number_format($amount_saved,2, '.', '')."€  (". number_format($percentage,0, '', '')."%)"; ?></p>						
              <?php		
        }
   }
}

add_action( 'woocommerce_single_product_summary', 'ts_you_save', 15 );
add_action( 'woocommerce_after_shop_loop_item', 'ts_you_save', 5 );

Mit einem einfachen Hook lassen sich Advanced Custom Fields (ACF) auch in Woocommerce integrieren.

add_action( 'woocommerce_before_add_to_cart_form', 'acf_field_woo', 30 ); 
 
function acf_field_woo() { 
echo get_field('feldname'); 
}

Im Woocommerce Bestellabschluss gibt es nur ein Feld für die Straße & Hausnummer. Leider kommt es oft vor das der Nutzer genau diese Hausnummer vergisst. Mit dem nachfolgenden Snippet wird geprüft ob das genannte Feld auch eine Hausnummer enthält.

add_action('woocommerce_checkout_process', 'custom_validation_process');
function custom_validation_process()
{
    global $woocommerce;
 
    if(isset($_POST['billing_address_1']) and $_POST['billing_address_1'] != '')
    {
        if (!preg_match('/([0-9]+)/Uis', $_POST['billing_address_1']))
        {
            if(function_exists('wc_add_notice'))
                wc_add_notice( __('Haben Sie die Hausnummer bei der Stra&szlig;e vergessen?'), 'error' );
            else
                $woocommerce->add_error( __('Haben Sie die Hausnummer bei der Stra&szlig;e vergessen?') );
        }
    }
   
    if(isset($_POST['ship_to_different_address']))
    {
        if(isset($_POST['shipping_address_1']) and $_POST['shipping_address_1'] != '')
        {
            if (!preg_match('/([0-9]+)/Uis', $_POST['shipping_address_1']))
            {
                if(function_exists('wc_add_notice'))
                    wc_add_notice( __('Haben Sie die Hausnummer bei der Stra&szlig;e vergessen?'), 'error' );
                else
                    $woocommerce->add_error( __('Haben Sie die Hausnummer bei der Stra&szlig;e vergessen?') );
            }
        }
    }
}

Um für ein bestimmtes Land im Shop einen Mindestbestellbetrag zu hinterlegen, hilft der nachfolgen Code Schnipsel. Zusätzlich sollte man noch einen textlichen Hinweis einfügen, um möglichen Käufern schon im Vorfeld über den Mindestbestellbetrag zu informieren.

add_action( 'woocommerce_check_cart_items', 'cw_min_num_products' );
function cw_min_num_products() {
  if( is_cart() || is_checkout() ) {
    global $woocommerce;
                $minimum = 20;
    	$county = array('DE');   
                $cart_tot_order = WC()->cart->total;
    if( $cart_tot_order < $minimum && in_array( WC()->customer->get_shipping_country(), $county )  ) {
          wc_add_notice( sprintf( '<strong>A Minimum order of $%s is required before checking out.</strong>' 
          	. '<br />Current order: $%s.',
          	$minimum,
                $cart_tot_order	),
          'error' );
    }
  }
}

Joomla

Bei Aktualisierungen des Joomla Core´s kommt es oft zu der Fehlermeldung: Ajax Loading Error: Forbidden. Verursacht wird dieser Fehler durch den .htaccess Schutz in den entsprechenden Ordnern. Die Folge ist ein Fehlschlagen der Aktualisierung.

Lösung: Deaktiviert man für die Dauer der Aktualisierung die htaccess Dateien, z.B. durch umbenennen in .#htacess /administrator/components, läuft des Update problemlos durch.

Alte Joomla Installationen können für große Probleme sorgen, wenn diese aktualisiert werden sollen, nachdem über Jahre hinweg, keine Updates mehr vorgenommen wurden. Auch alte Joomla Templates sind da keine Ausnahme.

Lösung: Unter folgenden Link findet sich eine Schritt für Schritt Anleitung: http://go-lux.de/go-lux-stellt-sich-vor/webtec/45-joomla-template-migrieren-1-5-nach-3-x

CSS & JavaScript

Manchmal kann es etwas umständlich sein, wenn man nach einer Verlinkung sucht, die entfernt werden soll. Wenn gar nichts mehr geht, kann man sich mit folgenden CSS Snippet behelfen. Dieser löscht zwar nicht die Verlinkung, sorgt aber dafür, dass sich dieser nicht mehr anklicken lässt.

.beispielelement { pointer-events: none; }

Die CSS Methode object-fit bietet ideale Lösungen, um Bilder an ein festen Seitenformat anzupassen. Leider ist in alten IE Version diese Methode nicht präsent. Ein Workaround bietet:

https://github.com/bfred-it/object-fit-images

Ein kleines Script, sorgt dafür das der IE mitspielt.

Dafür muss neben der normalen Anweisung, ein zusätzlicher Eintrag gemacht werden:

object-fit: contain;
font-family: 'object-fit: contain;'

Die Überschrift klingt vielleicht etwas verwirrend, letztlich geht es aber um eine Problemstellung, die immer mal wieder auftreten kann. Man benötigt einen Full Width Container genau an der Stelle, wo sich jedoch ein übergeordneter Container befindet, dessen breiten deutlich geringer ist.

Lösung: Mit folgenden Code Snippet lässt sich dieses Problem beheben.

html

<div class="container">
<div class="row-full">--- Full width container ---</div>
</div>

css

.row-full{
 width: 100vw;
 position: relative;
 margin-left: -50vw;
 height: 100px;
 margin-top: 100px;
 left: 50%;
}

Sofern man auf entsprechende Grafiken verzichten möchte und eine CSS Lösung vorzieht, ist folgendes Snippet recht hilfreich:

.element { transform: skewY(-12deg); }

Mit einer kuzzen Codezeile ist dieses Problem schnell gelöst.

.klassenname { height: 100vh; }

Wenn nur eine Anpassung mit CSS möglich ist um eine Bild an eine bestimmte Stelle zu platzieren, bietet sich die Lösung per :after Pseudoelement an.

.dasbild:after {
    background-image: url('/images/bild.png');
    background-size: 10px 20px;
    display: inline-block;
    width: 10px; 
    height: 20px;
    content:"";
}

Möchte man auf die typischen Bullet Points verzichten und alternative html Symbole einer Liste voranstellen, bringen diese Codezeilen den gewünschten Erfolg.

ul {
  list-style: none;
}

ul li:before {
  content: '✓';
}

Oftmals lassen sich html Anker nicht richtig positionieren, so dass es wünschenswert wäre, wenn der Anker bereits einige Pixel oberhalb der eigentlichen Position beginnen würde.

Nachfolgend finden sich eine einfache Lösung per CSS, sowie eine Variante mit jQuery, die ein langsameres sliden zum Anker ermöglicht.

Lösung: In beiden Fällen sorgt der top-Wert (-250px) für die gewünschte Positionierung.

a.anchorPos {
    display: block;
    position: relative;
    top: -250px;
    visibility: hidden;
}
jQuery(function() {
                jQuery('a[href*="#"]:not([href="#"])').click(function() {
                  if (location.pathname.replace(/^\//,'') == this.pathname.replace(/^\//,'') && location.hostname == this.hostname) {
                    var target = jQuery(this.hash);
                    target = target.length ? target : jQuery('[name=' + this.hash.slice(1) +']');
                    if (target.length) {
                      jQuery('html, body').animate({
                        scrollTop: target.offset().top -250
                      }, 1100); //scrolling speed
                      return false;
                    }
                  }
                });
              });

Vor allem in Safari scheint die Formatierung eines select Feldes nicht mit den Standard Einstellungen zu funktionieren. Nachfolgend eine einfache Lösung womit der Abstand zum linken Rand erhöht werden kann.

padding-left:17px; 
-webkit-padding-start:17px;

Nachfolgend ein einfaches Hamburger Menü (Toggle Menü) das ohne JavaScript auskommt.

html

<nav role="navigation">
  <div id="menuToggle">
    <input type="checkbox" />
    <span></span>
    <span></span>
    <span></span>
    <ul id="menu">
      <a href="#"><li>Home</li></a>
      <a href="#"><li>About</li></a>
      <a href="#"><li>Info</li></a>
      <a href="#"><li>Contact</li></a>
    </ul>
  </div>
</nav>

CSS

#menuToggle
{
  display: block;
  position: relative;
  top: 50px;
  left: 50px;
  z-index: 1;
  -webkit-user-select: none;
  user-select: none;
}

#menuToggle input
{
  display: block;
  width: 40px;
  height: 32px;
  position: absolute;
  top: -7px;
  left: -5px;
  cursor: pointer;
  opacity: 0;
  z-index: 2;
  -webkit-touch-callout: none;
}

#menuToggle span
{
  display: block;
  width: 33px;
  height: 4px;
  margin-bottom: 5px;
  position: relative;
  background: #cdcdcd;
  border-radius: 3px;
  z-index: 1;
  transform-origin: 4px 0px;
  transition: transform 0.5s cubic-bezier(0.77,0.2,0.05,1.0),
              background 0.5s cubic-bezier(0.77,0.2,0.05,1.0),
              opacity 0.55s ease;
}

#menuToggle span:first-child
{
  transform-origin: 0% 0%;
}

#menuToggle span:nth-last-child(2)
{
  transform-origin: 0% 100%;
}

#menuToggle input:checked ~ span
{
  opacity: 1;
  transform: rotate(45deg) translate(-2px, -1px);
  background: #232323;
}

#menuToggle input:checked ~ span:nth-last-child(3)
{
  opacity: 0;
  transform: rotate(0deg) scale(0.2, 0.2);
}

#menuToggle input:checked ~ span:nth-last-child(2)
{
  transform: rotate(-45deg) translate(0, -1px);
}

#menu
{
  position: absolute;
  width: 300px;
  margin: -100px 0 0 -50px;
  padding: 50px;
  padding-top: 125px;
  background: #ededed;
  list-style-type: none;
  -webkit-font-smoothing: antialiased;
  transform-origin: 0% 0%;
  transform: translate(-100%, 0);
  transition: transform 0.5s cubic-bezier(0.77,0.2,0.05,1.0);
}

#menu li
{
  padding: 10px 0;
  font-size: 22px;
}

#menuToggle input:checked ~ ul
{
  transform: none;
}

 

Schön und einfach ist es z.B. den YouTube Einbettungscode einzufügen. Jedoch müssen dafür feste Werte eingegeben werden, das auf Mobilen Geräte dann immer wieder zu Darstellungsproblemen führt.

Lösung: Mit folgenden Code lässt sich das Problem umgehen.

<div class="embed-container">//Hier wird das iframe eingefügt.</div>
.embed-container {
  position: relative;
  padding-bottom: 56.25%; /* ratio 16x9 */
  height: 0;
  overflow: hidden;
  width: 100%;
  height: auto;
}

.embed-container iframe {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
}

/* ratio 4x3 */
.embed-container.ratio4x3 {
  padding-bottom: 75%;
}

Mit CSS erzeugte Kreise sehen oftmals an den Rändern unsauber aus, mit der box-shadow Eigenschaft, lässt sich dies ändern.

-mox-box-shadow: 0 0 1px white;
-webkit-box-shadow: 0 0 1px white;
box-shadow: 0 0 1px white;

Mit ein wenig CSS lassen sich problemlos farbliche Overlays über Bilder erstellen. Dafür muss das entsprechende Bild lediglich innerhalb eines <div> liegen.

.card-overlay{
  position: relative;
}
.card-overlay:after {
  content:'';
  position:absolute;
  left:0px;
  top:0px;
  width:100%;
  height:100%;
  background: rgba(0, 0, 0, 0.5);
}

Es gibt viele Möglichkeiten eine Weiterleitung, sei es intern oder extern, umzusetzen. Wenn hingegen weder das Einbinden eines Codes, in den Header, Footer oder als body onload möglich ist und darüber hinaus auch auf jQuery verzichtet werden muss, werden die Lösungswege weniger.

Nachfolgend ein einfaches Skript, was innerhalb des body eingefügt werden muss.

<script language="javascript" type="text/javascript">
          <!--
  setTimeout(function()
  {window.open('https://www.hiergehteszurgewuenschtenwebseite.de', '_blank');
             } , 1000);
  
          // –>
</script>

In manchen Fällen ist es nötig, dass Text mit einer bestimmten Zeichenlänge gekürzt wird. Der nachfolgende Code ermöglicht genau dieses. Ist der Text länger als 53 Zeichen, wird dieser gekürzt und ein … angefügt.

jQuery(function($) { 
$(".page-id-1 .title a").text(function(index, currentText) {
  if (currentText.length > 53) {
    return currentText.substr(0, 53)+'...';
  }
});
});

Nachträglich jQuery Code einzufügen ist keine Seltenheit, in Kombination mit dem Revolution Slider kann es hier aber zu Konflikten kommen, so das entweder der Code oder der Slider nicht reagieren.

Lösung: jQuery Bibliotheken nutzen jQuery() und $(), man sollte hier jQuery() verwenden, um Konflikte zu vermeiden.

jQuery ( function($) {
//Hier den Code einfügen
} );

Es kann Webseiten Elemente geben (Buttons, Popups) die erst nach etwas scrollen auf der gewünschten Seite erscheinen sollen.

Lösung: Folgendes Skript sorgt genau für diesen Effekt. Dieses sollte im Header integriert werden.

$(document).scroll(function () {
    var y = $(this).scrollTop();
    if (y > 900) {
        $('.meinButton').fadeIn();
    } else {
        $('.meinButton').fadeOut();
    }
});

Der Wert 900 dient hier als Abstand. Das Element wird also sichtbar, wenn man mindestens 900 Pixel nach unten gescrollt hat.

Alternative:

jQuery(window).scroll(function(){
  if(jQuery(document).scrollTop() > 200){
    jQuery('.mehr-pfeil').hide();
  } else {
    jQuery('.mehr-pfeil').show();  
  }
});

Die Problemstellung ist recht einfach. Wir haben zu viel Text auf einer Seite und wollen einen Teil dieses Textes ausblenden und nur bei Bedarf einblenden lassen. Diese Funktion soll über einen Button geschehen. Dieser ist mit „Mehr“ beschriftet und soll sich in „Weniger“ ändern, wenn der restliche Text eingeblendet wird.

Lösung: Folgendes Code Snippet jetzt diese Bedingung um.

// #btn-mehr ist die ID des Buttons, #mehr-text die ID des versteckten Contents

jQuery( document ).on( 'click',  '#btn-mehr', function( event ) {
   event.preventDefault();
   jQuery('#mehr-text').fadeToggle("slow");
   if(jQuery('#btn-mehr .button-text').text() == "Mehr"){
       jQuery('#btn-mehr .button-text').text("Weniger");
    }else{
       jQuery('#btn-mehr .button-text').text("Mehr");
    }
});

Und damit der entsprechende Content auch im Vorfeld ausgeblendet ist, muss noch etwas CSS Code verwendet werden.

#mehr-text {
    display: none;
}

Google & Co

Mit wenigen Schritten lässt sich ein mailto:, sowie tel: Link mit Google Analytics tracken. Hierbei sind zwei Schritte nötig.

Aufbau tel:

<a href="tel:+310123456789" onclick="gtag('event', 'Click', { 'event_category': 'Call' });">Linkname</a>

Aufbau mailto:

<a href="mailto:info@example.com" onclick="gtag('event', 'Click', { 'event_category': 'Email' });">Linkname</a>

Skript Alternative:

<script src="https://code.jquery.com/jquery-3.1.0.js"></script>
<script>
$("[href*='tel:'], [href*='mailto:']").click(function(e) {

  e.preventDefault();
  var href = $(this).attr('href');

  // tel:
  if (href.toLowerCase().indexOf("tel:") >= 0) {
    eventCategory = 'Call';
    eventLabel = href.replace('tel:', '');

  }

  // mailto:
  if (href.toLowerCase().indexOf("mailto:") >= 0) {
    eventCategory = 'Email';
    eventLabel = href.replace('mailto:', '');
  }

  gtag('event', 'Click', {
    'event_category': eventCategory,
    'event_label': eventLabel
  });

  setTimeout(function() {
    window.location = href;
  }, 500);

});
</script>

Das Skript sollte dann eingesetzt werden, wenn generell alle mailto und tel Links auf einer Webseite getrackt werden sollen.

Einstellungen in Analytics:
Damit Analytics die Klicks nun auch verarbeiten kann, muß unter Verwaltung -> Zielvorhaben ein neues Ereignis angelegt werden.

analytics-ereignis

Eine Variante um ein Kontaktformular mit Google Analytics tracken zu können ist es, nicht das Formular selbst, sondern eine anschließende Erfolgsseite zu tracken.

Dafür stellt man das Kontaktformular so ein, das es nach erfolgten senden zu einer Seite weiterleitet, die dem Nutzer das erfolgreiche Absenden noch einmal bestätigt. Diese Seite ist es dann, die als neues Zielvorhaben in Analytics hinterlegt wird.

analytics-weiterleitung

Um Google Analytics rechtssicher einbinden zu können, muss u.a. die IP Adresse des Nutzers anonymisiert werden. Welche Punkte darüber gehend noch beachtet werden müssen, erkläre ich u.a. in diesem Video Tutorial.

ga('set', 'anonymizeIp', true);

Startet man eine Kampagne mit Facebook Ads, z.B. um eine Landingpage zu bewerben, glaubt man vermutlich an einen Fehler, wenn man die Facebook Insights Daten, mit den Google Analytics Werten von der Landingpage vergleicht. Hier kommt es zu teilweise extremen Differenzen.

Hintergrund: Analytics und Facebook haben grundlegend verschiedene Ansätze, wie dessen Werte gemessen werden. Aus diesem Grund ist es nicht ungewöhnlich, das Facebook zwar 500 Klicks gezählt hat, auf der Landingpage laut Analytics aber nur 30 Personen waren.

Mehr Infos: Auf ANALYTICSkiste geht Michaela Linhart ins Detail und erklärt die genauen Hintergründe und mögliche Lösungsansetze.

Wer einen Google My Business Eintrag sein eigenen nennt und hier seine Bewertungen erhöhen möchte, ist mit einer Verlinkung von der eigenen Webseite zu genau diesen Rezesionen gut beraten. So können Webseiten Besucher direkt eine Rezension auf Google schreiben.

Der Link zur Bewertung sieht folgendermaßen aus:

https://search.google.com/local/writereview?placeid=XXXXXXXXXXXXXXXXXXXXXXXXXXX

Die mit X gekennzeichnete PlaceID, ist die eindeutige Adresse zum eigenen Google My Business Eintrag. Nutzen Sie den Google eigenen Dienst PlaceID Lookup Tool um die entsprechende Adresse zu finden.

Mit Kritik muss man umgehen können, sofern Sie sachlich gehalten wird und den rechtlichen Bestimmungen unterliegen. Verleumdungen und das Behaupten falscher Tatsachen, muss hingegen niemand hinnehmen.

Neben dem Melden-Button neben der Rezension selbst, kann über das folgenden Formular direkt mit Google kommuniziert werden.

Wenn auch diese Variante ohne Erfolg bleibt, leider ist Google hier meist nicht hilfreich, sollte man sich an einen Anwalt wenden, der ein entsprechendes Schreiben an Google aufsetzt, dessen Erfolgschance deutlich höher sind.

Wär fremde Plugins benutzt, um Google Map auf der Webseite zu integrieren, sieht oft anstatt der gewünschte Karte den Hinweis „Hoppla, ein Fehler ist aufgetreten.“

Lösung: Zu allererst muss ein Google API Key erstellt werden, dies ist unter https://developers.google.com/maps/documentation/javascript/ möglich, wenn man dort auf Schlüssel anfordern klickt (ein Google Konto ist Voraussetzung). Der anschließend erzeugte Schlüssel wird in das entsprechende Plugin integriert. Mittlerweile muss im Google Konto eine Kredidkarte hinterlegt sein, damit die Karte auch wirklich aktiv geschaltet wird.

Funktioniert dies nicht so ohne weiteres, kann man dies auch manuell erledigen. Dafür sucht man in den Plugin Dateien nach dem Link zur Google Map und ergänzt diesen, wie in dem folgenden Beispiel:

<script type='text/javascript' src='https://maps.googleapis.com/maps/api/js?key=AIzaSyD_6SsSIeIwhkHkHVfvM_gj4nVjtOqkBQw&#038;language=de&#038;ver=1'></script>

Server / Hoster

Verwendet man ein Plugin wie Contact Form 7 um ein Kontaktformular auf seiner Webseite zu verwenden, besitzt HostEurope eine besondere Sicherheitseinstellung. Unter Produktverwaltung > WebHosting > Skripte&Datenbanken > Skript-Einstellungen muss die Absender E-Mail Adresse eingetragen sein, die identisch mit der im Plugin hinterlegten ist. Andernfalls werden diese Nachrichten, trotz erfolgreichen Versenden, nie zugestellt.

Unabhängig welches CMS eingesetzt wird, die Dateien- und Verzeichnisrechte sollten immer richtig gesetzt sein, da diese zur Sicherheit einer Webseite wesentlich beitragen.

Die einfachste Variante, um diese Rechte für eine Vielzahl an Ordnern, Unterordnern und Dateien setzen zu können, ist der Einsatz per SSH Verbindung. Für Windows Systeme gibt es das kostenlose Programm PuTTY, das eine solche verschlüsselte Verbindung zum Server ermöglicht.

WordPress nennt für Verzeichnisse (Ordner) die Rechte 755, für Dateien 644.
Ersetzt man die beiden in kursiv gesetzten Pfade durch die Server eigenen  absoluten Pfade (Document Root), werden alle darin befindlichen Ordner und Dateien automatisch angepasst.

Für Verzeichnisse:
find /path/to/your/wordpress/install/ -type d -exec chmod 755 {} \;

Für Dateien:
find /path/to/your/wordpress/install/ -type f -exec chmod 644 {} \;

Wird eine bereits in Suchmaschinen indexierte Webseite überarbeitet oder erst einmal generell abgeschaltete, macht es eventuell Sinn, alle bisherigen Seiten auf eine Startseite oder Wartungsseite weiterzuleiten. Durch das anpassen der .htaccess Datei im Hauptverzeichnis der Webseite, ist dies recht einfach möglich.

Aus SEO Sicht ist dies Variante nicht zu empfehlen, da es dadurch automatisch zu Ranking Verlusten kommen kann. In Fällen wo dies jedoch vernachlässigt werden kann, ist dieser Code Schnipsel recht hilfreich.

Lösung:

RewriteEngine On
RewriteBase /

RewriteCond %{REQUEST_URI} !^/(index\.html)?$ [NC]
RewriteRule ^.*$ /index.html [L,R=301]

Wurde ein Link versehentlich mit Leerzeichen veröffentlicht worden, wird der Nutzer diesen nicht öffnen können. Hier kann eine Weiterleitung von der fehlerhaften Domain sinnvoll sein.

Lösung:

Redirect 301 "/pfadmit leerzeichen.php" https://www.beispieldomain.de/pfadohneleerzeichen.php

Alternative, falls die obere variante auf dem Server nicht funktioniert:

Redirect 301 /pfadmit[\s]leerzeichen.php http://www.beispieldomain.de/pfadohneleerzeichen.php

Bei einigen Hostern ist das erhöhen des Memory Limits nur per php.ini Datei möglich. Hierzu erstellt man eine entsprechende leere Datei mit einem Editor und fügt zusätzlich noch die nachfolgende Zeile ein.

memory_limit = 256M

In WordPress muss sich diese Datei z.B. im wp-admin Ordner befinden, damit diese aktiv genutzt werden kann.

Auf der Webseite wurde erfolgreich ein SSL Zertifikat hinterlegt, doch die Webseite wird immer noch als unsicher betrachtet. Hier liegt es meist an Mixed Content, also eine Vermischung von sicheren und unsicheren Inhalten.

Lösung: Generell gilt es alle bestehenden Links von http auf https zu ändern. Lässt sich die fehlerhafte Verlinkung aber nicht finden, hilft die Verwendung von Google Chrome. Hier klickt man auf der entsprechenden Seite auf die rechte Maustaste, anschließend auf Untersuchen -> Console. Hier wird dann das genaue Element angezeigt und eine schnelle Fehlerbehebung ist möglich.

Tools & Links

Wer schnell eine kleine CSS Animation erstellen möchte, ohne direkt alle Befehle griffbereit zu haben, kann sich einem Online Tool wie cssanimate.com behelfen.

Hin und wieder tauchen Datenbank Dateien auf, die mehrere hundert MB groß sein können. Versucht man diese durch phpMyAdmin hochzuladen, kann es aufgrund der Dateigrößen Beschränkung zu Problemen kommen.

Lösung: Mit dem Tool „SQL Dump Splitter“ kann die Datenbank, erst einmal in kleine handliche Dateien aufgeteilt werden. Durch das php Skript „Big Dump“ was man in einem eigenen Verzeichnis auf dem Server ablegt und darin die aufgeteilten Datenbanken hoch lädt, funktioniert das Importieren schnell und unkompliziert.

Postet man einen Beitrag samt Webseiten Link, generiert Facebook aus den vorhandenen Link eine Auswahl an möglichen Vorschaubildern. Ist man mit der Auswahl nicht zufrieden bzw. wird nicht das richtige Bild angezeigt, gibt es zwei Lösungswege.

1. Wurde das Bild auf der Webseite schon korrigiert, aber Facebook hat dieses noch nicht übernommen, lässt sich über den Facebook Debugger, der entsprechende Webseiten Link neu einlesen.
Gibt es eventuell danach immer noch Probleme, lässt sich z.B. über das WordPress Plugin Yoast, ein Facebook Bild, für die entsprechende Unterseite bereits im Vorfeld festlegen.

2. Wurde der Beitrag bereits gepostet, muss dieser nicht unbedingt gelöscht werden. Klickt man den Beitrag oben rechts über den Pfeil an, gibt es hier die Möglichkeit, das Vorschaubild ebenfalls neu einlesen zu lassen.

Mit dem kostenlos Programm MailStore lassen sich E-Mails und Accounts problemlos sichern, unabhängig welche Anbieter oder Client man verwendet.

Neben der generellen Sicherung ist dies ein einfach Art, vor einem Domain Umzug eine Sicherung seiner bisherigen E-Mails vorzunehmen, vor allem wenn diese per IMAP Protokoll abgerufen wurden und nach einem Umzug automatisch gelöscht werden würden.

Aufgrund verschiedenster E-Mail Clients und Anbieter ist das Gestalten einer E-Mail recht umständlich. Wenn Logos als Signatur mitgesendet werden sollen, kommen diese beim Empfänger schon einmal anders an als gedacht.

Eine Möglichkeit ist das Logo im Inline Embedding Verfahren mit der E-Mail zu verschmelzen. Dafür muss im Vorfeld das Bild bzw. Logo in das Format Base64 umgewandelt werden.

Unter base64-image.de ist dies kostenlos möglich. Anschließend wird das Bild als <img> Tag eingefügt und wahlweise dann auch noch mit einem <a> Tag versehen, um das Bild mit der Webseite zu verlinken.

WordPress bietet für fast alle Bedürfnisse unterschiedlichste Plugins, kostenlose sowie kostenpflichtige und diese lassen sich in der Regel auch schnell finden. Nachfolgend eine Liste von hilfreichen Plugins, für die ich doch einmal länger suchen musste, dafür genau dies erfüllten, wofür sie benötigt wurden. Zudem sind alle aufgezählten Plugins kostenlos.

Phoenix Media Rename – Hiermit lassen sich nachträglich Dateinamen in der Mediathek anpassen. Auch bereits eingefügte Dateien, können automatisch umbenannt werden ohne diese neu verlinken zu müssen.

Enable Media Replace – geht noch einen Schritt weiter, hier lassen sich Medien komplett auswechseln ohne das diese neu im Content eingefügt werden müssen.

Visual Portfolio – Hilfreiche Portfolio Galerie mit allen Funktionen und Filtern, die man sonst nur bei kostenpflichtigen Plugins findet.

Fatal Error Notify – Sendet dem Seitenbetreiber eine E-Mail zu, wenn die Webseite z.B. auf Grund eines schweren Fehlers nicht mehr dargestellt werden kann.

Contact Form 7 – Repeatable Fields – Ist ein Addon für das Contact Form 7 Plugin und sorgt anhand von Gruppen dafür, das gewünschte Felder beliebig oft wiederholt werden können.

GamiPress – Belohnungssystem für Nutzer.

Dank Video DownloadHelper lässt sich so gut wie jedes Video herunterladen. Die Erweiterung wird in Firefox installiert, zusätzlich muß noch die Video DownloadHelper Companion App 1.2.4 , als zusätzliches Programm ebenfalls installiert werden.

So einfach geht es:

1.) Strg + H (Ersetzen)
2.) Wählen Extended aus SearchMode
3.) In Finden: \r\n\r\n einsetzen
4.) In Ersetzen mit: \r\n einfügen

Die Überschrift passt vielleicht nicht ganz, denn Jekyll ist ein Generator für statische Webseiten basierend auf Ruby. Dabei arbeitet es mit Plain-Text HTML und kommt ohne Datenbank aus, so dass generierte Seiten vom Webserver sehr schnell bereitgestellt werden können.

Hier werden neue Inhalte per Editor hinterlegt oder per GitHub. Wir erhalten so eine schnelle statische Webseite, jedoch keine durchdesignte Webseite mit einfacher Benutzeroberfläche.

Sofern man nicht über GitHub arbeiten möchte, sondern lokal auf dem Rechner, um anschließend die Dateien auf dem Webserver zu übertragen, muß die Grundlage geschaffen werden.

Installiere Ruby ( www.ruby-lang.org )

Installiere Ruby Installer ( rubyinstaller.org )

Anschließend sind folgende Befehle in der Konsole nötig:

gem install jekyll bundler

und danach

bundle exec jekyll serve

Die Webseite sollte dann unter 127.0.0.1:4000 im Browser zu finden sein.

Problemlösung
Fehler:
Could not find gem ‚jekyll-sitemap‘ in any of the gem sources listed in your Gemfile or available on this machine.
Lösung:

$ sudo gem install jekyll-sitemap
$ sudo gem install pygments.rb
$ gem install bundler
$ bundle install


Fehler:
Unable to load the EventMachine C extension; To use the pure-ruby reactor, require ‚em/pure_ruby‘
Lösung:

gem uninstall eventmachine
gem install eventmachine --platform ruby

 

Lösung:

Über michÜber mich

CMS ist mein Leben

Als Medieninformatiker und Frontend-Entwickler in einer Agentur, liegt es in der Natur der Sache sich täglich mit Content Management Systemen (kurz CMS) zu beschäftigen. Hierbei werden alle Bereiche von Design, Umsetzung, Sicherheit und Problemlösung abgedeckt.

Da viele Fragen bei Schulungen immer wieder auftreten, möchte ich auf dieser Webseite, die passenden Lösungen anbieten. Kostenlose Video Tutorials zeigen Schritt für Schritt den Weg zum Ziel und dieses nicht nur oberflächlich, sondern im Detail. Der Schwerpunkt liegt hier auf dem CMS WordPress.

Also, viel Spaß.

  • 0%
    WORDPRESS
  • 0%
    WOOCOMMERCE (auch wenn im eigentlichen Sinne kein CMS)
  • 0%
    JOOMLA
  • 0%
    TYPO3
  • 0%
    DRUPAL

WordPress bietet neben vielen kostenlosen Plugins, eine extrem gute und motivierte Community. Hier bleiben die wenigsten Fragen lange unbeantwortet. Wer Zeit und Lust hat sich hier zu engagieren, ist gerne gesehen und kann viele Bereiche näher kennenlernen.

Der auf dieser Webseite befindliche Kontakt Button (Floating Contact Button) ist von mir entwickelt worden und kann kostenlos als Plugin für die eigene Webseite genutzt werden.

Floating Contact Button