Webdesign- Blog
Hier finden sich vor allem Tipps, Tricks und Code-Schnipsel aus unserem Arbeitsalltag, die (in der Regel) nicht dutzendfach bei Google auftauchen, wenn man danach sucht. Viel Spaß!
WP_Query: Posts nach Custom Field sortieren und filtern
Posts nach einem Custom Field zu sortieren und zu filtern ist nicht ganz trivial. Hier ein Code-Beispiel für Trive-Events-Posts anhand des Startdatums:
<?php
// Query vorbereiten
$args=array(
'post_type' => 'tribe_events',
'post_status' => 'publish',
'orderby' => 'meta_value',
'meta_key' => '_EventStartDate',
'order' => 'ASC',
'meta_query' => array(
array(
'key' => '_EventStartDate',
'type' => 'DATE',
'value' => date('y-m-d H:i:s'),
'compare' => '>'
),
),
'posts_per_page' => -1
);
// Query durchführen
$wp_query=new WP_Query($args);
// Alle Events durchgehen
foreach ($wp_query->posts as $event)
{
// Event verarbeiten ...
}
In diesem Beispiel werden alle Events deren Startdatum _EventStartDate
in der Zukunft liegt abgefragt und aufsteigend nach ebendiesem sortiert.
jQuery: Aktiven Hauptmenüpunkt erkennen
Je nach dem wie ein Menü aufgebaut ist, lässt sich nicht direkt sagen zu welchem Hauptmenüpunkt die aktuelle Unterseite gehört. Mit folgendem kleinen Script lässt sich das Problem lösen:
jQuery(document).ready(function($)
{
$('#hauptmenue .sub-menu a').each(function()
{
var nav_item_link=$(this);
var nav_item_url=nav_item_link.attr('href');
if(nav_item_url==window.location.href)
{
var top_parent=nav_item_link.parents('.menu-item');
top_parent.addClass('active');
}
});
});
Zunächst prüfen wir alle Links der Unternavigation und gleichen diese mit der aktuellen URL ab. Sind die URLs gleich, markieren wir den Hauptmenüpunkt mit der CSS-Klasse active
. Die Selektoren müssen natürlich entsprechend dem jeweiligen Aufbau der Website angepasst werden.
JavaScript: Externe Skripte verzögert laden
Manchmal kann es praktisch sein, bestimmte JavaScript-Dateien nachträglich zu laden, wenn bestimmte Bedingungen erfüllt sind. Das lässt sich mit folgenden Zeilen JavaScript bewerkstelligen:
if(my_condition==true)
{
var script = document.createElement('script');
script.src = 'https://www.example.com/my-script.js';
document.head.appendChild(script);
}
jQuery: Erkennen von externen Links
Mit folgendem jQuery-Selector lassen sich externe Links auf einer Website erfassen:
jQuery(document).ready(function($)
{
// Klick auf externen Link erfassen
$('a[href^="http"]:not([href*="'+window.location.hostname+'"])').each(function() {
// do stuff
});
});
Der Selektor prüft im ersten Schritt, ob die URL mit http
anfängt. Damit werden zum Beispiel Anker-, Mail- oder Telefon-Links aussortiert. Im zweiten Schritt wird geprüft, ob die URL den aktuellen Host-Namen enthält. Ist das nicht der Fall wird die Funktion ausgeführt.
JavaScript: PHP-Array in ein JavaScript-Array wandeln
Mit dem folgenden Code ist es möglich ein PHP-Array direkt in ein JavaScript-Array zu wandeln um es dann im Frontend weiter zu verwenden:
$my_array = array(
"foo" => "bar",
"bar" => "foo",
);
<script type="text/javascript">
var project_data=<?=json_encode($my_array)?>;
</script>
WordPress: Große Anzahl an Posts mit WP_Query() abfragen
Will man eine große Anzahl an Posts abfragen oder bearbeiten stößt man irgendwann an das PHP-Speicherlimt, da nicht alle Posts gleichzeitig im WP_Query Object geladen werden können. Mit der folgenden optimierten WP_Query-Abfrage kann man dieses Problem umgehen und tausende oder sogar zehntausende Posts abfragen:
<?php
// Query vorbereiten
$args=array(
'post_type' => 'my_post_type', // optional
'post_status' => 'publish', // optional
'fields' => 'ids', // nur Post-IDs laden
'nopaging' => true, // keine Pagination, alle Posts abfragen
'no_found_rows' => true, // Posts nicht zählen
'cache_results' => false, // Posts nicht im Cache ablegen
'update_post_meta_cache' => false, // Meta-Cache nicht füllen
'update_post_term_cache' => false // Term-Cache nicht füllen
);
// Query durchführen
$wp_query=new WP_Query($args);
// Alle Posts durchgehen
foreach ($wp_query->posts as $post_id)
{
// Post laden
$post=get_post($post_id);
// ... Post verarbeiten ...
}
Elementor: Widgets mit gleicher Höhe
Leider bietet Elementor aktuell nicht die Möglichkeit mehreren Elementen (zum Beispiel Icon-Boxen), die in Spalten nebeneinander angeordnet sind, die gleiche Höhe zu geben. Mit der CSS-Klasse equal_height
und diesem CSS lässt sich das trotzdem bewerkstelligen:
.elementor-widget.equal_height
{
display: flex;
height: 100%;
}
.elementor-widget.equal_height > .elementor-widget-container
{
flex-basis: 100%;
}
PHP: Skript-Ausführung per CLI/Kommandozeile verhindern
Manchmal kann es praktisch sein die Ausführung eines PHP-Skripts per Kommandozeile zu unterbinden, etwa weil die PHP-Version für die CLI nicht passend konfiguriert ist. Das lässt sich mit der PHP-Funktion php_sapi_name()
erreichen:
<?php
if(php_sapi_name()=='cli') exit('PHP CLI disabled.');
404-Fehlerseiten von statischen Dateien durch Apache statt WordPress ausliefern
Gute Cache-Plugins für WordPress liefern für die meisten Zugriffe die Website direkt über den Webserver aus, ohne erst langwierig WordPress zu starten und Datenbankabfragen durchzuführen. Wird jedoch zum Beispiel auf ein nicht vorhandenes Bild zugegriffen, passiert in der Regel genau das, was man als Website-Betreiber nicht will: WordPress wird gestartet um zu prüfen, ob die URL eventuell doch gültig ist und was anschließend passieren soll.
Und das kann auf stark frequentierten Websites zum Problem werden, auch wenn man eigentlich keine 404-Fehler auf der Website hat:
Browser suchen unaufgefordert nach bestimmten Touch-Icons und Bots nach Sicherheitslücken. Je nach Hosting und Besucher- beziehungsweise Bot-Andrang können diese Anfragen die Performance der Website deutlich verschlechtern.
Mit diesen Anweisungen für die htaccess-Datei wird WordPress bei 404-Fehlern von statischen Dateien umgangen und der Apache-Webserver antwortet direkt und deutlich ressourcen-schonender mit einer schlichten Fehlerseite:
# 404-Fehler von statischen Dateien durch Apache statt WordPress ausliefern
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# Multisite check – nicht benötigt für normale WordPress-Installationen
RewriteCond %{REQUEST_URI} [_0-9a-zA-Z-]+/(wp-(content|admin|includes).*)
RewriteRule ^[_0-9a-zA-Z-]+/(wp-(content|admin|includes).*) $1 [L]
RewriteCond %{REQUEST_URI} !(robots\.txt|[a-z0-9_\-]*sitemap[a-z0-9_\-]*\.(xml|xsl|html)(\.gz)?)
RewriteCond %{REQUEST_URI} \.(css|htc|less|js|js2|js3|js4|html|htm|rtf|rtx|svg|txt|xsd|xsl|xml|asf|asx|wax|wmv|wmx|avi|bmp|class|divx|doc|docx|eot|exe|gif|gz|gzip|ico|jpg|jpeg|jpe|webp|json|mdb|mid|midi|mov|qt|mp3|m4a|mp4|m4v|mpeg|mpg|mpe|mpp|otf|_otf|odb|odc|odf|odg|odp|ods|odt|ogg|pdf|png|pot|pps|ppt|pptx|ra|ram|svg|svgz|swf|tar|tif|tiff|ttf|ttc|_ttf|wav|wma|wri|woff|woff2|xla|xls|xlsx|xlt|xlw|zip)$ [NC]
RewriteRule .* - [L]
</IfModule>
Normale Besucher bekommen davon in der Regel nichts mit, da 404-Meldungen zu Seiten oder Beiträgen immer noch von WordPress im passenden Website-Design beantwortet werden.
Cookiebot: Zusätzlicher Button „Alle auswählen“
Cookiebot ist eine weit verbreitete und beliebte Cookie-Consent-Lösung. Leider bietet es keinen Button an, um alle Cookie-Arten auf einmal zu akzeptieren und fortzufahren. Mit diesem Code für den HTML-Head wird ein Button „Alle auswählen“ ergänzt:
<!-- Cookiebot CSS -->
<style type="text/css">
#CybotCookiebotDialog
{
font-family: inherit !important;
border-color: white !important;
border-width: 13px !important;
}
#CybotCookiebotDialog *
{
font-family: inherit !important;
}
#CybotCookiebotDialogBodyLevelButtonAccept,
#CybotCookiebotDialogBodyLevelButtonAccept_all
{
display: inline-block;
z-index: 10;
min-width: 80px;
padding: 3px 10px;
margin-left: 10px;
margin-top: 6px;
margin-right: 0;
margin-bottom: 20px;
font-size: 16px !important;
font-weight: 400;
text-align: center;
text-decoration: none !important;
white-space: nowrap;
color: #ffffff !important;
background-color: #18a300;
border: 1px solid #18a300;
cursor: pointer !important;
}
#CybotCookiebotDialogBodyLevelButtonAccept
{
color: black !important;
background: white !important;
border-color: #cccccc !important;
}
#CybotCookiebotDialogDetailFooter
{
margin-top: 10px;
text-align: left !important;
font-size: 12px;
}
#CybotCookiebotDialogDetailFooter *
{
font-size: 12px;
}
.CookieDeclaration
{
display: none;
}
</style>
<!-- Cookiebot Head -->
<script type="text/javascript">
var cookiebot_button_text_ok='Auswahl bestätigen';
var cookiebot_button_text_all='Alle auswählen';
window.addEventListener('CookiebotOnDialogDisplay', function (e)
{
// Modifikation prüfen:
if(document.getElementById("CybotCookiebotDialog").classList.contains("modified")) return;
console.log('do mod');
// Standard-Button Anpassen
var cookiebot_button_ok=document.getElementById("CybotCookiebotDialogBodyLevelButtonAccept");
cookiebot_button_ok.innerHTML = cookiebot_button_text_ok;
// Button [Alle auswählen] anlegen
var cookiebot_button_all = document.createElement("a");
cookiebot_button_all.innerHTML = cookiebot_button_text_all;
document.getElementById("CybotCookiebotDialogBodyLevelButtonAcceptWrapper").appendChild(cookiebot_button_all);
cookiebot_button_all.setAttribute("id", "CybotCookiebotDialogBodyLevelButtonAccept_all");
// Button [Alle auswählen] Click-Event
cookiebot_button_all.addEventListener("click", function() {
document.getElementById("CybotCookiebotDialogBodyLevelButtonPreferences").click();
document.getElementById("CybotCookiebotDialogBodyLevelButtonStatistics").click();
document.getElementById("CybotCookiebotDialogBodyLevelButtonMarketing").click();
document.getElementById("CybotCookiebotDialogBodyLevelButtonAccept").click();
});
// Markierung: Anpassungen durchgeführt
document.getElementById("CybotCookiebotDialog").classList.add("modified");
}, false);
</script>
<script id="Cookiebot" src="https://consent.cookiebot.com/uc.js" data-cbid="XXXXXXXXXXXXXXXXXXXXXXXXXXXXX" data-blockingmode="auto" type="text/javascript"></script>
Anstelle von XXXXXXXXXXXXXXXXXXXXXXXXXXXXX natürlich die Domaingruppen ID eintragen. Hier die Vorschau:
Vorlage: Outlook HTML-Signatur mit Bild
Eine funktionierende HTML-Signatur mit Bild in Outlook zu erstellen birgt gewisse Herausforderungen. Mit dieser Vorlage (ZIP-Datei 32 KB) und der folgenden Kurzanleitung sollte das aber deutlich leichter von der Hand gehen:
- Signatur mit dem Namen „Mein Mail Footer“ in Outlook anlegen wie hier im JOC Blog beschrieben.
- Die Dateien aus der Vorlage in
C:\Users\BENUTZERNAME\AppData\Roaming\Microsoft\Signatures
kopieren. - Inhalte in
Mein-Mail-Footer.htm
wie gewünscht anpassen und individualisieren. Hier gibt es ein ausführliches Tutorial zur Erstellung responsiver HTML-Mails. - Grafiken in
Mein-Mail-Footer-Dateien\filelist.xml
aktualisieren. - Falls die Signatur einen anderen Namen haben soll als „Mein Mail Footer“ alle Vorkommnisse von
Mein-Mail-Footer-Dateien
undMein-Mail-Footer.htm
entsprechend anpassen.
Tipp: Boot-Camp-Meldung „Beim Kopieren der Windows-Installationsdateien ist ein Fehler aufgetreten.“
Beim Versuch Windows 10 per Boot Camp Assistent zu installieren kann es vorkommen, dass dieser die Installation mit der wenig aussagekräftigen Meldung abbricht:
Boot Camp-Installation fehlgeschlagen
Beim Kopieren der Windows-Installationsdateien ist ein Fehler aufgetreten.
Der Grund dafür ist, dass das Kopieren der Datei install.wim vom Windows-ISO-Image auf die vom Boot Camp Assistenten angelegten Partition OSXRESERVED fehlschlägt. Diese Partition ist mit FAT32 formatiert und kann keine Dateien größer 4 GB verarbeiten. Bei vielen Windows-Installationen ist die Datei install.wim jedoch größer. Genauer wird das Problem in diesem Artikel Using larger Windows 10 ISOs with Boot Camp Assistant von Twocanoes Software erklärt.
Um die Verwirrung für den Benutzer komplett zu machen, hängt Boot Camp anschließend mit der Meldung:
Partitionen zurücksetzen
Warte bis der Boot Camp Assistent die erstellten Partitionen entfernt hat …
Mit folgenden Schritten kommt man doch noch zum Ziel:
- Mac neu starten und mit dem Boot Camp Assistenten die Festplatte wieder zu einer Partition zusammenfassen:
- Die Software Boot Camp ISO Converter von Twocanoes Software laden und damit das Windows-Image anpassen:
- Boot Camp Assistent erneut starten und das angepasste Windows-Image verwenden
Tipp: WordPress-Übersetzungen mit LocoTranslate
Das kostenlose Übersetzungs-Plugin LocoTranslate des Übersetzungs-Management-Anbieters Loco macht Übersetzungen für Themes und Plugins in WordPress sehr einfach und übersichtlich möglich. Über 700.000 aktive Installationen und eine durchschnittliche Bewertung von 4,9 von 5 Sternen sprechend für sich:
PHP: Eigene Log-Dateien für Tests
Mit der folgenden Funktion lassen sich eigene Log-Files für Tests oder Debugging sichern. In diesem Beispiel werden die Werte der globalen PHP-Variablen $_GET und $_POST gesichert.
<?php
function write_test_log()
{
// Parameter bestimmen
$file_path='';
$file_name='test.log';
// Datei öffnen / anlegen
$handle=fopen($file_path.$file_name, 'a');
// Daten zusammenstellen: URL
$full_url = (isset($_SERVER['HTTPS']) ? 'https':'http').'://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'];
// Daten zusammenstellen: $_GET
ob_start();
print_r($_GET);
$output_GET=ob_get_clean();
// Daten zusammenstellen: $_POST
ob_start();
print_r($_POST);
$output_POST=ob_get_clean();
// Daten sichern
fwrite($handle, date('d.m.Y H:i:s').' ------------------------------'.chr(10).chr(10));
fwrite($handle, 'URL: '.$full_url.chr(10).chr(10));
fwrite($handle, '$_GET:'.chr(10));
fwrite($handle, $output_GET.chr(10).chr(10));
fwrite($handle, '$_POST:'.chr(10));
fwrite($handle, $output_POST.chr(10));
// Datei schließen
fclose($handle);
}
if($_GET or $_POST) write_test_log();
jQuery: Verwendung von DOMNodeInserted zur Anpassung dynamischer Inhalte
Manchmal ist es notwendig dynamisch erzeugte Elemente zu manipulieren, die zum Zeitpunkt von $(document).ready()
oder $(window).load()
noch nicht vorhanden sind. Dafür ist das Event $('body').on('DOMNodeInserted')
sehr nützlich.
Im folgenden Beispiel wird ein von Magnific Popup dynamisch erzeugtes YouTube-Iframe auf die No-Cookie-Variante von YouTube geändert:
jQuery(document).ready(function($)
{
// Event-Listener für DOMNodeInserted
$('body').on('DOMNodeInserted', function()
{
// Prüfen, ob das gesuchte Iframe ins DOM eingefügt wurde
var mfp_iframe=$(this).find('iframe.mfp-iframe');
if(mfp_iframe.length)
{
// Parameter vorbereiten
var src=mfp_iframe.attr('src');
var src_no_cookie=src.replace('youtube.com', 'youtube-nocookie.com');
// Iframe anpassen
mfp_iframe.attr('src', src_no_cookie);
mfp_iframe.attr('rel', '0');
}
});
});
WordPress: Ausgabetexte aus Themes und Plugins ändern
Manchmal sind Wörter oder Formulierungen in Themes beziehungsweise Plugins enthalten, die einem einfach nicht gefallen. Falls es sich hierbei um eine Übersetzung handelt, kann diese mit dem Plugin Loco Translate ändern.
Ansonsten kann man mit der folgenden kleinen PHP-Funktion beliebige Ausgabetexte aus Themes und Plugins ändern:
function my_text_strings( $translated_text, $text, $domain )
{
switch ( $translated_text )
{
case 'Dieser Text ist nicht schön :-(':
$translated_text = __( 'Dieser Text ist viel besser :-)', $domain );
break;
}
return $translated_text;
}
add_filter('gettext', 'my_text_strings', 20, 3);
Tipp: Sehr gute automatische Übersetzungen mit DeepL
Die Übersetzungsautomaten von Google uns Microsoft sind ja so gut wie jedem bekannt, nicht zu letzt wegen dem einen oder anderen Lacher der aufkommt wenn man sich dort ganze (Ab)Sätze übersetzen lässt. Ganz ohne Lacher, dafür aber mit erstaunlich guten Übersetzungen überzeugt das neue Übersetzungs-Tool DeepL.
WordPress: Benutzer per PHP anlegen
Manchmal kommt es vor, dass man die FTP-Zugangsdaten zu einer Website hat, aber keinen WordPress-Zugang. Der Kunde kennt sich nicht aus und der Webdesigner, der die Seite mal vor langer Zeit erstellt hat, ist nicht mehr greifbar. In so einem Fall leistet diese kleine PHP-Funktion in den functions.php
sehr gute Dienste:
function add_admin_user()
{
$login = 'myself';
$passw = 'very#secret';
$email = 'me@example.com';
if ( !username_exists( $login ) && !email_exists( $email ) ) {
$user_id = wp_create_user( $login, $passw, $email );
$user = new WP_User( $user_id );
$user->set_role( 'administrator' );
}
}
add_action('init','add_admin_user');
JavaScript: URL-Parameter abfragen
Mit dieser kleinen Funktion lassen sich in JavaScript URL-Parameter / Query-Strings abfragen:
// URL-Parameter abfragen
function getUrlParameterByName(name, url)
{
if (!url) url = window.location.href;
name = name.replace(/[\[\]]/g, "\\$&");
var regex = new RegExp("[?&]" + name + "(=([^]*)|&|#|$)"), results = regex.exec(url);
if (!results) return null;
if (!results[2]) return '';
return decodeURIComponent(results[2].replace(/\+/g, " "));
}
alert(getUrlParameterByName('mein-url-parameter'));
PHP: ZIP-Archive extrahieren
Trotz immer schneller werdenden Internet-Verbindungen dauert das Hochladen von Verzeichnissen mit tausenden von Dateien und Unterverzeichnissen, wie das zum Beispiel bei kompletten WordPress-Installationen oder komplexen Themes der Fall ist, immer noch seine Zeit.
Deutlich schneller ist es, statt dessen ein ZIP-Archiv hochzuladen. Falls man auf dem Server keine SSH-Zugang hat, lässt sich die ZIP-Datei mit folgendem kleinen PHP-Skript zu extrahieren.
<?php
// Dateiname bestimmen (muss hier im selben Verzeichnis liegen)
$file="meine-datei.zip";
// Absoluten Pfad bestimmen
$path=pathinfo(realpath($file), PATHINFO_DIRNAME);
// ZIP-Datei öffnen und prüfen
$zip=new ZipArchive;
$res=$zip->open($file);
if ($res===TRUE)
{
// ZIP-Datei extrahieren
$zip->extractTo($path);
$zip->close();
// Erfolgsmeldung
echo("<h2>Erfolg :-)</h2>");
echo("<p><code><strong>$file</strong></code> erforgreich in das Verzeichnis <code><strong>$path</strong></code> entpackt.</p>");
}
// Fehlermeldung
else
{
echo("<h2>Fehler :-(</h2>");
echo("<p><code><strong>$file</strong></code> konnte nicht geöffnet werden.</p>");
}
Tipp: Firefox Developer Edition
Sehr empfehlenswert: Von Mozilla gibt es eigens für Web-Entwickler die Firefox Developer Edition mit zusätzlichen Werkzeugen zur Analyse und Fehlersuche.
WordPress: Seitenweite Suche mit Omnisearch und Search Everything
Leider verfügt WordPress über keine seitenweite Suche, die in allen Post Types gleichzeitig sucht. Das ist aber vor allem bei großen Seiten sehr praktisch. Zum Glück lässt sich diese Funktion relativ einfach mit den Plugins Jetpack Omnisearch und Search Everything nachrüsten:
Schritt 1: Jetpack installieren
Jetpack installieren und Omnisearch aktivieren:
Tipp: Man muss Jetpack nicht zwingend mit WordPress.com verbinden, Omnisearch lässt sich auch im Development Mode verwenden. Dazu einfach die Zeile define('JETPACK_DEV_DEBUG', true);
in die wp-config.php
einfügen.
WordPress: Standard-Editor-Farben ersetzen
Der WordPress-Editor bietet die Möglichkeit an, Texten eine Farbe zuzuweisen:
Nur leider stimmen diese Farben natürlich nicht mit den Farben der Website überein. Mit der folgenden PHP-Funktion lassen sich die Standard-Farbwerte entsprechend den Vorgaben des Corporate Designs ändern:
function modify_colors($content)
{
// Farben zuordnen
$array = array (
'#ff0000' => '#de0202',
'#3366ff' => '#006bad'
);
// Farben im Inhalt suchen und ersetzen
$content=strtr($content, $array);
return $content;
}
add_filter('the_content', 'modify_colors');
JavaScript: Session-Daten mit JavaScript
Vor allem bei Websites mit aktivem Caching, die nicht bei jedem Aufruf dynamisch neu erstellt werden, kann es praktisch sein, Nutzereingaben mit den JavaScript-Funktionen sessionStorage.setItem()
und sessionStorage.getItem()
zu sichern. Hier ein einfaches Beispiel:
// Beispiel: Verwendung sessionStorage.setItem()
$('#my_alert .close').click(function() {
sessionStorage.setItem('popup', 'closed');
});
// Beispiel: Verwendung sessionStorage.getItem()
if(sessionStorage.getItem('popup')=='closed') {
$('#my_alert').remove();
}
jQuery: Events und Statusabfragen für responsives Webdesign
Bei der Umsetzung komplexer responsiver Webdesigns sind CSS-Media-Queries oft nicht ausreichend um alle gewünschten Änderungen zu erfassen und entsprechende Anpassungen vorzunehmen. Mit der folgenden Funktion und den dazugehörenden Events lassen sich über erweiterte Regeln das responsive Verhalten einer Website bestimmen.
Events
$(document).ready()
: Das Document Object Model ist verfügbar.$(window).load()
: Die Website ist komplett geladen.$(window).resize()
: Die Größe des Browser-Fensters wird verändert.$(window).orientationchange()
: Das Gerät wird vom Quer- zum Hochformat gedreht oder umgekehrt.$('form').submit()
: Ein Formular wurde gesendet.
jQuery(document).ready(function($)
{
var window_width=null;
var window_width_old=null;
function update_responsive_settings(mode)
{
// Viewport dynamisch anpassen
viewport = document.querySelector("meta[name=viewport]");
if(mode=='orientationchange') viewport.setAttribute('content', 'width=device-width');
if($(window).width()>420) viewport.setAttribute('content', 'width=1100');
// Breite sichern
window_width_old=window_width;
window_width=$(window).width();
// Breite prüfen und falls unverändert abbrechen
if(window_width_old==window_width) return;
// Aktionen entsprechend Breite
if(window_width<=420)
{
mobile_nav('create'); // Beispielfunktion
}
else
{
mobile_nav('remove'); // Beispielfunktion
}
// Aktionen entsprechend Bereite und Modus
if(window_width<=420 && mode=='load')
{
$('#my_box').fadeIn();
}
}
update_responsive_settings('ready');
$(window).load(function() { update_responsive_settings('load'); });
$(window).resize(function() { update_responsive_settings('resize'); });
$(window).bind('orientationchange', function() { update_responsive_settings('orientationchange'); });
$('form').submit(function() { update_responsive_settings('form_submit'); });
});
jQuery: HTML-Formular per AJAX senden
So lässt sich ein bestehendes HTML-Formular samt aller Input-Felder mit jQuery per AJAX senden:
jQuery(document).ready(function($)
{
$("#my_form").submit(function(event) {
// Standard-Aktion abbrechen
event.preventDefault();
// Formular per AJAX senden
var form=$(this);
$.ajax({
type: 'POST',
url: form.prop('action'),
data : form.serialize(),
dataType: 'json',
encode: true
}).done(function(data) {
// Aktionen bei Erfolg
console.log('done: '+data);
}).fail(function(data) {
// Aktionen bei einem Fehler
console.log('fail: '+data);
});
});
});
PHP: Zeilenanzahl großer Dateien ermitteln
Auf Linux/Unix-Systemen lässt sich die Zeilenanzahl (sehr) großer Textdateien mit exec() und wc -l ermitteln:
$logfile_location='logs/my_logfile.txt';
if(file_exists($logfile_location)) $logfile_lines=intval(exec("wc -l ".$logfile_location));
else $logfile_lines=0;
WordPress: Sprache und Übersetzung in PHP anpassen
Die Spracheinstellungen lassen sich in WordPress nicht nur über die Einstellungen sondern auch über den Filter add_filter(‚locale‘, …) in den functions.php dynamisch anpassen. Die folgende Funktion zum Beispiel setzt Französisch als Sprache für die Website wohingegen der WordPress-Adminbereich auf deutsch ausgegeben wird:
// WordPress Locale setzen
function set_locale_frontend($locale)
{
if(is_admin()) return 'de_DE';
else return 'fr_FR'
}
add_filter('locale', 'set_locale_frontend');
Das kann für Multisite-Übersetzungen sehr praktisch sein, wenn man den Adminbereich nicht in der Übersetzungssprache bedienen will.
Mit der Funktion load_textdomain() lässt sich wiederum eine weitere Übersetzung laden:
echo(__('Hallo Welt!', 'meine_text_domain')); // Bonjour tout le monde!
load_textdomain('medianotions', get_stylesheet_directory().'/languages/en_GB.mo');
echo(__('Hallo Welt!', 'meine_text_domain')); // Hello world!
Bezüglich erstellen und bearbeiten von Übersetzungsdateien ist das Plugin Loco Translate das Mittel der Wahl:
WordPress: robots.txt dynamisch anpassen
Die robots.txt wird in WordPress dynamisch erzeugt. Die einfachste Möglichkeit diese anzupassen ist, eine statische robots.txt in das Root-Verzeichnis der WordPress-Installation anzulegen. Die andere, flexiblere Möglichkeit ist in der functions.php mit folgendem Filter zu arbeiten:
// robots.txt anpassen
function robots_mod( $output, $public )
{
if($public)
{
$output .= "Allow: /*.js$\n";
$output .= "Allow: /*.css$\n";
}
return $output;
}
add_filter('robots_txt', 'robots_mod', 10, 2);
Damit ist es möglich die Ausgabe der robots.txt mit einer eigenen Logik zu verknüpfen:
// robots.txt anpassen
function robots_mod( $output, $public )
{
if($_SERVER['HTTP_HOST']=='hide-from-search-engines.com') $output = "Disallow: /\n";
return $output;
}
add_filter('robots_txt', 'robots_mod', 10, 2);
Performance-Tipp: Die robots.txt
wird von Suchmaschinen zum Teil sehr oft aufgerufen. Falls das verwendete Caching-Plugin die robots.txt
nicht abdeckt und man keine dynamische Anpassung benötigt, bietet es sich an die robots.txt
als statische Text-Datei im Webroot-Verzeichs zu hinterlegen.
Tipp: Bilder in WordPress automatisch optimieren mit ShortPixel
Mit dem Anbieter ShortPixel und dem dazugehörigen Plugin „ShortPixel Image Optimizer“ lassen Bilder in WordPress unkompliziert optimieren und die Ladezeiten der eigenen Website verbessern:
PHP: Mit strpos_all() alle Vorkommnisse in einem String finden
Mit dieser Funktion lassen sich alle Vorkommnisse in von $needle in $haystack finden. Zurückgegeben wird ein Array mit den Positionen:
function strpos_all($haystack, $needle)
{
$lastPos = 0;
$positions = array();
while (($lastPos = strpos($haystack, $needle, $lastPos))!== false) {
$positions[] = $lastPos;
$lastPos = $lastPos + strlen($needle);
}
return $positions;
}
// Aufruf
$str_positions=strpos_all('a', 'abcd ab abcdefg abcde');
Website-Zoom mit jQuery und CSS
Mit der CSS-Eigenschaft transform: scale()
und etwas jQuery lässt sich ziemlich gut das ein- und auszoomen einer Website simulieren. Das ist für alle praktisch, die Ihren Benutzern entsprechende Buttons auf ihrer Website anbieten wollen. Hier unsere Lösung:
<!-- Trigger -->
<ul id="zoom_triggers">
<li><a id="zoom_in">Vergrößern</a></li>
<li><a id="zoom_out">Verkleinern</a></li>
<li><a id="zoom_reset">Zurücksetzen</a></li>
</ul>
<script>
jQuery(document).ready(function($)
{
// Zoom-Level setzen
var zoom_level=100;
// Click-Events
$('#zoom_in').click(function() { zoom_page(10, $(this)) });
$('#zoom_out').click(function() { zoom_page(-10, $(this)) });
$('#zoom_reset').click(function() { zoom_page(0, $(this)) });
// Zoom-Funktion
function zoom_page(step, trigger)
{
// Nur zwei Schritte ein- beziehungsweise ausblenden
if(zoom_level>=120 && step>0 || zoom_level<=80 && step<0) return;
// Zoom berechnen / zurücksetzen
if(step==0) zoom_level=100;
else zoom_level=zoom_level+step;
// Zoom per CSS setzen
$('body').css({
transform: 'scale('+(zoom_level/100)+')', // Zoom anpassen
transformOrigin: '50% 0' // Ausgangspunkt für transform scale setzen
});
// Seitenbreite am Zoom anpassen
if(zoom_level>100) $('body').css({ width: (zoom_level*1.2)+'%' });
else $('body').css({ width: '100%' });
// Trigger deaktivieren / aktivieren (per CSS entsprechend optisch kennzeichnen)
if(zoom_level>=120 || zoom_level<=80) trigger.addClass('disabled');
else trigger.parents('ul').find('.disabled').removeClass('disabled');
if(zoom_level!=100) $('#zoom_reset').removeClass('disabled');
else $('#zoom_reset').addClass('disabled');
}
});
</script>
PHP: file_put_contents() via FTP mit ftp_file_put_contents()
Mit dieser Funktion lässt sich ein PHP-String als Datei via FTP-Verbindung sichern:
function ftp_file_put_contents($remote_file, $file_string)
{
// FTP-Zugangsdaten
$ftp_server="mein-ftp-server.de";
$ftp_user_name="mein-benutzername";
$ftp_user_pass="mein-passwort";
// Temporäre Datei aus dem Filestring erstellen
$local_file=fopen('php://temp', 'r+');
fwrite($local_file, $file_string);
rewind($local_file);
// FTP-Verbindung aufbauen
$ftp_conn=ftp_connect($ftp_server);
// FTP-Login
@$login_result=ftp_login($ftp_conn, $ftp_user_name, $ftp_user_pass);
// FTP-Upload
if($login_result) $upload_result=ftp_fput($ftp_conn, $remote_file, $local_file, FTP_ASCII);
// Fehlerprüfung
if(!$login_result or !$upload_result)
{
echo('FTP-Fehler: Datei konnte nicht geschrieben werden.
');
}
// FTP-Verbindung beenden
ftp_close($ftp_conn);
// Datei-Handle Temporäre-Datei schließen
fclose($local_file);
}
// Aufruf
ftp_file_put_contents('meine-datei.txt', 'Dieser Inhalt wird in die Textdatei geschrieben.');
PHP: XSS-Attacken auf bestehenden Websites verhindern
Eine bestehende, eventuell komplexere Website nachträglich vor Cross-Site-Scripting-Attacken (XSS) zur sichern, kann sich als sehr aufwändig erweisen. Mit diesem PHP-Skript, dass bei jedem Aufruf der Website vor allen anderen Funktionen ausgeführt werden sollte, lassen sich die meisten Angriffsszenarien entschärfen.
function xss_protect($string)
{
// nur Strings prüfen
if(!is_string($string)) return $string;
// eventuelle Kodierung berücksichtigen
$string=urldecode($string);
// Ausführbaren Code entfernen
$string=strip_tags($string);
$string=htmlspecialchars($string);
$string=filter_var($string, FILTER_SANITIZE_STRING);
return $string;
}
if(is_array($_GET)) $_GET = array_map("xss_protect", $_GET);
if(is_array($_POST)) $_POST = array_map("xss_protect", $_POST);
if(is_array($_REQUEST)) $_REQUEST = array_map("xss_protect", $_REQUEST);
$_SERVER['REQUEST_URI'] = array_map("xss_protect", $_SERVER['REQUEST_URI']);
$_SERVER['REDIRECT_QUERY_STRING'] = array_map("xss_protect", $_SERVER['REDIRECT_QUERY_STRING']);
$_SERVER['QUERY_STRING'] = array_map("xss_protect", $_SERVER['QUERY_STRING']);
Tipp: mit draGGradients einfach radiale CSS-Verläufe erstellen
draGGradients ist sehr praktisch um ein oder mehrere radiale CSS-Verläufe zu erstellen:
Tipp: Einfach zur individuellen Google-Maps-Integration mit dem MapBuildr
Tipp: CSS-Hover-Effekte mit Hover.css
Tipp: CSS mit PHP inline verwenden
Mit der PHP-Class CssToInlineStyles kann man CSS-Definitionen automatisch inline auf HTML-Tags anwenden. Sehr praktisch, wenn man aus PHP heraus HTML-E-Mails versenden will.
HTML: Automatische Vervollständigung (Autocomplete) von Formularen deaktivieren
Bei Formularen mit sensiblen Daten ist es sinnvoll die automatische Vervollständigung (Autocomplete) durch den Browser zu unterbinden. Das kann mit dem Attribut autocomplete
erreicht werden:
<!-- Autocomplete für das gesamte Formular deaktivieren -->
<form action="mein-formular.php" method="post" autocomplete="off">
<!-- Autocomplete für ein einzelnes Feld deaktivieren -->
<input type="text" name="IBAN" value="<?=$_POST['IBAN']?>" autocomplete="off">
WordPress: Menüeinträge im WordPress-Admin ausblenden
Wer bestimmte Menüeinträge im WordPress-Admibereich ausblenden möchte, weil die Funktionen nicht gebraucht werden, kann dies mit folgender Aktion in der functions.php
umsetzen:
// Menüeinträge ausblenden
function modify_menus()
{
// remove_menu_page( 'index.php' ); // Dashboard
// remove_menu_page( 'edit.php' ); // Posts
// remove_menu_page( 'upload.php' ); // Media
// remove_menu_page( 'edit.php?post_type=page' ); // Pages
remove_menu_page( 'edit-comments.php' ); // Comments
// remove_menu_page( 'themes.php' ); // Appearance
// remove_menu_page( 'plugins.php' ); // Plugins
// remove_menu_page( 'users.php' ); // Users
// remove_menu_page( 'tools.php' ); // Tools
// remove_menu_page( 'options-general.php' ); // Settings
}
add_action( 'admin_menu', 'modify_menus', 999 );
In diesen Beispiel werden die Kommentare aus dem Menü entfernt.
Tipp: Websites als Photoshop-Ebenendatei sichern
Streng genommen kein Coding-Tipp aber sehr nützlich für alle, die schnell grafische Anpassungen an einer bestehenden Website darstellen wollen: mit Page Layers lassen sich Websites als Photoshop-Ebenendatei sichern:
WordPress: Browser und OS als CSS-Klassen im Body-Tag
Zum Glück benötigt man als Web-Entwickler Browser-Weichen mittlerweile nicht mehr so oft wie früher. Trotzdem kommt es immer noch vor, dass Darstellungsunterschiede angepasst werden müssen. Mit diesen beiden Funktionen in der functions.php
lassen sich die wichtigsten Browser und Betriebssysteme als CSS-Klassen in den Body-Tag einbinden:
// Client-Eigenschaften bestimmen
function detect_client_properties()
{
// Client: Browser
if(!isset($_SESSION['CLIENT_BROWSER']))
{
if(strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE 7')) $browser='ie_7';
elseif(strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE 8')) $browser='ie_8';
elseif(strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE 9')) $browser='ie_9';
elseif(strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE 10')) $browser='ie_10';
elseif(strpos($_SERVER['HTTP_USER_AGENT'], 'Trident') and strpos($_SERVER['HTTP_USER_AGENT'], 'rv:11')) $browser='ie_11';
elseif(strpos($_SERVER['HTTP_USER_AGENT'], 'Chrome')) $browser='chrome';
elseif(strpos($_SERVER['HTTP_USER_AGENT'], 'Safari')) $browser='safari';
elseif(strpos($_SERVER['HTTP_USER_AGENT'], 'Firefox')) $browser='firefox';
else $browser=false;
if($browser) $_SESSION['CLIENT_BROWSER']=$browser;
else $_SESSION['CLIENT_BROWSER']=false;
}
// Client: Betriebssystem
if(!isset($_SESSION['CLIENT_OS']))
{
if(strpos($_SERVER['HTTP_USER_AGENT'], 'Macintosh')) $os='mac';
elseif(strpos($_SERVER['HTTP_USER_AGENT'], 'Windows')) $os='win';
elseif(strpos($_SERVER['HTTP_USER_AGENT'], 'iPhone')) $os='ios';
elseif(strpos($_SERVER['HTTP_USER_AGENT'], 'iPad')) $os='ios';
else $os=false;
if($os) $_SESSION['CLIENT_OS']=$os;
else $_SESSION['CLIENT_OS']=false;
}
// Client: Mobile
if(!isset($_SESSION['CLIENT_IS_MOBILE']))
{
if(wp_is_mobile()) $_SESSION['CLIENT_IS_MOBILE']=true;
else $_SESSION['CLIENT_IS_MOBILE']=false;
}
}
add_action('init', 'detect_client_properties', 0);
// Body-CSS-Klassen ergänzen
function additional_body_classes($classes)
{
// Browser
if($_SESSION['CLIENT_BROWSER']) $classes[]=$_SESSION['CLIENT_BROWSER'];
// Betriebssystem
if($_SESSION['CLIENT_OS']) $classes[]=$_SESSION['CLIENT_OS'];
// Mobile
if($_SESSION['CLIENT_IS_MOBILE']) $classes[]='mobile';
return $classes;
}
add_filter('body_class', 'additional_body_classes', 99);
Auf ähnliche Weise lassen sich auch weitere CSS-Klassen im Body-Tag einfügen, zum Beispiel die aktuelle Sprache bei mehrsprachigen Websites oder aktuelle Kategorien, Templates, Parent-Seite usw.
Tipp: CSS Animationen erstellen mit bouncejs.com
Auf bouncejs.com lassen sich schnell und unkompliziert CSS3-Animationen auf Basis von Vorlagen erstellen, als CSS-Code exportieren und in eigenen Projekten verwenden:
WordPress: Eigene Bildgrößen definieren
Mit diesen beiden Filteraufrufen in der functions.php
lassen sich eigene Bildgrößen für die WordPress-Medien definieren. Mit der ersten Funktion add_image_sizes($sizes)
wird die neue Bildgröße angelegt und mit der zweiten Funktion add_image_sizes($sizes)
zur Bildgrößenauswahl hinzugefügt:
// Bildgrößen: Eigene Größen definieren
function add_image_sizes($sizes)
{
add_theme_support('post-thumbnails');
add_image_size('content_width', 800, 500, true);
}
add_filter('init', 'add_image_sizes');
// Bildgrößen: Eigene Namen definieren
function set_image_sizes($sizes)
{
// Bildgrößen zur Auswahl hinzufügen
$custom_image_size_names=array(
"content_width" => __("Inhalt")
);
// Vorhandene Namen ergänzen
return array_merge($sizes, $custom_image_size_names);
}
add_filter('image_size_names_choose', 'set_image_sizes');
PHP: HTTP / HTTPS bestimmen
Update 26. Mai 2014: Der Server-Port für HTTPS-Verbindungen muss je nach Server-Konfiguration nicht zwingend 443 sein.
So lässt sich mit PHP bestimmen ob eine Website über HTTP oder HTTPS aufgerufen wird:
// HTTP / HTTPS bestimmen
if(!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS']!='off' or $_SERVER['SERVER_PORT']==443) $protocol='https';
else $protocol='http';
WordPress: Shortcodes in Zusammenfassungen und Widgets ausführen
Mit diesen beiden Filteraufrufen in der functions.php
werden Shortcodes auch in Beitragszusammenfassungen und Widgets ausgeführt:
// Shortcodes in der Zusammenfassung ausführen
add_filter('the_excerpt', 'do_shortcode');
// Shortcodes in Widgets ausführen
add_filter('widget_text', 'do_shortcode');
Tipp: Syntax-Highlighting für WordPress mit PRISM
PRISM ist wohl eines der besten Syntax-Highlighting-Tools und lässt sich leicht in WordPress integrieren:
functions.php
function my_theme_resources()
{
// Prism laden | http://prismjs.com
wp_enqueue_style('prism-css', get_stylesheet_directory().'/libs/prism/prism.css');
wp_enqueue_script('prism-js', get_stylesheet_directory().'/libs/prism/prism.js');
}
add_action('wp_enqueue_scripts', 'my_theme_resources');
WordPress-Texteditor
<pre><code class="language-php">
// PHP-Beispiel-Code
$prism=true;</code></pre>
WordPress: P-Tags um Shortcodes entfernen
Mit dieser kleinen Funkton in der functions.php
lassen sich die P-Tags um und die BR-Tags nach Shortcodes entfernen, hier mit Filter für den Post-Inhalt und den Advanced Custom Fields WYSIWYG-Editor:
function shortcode_paragraph_fix($content)
{
// Suchen und Ersetzen Strings festlegen
$array = array (
'<p>[' => '[',
']</p>' => ']',
']<br />' => ']'
);
return strtr($content, $array);
}
add_filter('the_content', 'shortcode_paragraph_fix');
add_filter('acf/load_value/type=wysiwyg', 'shortcode_paragraph_fix');
Alternativ lässt sich die Funktion manuell auf Inhalts-Strings anwenden die Shortcodes enthalten.
Gravity Forms: deutsche Lokalisierung für die Datumsauswahl (Datepicker)
Für alle die ein Gravity-Forms Datumsfeld (Datepicker) verwenden und diesen aber nicht mit der englischen Lokalisierung belassen wollen, gibt es eine einfache Lösung. Gravity Forms nutzt den jQuery-Datepicker mit Lokalisierungen für viele Sprachen. Also einfach jQuery-Datepicker laden und die entsprechende Lokalisierungsdatei mit wp_enqueue_script()
im Theme einbinden:
function my_theme_resources()
{
// jQuery UI Datepicker-Lokalisierung laden
wp_enqueue_script('jquery-ui-datepicker-de', get_stylesheet_directory().'/libs/jquery.ui.datepicker-de.min.js', array('jquery-ui-datepicker'));
}
add_action('wp_enqueue_scripts', 'my_theme_resources');
Gravity Forms: Aktuelle Seite eines Formulars ermitteln
Mit dieser kleinen Funktion lässt sich bei einem Mehrseitigen Gravity-Forms-Formular die aktuelle Seite ermitteln:
function gf_get_current_page()
{
return GFFormDisplay::get_current_page($_POST['gform_submit']);
}
Tipp: WordPress-Spickzettel für eigene Themes
Auf wp-cheatsheet.com finden sich eine Sammlung der wichtigsten Informationen und Code-Schnipsel für das eigene WordPress-Theme:
GenerateWP: PHP-Code für WordPress-Standardsituationen
Auf der Website generatewp.com kann man sich den PHP-Code für WordPress-Standardsituationen wie das anlegen von Custom Post Types oder Custom Taxonomies mit wenigen Klicks zusammenstellen:
Tipp: CSS-Pfeile einfach erstellen auf cssarrowplease.com
WordPress: Beitragsdatum außerhalb des Loops
So lässt sich das Datum eines Beitrags auch außerhalb der WordPress-Loop entsprechend der Datumskonfiguration in PHP abrufen:
$datum=get_the_time(get_option('date_format'), $post->ID);
Sticky-Header mit jQuery
Mit dieser kleinen JavaScript/jQuery-Funktion lässt sich der Website-Header in einen Sticky-Header verwandeln. Beim Scrollen über eine bestimmte Position wird dynamisch eine .sticky
CSS-Klasse hinzugefügt, der dann per CSS beliebige Eigenschaften zugewiesen werden können. Natürlich funktioniert das auch mit beliebigen anderen HTML-Elementen.
JavaScript/jQuery
jQuery(document).ready(function($) {
function sticky()
{
var window_top=$(window).scrollTop();
var top_position=$('body').offset().top;
var element_to_stick=$('#header');
if (window_top > top_position) {
element_to_stick.addClass('sticky');
} else {
element_to_stick.removeClass('sticky');
}
}
$(window).scroll(sticky);
sticky();
});
CSS
#header.sticky
{
position: fixed;
}
WordPress: nach Dateinamen in den Medien suchen
WordPress berücksichtigt leider keine Dateinamen bei der Suche in den Medien.
Mit dieser PHP-Funktion in der functions.php
lässt sich die Mediensuche erweitern:
// Nach Dateinamen in der Mediathek suchen
function posts_search_media_filenames($search, $a_wp_query)
{
global $wpdb, $pagenow;
// Only Admin side && Only Media Library page
if ( !is_admin() && 'upload.php' != $pagenow ) return $search;
// Original search string:
// AND (((wp_posts.post_title LIKE '%search-string%') OR (wp_posts.post_content LIKE '%search-string%')))
$search = str_replace(
'AND ((',
'AND (((' . $wpdb->prefix . 'posts.guid LIKE \'%' . $a_wp_query->query_vars['s'] . '%\') OR ',
$search
);
return $search;
}
add_filter('posts_search', 'posts_search_media_filenames', 10, 2);