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.
Aufgrund von Aktualisierungen (Core, Theme, Plugins) ist es zudem möglich, dass der ein oder andere Code nicht mehr vollständig funktioniert.
WordPress
Dieses Problem kommt sicherlich nicht so häufig vor. Sollte man sich einmal nicht mehr auf der eigenen WordPress Webseite einloggen können, aber Zugriff auf die Datenbank haben, hilft die nachfolgende Lösung. (In dem beschriebenen Fall würde es auch reichen, nur das Passwort zurückzusetzen.)
In der Tabelle _users erstellt man einen neuen Benutzer. Beim Passwortfeld verwendet man die Funktion „MD5“, damit das gewählte Passwort entsprechend umgewandelt werden kann.
Anschließend merkt man sich die „ID“ des neuen Nutzers.
Man wechselt dann in die Tabelle _usermeta und erstellt für den neuen Nutzer einen weiteren Eintrag. Die user_id ist bekannt, der meta_key ist _capabilities
und als meta_value gibt man a:1:{s:13:“administrator“;b:1;} ein.
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.
/* Kommentar Feed entfernen */ add_filter( 'feed_links_show_comments_feed', '__return_false' ); /* WordPress Generator entfernen */ remove_action('wp_head', 'wp_generator'); /* Slider Revolution Meta Generator entfernen */ function remove_revslider_meta_tag() { return ""; } add_filter( 'revslider_meta_generator', 'remove_revslider_meta_tag' );
Generell ist es möglich innerhalb eines WordPress Verzeichnisses mehrere weitere WordPress Webseiten zu integrieren. Ob dies immer der beste Weg ist sei dahingestellt.
Nennt man das Unterverzeichnis für die weitere WordPress Installation z.B. /intern/, dann darf in der übergeordneten WordPress Installation dieser Name nicht für eine Unterseite verwendet werden, damit es nicht zu Konflikten kommt.
Zudem muss die .htaccess Datei in dem Unterverzeichnis wie nachfolgend erklärt angepasst werden:
# BEGIN WordPress <IfModule mod_rewrite.c> RewriteEngine On RewriteBase /intern/ RewriteRule ^index.php$ - [L] RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule . /intern/index.php [L] </IfModule> # END WordPress
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 }); });
Die meisten WordPress Webseiten verwenden Google Fonts und laden diese vom Google Server. Aufgrund der Verbindung zum Google Server kann es hier zu rechtlichen Problem führen, sodass ein lokales einbinden der Schriften auf der Webseite dringend empfohlen wird. Je nach verwendeten Theme kann dieses auch schnell einmal komplizierter ausfallen. Wenden Sie sich an entsprechende Experten, wenn die nachfolgenden Schritte nicht funktionieren.
1. Schriftarten und Stile feststellen
Zu allererst muss klar sein, welche Schriften auf den Webseiten aktuell verwendet werden. Dies kann über die Entwickler Konsole geschehen oder noch einfacher über eine der beiden nachfolgenden Seiten: https://sicher3.de/google-fonts-checker/ oder https://google-fonts-checker.54gradsoftware.de/de
2. Schriftarten herunterladen
Wenn man die Schriften nicht direkt von Google herunterladen möchte, ist die nachfolgende Webseite genau das richtige. Hier kann auch direkt der CSS Code mitkopiert werden, der benötigt wird damit die Schriften auf der Webseite integriert werden können: https://google-webfonts-helper.herokuapp.com/fonts
3. Schriften integrieren
Nutzt man „Elementor“ können hier die Schriftarten unter „Benutzerdefinierte Schriften“ übertragen werden. Andernfalls wird ein entsprechender Ordner auf dem Server erstellt, die Schriften da rein kopiert und der zuvor genannten CSS Code in die style.css des verwenden Themes übertragen.
4. Prüfung
Unter Elementor muss folgenden Codezeile in der function.php Datei integriert werden, damit die Schriften wirklich nur noch lokal abgerufen werden.
add_filter( 'elementor/frontend/print_google_fonts', '__return_false' );
Für andere Webseiten gilt es in den Theme Dateien nach Codeaufrufen wie „fonts.googleapis.com“ zu suchen, diese dann zu löschen oder auskommentieren. Anschließend sollte wie unter Punk 1 beschrieben, die Webseiten noch einmal durchsucht werden.
Sofern auch Google Captcha verwendet wird, ist im nächsten Beitrag eine Alternative genannt.
Wie auch Google Fonts, die über den Google Server aufgerufen werden, besteht bei der Verwendung von Google Captcha ein Konflikt mit der DSGVO. Leider ist hier die lokale Einbindung so nicht möglich.
Um sich dennoch vor Spam über Formulare retten zu können, hat sich der Einsatz von Honeypots (Honigtöpfen) als Hilfreich erwiesen.
Das WordPress Plugin WP Armour bietet so einen Honigtopf an, ohne dass eine aufwendige Integration nötig ist.
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)
Mit folgenden Code in der functions.php, lässt sich ein eigenes Logo oberhalb der Login Box erstellen.
function geek_login_logo() { ?> <style type="text/css"> #login h1 a, .login h1 a { background-image: url(https://www.cms-geek.de/wp-content/uploads/logo.png); margin-bottom: 0; background-size: 200px; height: 200px; width: 200px; margin-left: auto; margin-right: auto; border-radius: 50%; } body.login {background-color: #fff;} .login #backtoblog a, .login #nav a {color: #ff0000 !important} </style> <?php } add_action( 'login_enqueue_scripts', 'geek_login_logo' );
Folgender Code kann als neue Template Datei im Theme Ordner verwendet werden:
<?php /* Template Name: Password Reset Template */ global $wpdb, $user_ID; function tg_validate_url() { global $post; $page_url = esc_url( get_permalink( $post->ID )); $urlget = strpos( $page_url, "?" ); if ($urlget === false) { $concate = "?"; } else { $concate = "&"; } return $page_url.$concate; } if ( !$user_ID ) { //block logged in users if(isset( $_POST['action']) && $_POST['action']=='save_pw_reset' ){ if ( !wp_verify_nonce( $_POST['save_pwd_nonce'], "save_reset_password" ) ) { exit("No trick please"); } $user_login = base64_decode( $_POST['user_token'] ); $user_data = $wpdb->get_row( "SELECT ID, user_login, user_email FROM $wpdb->users WHERE ID = '". $user_login ."'" ); if( $user_data ) { wp_set_password( $_POST['new_password'], $user_login ); $wpdb->update( $wpdb->users,array('user_activation_key'=>'' ), array( 'ID'=>$user_login ) ); echo json_encode( array( 'status' => 'success', 'msg' => 'Password Reset successfully' ) ); }else{ echo json_encode( array( 'status' => 'error', 'msg' => 'please try again' ) ); } exit(); } if(isset( $_GET['key'] ) && $_GET['action'] == "reset_pwd" ) { $reset_key = $_GET['key']; $user_login = base64_decode($_GET['login']); $user_data = $wpdb->get_row( $wpdb->prepare( "SELECT ID, user_login, user_email FROM $wpdb->users WHERE user_activation_key = %s AND (user_login = %s OR user_email = %s )" , $reset_key, $user_login,$user_login )); $user_login = $user_data->user_login; $user_email = $user_data->user_email; if( !empty( $reset_key ) && !empty( $user_data ) ) { get_header(); ?> <div data-height="200" class="title_outer title_without_animation"> <div style="height:100px;" class="title title_size_small position_left "> <div class="image not_responsive"></div> <div style="height:100px;" class="title_holder"> <div class="container"> <div class="container_inner clearfix"> <div class="title_subtitle_holder"> <h1><span><?php echo the_title(); ?></span></h1> </div> </div> </div> </div> </div> </div> <div class="container"> <?php if( isset( $qode_options_proya['overlapping_content'] ) && $qode_options_proya['overlapping_content'] == 'yes' ) { ?> <div class="overlapping_content"><div class="overlapping_content_inner"> <?php } ?> <div class="container_inner forgot_password default_template_holder clearfix"> <div class="forgot_box"> <?php if ( have_posts() ) : ?> <?php while ( have_posts() ) : the_post(); ?> <div class="pwd_res_container"> <p>Please enter your new password.</p> <form method="post" action="" id="saveresetpwdfrm"> <label>New password</label> <br /> <input type="password" class="text" name="new_password" id="new_password" value="" style="width:200px" /><br /><br /> <label>Repeat new password</label> <br /> <input type="hidden" name="user_email" value="<?php echo $user_email; ?>" /> <input type="password" class="text" name="repeat_new_password" id="repeat_new_password" value="" style="width:200px" /><br /> <input type="hidden" name="action" value="save_pw_reset" /> <input type="hidden" name="save_pwd_nonce" value="<?php echo wp_create_nonce("save_reset_password"); ?>" /> <input type="hidden" name="user_token" value="<?php echo base64_encode($user_data->ID); ?>" /> <input type="submit" id="savesubmitbtn" class="reset_password" name="submit" value="Save" /> </form> <div id="result"></div> <!-- To hold validation results --> </div> <script type="text/javascript"> jQuery( "#saveresetpwdfrm" ).submit( function() { if( jQuery( '#new_password' ).val() != '' ){ if( jQuery( '#repeat_new_password' ).val() != '' ){ if( jQuery( '#new_password' ).val() == jQuery( '#repeat_new_password' ).val() ){ jQuery( '#result' ).html( '<span class="loading">Validating...</span>' ).fadeIn(); var input_data = jQuery( '#saveresetpwdfrm' ).serialize(); jQuery.ajax({ type: "POST", url: "<?php echo get_permalink( $post->ID ); ?>", data: input_data, success: function( msg ){ change_data = JSON.parse(msg); if(change_data.status=='success'){ jQuery( '.pwd_res_container' ).html( '<div><p>Your password reset successfully.</p><p><a href="<?php echo home_url('/login'); ?>">Click here </a> to logged in.</p></div>' ).fadeIn(); }else{ jQuery( '#result' ).html( change_data.msg ).fadeIn(); } } }); }else{ jQuery( '#result' ).html( '<span class="loading">Password and repeat password not matched</span>' ).fadeIn(); } }else{ jQuery( '#result' ).html( '<span class="loading">Please enter repeat password</span>' ).fadeIn(); } }else{ jQuery( '#result' ).html( '<span class="loading">Please enter password</span>' ).fadeIn(); } return false; }); </script> <?php endwhile; ?> <?php else : ?> <h2><?php _e('Not Found'); ?></h1> <?php endif; ?> </div> </div> <?php if(isset($qode_options_proya['overlapping_content']) && $qode_options_proya['overlapping_content'] == 'yes') {?> </div></div> <?php } ?> <style> .container_inner.forgot_password.default_template_holder.clearfix > div { margin-bottom: 35px; } #savesubmitbtn { background: #ff9900 none repeat scroll 0 0; border: medium none; border-radius: 3px; color: #fff !important; font-size: 15px; margin-top: 15px; padding: 10px; text-transform: capitalize; cursor: pointer; } .forgot_box { border: 2px solid rgb(0, 128, 0); padding: 20px; width: 50%; } .pwd_res_container div#result { font-style: italic; font-weight: bold; margin-top: 20px; } </style> </div> <?php get_footer(); }else{ $redirect_to = get_permalink( $post->ID ); wp_safe_redirect($redirect_to); exit(); } } //exit(); if( $_POST['action'] == "tg_pwd_reset" ){ if ( !wp_verify_nonce( $_POST['tg_pwd_nonce'], "tg_pwd_nonce" )) { exit( "No trick please" ); } if( empty( $_POST['user_input'] ) ) { echo "<div class='error'>Please enter your Username or E-mail address</div>"; exit(); } //We shall SQL escape the input $user_input = $wpdb->escape( trim( $_POST['user_input'] ) ); if ( strpos( $user_input, '@' ) ) { $user_data = get_user_by_email( $user_input ); if( empty( $user_data ) ) { //delete the condition $user_data->caps[administrator] == 1, if you want to allow password reset for admins also echo "<div class='error'>Invalid E-mail address!</div>"; exit(); } }else { $user_data = get_userdatabylogin($user_input); if(empty( $user_data ) ) { //delete the condition $user_data->caps[administrator] == 1, if you want to allow password reset for admins also echo "<div class='error'>Invalid Username!</div>"; exit(); } } $user_login = $user_data->user_login; $user_email = $user_data->user_email; $key = $wpdb->get_var( $wpdb->prepare( "SELECT user_activation_key FROM $wpdb->users WHERE user_login = %s OR user_email = %s ", $user_login ) ); //generate reset key $key = wp_generate_password( 20, false ); $key = sha1( $key . $user_email . uniqid( time(), true ) ); $wpdb->update( $wpdb->users, array( 'user_activation_key' => $key), array( 'user_login' => $user_login ) ); //mailing reset details to the user $message = __( 'Someone requested that the password be reset for the following account:' ) . "\r\n\r\n"; $message .= get_option('siteurl') . "\r\n\r\n"; $message .= sprintf( __( 'Username: %s' ), $user_login ) . "\r\n\r\n"; $message .= __( 'If this was a mistake, just ignore this email and nothing will happen.' ) . "\r\n\r\n"; $message .= __( 'To reset your password, visit the following address:' ) . "\r\n\r\n"; $message .= tg_validate_url() . "action=reset_pwd&key=$key&login=" . base64_encode($user_login) . "\r\n"; $headers[] = 'From: Max Muster < test@test.de >'; if ( $message && !wp_mail( $user_email, 'Password Reset Request', $message, $headers ) ) { echo "<div class='error'>Email failed to send for some unknown reason.</div>"; exit(); }else { echo "<div class='success'>We have just sent you an email with Password reset instructions.</div>"; exit(); } } else if( $_REQUEST['action']!='reset_pwd' ) { get_header(); ?> <div data-height="200" class="title_outer title_without_animation"> <div style="height:100px;" class="title title_size_small position_left "> <div class="image not_responsive"></div> <div style="height:100px;" class="title_holder"> <div class="container"> <div class="container_inner clearfix"> <div class="title_subtitle_holder"> <h1><span><?php echo the_title(); ?></span></h1> </div> </div> </div> </div> </div> </div> <div class="container"> <?php if( isset($qode_options_proya['overlapping_content'] ) && $qode_options_proya['overlapping_content'] == 'yes' ){ ?> <div class="overlapping_content"><div class="overlapping_content_inner"> <?php } ?> <div class="container_inner forgot_password default_template_holder clearfix"> <div class="forgot_box"> <?php if ( have_posts() ) : ?> <?php while ( have_posts() ) : the_post(); ?> <p>Please enter your username or email address. <br/>You will receive a link to create a new password via email.</p> <form class="user_form" id="wp_pass_reset" action="" method="post"> <label>Username or Email:</label> <br /> <input type="text" class="text" name="user_input" value="" style="width:200px" /><br /> <input type="hidden" name="action" value="tg_pwd_reset" /> <input type="hidden" name="tg_pwd_nonce" value="<?php echo wp_create_nonce("tg_pwd_nonce"); ?>" /> <input type="submit" id="submitbtn" class="reset_password" name="submit" value="Reset Password" /> </form> <div id="result"></div> <!-- To hold validation results --> <script type="text/javascript"> jQuery( '#wp_pass_reset' ).submit(function() { jQuery( '#result' ).html( '<span class="loading">Validating...</span>' ).fadeIn(); var input_data = jQuery( '#wp_pass_reset' ).serialize(); jQuery.ajax({ type: "POST", url: "<?php echo get_permalink( $post->ID ); ?>", data: input_data, success: function( msg ){ jQuery( '.loading' ).remove(); jQuery( '<div>' ).html( msg ).appendTo( 'div#result' ).hide().fadeIn( 'slow' ); } }); return false; }); </script> <?php endwhile; ?> <?php else : ?> <h2><?php _e('Not Found'); ?></h1> <?php endif; ?> </div> </div> <?php if( isset($qode_options_proya['overlapping_content'] ) && $qode_options_proya['overlapping_content'] == 'yes' ){ ?> </div></div> <?php } ?> </div> <style> .container_inner.forgot_password.default_template_holder.clearfix > div { margin-bottom: 35px; } #submitbtn.reset_password, #savesubmitbtn { background: #ff9900 none repeat scroll 0 0; border: medium none; border-radius: 3px; color: #fff !important; font-size: 15px; margin-top: 15px; padding: 10px; text-transform: capitalize; } .forgot_box { border: 2px solid rgb(0, 128, 0); padding: 20px; width: 50%; } .forgot_box > div#result { font-style: italic; font-weight: bold; margin-top: 20px; } </style> <?php get_footer(); } } else { wp_redirect( home_url() ); exit; //redirect logged in user to home page } ?>
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' ), )); }
Das obere Beispiel eignet sich gut um ein Custom Post Type zu erstellen, aber nicht um noch weitere hinzufügen zu können. Ist dies der Fall hilft der nachfolgende Code. Lediglich die Variablen müssen angepasst werden.
function create_new_ansprechpartner() { $labels = array( 'name' => _x('Ansprechpartner', 'Ansprechpartner', 'ubert'), 'singular_name' => _x('Ansprechpartner', 'Ansprechpartner', 'ubert'), 'menu_name' => __('Ansprechpartner', 'ubert'), 'edit_item' => __('Ansprechpartner bearbeiten', 'ubert'), 'add_new_item' => __( 'Neuer Ansprechpartner', 'ubert' ), 'update_item' => __( 'Ansprechpartner aktualisieren', 'ubert' ), 'view_item' => __( 'Ansprechpartner ansehen', 'ubert' ), 'not_found_in_trash' => __('Not found in Trash', 'ubert') ); $args = array( 'labels' => $labels, 'description' => __('Ansprechpartner', 'ubert'), 'supports' => array('title', 'author', 'editor', 'thumbnail', 'excerpt', 'revisions', 'custom-fields'), 'menu_icon' => 'dashicons-welcome-write-blog', 'menu-position' => null, 'public' => true, 'publicly_queryable'=> true, 'show_ui' => true, 'show_in_menu' => true, 'show_in_admin_bar' => true, 'rewrite' => array( 'slug' => 'unsere-ansprechpartner' ), 'capability_type' => 'post', 'can_export' => true, 'has_archive' => false, 'hierarchical' => false, 'publicly_queryable'=> true ); register_post_type('uansprechpartner', $args); $labels = array( 'name' => esc_html__( 'Abteilungen', 'ubert' ), 'singular_name' => esc_html__( 'Abteilung', 'ubert' ), 'search_items' => esc_html__( 'Abteilung suchen', 'ubert' ), 'all_items' => esc_html__( 'Alle Abteilungen', 'ubert' ), 'parent_item' => esc_html__( 'Parent Category', 'ubert' ), 'parent_item_colon' => esc_html__( 'Parent Category:', 'ubert' ), 'edit_item' => esc_html__( 'Abteilung bearbeiten', 'ubert' ), 'update_item' => esc_html__( 'Abteilung aktualisieren', 'ubert' ), 'add_new_item' => esc_html__( 'Abteilung hinzufügen', 'ubert' ), 'new_item_name' => esc_html__( 'New Category Name', 'ubert' ), 'menu_name' => esc_html__( 'Abteilungen', 'ubert' ), ); register_taxonomy( 'uansprechpartner_category', array( 'uansprechpartner' ), array( 'hierarchical' => true, 'labels' => $labels, 'show_ui' => true, 'show_admin_column' => true, 'query_var' => true, ) ); $labels = array( 'name' => esc_html__( 'Ansprechpartner Tags', 'ubert' ), 'singular_name' => esc_html__( 'Ansprechpartner Tag', 'ubert' ), 'search_items' => esc_html__( 'Search Tags', 'ubert' ), 'all_items' => esc_html__( 'All Tags', 'ubert' ), 'parent_item' => esc_html__( 'Parent Tag', 'ubert' ), 'parent_item_colon' => esc_html__( 'Parent Tag:', 'ubert' ), 'edit_item' => esc_html__( 'Edit Tag', 'ubert' ), 'update_item' => esc_html__( 'Update Tag', 'ubert' ), 'add_new_item' => esc_html__( 'Add New Tag', 'ubert' ), 'new_item_name' => esc_html__( 'New Tag Name', 'ubert' ), 'menu_name' => esc_html__( 'Tags', 'ubert' ), ); register_taxonomy( 'uansprechpartner_tag', array( 'uansprechpartner' ), array( 'hierarchical' => false, 'labels' => $labels, 'show_ui' => true, 'show_admin_column' => true, 'query_var' => true, ) ); } add_action('init', 'create_new_ansprechpartner');
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.
Wird die SVG Grafik in manchen Browsern nicht gerendert hilft möglicherweise folgendes:
Die entsprechende SV Datei mit einem Texteditor.
xlink:href="data:img/png;base64,
ersetzen durch
xlink:href="data:image/png;base64,
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.
Folgende Anpassungen sorgen für die richtige responsive Ansicht beim einbetten von Videos in der Webseite:
function evolution_wrap_oembed( $html ){ $html = preg_replace( '/(width|height)="\d*"\s/', "", $html ); return'<div class="embed-responsive embed-responsive-16by9">'.$html.'</div>'; } add_filter( 'embed_oembed_html','evolution_wrap_oembed',10,1);
.embed-responsive.embed-responsive-16by9 { position: relative; padding-bottom: 56.25%; /* 16:9 */ padding-top: 25px; height: 0; } .embed-responsive.embed-responsive-16by9 iframe { position: absolute; top: 0; left: 0; width: 100%; height: 100%; } video { width: 100% !important; height: auto !important; }
Wie es der Titel schon beschreibt, wird mit dem folgenden Code ein ACF Field, das zuvor natürlich angelegt sein muss, in den Textauszug von Beiträgen integriert.
function testexcerpt() { $t_field1 = get_post_meta( get_the_ID(), 'testfeld1', true ); $t_field2 = get_post_meta( get_the_ID(), 'testfeld2', true ); $original = get_the_excerpt(); //Verändert nur Beiträge die auf einer bestimmten Seite dargestellt werden if ( is_page( 12204 ) ) { $excerpt = '<div class="new-meta"><img src="beispiel1.png"><br>'. $t_field1 .' </div><div class="new-meta"><img src="beispiel2.png"><br> '. $t_field2 .' </div> '; echo $excerpt; } else { echo $original; } }; add_filter( 'the_excerpt', 'testexcerpt' );
Integriert man ein Skript / Funktion / Element in der Header oder Footer Datei, wird dieses global auf allen Seiten verwendet. Mit dem nachfolgenden Skript lässt sich dieses nur auf bestimmten Seiten begrenzen.
<?php if ( is_page('ID DER GEWÜNSCHTEN SEITE') ) { ?> <!-- Hier kommt das Skript hinein --> <?php } ?>
Bei Linkedin ist es möglich, Webseite als Referenzen zu integrieren. Dabei wird automatisch ein Bild, Titel und Beschreibungstext von der Webseite übernommen. Titel ist hierbei der Seitenname und die Beschreibung die Meta-Description. Das Bild wiederrum lässt sich durch das Plugin Yoast SEO ändern. Hierzu auf der Startseite in den Bearbeitungsmodus gehen und in den Yoast Einstellungen dieser den Reiter „Social“ > „Facebook Image“ wählen und ein entsprechendes Bild hochladen.
Wurde im Vorfeld schon einmal versucht die Webseite bei Linkedin zu übernehmen, muss eine Aktualisierung dieser Seite vorgenommen werden. Dafür gibt man die gewünschte Domain auf https://www.linkedin.com/post-inspector/inspect/ ein und versucht es anschließend noch einmal.
Stellt man die letzten Blogeinträge auf einer Webseite da, wird der Auszugstext üblicherweise aus den ersten Worten im Gesamttext generiert oder vom Nutzer im Backend selbst festgelegt. Nutz man hingegen Benutzerdefinierte Felder im Backend und möchte die Beitragsvorschau entsprechend dieser Inhalte gestalten, lässt sich dies in Kombination mit dem Auszugstext sehr gut lösen.
Mit Hilfe des folgenden Codes lassen sich bestehende Bloginhalte, sowie benutzerdefinierte Felder kombinieren. Überflüssige Darstellungen müssen anschließend noch per CSS ausgeblendet werden.
function testexcerpt() { $t_field1 = get_post_meta( get_the_ID(), 'FELD1', true ); $t_field2 = get_post_meta( get_the_ID(), 'FELD2', true ); $original = get_the_excerpt(); $titel = get_the_title(); echo '<div class="new-meta-date">'. $t_field1 .' </div> '; echo '<div class="new-meta-sub">'. $t_field2 .' </div> '; echo '<div class="new-meta-titel">'. $titel .' </div> '; echo $original; }; add_filter( 'the_excerpt', 'testexcerpt' );
Nicht alle Themes bzw. Editoren zeigen Beitragsformate an, mit dem nachfolgenden functions.php Code, wird die Unterstützung aktiviert.
add_action( 'after_setup_theme', 'wpsites_child_theme_posts_formats', 11 ); function wpsites_child_theme_posts_formats(){ add_theme_support( 'post-formats', array( 'aside', 'audio', 'chat', 'gallery', 'image', 'link', 'quote', 'status', 'video', ) ); }
add_filter( 'gettext_with_context', 'rename_post_formats', 10, 4 ); function rename_post_formats( $translation, $text, $context, $domain ) { $names = array( 'Audio' => 'Custom Name', 'Chat' => 'Custom Name', 'Aside' => 'Custom Name', ); if ( $context == 'Post format' ) { $translation = str_replace( array_keys( $names ), array_values( $names ), $text ); } return $translation; }
Zum Importieren von XML bzw. CSV Dateien eignet sich Import all XML, CSV & TXT into WordPress sehr gut. Sollen in diesem Zusammenhang Benutzerdaten übertragen werden, z.B. aus Joomla, eignet sich für dieses Plugin die Erweiterung User Import with meta.
Seit einigen Jahren benutze ich zur Sicherung von WordPress Webseiten das Plugin „Duplicator“. Die Wiederherstellung ist dank einer .zip Datei und php Datei zum ansprechen kinderleicht von der Hand. In wenigen Fällen funktioniert das Plugin jedoch nicht auf allen Servern bzw. das Entpacken der .zip Datei wird nicht vollständig durchgeführt. In diesen Fällen lässt sich das Archiv auch von Hand entpacken und auf den Server hochladen.
Bei manuellen Wiederherstellen werden oft die zuvor gemachten Theme Einstellungen nicht übernommen. Zudem bietet nicht jedes Theme eine Import/Export Funktion. Hilfreich kann hier das Plugin „Customizer Export/Import“ sein, dass eine Export Datei auf der Ursprungsseite generiert. Diese Datei lässt sich dann auf der Wiederhergestellten Webseite importieren.
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');
Wenn WordPress nicht mehr richtig läuft, kommen meist die typischen Kandidaten als mögliche Fehlerursache in Frage: Veralteter Core, veraltetes Theme oder Plugin, Probleme aufgrund von geänderter PHP Version, Plugin Konflikte untereinander oder zu geringer Speicher.
Nicht alle Fehler lassen sich auf den ersten Blick feststellen. Bevor man also zu viel Zeit investiert, solle erst einmal der Fehler Log ausgelesen werden. Hierfür muss eine entsprechende Ergänzung in der wp-config.php vorgenommen werden (je nach Hoster müssen dort eventuell zusätzliche Einstellungen vorgenommen werden).
define( 'WP_DEBUG', true ); define( 'WP_DEBUG_LOG', true ); define( 'WP_DEBUG_DISPLAY', false );
Die entsprechende Log Datei sollte dann auf dem Server unter /wp-content/debug.log zu finden sein.
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;
Der TypeError … is not a function spricht in den meisten Fällen für ein fehlendes jQuery Skript. Das Skript fehlt entweder generell, wurde also nicht im Header integriert, oder wird zu spät geladen, also erst nachdem das eigentliche Skript bereits aufgerufen wurde.
Im genannten Beispiel ist es hingegen das fehlende Bootstrap Skript, das nachfolgend hinzugefügt werden kann.
<script type="text/javascript" src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
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 = '' ) {
Der Aufruf $.browser() wird von neuren jQuery Versionen nicht mehr unterstützt. Fügt man den nachfolgenden Code in die fehlerhafte .js Datei ein, lässt sich die Funktion wiederherstellen.
var matched, browser; jQuery.uaMatch = function( ua ) { ua = ua.toLowerCase(); var match = /(chrome)[ \/]([\w.]+)/.exec( ua ) || /(webkit)[ \/]([\w.]+)/.exec( ua ) || /(opera)(?:.*version|)[ \/]([\w.]+)/.exec( ua ) || /(msie) ([\w.]+)/.exec( ua ) || ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec( ua ) || []; return { browser: match[ 1 ] || "", version: match[ 2 ] || "0" }; }; matched = jQuery.uaMatch( navigator.userAgent ); browser = {}; if ( matched.browser ) { browser[ matched.browser ] = true; browser.version = matched.version; } // Chrome is Webkit, but Webkit is also Safari. if ( browser.chrome ) { browser.webkit = true; } else if ( browser.webkit ) { browser.safari = true; } jQuery.browser = browser;
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.
Leider müssen Fehler nicht immer zwangsläufig durch das WordPress System selbst entstehen, eine nicht leichte Lösung ist es, wenn der Server ein Problem verursacht.
Der Hoster Strato bietet für seine PHP Auswahl z.B. eine Art Boost Funktion an. Im aktivierten Zustand kann diese zu einer gelegentlichen Fehler 500 Meldung führen, wenn man versucht eine Seite oder einen Beitrag zu bearbeiten. Deaktiviert man diese Funktion innerhalb seines Hosting Pakets, läuft die Seite wieder fehlerfrei.
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.
Wird ein Plugin nicht richtig oder nur teilweise übersetzt, ist es nicht immer ein Fehler der dahinter steckt. Voraussetzungen ist, dass dieses Plugin überhaupt übersetzt wurde. In diesem Fall befindet sich ein Unterordner „language“ im entsprechenden Plugin Ordner. Die entsprechende deutsche Übersetzungsdatei muss sich dann auch im richtigen „language“ Verzeichnis (/wp-content/language/) befinden bzw. händisch dahin kopiert werden.
Besonderheit: In der deutschen Sprache lässt sich WordPress nicht nur in Deutsch, sondern auch in der deutschen Sie Form einstellen. Das hat dann den Vorteil, wenn Sie Nutzer bei Standartausgaben nicht mit Du ansprechen wollen. Das gewünschte Plugin besitzt diese Sie Form eventuell nicht und muss dann händisch angepasst werden, damit in diesem Fall die Übersetzung aber überhaupt funktioniert, muss der Dateiname erweitert werden: PLUGINNAME-de_DE_formal.DATEIENDUNG
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.
Abhängig von beeinflussenden CSS-Eigenschaften, kann es beim Aktivieren von Animationen in Elementor, zu kurzzeitigen auftauchen von horizontalen Scrollbalken kommen, wenn z.B. ein seitliches einfliegen von Elementen eingestellt ist.
Die nachfolgenden CSS-Einstellungen sollten dieses Problem beheben.
body { margin: 0; overflow-x: hidden; }
Klickt man auf eine Seite um diese mit Elmentor zu bearbeiten, kommt es in Ausnahmefällen zu einem endlosen Laden oder der Fehlermeldung das Elementor nicht geladen werden kann.
Die Fehlerquellen können hier vielfältig sein. Eine Möglichkeit ist jedoch unter „Einstellungen“ > „Permalinks“, diese einmal neu zu speichern.
Zur Fehlerbehebung muss folgender Eintrag in der .htaccess Datei vorgenommen werden:
<IfModule mod_headers.c> Header always set X-Frame-Options SAMEORIGIN </IfModule>
Diese Fehlermeldung ist vielfältig und kann von tatsächlichen fehlenden Benutzerrechten, über fehlende Dateirechte bis hin zu nicht übernommenen Prefixes verursacht werden.
In meinem Fall hatte ich Admin Rechte, konnte mich einloggen, so dass die Admin Leiste sichtbar war, aber ich kam nicht auf dem Dashboard bzw. andere Backend Seiten.
Lösung: Die ID und der Name des Admin musste geändert werden, zu ID 1 und Administrator. Zusätzlich der Eintrag unter wp_capabilities korrigiert werden zu:
a:1:{s:13:"administrator";b:1;}
Fehler: In der URL wird hinter dem Namen z.B. -2 eingefügt, obwohl die Seite nicht doppelt existiert
Nutzt man bei den Permalinks richtige Namen und erstellt mehrere Seiten mit demselben Seitennamen, wird automatisch hinter der URL eine Nummer eingefügt. Taucht diese Nummer auch dann auf, wenn es keine weiteren Seiten mit diesem Namen gibt, kann dies an einem Bild liegen.
Hat ein Bild diese bestimmten Namen, wird automatisch eine Anhang-Seite erstellt, die dann zu diesem Problem führt.
Lösung: Den Bildnamen einfach ändern, z.B. mit Enable Media Replace und anschließend die betreffende URL anpassen.
Dies lässt sich mit der folgenden SQL Anweisung ändern:
UPDATE wp_options SET option_value = replace(option_value, 'oldurl.com', 'newurl.com') WHERE option_name = 'home' OR option_name = 'siteurl';UPDATE wp_posts SET guid = replace(guid, 'oldurl.com','newurl.com');UPDATE wp_posts SET post_content = replace(post_content, 'oldurl.com', 'newurl.com'); UPDATE wp_postmeta SET meta_value = replace(meta_value,'oldurl.com','newurl.com');
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');
Leider gibt es bis heute noch keine simple Möglichkeit den Button Text in den Beiträgen von Avada abzuändern.
Mit dem folgenden Code in der Theme functions.php kann der Text angepasst werden:
add_filter( 'avada_blog_read_more_link', 'my_read_more_link' ); function my_read_more_link( $read_more ) { $read_more = "Anderer Text"; return $read_more; }
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!
Die Art des Hacks kann unterschiedlich ausfallen. Es gibt Variante die einem sofort auffallen und andere die im Hintergrund ablaufen, so dass man diese nur selten mitbekommt, sofern man nicht regelmäßig alle Unterseiten einer Webseite prüft.
Wie: Die Vorgehensweise ist oft dieselben, Schwachstellen in veralteten WordPress Version oder ein veraltetes Plugin können dafür sorgen das Hacker auf die Webseite gelangen. Auch veraltete Skripte in gekauften Themes können eine Ursache sein. Oftmals ist ein Hacker auch nicht gezielt auf eine Webseite aufmerksam geworden, sondern nutzt Tools die gängige Sicherheitslücken in Webseiten versucht auszuspionieren und bei einem Treffer automatisch diese Webseite zu infiltrieren. Hier kommt es oft zu Script Injections, also das Einfügen von Skripten das entweder Nutzerdaten ausliest oder Besucher der Webseite zu anderen Webseiten weiterleitet. Im schlimmsten Fall wird Malware auf der Webseite hinterlegt, die der Besucher versehentlich herunterlädt.
Generell: Wurde eine Webseite gehackt, sollte im Idealfall eine Sicherung eingespielt werden und anschließend das System aktualisiert werden. Das Ändern alles Zugangsdaten (Backend, Datenbank, etc.) ist ebenfalls wichtig.
Suche: Möchte man sich auf die Suche nach dem Problem machen, ist eine allgemeine Anleitung nicht möglich, da diese Skripte bzw. Schadcode überall hinterlegt sein kann. In einer vorhandenen Datei, in einer neuen Datei oder direkt in der Datenbank. Hilfreich ist es, wenn man den problematischen Code z.B. im Quellcode gefunden hat, so dass man schon einmal weiß wonach man suchen muss. Eine Möglichkeit ist auf dem Server nach Dateien zu suchen, deren Änderungsdatum mit dem Hackdatum übereinstimmen, sofern man den genauen Zeitraum des Hacks halbwegs sicher bestimmen kann.
Hilfreich bei der Suche kann https://sitecheck.sucuri.net/ sein, zusätzlich gibt es hierzu auch noch ein WordPress Plugin. Ebenfalls gute Erfahrungen konnte ich mit dem Quttera Web Malware Scanner https://wordpress.org/plugins/quttera-web-malware-scanner/ machen. Oftmals können Sie die problematische Datei bzw. Dateien bestimmen oder zumindest einen ungefähren Hinweis dazu preisgeben.
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
Kleine Einstellung, große Wirkung. Wird das „Von“ Feld in Contact Form 7 nicht korrekt ausgefüllt, steht WordPress als Sender in der E-Mail. Passt man dies wie nachfolgend erklärt an, gehört dieses Problem der Vergangenheit an.
Sendername <senderemail@test.de>
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.
Plugin Contact Form 7: "This email address does not belong to the same domain as the site." beheben.
Der genannte Fehler tritt immer dann auf, wenn die VON Adresse, nicht zur Webseiten Domain passt. Dies ist oftmals dann der Fall, wenn man in dem VON Feld den Inhalt des [your-email] Felds hinterlegt.
Lösung: Hier sollte ebenfalls die Adresse hinterlegt werden, die auch im AN Feld angegeben wird. Damit man beim Antworten auf diese E-Mail jedoch bereits den richtigen Empfänger hat und nicht sich selbst antwortet, kann im Additional Headers folgendes hinterlegt werden: „Reply-To: [your-email]“.
Das Plugin Ninja Forms mit der Erweiterung Multi Part Forms lässt sich so erweitern, dass der „Nächste Schritt“ Button teilweise überflüssig wird. Befindet sich im Formular ein Feld das mit einem normalen Klick aktiviert wird, lässt sich dies mit dem nachfolgenden Code realisieren. Bei Mehrfachauswahl ist dies auch möglich, ohne dass hier das Skript bereits beim ersten Klick auf den nächsten Schritt springt.
$(document).ready(function () { $(document).on('click', '.clicky', function(event) { event.preventDefault; $(".nf-next").click(); function greet(){ $(".nf-next").click(); } setTimeout(greet, 500); });
jQuery(document).on( 'nfFormReady', function( e, layoutView ) { // Your code goes here... });
<script type="text/javascript"> jQuery(document).on( 'nfFormReady', function( e, layoutView ) { setInterval(function() { jQuery('.checklist').hide(); if(!jQuery("#nf-field-566").val()){ jQuery('.checklist').hide(); } else { jQuery('.checklist').show(); } }, 1000); }); </script>
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); } });
Wenn man auf Slides von außerhalb des Plugins zugreifen möchte, z.B. das über einen bestimmten Link / Button ein bestimmter Slide angezeigt werden soll, kann sich wie folgt behelfen:
1. Zuerst erstellt man einen entsprechenden Link, samt Klasse.
<a href="#" class="slider-link">Show Slide Number Two</a>
2. Folgender Code wird in der Custom JavaScript section des Sliders selbst hinterlegt.
jQuery('body').on('click', '.slider-link', function() { // revapi5 equals the API identified for the slider // revshowslide(2) will load the second slide revapi5.revshowslide(2); return false; });
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 (in der neueren Version unter Tags & Link , im Feld HTML Data):
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('rs-slide').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;}
Die Lösung funktioniert beim Theme Avada, für andere Themes muß hier eventuell die Klasse geändert werden.
function add_slider_rev_to_post() { if ( is_single() && 'post' == get_post_type() ) { print do_shortcode('[rev_slider alias="aktuelles"][/rev_slider]'); } } add_filter( 'avada_after_header_wrapper', 'add_slider_rev_to_post' );
Wurde ein Domainumzug durchgeführt, sind meist die eingefügten Bilder im Slider nicht mehr zu erkennen, da diese noch falsch verlinken. In den neuen Versionen des Plugins ist eine kostenpflichtige Erweiterung nötig um die Anpassungen automatisch vornehmen zu können.
Lösung: Hat man Zugriff auf die Datenbank können in der Tabelle „wp_revslider_slides“ die entsprechenden Links händisch angepasst werden.
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.
Das Backup Plugin Duplicator erzeugt seit der neueren Version ein DUP Archiv. Mit herkömmlichen Archiv Tools lässt sich dieses leider nicht entpacken.
Der eigenen Dup Archive Extractor von Snapcreek löst dieses Problem und kann hier heruntergeladen werden.
Einen Sticky Header in Elementor umzusetzen geht relativ einfach.
1. Das komplette Header Element über „Bewegeungseffekte“ auf Sticky „Oben“ setzen und als Offset Wert 10 einstellen.
2. Damit sich das Logo mittverkleinert, muss dieses die Klasse „logo“ zugewiesen bekommen.
3. Das Header Element bekommt einen „Eigenes CSS“ Code:
/* Hintergrundfarbe wird weiß wenn scroll */ .elementor-sticky--effects { background-color:rgba(255,255,255,1); transition: all 0.5s ease; } /* Menü Farbe ändern on scroll */ .elementor-sticky--effects .elementor-nav-menu a{ color: #333!important; transition: all 0.5s ease; } /* Logo größe normal */ .logo img { width: auto; max-height: 120px; transition: all 0.5s ease; } /* Logo größe on scroll */ .elementor-sticky--effects .logo img { max-height: 60px; width: auto; }
Wahlweise lässt sich das Menü selbst ebenfalls noch etwas anpassen, damit die komplette Header Höhe reduziert wird.
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 das automatische nachladen der Google Fonts verhindern, da man diese z.B. lokal auf dem Server gespeichert hat, sind folgende Schritte notwendig:
1.) Mit dem Plugin OMGF | Host Google Fonts Locally lässt sich die bestehende Webseite nach entsprechenden Google Fonts durchsuchen, herunterladen und lokal speichern.
2.) Unter Elementor -> Einstellungen -> Standardschriftarten deaktivieren anklicken. Anschließend unter Elementor -> Werkzeuge -> CSS erneuern anklicken.
3.) Werden anschließend noch immer Google Schriften geladen, lässt sich folgendes Script in der functions.php Datei hinterlegen:
add_filter( 'elementor/frontend/print_google_fonts', '__return_false' );
4.) Setzt man parallel auch das Plugin Slider Revolution ein, gibt es hier unter Einstellungen ebenfalls noch eine Möglichkeit, dass keine Schriften mehr vom Google Server geladen werden.
Die Popup Funktion von Elementor scheint noch einige kleinere Schwierigkeiten zu haben, so dass man sich hier und da noch etwas behelfen muss. Möchte man gerne einen einfachen Audio Player im Popup integrieren, funktioniert der WordPress eigene Embed Code nicht richtig. Alternativ lässt sich dies mit dem nachfolgenden Skript lösen.
<audio controls autoplay> <source src="datei.mp3" type="audio/mpeg"> Ihr Browser unterstützt den Audio Player leider nicht. </audio>
Bei mehrzeiligen Texten in der Elementor Icon List wird das Icon immer mittig vor dem Text zentriert und leider nicht oben. Der nachfolgende Code ändert dies.
.elementor-icon-list-item { align-items: baseline !important; } .elementor-icon-list-item .elementor-icon-list-icon { margin-top:6px; }
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 Tab:
<script> document.addEventListener('DOMContentLoaded', function() { setTimeout(function() { jQuery(function($){ let desktoptitles = $('.elementor-tab-desktop-title'); let mobiletitles = $('.elementor-tab-mobile-title'); let strings = ['?tab1','?tab2','?tab3']; strings.forEach( (string,i) => { if (window.location.href.indexOf(string) > -1) { desktoptitles.eq(i).click(); mobiletitles.eq(i).click(); $('html, body').animate({ scrollTop: desktoptitles.eq(i).offset().top - 100 },'slow'); } } ); }); }, 1200); }); </script>
Lösung Akkordeon:
<script> document.addEventListener('DOMContentLoaded', function() { setTimeout(function() { jQuery(function($){ let accordiontitles = $('.elementor-accordion-item .elementor-tab-title'); let strings = ['?akkordeon1','?akkordeon2','?akkordeon3']; strings.forEach( (string,i) => { if (window.location.href.indexOf(string) > -1) { accordiontitles.eq(i).click(); $('html, body').animate({ scrollTop: accordiontitles.eq(i).offset().top - 100 },'slow'); } } ); }); }, 1200); }); </script>
Lösung Toggle:
<script> document.addEventListener('DOMContentLoaded', function() { setTimeout(function() { jQuery(function($){ let toggletitles = $('.elementor-toggle-item .elementor-tab-title'); let strings = ['?toggle1','?toggle2','?toggle3']; strings.forEach( (string,i) => { if (window.location.href.indexOf(string) > -1) { toggletitles.eq(i).click(); $('html, body').animate({ scrollTop: toggletitles.eq(i).offset().top - 100 },'slow'); } } ); }); }, 1200); }); </script>
jQuery(".menu").click(function(){ jQuery("body").addClass("open"); elementorProFrontend.modules.popup.showPopup( {id:XXX}, event); });
Mit relativ einfachem Mittel lässt sich ein beliebiger Button erstellen, der beim Klick ein Elementor Popup öffnet und nach erneutem Klick diesen Popup auch wieder schließt. Nachfolgend ist nur die Grundstruktur hinterlegt.
Einstellungen im Popup unter „Open By Selector“:
a[href="#bmenue"]
Skript zum „Schließen“ des Popups:
jQuery("#burger-menue").click(function(){ if (jQuery("#burger-menue").hasClass("open")) { jQuery("#burger-menue").removeClass("open"); jQuery(".dialog-close-button").click(); } else { jQuery("#burger-menue").addClass("open"); } });
Angenommen man möchte von der Startseite aus, ein Popup ansteuern, das sich auf der Kontaktseite befindet.
Man erstellt zuerst auf der Kontaktseite einen Button der das Popup öffnet. Den Link dieses Buttons kopiert man und setzt diesen entsprechend auf der Startseite ein.
jQuery(function($){ $('.yesclick').on('click','.elementor-location-popup a', function(event){ elementorProFrontend.modules.popup.closePopup( {}, event); }); });
Fehlt beim automatischen Scrollen zum Ankerpunkt ein nötiger Offset Wert, lässt sich dieser mit dem nachfolgenden Code in der functions.php Datei hinzufügen.
add_action( 'wp_footer', function() { if ( ! defined( 'ELEMENTOR_VERSION' ) ) { return; } ?> <script> jQuery( function( $ ) { // Add space for Elementor Menu Anchor link $( window ).on( 'elementor/frontend/init', function() { elementorFrontend.hooks.addFilter( 'frontend/handlers/menu_anchor/scroll_top_distance', function( scrollTop ) { return scrollTop - 30; } ); } ); } ); </script> <?php } );
Bis zum jetzigen Zeitpunkt bietet Elementor einen Filter nur für das Portfolio, nicht aber für das Blog Widget an.
Lösung: Auf Github findet sich das Elementor Super Cat Plugin, das u.a. genau dafür entwickelt wurde.
Mit Elementor Super Cat lässt sich einfach eine schöne Filterfunktion für Beiträge realisieren. Problemtisch wird es bei WooCommerce Produkten. Über das Blog Widget lassen sich auch Produkte einbinden, meist fehlen hier aber einige Funktionen.
Ein Workaround ist hier ein wenig jQuery. Man erstellt für jede Filterart einen eigenen Container und gibt diesem eine feste ID oder Klasse. Abgesehen von dem „Alle anzeigen“ Container, blendet man die übrigen Container per CSS aus und baut den folgenden Code ein:
<script> jQuery(document).ready(function() { jQuery(".cat-filter-for-produkte li:nth-child(1)").click(function(){ jQuery("#produkte-filter1").hide(); jQuery("#produkte-filter2").hide(); jQuery("#produkte-alle").show(); }); jQuery(".cat-filter-for-produkte li:nth-child(2)").click(function(){ jQuery("#produkte-filter1").show(); jQuery("#produkte-filter2").hide(); jQuery("#produkte-alle").hide(); }); jQuery(".cat-filter-for-produkte li:nth-child(3)").click(function(){ jQuery("#produkte-filter1").hide(); jQuery("#produkte-filter2").show(); jQuery("#produkte-alle").hide(); }); }); </script>
In Elementor lässt sich zwar die Länge des Textauszuges festlegen, aber nicht wie dieses Ende sollen. z.B. mit …
Lösung: Mit dem folgenden Code in der functions.php lässt sich dies beliebig anpassen.
function custom_post_excerpt_length($post_excerpt, $post) { //Maximale Buschstaben $length = 70; //Endet mit ... $excerpt = strlen($post_excerpt) > $length ? mb_substr($post_excerpt, 0, $length - 3, "utf-8") . "..." : $post_excerpt; return $excerpt; } add_filter('get_the_excerpt', 'custom_post_excerpt_length', 20, 2);
Dies funktioniert mit folgenden Code in der functions.php Datei.
function close_elementor_accordion() { ?> <script> jQuery(document).ready(function($) { var delay = 100; setTimeout(function() { $('.elementor-tab-title').removeClass('elementor-active'); $('.elementor-tab-content').css('display', 'none'); }, delay); }); </script> <?php } add_action('wp_footer', 'close_elementor_accordion');
Leider gibt es bisher keine integrierte Funktion in Elementor die es ermöglich, das Spalten anklickbar und mit einem Link hinterlegt werden. Neben der Plugin Lösung gibt es auch einen manuellen Weg.
Lösungsschritte:
1.) Man erstellt einen Button oder Link innerhalb dieser Spalte und fügt ein Linkziel ein.
2.) Anschließend weißt man diesem Element oder Link eine Klasse zu, z.B. „clickable“.
3.) Zum Schluss wird folgender CSS Code hinterlegt:
.elementor-column.clickable a:after { content: ""; display: block; position: absolute; top: 0; left: 0; right: 0; bottom: 0; z-index: 2; } .clickable .elementor-widget, .clickable .elementor-widget-wrap { position: static; }
Zuerst muss das Plugin „Elementor Datepicker Localization“ von https://github.com/creame/elementor-datepicker-localization heruntergeladen und installiert und anschließend der folgende Code in der functions.php hinterlegt werden.
// Beispiel, Umstellung auf 'de' Sprache add_filter( 'elementor/datepicker/locale', function(){ return 'de'; } ); // Beispiel, ändern Sie das Datumsformat in j F, Y add_filter( 'elementor/datepicker/format', function(){ return 'j F, Y'; } ); // Beispiel, verwenden Sie das 24-Stunden-Format für die Zeiteingabe add_filter( 'elementor/datepicker/24h', '__return_true' );
<script type="text/javascript"> window.onload = function check() { document.getElementById("form-field-LABEL-#").checked = true; } </script>
In der entsprechenden Skin Datei des Widgets wird folgender Code ergänzt. Bei Updates wird dies natürlich überschrieben.
protected function render_post_header() { ?> <article <?php post_class( [ 'elementor-post elementor-grid-item' ] ); ?>> <div class="elementor-post__card"> <span class="koopimg"> <?php $values = get_field('partner'); if($values) { foreach($values as $value) { if( $value == 'bestimmtes') { echo "<img src='bild.png'>"; } } } ?> </span> <?php }
In der entsprechenden Skin Datei des Widgets wird folgender Code ergänzt. Bei Updates wird dies natürlich überschrieben.
<article <?php post_class( $classes ); ?>> <a class="elementor-post__thumbnail__link" href="<?php echo esc_url($featured_img_url); ?> "> <?php
wird ersetzt mit
<article <?php post_class( $classes ); ?>> <a class="elementor-post__thumbnail__link" href="<?php echo get_the_post_thumbnail_url(get_the_ID(),'full'); ?> "> <?php
In Elementor lassen sich relativ einfach eigene Eingangsanimationen erstellen. Der nachfolgende Aufbau ist zur groben Orientierung und lässt sich auf die eigene Animation bequem übertragen.
function my_entrance_animations() { return array( 'Basic Scale Animations' => [ 'stretchLeft' => 'Strentch Left', 'stretchRight' => 'Stretch Right', 'stretchDown' => 'Strentch Down', 'stretchUp' => 'Strentch Up', ], ); } add_filter( 'elementor/controls/animations/additional_animations', 'my_entrance_animations' );
/* Stretch Left */ .stretchLeft{ animation-name: stretchLeft; transform-origin: 100% 0%; } @keyframes stretchLeft { 0% {transform: scaleX(0);} 100% {transform: scaleX(1);} } /* Stretch Right */ .stretchRight{ animation-name: stretchRight; transform-origin: 0% 0%; } @keyframes stretchRight { 0% {transform: scaleX(0);} 100% {transform: scaleX(1);} } /* Stretch Down */ .stretchDown{ animation-name: stretchDown; transform-origin: 50% 0%; } @keyframes stretchDown { 0% {transform: scaleY(0);} 100% {transform: scaleY(1);} } /* Stretch Up */ .stretchUp{ animation-name: stretchUp; transform-origin: 50% 100%; } @keyframes stretchUp { 0% {transform: scaleY(0);} 100% {transform: scaleY(1);} }
Dies funktioniert mit ein paar kleinen Anpassungen in CSS.
li[data-filter="__all"] { order: -20;} li[data-filter="25"] { order: -10;} li[data-filter="11"] { order: -9; } li[data-filter="27"] { order: -8; } li[data-filter="10"] { order: -7; } li[data-filter="16"] { order: -6; } li[data-filter="10"] { order: -5; }
Die meisten Formular Plugins nutzen für Datei Uploads einen einfachen „Durchsuchen“ Button, da ist Elementor keine Ausnahme. Folger Code hübscht das ganze etwas auf.
add_action( 'wp_head', function (){ ?> <style> .file-input { width: 0.1px; height: 0.1px; opacity: 0; overflow: hidden; position: absolute; z-index: -1; } .elementor-widget-form .elementor-field-group > .file-input + label, .elementor-widget-form .elementor-field-subgroup .file-input + label { font-family: "IBM Plex Sans", Sans-serif; font-size: 0.9em !important; font-weight: 300; color: white; text-transform: uppercase; background-color: #37b5e7; display: inline-block; padding: 13px 25px 13px 25px !important; cursor: pointer; border: 1px solid #37b5e7; height: 40px; transition: all .3s; } .file-input:focus + label, .file-input + label:hover { background-color: #fff !important; color: #37b5e7 !important; transition: all .3s; } </style> <?php }); add_filter( 'elementor_pro/forms/render/item/upload', function ( $item, $item_index, $form ) { $item['field_type'] = 'file'; return $item; }, 10, 3 ); add_action( 'elementor_pro/forms/render_field/file', function ( $item, $item_index, $form ) { $form->add_render_attribute( 'input' . $item_index, 'class', 'file-input elementor-upload-field' ); $form->add_render_attribute( 'input' . $item_index, 'type', 'file', true ); if ( ! empty( $item['allow_multiple_upload'] ) ) { $form->add_render_attribute( 'input' . $item_index, 'multiple', 'multiple' ); $form->add_render_attribute( 'input' . $item_index, 'name', $form->get_attribute_name( $item ) . '[]', true ); } if ( ! empty( $item['file_sizes'] ) ) { $form->add_render_attribute( 'input' . $item_index, [ 'data-maxsize' => $item['file_sizes'], 'data-maxsize-message' => __( 'This file exceeds the maximum allowed size.', 'elementor-pro' ), ] ); } echo '<input ' . $form->get_render_attribute_string( 'input' . $item_index ) . '>'; echo '<label for="' . $form->get_attribute_id( $item ) . '"><i class="fa fa-upload"></i> Datei hochladen</label>'; }, 10, 3 );
Zugegeben die Überschrift ist ein wenig plakativ, da es die perfekten Einstellungen nicht gibt. Unterschiedliche Server, Hosterpakete, verwendete Plugins, etc. sorgen dafür, das individuelle Anpassungen vorgenommen werden müssen. Nachfolgend jedoch die grundlegenden Einstellungen.
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.
Je nach verwendeten Theme oder Plugin kann WP Rocket zu verschiedenen Darstellungsfehlern führen. Daher kann man bei den Einstellungen immer nur allgemeine Tipps geben, die individuell nach der jeweiligen Webseite angepasst werden müssen.
Typische Probleme hat WP Rocket auf eine Hilfeseite zusammengefasst und gleichzeitig für bekannte Themes und Plugins die Einstellungen notiert. Hier müssen dann bestimmte Skripte vom Caching ausgenommen werden.
Diese Seite ist unter https://docs.wp-rocket.me/article/1560-delay-javascript-execution-compatibility-exclusions zu finden.
Vor allem bei Newsartikel und kleineren Animationen sorgt WP Rocket für Probleme, wenn JavaScript verzögert geladen werden soll. Folgenden beide Varianten habe als Ausnahme mir zuletzt immer geholfen.
Variante 1:
/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js /jquery-migrate(.min)?.js /header-footer-elementor/inc/js/frontend.js /wp-includes/js/imagesloaded.min.js ElementorProFrontendConfig elementorFrontendConfig
Variante 2:
/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js /jquery-migrate(.min)?.js /header-footer-elementor/inc/js/frontend.js /elementor/ /elementor-pro/ /wp-includes/js/imagesloaded.min.js ElementorProFrontendConfig elementorFrontendConfig /wp-content/plugins/elementor/assets/js/frontend-modules.min.js /wp-content/plugins/elementor-pro/assets/js/preloaded-elements-handlers.min.js /wp-includes/js/dist/api-fetch.min.js /wp-includes/js/dist/hooks.min.js /wp-includes/js/dist/i18n.min.js
Und sollte Google Maps einmal nicht mitspielen, dann kommt folgendes ebenfalls noch mit zur Ausnahme:
maps.googleapis.com
<?php add_filter('body_class', 'append_language_class'); function append_language_class($classes){ $classes[] = ICL_LANGUAGE_CODE; return $classes; } ?>
1. Die neuen Flaggenbilder werden unter WPML >> Sprachen >> Sprachen bearbeiten hochgeladen.
2. Wenn die Standartgröße der Flaggen geändert werden soll, dann müssen diese unter wp-content/uploads/flags ebenfalls hochgeladen werden.
3. CSS Code anpassen
.wpml-ls-menu-item .wpml-ls-flag { height: auto !important; width: auto !important; }
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.
Nicht alle Skripte und CSS-Dateien die Themes und Plugins verwenden, werden auch benötigt. Hier gibt es also Optimierungs-Potenzial die vor allem beim Laden der Webseite von Vorteil ist.
1. Im ersten Schritt muss die ID herausgefunden werden. Die geht am besten mit dem Inspektor.
<link rel='stylesheet' id='default_styles-css' href='https://example.com/wp/wp-content/themes/example/style.css' type='text/css' media='all' />
2. Wird die ID nicht angezeigt, kann man sich mit dem folgenden Skript in der functions.php behelfen und anschließend die ID mit dem Inspektor im Head Bereich auslesen.
/* Get Script and Style IDs Adds inline comment to your frontend pages View source code near the <head> section Lists only properly registered scripts @ https://digwp.com/2018/08/disable-script-style-added-plugins/ */ function shapeSpace_inspect_script_style() { global $wp_scripts, $wp_styles; echo "\n" .'<!--'. "\n\n"; echo 'SCRIPT IDs:'. "\n"; foreach($wp_scripts->queue as $handle) echo $handle . "\n"; echo "\n" .'STYLE IDs:'. "\n"; foreach($wp_styles->queue as $handle) echo $handle . "\n"; echo "\n" .'-->'. "\n\n"; } add_action('wp_print_scripts', 'shapeSpace_inspect_script_style');
3. Sind die IDs der gewünschten Elemente bekannt, kommt der eigentliche Teil in dem diese entfernt werden.
function disable_scripts_styles() { if (!is_page('checkout') && !is_page('purchase-confirmation') && !is_page('purchase-history') && !is_page('transaction-failed')) { wp_dequeue_script('beispiel01'); wp_dequeue_style('beispiel02'); } wp_dequeue_style('beispiel03'); } add_action('wp_enqueue_scripts', 'disable_scripts_styles', 100);
Sollte das obere Skript nicht funktionieren, ist nachfolgend eine Alternative:
add_action( 'wp_enqueue_scripts', 'yith_wcbm_dequeue_google_fonts',999 ); function yith_wcbm_dequeue_google_fonts(){ wp_dequeue_style( 'HIER KOMMT DIE ID BEZEICHNUNG HINEIN' ); }
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; }
Nicht jedes Theme zeigt in der Produktübersicht möglicherweise einen „Produktdetails“-Button an, der aus Benutzersicht dennoch sehr hilfreich sein kann, da nicht jedem bewusst ist, dass z.B. der Produkttitel die entsprechende Detailseite nach dem anklicken anzeigt.
Der nachfolgende Code in der functions.php löst dieses Problem:
add_action('woocommerce_after_shop_loop_item', 'add_a_custom_button', 5 ); function add_a_custom_button() { global $product; if( $product->is_type('variable') || $product->is_type('grouped') ) return; echo '<div style="margin-bottom:10px;"> <a class="button custom-button" href="' . esc_attr( $product->get_permalink() ) . '">' . __('Produktdetails') . '</a> </div>'; }
Im Folgenden wird das Buttonziel des „Zurück zum Shop“ Buttons so geändert, das dieses zur letzte Seite zurückgeführt wird. Dafür muss folgende Änderung in der cart-empty.php vorgenommen werden.
if ( wc_get_page_id( 'shop' ) > 0 ) : ?> <p class="return-to-shop"> <a href="#" onclick="window.history.go(-1); return false;"> <?php _e( 'Zurück', 'woocommerce' ) ?> </a> </p> <?php endif; ?>
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ße vergessen?'), 'error' ); else $woocommerce->add_error( __('Haben Sie die Hausnummer bei der Straß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ße vergessen?'), 'error' ); else $woocommerce->add_error( __('Haben Sie die Hausnummer bei der Straß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' ); } } }
add_action( 'woocommerce_proceed_to_checkout', 'rabatt_text_eins', 1 ); add_action( 'woocommerce_review_order_before_submit', 'rabatt_text_eins', 1 ); function rabatt_text_eins() { $text = "Inhaltstext"; echo $text; }
Der Text lässt sich zum einen im Template bzw. mit einem Template Designer anpassen oder auch in der Übersetzungsdatei. Eine Möglichkeit dies über die functions.php zu lösen, ist mit dem nachfolgenden Code möglich.
add_action( 'woocommerce_email_before_order_table', 'rabatt_text_hinweismail', 1 ); function rabatt_text_hinweismail() { $text = "Beispieltext"; echo $text; }
Um einen Online-Shop rechtlich sauber zu gestalten, sollte die Bestellemail auch die AGB und den Widerruf enthalten. Diese Texte lassen sich im Footer der E-Mail unterbringen oder optisch sauberer als angehangene pdf Datei. Das nachfolgende Skript in der functions.php bindet eine entsprechende Datei ein:
add_filter( 'woocommerce_email_attachments', 'wphelp_email_files_woo', 10, 4 ); function wphelp_email_files_woo( $attachments, $email_id, $order, $email ) { $email_ids = array( 'new_order', 'customer_processing_order' ); if ( in_array ( $email_id, $email_ids ) ) { $upload_dir = wp_upload_dir(); $attachments[] = $upload_dir['basedir'] . "/datei.pdf"; } return $attachments; }
In manchen Fällen ist die automatische Download Tabelle, die Woocommerce in der Bestellmail integriert, nicht sinnvoll. Mit dem nachfolgenden Code in der functions.php Datei wird diese entfernt.
add_action( 'woocommerce_email', 'remove_order_downloads_from_emails', 10, 1 ); function remove_order_downloads_from_emails( $emails ){ remove_action( 'woocommerce_email_order_details', array( $emails, 'order_downloads' ), 10 ); }
add_action( 'woocommerce_cart_calculate_fees', 'custom_discount_for_pickup_shipping_method', 10, 1 ); function custom_discount_for_pickup_shipping_method( $cart ) { if ( is_admin() && ! defined( 'DOING_AJAX' ) ) return; $percentage = 5; // Rabatt in % $chosen_shipping_method_id = WC()->session->get( 'chosen_shipping_methods' )[0]; $chosen_shipping_method = explode(':', $chosen_shipping_method_id)[0]; if ( strpos( $chosen_shipping_method_id, 'local_pickup' ) !== false ) { $discount = $cart->get_subtotal() * $percentage / 100; $cart->add_fee( __('Rabatt') . ' (' . $percentage . '%)', -$discount ); } }
Bietet man seinen Kunden ab einem bestimmten Warenwert die Möglichkeit des kostenlosen Versands an, ist es eventuell sinnvoll den noch benötigten Restbetrag, der nötig ist, anzuzeigen. Dies wird durch den folgenden Codeschnipsel, der in der functions.php Datei hinterlegt werden muss, ermöglicht.
add_action( 'woocommerce_before_cart', 'balance_free_shipping_cart_notice' ); function balance_free_shipping_cart_notice() { $min_amount = 49; //Betrag, ab dem kostenloser Versand angeboten wird $current = WC()->cart->subtotal; if ( $current < $min_amount ) { $added_text = 'Zum kostenlosen Versand fehlt noch ein Restbetrag von ' . wc_price( $min_amount - $current ) . ' !'; $return_to = wc_get_page_permalink( 'shop' ); $notice = sprintf( '<a href="%s" class="button wc-forward">%s</a> %s', esc_url( $return_to ), 'Einkauf fortsetzen', $added_text ); wc_print_notice( $notice, 'notice' ); } }
Beim Einrichten der AGB Schnittstelle sollte auf den Einsatz eines Caching Plugins vorübergehend verzichtet werden, hier kann es sonst zu Fehlern kommen. Zudem müssen die genauen Seitennamen eingehalten werden:
Bestehende URL-Titelform |
URL-Titelform Deutsch |
URL-Titelform Englisch |
---|---|---|
Zahlungsarten | bezahlmoeglichkeiten | payment-methods (en) |
Widerrufsbelehrung digitale Waren | widerrufsbelehrung-digitale-waren | revocation_digital (en) |
Widerrufsbelehrung Dienstleistungen | widerrufsbelehrung-dienstleistungen | revocation_repair (en) |
Widerrufsbelehrung | widerrufsbelehrung | revocation (en) |
Versandarten | versandmethoden | shipping-methods (en) |
Impressum | impressum | imprint (en) |
Datenschutzbelehrung | datenschutzbelehrung | data-security (en) |
Batteriehinweis | batteriehinweis | battery_note (en) |
AGB / Kundeninformationen | agb | terms (en) |
Eigentlich sollte durch das ändern der Adresse in der Kasse eine automatische Anpassung der Versandkosten (sofern diese unterschiedlich angelegt sind) erfolgen. Ist dies nicht der Fall, kann das nachfolgende Skript das Problem beheben.
add_action('wp_footer', 'billing_country_update_checkout', 50); function billing_country_update_checkout() { if ( ! is_checkout() ) return; ?> <script type="text/javascript"> jQuery(function($){ $('select#billing_country, select#shipping_country').on( 'change', function (){ var t = { updateTimer: !1, dirtyInput: !1, reset_update_checkout_timer: function() { clearTimeout(t.updateTimer) }, trigger_update_checkout: function() { t.reset_update_checkout_timer(), t.dirtyInput = !1, $(document.body).trigger("update_checkout") } }; $(document.body).trigger('update_checkout'); console.log('Event: update_checkout'); }); }); </script> <?php }
Damit die AGB Checkbox kurz über dem finalen Bestellung abschließen Button landet, ist folgender Code nötig:
add_action( 'init', 'my_child_move_legal_checkboxes', 50 ); function my_child_move_legal_checkboxes() { remove_action( 'woocommerce_review_order_after_payment', 'woocommerce_gzd_template_render_checkout_checkboxes', 10 ); add_action( 'woocommerce_gzd_review_order_before_submit', 'woocommerce_gzd_template_render_checkout_checkboxes', 10 ); }
Zeigt Germanized keine Grundpreiseinheiten an, ist folgenden Einstellung möglich:
({base_price} / {base} {unit})
Alternativ händisch: ({base_price} / 1 {unit})
Standartmäßig finden man in der Kasse im Adressfeld nur die Bezeichnung „Straße“ und als Standartwert „Straßenname und Hausnummer“. Vor allem wenn man sonst keine Standardwerte in den Feldern verwendet, wirkt das ganze hier sehr unsauber. Zudem müsste als Bezeichnung auch noch die Hausnummer stehen.
Mit dem folgenden Code in der functions.php, löst man das Problem:
add_filter('woocommerce_default_address_fields', function ($address_fields) { unset($address_fields['address_1']['placeholder'], $address_fields['address_2']['placeholder']); $address_fields['address_1']['label'] = __('Straße & Hausnummer'); return $address_fields; });
Für CSS Anpassungen kann es wichtig sein, dass die jeweilige Kategorie im Body angezeigt wird. Dies funktioniert mit Hilfe folgenden Codes in der functions.php:
add_filter( 'body_class', 'wc_product_cats_css_body_class' ); function wc_product_cats_css_body_class( $classes ){ if ( is_singular( 'product' ) ) { $current_product = wc_get_product(); $custom_terms = get_the_terms( $current_product->get_id(), 'product_cat' ); if ( $custom_terms ) { foreach ( $custom_terms as $custom_term ) { $classes[] = 'product_cat_' . $custom_term->slug; } } } return $classes; }
Dies funktioniert mit Hilfe folgenden Codes in der functions.php:
function filter_site_upload_size_limit( $size ) { if ( ! current_user_can( 'manage_options' ) ) { $size = 1024 * 4000; // max. 4 MB } return $size; } add_filter( 'upload_size_limit', 'filter_site_upload_size_limit', 20 );
Dies funktioniert mit Hilfe folgenden Codes in der functions.php:
add_filter('upload_mimes','restrict_mime'); function restrict_mime($mimes) { if ( ! current_user_can( 'manage_options' ) ) { $mimes = array( 'jpg|jpeg|jpe' => 'image/jpeg', 'png' => 'image/png', 'pdf' => 'application/pdf' ); } return $mimes; }
Wer Zahlungsdienste benutzt die automatisch ablaufen (PayPal, Klarna,..), also keine manuelle Prüfung voraussetzt, wie es bei Vorkasse der Fall ist, möchte den Status der Zahlung vermutlich gerne automatisch auf „Abgeschlossen“ stellen lassen. Dies ermöglicht das nachfolgende Snippet.
add_action( 'woocommerce_payment_complete', 'wpdesk_set_completed_for_paid_orders' ); function wpdesk_set_completed_for_paid_orders( $order_id ) { $order = wc_get_order( $order_id ); $order->update_status( 'completed' ); }
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
Werden händisch Scripte in einem Beitrag hinterlegt, werden diese nach dem Speichern vom TinyMCE Editor automatisch wieder gelöscht.
Lösung: Zum einen lässt sich der Editor komplett abschalten, wesentlich benutzerfreundlicher ist jedoch folgende Anpassung:
– Unter Extensions > Plugins > Editor
– Hier das TinyMCE Plugin auswählen.
– Unter Use Joomla Text Filter Option, diese auf On schalten.
– Anschließend speichern.
Tritt in vielen Fällen u.a. dann auf, wenn die Weiterleitung nicht richtig gesetzt ist. Dies kann an einer falschen oder fehlerhaften http zu https Weiterleitung liegen oder auch an eine Weiterleitung per JavaScript. Im letzteren Fall sollte man mit einer sauberen Redirect 301 Weiterleitung arbeiten.
HTML, CSS & JavaScript
<center> <embed src="https://www.cms-geek.de" style="border:4px solid #ff0000;" /> </center>
<input list="countries" placeholder="Start typing..."> <datalist id="countries"> <option>Russia</option> <option>Germany</option> <option>United Kingdom</option> <option>France</option> </datalist>
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; }
Dies gehört eigentlich zum Grundwissen, kennt aber eventuell dennoch nicht jeder. Damit CSS Anpassungen nur auf Elternelemente angewendet werden, wird hier mit dem > gearbeitet.
#hauptmenue > ul:hover { /* style */ }
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;'
Haben Kinder-Elemente denselben Klassennamen wie das Eltern-Element, wird eine CSS Eigenschaft für das Elternelement unweigerlich auch auf alle Kinder übertragen. Mit einer simplen Lösung, lässt sich dies verhindern.
#beispielklasse > div.elternelement { color: ff0000; }
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%; }
.zweispalten { -webkit-columns: 40px 2; -moz-columns: 60px 2; columns: 60px 2; column-gap: 50px; }
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:""; }
Alternative mit ‚mask‘:
.elementor-post__read-more:after { width: 20px; height: 14px; display: inline-block; content: ''; mask: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 7.53 5.95" xml:space="preserve"><path d="M4.505.008a.16.16 0 0 0-.094.166c.007.04.171.208 1.309 1.348l1.301 1.302H3.57c-3.439 0-3.451 0-3.492.025A.186.186 0 0 0 0 2.981c0 .012.009.04.021.064.041.087-.266.08 3.546.08h3.454l-1.3 1.302c-1.359 1.36-1.333 1.332-1.309 1.412.013.042.067.095.108.104.092.02.039.069 1.546-1.436.861-.859 1.436-1.442 1.447-1.467.014-.033.015-.052.004-.094-.013-.048-.166-.205-1.454-1.494C4.696.084 4.621.011 4.574.006a.208.208 0 0 0-.069.002"/></svg>') no-repeat 50% 50%; -webkit-mask: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 7.53 5.95" xml:space="preserve"><path d="M4.505.008a.16.16 0 0 0-.094.166c.007.04.171.208 1.309 1.348l1.301 1.302H3.57c-3.439 0-3.451 0-3.492.025A.186.186 0 0 0 0 2.981c0 .012.009.04.021.064.041.087-.266.08 3.546.08h3.454l-1.3 1.302c-1.359 1.36-1.333 1.332-1.309 1.412.013.042.067.095.108.104.092.02.039.069 1.546-1.436.861-.859 1.436-1.442 1.447-1.467.014-.033.015-.052.004-.094-.013-.048-.166-.205-1.454-1.494C4.696.084 4.621.011 4.574.006a.208.208 0 0 0-.069.002"/></svg>') no-repeat 50% 50%; -webkit-mask-size: cover; mask-size: cover; margin-left: 7px; background-color: #d51030; transition: all .3s; } .elementor-post__read-more:hover:after { background-color: #000; transition: all .3s; }
#element:before { background-image: url('Pfad zum gewünschten Bild'); background-size: 150px 200px; display: block; width: 150px; height: 200px; content:""; position: absolute; z-index: 1; top: 50%; -webkit-transform: translateY(-50%); -moz-transform: translateY(-50%); -ms-transform: translateY(-50%); transform: translateY(-50%); /* Hälfte der Element Breite nehmen, in diesem Fall 200px / 2 */ left: calc(50% - 100px); }
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: '✓'; }
Alternativ können auch direkt ASCII Symbole verwendet werden. Mit dem nachfolgenden CSS Code, lässt sich der Doppelfeil darstellen.
/* \0020 sorgt hier für Abstand zwischen dem Symbol und nachfolgenden Listentext */ ul li:before { content: "\00BB \0020"; }
Generell lassen sich per CSS auch alle ASCII Zeichen darstellen, problematischer ist, das hierfür nicht immer gleich der richtige Wert zu finden ist, damit das Symbol auch per content eingefügt werden kann.
#main .element:before { content: "\2713 "; }
Die meisten Symbole lassen sich u.a. auf der Webseite von key-shortcut.com finden. Liegt der richtige Code für das Symbol nicht vor, kann dieser mit dem Entity Conversion Calculator entsprechend umgewandelt werden.
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; } } }); });
Eine simple Lösung ist folgende CSS Anpassung, die am entsprechenden Anker hinterlegt wird:
scroll-margin-top: 1em;
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; }
#dasmenue .menu-item:not(:last-child) a { border-right: 1px solid #ededed; padding:5px 10px 5px 5px; } #dasmenue .menu-item:last-child a { padding:5px 3px 5px 5px; }
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%; }
iframe { height: 100vh; width: 100vw; position:relative; }
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); }
Um Textblöcke schöner aussehen zu lassen, ist eine Möglichkeit diese als Blocksatz umzusetzen.
p { text-align: justify; };
Wer er doch lieber linkbündig mag, kann auch die Silbentrennung nutzen.
p { hyphens: auto; }
Damit diese funktioniert muss die Sprache der Webseite gesetzt sein.
<html lang="de">
Die Variante „hyphens: auto;“ bewirkt vor allem bei kleinen Displays das Umbrüche entstehen können, die grammatikalisch nicht ganz sauber sind. Hier ist es ratsam, eine manuelle Anpassung, zumindest bei sehr langen Worten, vorzunehmen.
Hierzu wird bei dem entsprechenden Wort eine „Sollbruchstelle“ erstellt und zwar mit:
­
Damit nicht auch in der Desktop-Ansicht ein Umbruch entsteht, wird dies mit Media Queries eingeschränkt:
@media only screen and (max-width: 825px) { p { -webkit-hyphens: manual !important; -ms-hyphens: manual !important; hyphens: manual !important; } }
In der Tat ist diese Anpassung schon etwas extravagant, aber es gibt sicherlich Gründe in der diese Sinn ergeben und zwar die Hintergrundfarbe bei Textmarkierungen. Diese werden meist vom verwendeten Browser gesteuert, jedoch lässt sich per CSS die Textfarbe sowie der Hintergrund bei Markierungen ebenfalls steuern.
::-moz-selection { color:#fff; background:#000; } ::selection { color:#fff; background:#000; }
.button { width: 130px; height: 130px; text-transform: uppercase; letter-spacing: 1px; color: #fff; text-align: center; background: rgba(30, 144, 255, 0.6); border-radius: 50%; animation: shadow-pulse 1s infinite; } @keyframes shadow-pulse { 0% { box-shadow: 0 0 0 0px rgba(0, 0, 0, 0.2); } 100% { box-shadow: 0 0 0 35px rgba(0, 0, 0, 0); } }
Die Überschrift sagt alles und die Umsetzung ist ebenfalls recht einfach.
#eltern-container { position: relative; float: none; margin: 0 auto; width: 100%; /* Die nachfolgenden drei Anweisungen sind entscheident! */ display: flex; justify-content: center; align-items: center; }
margin-left: auto; margin-right: 0;
a { -moz-box-sizing: border-box; display:flex; align-items:center; justify-content:center; }
Bei Pseudo-Elementen :before und :after ist es etwas schwieriger, einer Linie bzw. Border eine entsprechende Länge zuweisen zu können. Nachfolgend eine mögliche Variante.
.linie-unten:after { background-color: #fff; bottom: 0; content: ''; display: block; height: 6px; left: 50%; position: absolute; transform: translate(-50%,0); width: 575px; }
Dieser Effekt beschreibt das langsamen reinzoomen in ein Foto, was oft bei Slidern verwendet wird, um hier ein wenig mehr Bewegung auf einer sonst statischen Webseite entstehen zu lassen.
Dieser Effekt lässt sich auch mit etwas CSS nachstellen:
<div class="image-wrap"> <img src="https://www.cms-geek.de/wp-content/uploads/cms-geek-schreibtisch.jpg"> </div>
.image-wrap { width: 100%; height: 50vw; margin: 0 auto; overflow: hidden; position: relative; } .image-wrap img { width: 100%; animation: move 40s ease; -ms-animation: move 40s ease; -webkit-animation: move 40s ease; -0-animation: move 40s ease; -moz-animation: move 40s ease; position: absolute; } @-webkit-keyframes move { 0% { -webkit-transform-origin: bottom left; -moz-transform-origin: bottom left; -ms-transform-origin: bottom left; -o-transform-origin: bottom left; transform-origin: bottom left; transform: scale(1.0); -ms-transform: scale(1.0); /* IE 9 */ -webkit-transform: scale(1.0); /* Safari and Chrome */ -o-transform: scale(1.0); /* Opera */ -moz-transform: scale(1.0); /* Firefox */ } 100% { transform: scale(1.2); -ms-transform: scale(1.2); /* IE 9 */ -webkit-transform: scale(1.2); /* Safari and Chrome */ -o-transform: scale(1.2); /* Opera */ -moz-transform: scale(1.2); /* Firefox */ } }
Damit z.B. eine Box responsive quadratisch dargestellt werden kann, sind die folgenden CSS Anpassungen nötig.
.square { position: relative; width: 50%; } .square:after { content: ""; display: block; padding-bottom: 100%; } .content { position: absolute; width: 100%; height: 100%; }
.container { display: flex; justify-content: center; }
h2 { display: flex; align-items: center; } h2::after { content: ''; flex: 1; margin-left: 1rem; height: 1px; background-color: #000; }
Wort1 <span style="width: 100px"> </span> Wort2
span { display:inline-block; border-bottom: 1px solid black; line-height:0 }
#line h2 { position: relative; } #line h2::before { content: ''; height: 2px; background: #2a0717; position: absolute; top: 8px; right: 101%; width: 999%; }
Einzelne Elemente / Ebenen in SVG Dateien lassen sich per CSS manipulieren, wenn diese zuvor richtig angelegt wurden.
Dafür sollte die gewünschte Ebene oder eben mehrere jeweils in einem separaten Ordner hinterlegt werden und dieser Ordner eindeutig benannt werden. Wird die Grafik nun gespeichert, hier bietet sich Adobe Illustrator an, sind folgende Exporteinstellungen einzuhalten:
.eicon-chevron-right::before { font-family: "Font Awesome 5 Free"; content: "" !important; width: 35px; height: 35px; border-color: #000; display: inline-block; border-bottom: 2px solid; border-left: 2px solid; -webkit-transition: all 0.5s ease; -moz-transition: all 0.5s ease; -o-transition: all 0.5s ease; -ms-transition: all 0.5s ease; transition: all 0.5s ease; -ms-transform: rotate(225deg); -webkit-transform: rotate(225deg); margin-right:10px; } .eicon-chevron-left::before { font-family: "Font Awesome 5 Free"; content: "" !important; width: 35px; height: 35px; border-color: #000; border-bottom-color: rgb(0, 0, 0); border-left-color: rgb(0, 0, 0); display: inline-block; border-bottom: 2px solid; border-left: 2px solid; -webkit-transition: all 0.5s ease; -moz-transition: all 0.5s ease; -o-transition: all 0.5s ease; -ms-transition: all 0.5s ease; transition: all 0.5s ease; -ms-transform: rotate(45deg); -webkit-transform: rotate(45deg); transform: rotate(45deg); margin-left:10px; }
Im body muss die Klasse „animate-in“ eingefügt werden.
.animate-in { -webkit-animation: fadeIn .1s ease-in; animation: fadeIn .1s ease-in; } .animate-out { -webkit-transition: opacity .1s; transition: opacity .1s; opacity: 0; } @-webkit-keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } } @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
window.addEventListener("beforeunload", function () { document.body.classList.add("animate-out"); });
Nicht immer sollen Radio Buttons so aussehen wie sie eben aussehen und manchmal können diese auch nicht durch andere Formelemente ersetzt werden, somit muss eine Lösung her.
#form1 input[type="radio"] { opacity: 0 !important; position: fixed; width: 0px; } #form1 label:before, #form1 label:after { opacity: 0 !important; } #form1 label { display: table-cell; background-color: #ff0000; padding: 10px 20px; border: 1px solid #ff0000; border-radius: 15px; color: #fff; cursor: pointer; width: 110px; height: 110px; text-align: center; vertical-align: middle; font-weight: 400; font-size: 1.1em; } #form1 input[type="radio"]:checked + label, #form1 input[type="checkbox"]:checked + label { background-color:#fff; color: #ff0000; } #bewerbungen label:hover { background-color: #fff; color: #ff0000; }
Auf iOS Geräten werden Telefonnummern die verlinkt sind, optisch hervorgehoben. Dies kann unter Umständen nicht zum Design passen. Mit folgenden Mitteln lässt sich dies beheben.
Automatische Markierung komplett entfernen:
<meta name="format-detection" content="telephone=no" />Automatische Markierung optisch anpassen:
Automatische Markierung optisch anpassen:
a[href^=tel]{ color:#000; text-decoration:none;}
Nutzt man den mix-blend-mode, wirkt sich dieser automatisch auf alle Kind Elemente des betreffenden Objekts aus. Durch den Einsatz eines Pseudoelements und der Position, lässt sich dieses Problem lösen.
.elementor-portfolio-item:hover .elementor-portfolio-item__overlay { position: relative; width: 100%; height: 100%; transition: .5s; } .elementor-portfolio-item:hover .elementor-portfolio-item__overlay:before { background-color: #c0001f; mix-blend-mode: multiply; transition: .5s; content: ''; width: 100%; height: 100%; position: absolute; left: 0; top: 0; z-index: 1; } .elementor-portfolio-item__title { position: absolute; padding: 25px; z-index: 1; bottom: 0px; }
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>
Ein einfaches Skript das eine Weiterleitung anhand der eingestellten Sprache des verwendeten Browsers durchführt.
<script type="text/javascript"> var langcodes=new Array("en", "de", "default") var langredirects=new Array("/englischeseite.html", "/deutscheseite.html","/englischeseite.htmln") var languageinfo=navigator.language? navigator.language : navigator.userLanguage var gotodefault=1 function redirectpage(dest){ if (window.location.replace) window.location.replace(dest) else window.location=dest } for (i=0;i<langcodes.length-1;i++){ if (languageinfo.substr(0,2)==langcodes[i]){ redirectpage(langredirects[i]) gotodefault=0 break } } if (gotodefault) redirectpage(langredirects[langcodes.length-1]) </script>
var url_string = "http://www.example.com/t.html?a=1&b=3&c=m2-m3-m4"; //window.location.href var url = new URL(url_string); var c = url.searchParams.get("c"); console.log(c);
Folgende beiden Anpassungen sind dafür notwendig.
In der functions.php:
add_action('wp_enqueue_scripts', function() { wp_enqueue_script('autocomplete-search', get_stylesheet_directory_uri() . '/assets/js/autocomplete.js', ['jquery', 'jquery-ui-autocomplete'], null, true); wp_localize_script('autocomplete-search', 'AutocompleteSearch', [ 'ajax_url' => admin_url('admin-ajax.php'), 'ajax_nonce' => wp_create_nonce('autocompleteSearchNonce') ]); $wp_scripts = wp_scripts(); wp_enqueue_style('jquery-ui-css', '//ajax.googleapis.com/ajax/libs/jqueryui/' . $wp_scripts->registered['jquery-ui-autocomplete']->ver . '/themes/smoothness/jquery-ui.css', false, null, false ); }); add_action('wp_ajax_nopriv_autocompleteSearch', 'awp_autocomplete_search'); add_action('wp_ajax_autocompleteSearch', 'awp_autocomplete_search'); function awp_autocomplete_search() { check_ajax_referer('autocompleteSearchNonce', 'security'); $search_term = $_REQUEST['term']; if (!isset($_REQUEST['term'])) { echo json_encode([]); } $suggestions = []; $query = new WP_Query([ 's' => $search_term, 'posts_per_page' => -1, ]); if ($query->have_posts()) { while ($query->have_posts()) { $query->the_post(); $suggestions[] = [ 'id' => get_the_ID(), 'label' => get_the_title(), 'link' => get_the_permalink() ]; } wp_reset_postdata(); } echo json_encode($suggestions); wp_die(); }
Erstellen der autocomplete.js:
jQuery(function($) { $('.search-form .search-field').autocomplete({ source: function(request, response) { $.ajax({ dataType: 'json', url: AutocompleteSearch.ajax_url, data: { term: request.term, action: 'autocompleteSearch', security: AutocompleteSearch.ajax_nonce, }, success: function(data) { response(data); } }); }, select: function(event, ui) { window.location.href = ui.item.link; }, }); });
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 } );
Nicht immer kann dem body händisch eine Klasse hinzugefügt werden. In diesen Fällen hilft die folgende Lösung.
Lösung:
add_filter( 'body_class','my_body_classes' ); function my_body_classes( $classes ) { $classes[] = 'klassenname'; return $classes; }
var targetDiv = $('body'); $(window).scroll(function() { var windowpos = $(window).scrollTop(); if( windowpos >= 50 ) { targetDiv.addClass('active'); } else { targetDiv.removeClass('active'); } });
Ein nützlicher Effekt kann es sein, CSS Elemente abhängig von der Tageszeit zu ändern. Das nachfolgende Beispiel ändert ein Hintergrundbild.
var d = new Date(); var n = d.getHours(); if (n > 19 || n < 6) $("#header").css("background", "url('nacht.jpg')"); else $("#header").css("background", "url('tag.jpg')");
<script type="text/javascript"> $(".news-btn").click(function() { $('html, body').animate({ scrollTop: parseInt($("#newsletter").offset().top - 200) }, 2000); }); </script>
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(); } });
Folgender Code im Footer oder als eigenständige js Datei löst dieses Problem.
<script> jQuery ( function($) { $(document).ready(function() { $(".fcb-link-button").delay(7000).fadeIn(500); }); }); </script>
Der Wert 7000 steht für Sekunden, hier also 7s.
In der CSS Datei muss noch folgendes eingefügt werden, damit das Element beim Aufruf der Webseite unsichtbar ist:
.fcb-link-button {display:none;}
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; }
Die Vorgabe ist relativ simpel, nach Klick auf einen Button, wir ein neues Element eingeblendet, das ebenfalls einen Button beinhaltet. Dieser unterscheidet sich zwar von der Funktion, trägt aber dieselbe Bezeichnung wie der erste Button und sorgt daher eher für Irritationen.
Das nachfolgende Skript löst genau dieses Problem.
<script type="text/javascript"> jQuery( document ).on( 'click', '.KlasseDesErstenButtons', function( event ) { event.preventDefault(); if (jQuery('KlasseDesElementsDasSichtbarWird').css('display') == 'block') { jQuery("KlasseDesButtonsDerGeändertWerdenSoll").val('Anfrage absenden'); } }); </script>
Das nachfolgende Beispiel lässt eine CSS Animation erst dann ablaufen, wenn diese im Sichtfeld des Nutzers ist, was z.B. durch scrollen erreicht wird. Dabei wird ein Bild sichtbar, das eine gezeichnete Linie ergibt.
Die gezeichnete Linie liegt als Bild bereits vor. Per CSS wird diese zu Anfang komplett verdeckt und dann langsam sichtbar, so dass der Effekt einer von oben nach unten gezeichneten Linie entsteht.
html
<div class="contain-element"> <img class="prints" src="/line.png" alt="Linie"> <span class="cover"></span> </div>
CSS
.contain-element { position: relative; text-align: center; } .cover { position: absolute; left: 0; background: #fff; height: 1000px; width: 1420px; } @keyframes walk { to { transform: translateY(675px); } }
jQuery
<script> jQuery ( function($) { $(document).ready(function(){ $(window).scroll(function(){ if ($('.contain-element').isOnScreen()) { $(".cover").css("animation","walk 4s steps(28, end) forwards"); } else { // The element is NOT visible, do something else } }); }); $.fn.isOnScreen = function(){ var win = $(window); var viewport = { top : win.scrollTop(), left : win.scrollLeft() }; viewport.right = viewport.left + win.width(); viewport.bottom = viewport.top + win.height(); var bounds = this.offset(); bounds.right = bounds.left + this.outerWidth(); bounds.bottom = bounds.top + this.outerHeight(); return (!(viewport.right < bounds.left || viewport.left > bounds.right || viewport.bottom < bounds.top || viewport.top > bounds.bottom)); }; } ); </script>
Soll ein bestimmtes Element erst sichtbar werden, wenn während des scrollen ein anderes Element erscheint, kann nachfolgender Code hilfreich sein.
var p = $( ".passedMe" ); //Element das erscheint var offset = p.offset(); offset = offset.top; $(window).scroll(function () { if ($(window).scrollTop() > offset ) { $('.showHide').fadeIn(); //Element das sichtbar werden soll } else { $('.showHide').fadeOut(); } });
<ul id="navlist"> <li id="home"><a class="nav" href="home">Home</a></li> <li id="about"><a class="nav" href="about-us">About Us</a></li> </ul>
$('#navlist a').click(function(e) { e.preventDefault(); $('#navlist a').removeClass('selected'); $(this).addClass('selected'); });
Der nachfolgende Code fügt einen Hinweis auf allen Unterseiten einer Domain ein, wenn eine bestimmte Zeichenfolge innerhalb der URL vorhanden ist.
function add_code_to_body() { if (strpos($_SERVER['REQUEST_URI'], 'zeichenfolge-in-der-url') !== false){ ?> <div style="background-color:#000;color:#fff;font-size: 17px;padding: 8px;text-align: center;">Hier kommt der Hinweis.</div> <?php } } add_action( 'wp_body_open', 'add_code_to_body' );
Die Fehlermeldung tritt oftmals dann auf, wenn veraltete Befehle Verwendung finden, die in aktuellen jQuery Versionen nicht mehr unterstützt werden.
Lösung: Wenn möglich programmiert man den Code um, damit dieser auf dem aktuellen Stand ist. Andernfalls hilft das jQuery Migrate Plugin, das die Verwendung älteren Codes erlaubt.
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script> <script src="https://code.jquery.com/jquery-migrate-1.4.1.min.js"></script>
Die Timeout Funktion kann eventuell auch weggelassen werden, war in meinem Fall aber nötig.
$(document).ready(function() { setTimeout(function() { var text = $('.slp_result_citystatezip').html().split(' '); $('.slp_result_citystatezip').text(text[1] + ' ' + text[0]); }, 1000); });
Hierzu muss das gewünschte Element lediglich eine eindeutige ID oder Klasse besitzen.
$('.meineklasse').attr('onclick', 'myFunction()');
Google & Co
Nachfolgend die wichtigsten Begriffe die innerhalb von Google Analytics auftauchen, samt ihrer Bedeutung:
Absprungsrate: Wie viele Personen gehen nach dem Aufruf einer einzelnen Seite wieder. Diese besuchen somit keine anderen Seiten, sondern gehen gleich wieder.
Ausstiegsrate: Die Ausstiegsrate ist nicht zu verwechseln mit der Absprungrate, denn sie gibt den Prozentsatz der Seitenaufrufe an, die die letzten während einer Sitzung waren. Es wurden also vorher mindestens noch eine weitere Seite während der Sitzung aufgerufen.
Conversion-Rate: Die Conversion-Rate gibt den prozentualen Anteil an Webseiten Besuchen wieder, die ein zuvor definiertes Ziel auf der Webseite erreicht haben.
Ereignisse (Events): Unter Ereignissen versteht man in Google Analytics Nutzeraktionen, die nicht als Seitenaufrufe erfasst werden können, beispielsweise einen Download oder einen Klick auf einen Button.
Sitzungen: Ist die Anzahl der Besuche auf der Webseite, auch wenn derselbe Nutzer mehrfach die Webseite besucht, wird jedes Mal dies als Sitzung gewertet.
Neue Sitzungen: Wie viele Nutzer/Sitzungen sind „neu“ oder „wiederkehrend“.
Durchschnittliche Sitzungsdauer: Die durchschnittliche Dauer einer Sitzung.
Nutzer: Die Anzahl der Besuche eines Nutzers an einem Tag auf der Webseite.
Seitenaufrufe: Wie viele einzelne Seiten wurden während einer Sitzung aufgerufen.
Seiten/Sitzung: Wie viele Seiten werden pro Sitzung aufgerufen.
Trichter: Bei der Einrichtung von Zielen kann ein Trichter erstellt werden. Er steht für eine Abfolge von Webseiten, die aufgerufen werden müssen, damit das Ziel als erreicht gilt.
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.
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.
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.
Lassen sich z.B. Zahlungsmethoden nicht mehr ändern, liegt es oftmals daran, dass es Einschränkungen im Konto gibt.
Zum einen sollte man sich dann an den Support wenden, oftmals hilft auch das verifizieren seiner Daten unter: https://support.google.com/googlepay/contact/account_verification
Aktuell ist das tracken einer erfolgreichen versendeten Nachricht über das Elementor Formular ein wenig schwierig und viele Varianten führen nicht zum Ziel. Der nachfolgende Ansatz nutzt den entsprechenden Nutzerhinweis der unter dem Formular erscheint, wenn die Nachricht gesendet wurde.
Hierzu wird ein entsprechender Trigger angelegt:
Eventuell muss hier das Auslösen des Triggers individuell nach den eigenen Bedürfnissen angepasst werden.
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&language=de&ver=1'></script>
Server / Hoster / Datenbanken
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.
Gibt es z.B. bei einer WordPress Webseite technische Probleme, sind hier die Fehlermeldungen recht praktisch, um einen ersten Anhaltspunkt für die Fehlerbehebung zu bekommen. Ist die Webseite bei Hosteurope gehostet, bleiben diese Meldungen aus und müssen händisch im Backend von Hosteurope aktiviert werden.
-> Administration > Webhosting > PAKETNUMMER > Skripte > Skript-Einstellungen
-> Logging Output -> On
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|bg\.jpg)?$ [NC] RewriteCond %{REQUEST_URI} !^/img(/|$) [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
Möchte man eine Weiterleitung vornehmen, bei der das Elternelement weitergeleitet werden soll, das Kindelement jedoch nicht, ist folgender .htaccess Eintrag nötig:
Redirect 301 /products/?$ http://www.domain.com/404/
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.
Gelegentlich kann es wichtig sein, Datenbank-Einträge direkt in dieser zu bearbeiten. Um einen bestimmten Datensatz zu finden und diesen zu ersetzen, ist folgende SQL-Anweisung möglich:
UPDATE tabellenName SET tabellenWert = replace(tabellenWert,"alterEintrag","neuerEintrag");
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.
Bei Umzügen von Datenbanken auf andere Server ist in Einzelfällen mit Fehlern beim Importieren der Datenbank zu rechnen. Dies liegt oft an veraltete Software, hier ist dann die MySQL Version auf einem älteren Stand.
Lösung: In einigen Fällen kann die zu importierenden SQL-Datei mit einem Editor bearbeitet werden.
ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_520_ci; ersetzen mit: ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
utf8mb4_unicode_520_ci ersetzen mit: utf8mb4_unicode_ci
In einigen Fällen reicht es auch die MySQL Version zu erhöhen.
Registriert man eine Domain bei IONOS und verwendet diese nicht direkt, wird standartmäßig SEDO Werbung auf der entsprechenden leeren Domain ausgegeben. Dieses lässt sich zum Glück beheben.
Lösung: Hierzu klickt man im IONOS Kundenbackend auf „Domains und SSL“ > unten rechts auf „Schnellzugriff“, anschließend den Punkt „Domain Parking“ auswählen. Dort lässt sich die Werbung ausschalten.
Tools & Links
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.
Media Cleaner – Clean & Optimize Space – löscht nicht mehr verwendete Bilder aus der Mediathek und dem Server. Zuvor jedoch unbedingt eine Sicherung vornehmen.
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.
Image Source Control – Plugin zum Hinterlegen von Copyright-Rechten eines Bildes direkt am bzw. im Bild.
Shortcode Cleaner Lite – Säubert den Quellcode, z.B. wenn der Editor gewechselt wurde und dadurch noch alter Code / Shortcodes auf der Webseite hinterlegt sind.
Canvas Image Resize – Erlaubt das definieren der maximalen Höhe und Breite eines Bildes, bevor dieses hochgeladen wird.
Filter Posts By Category – Schöne Filterfunktion mit Ajax die auch mit Elementor und Custom Post Types zusammenarbeitet.
Make Column Clickable Elementor – Wie der Name schon verrät, können hiermit Spalteninhalte auch klickbar gemacht werden.
Tuxedo Big File Uploads – Sorgt dafür das auch sehr große Dateien in der Mediathek hochgeladen werden können, auch wenn es hier eigentlich eine Uploadgrenze gibt.
Products Suggestions for WooCommerce – Bietet ausgewählte Artikel dem Nutzer zum Beispiel auf der Warenkorb oder auf der Kassenseite an.
Go Live Update Urls – Gute Alternative zu Better Search Replace, um alle URLs einer Webseite, samt Datenbank zu ändern.
Complianz – GDPR/CCPA Cookie Consent – Selbst in der kostenlosen Version eine sehr gute Alternative zu Borland Cookies und Co.
CF7 Form Submission Limit – Beeinflusst wie oft ein Formular gesendet werden kann.
Better Find and Replace – Durchsucht die Datenbank nach einem gewünschten Begriff oder URL oder ersetzt diesen.
MouseWheel Smooth Scroll – Macht was der Name schon sagt, sorgt für ein langsameres scrollen über die gesamte Webseite.
Kadence WooCommerce Email Designer – Erleichtert das Bearbeiten von WooCommerce E-Mail Vorlagen.
Change Admin Email – Lässt einen die Admin E-Mailadresse ändern, ohne das eine automatische Nachricht vom Server gesendet wird.
Sind SVG Dateien nicht korrekt abgespeichert worden, lassen sie sich per CSS nur schwer manipulieren (Farbe bei Hover ändern, etc.). Nachfolgend zwei hilfreiche online Generatoren, die diese Fehler beheben können:
https://iconly.io/tools/svg-convert-stroke-to-fill
https://jakearchibald.github.io/svgomg/ (Hier sollten ‚Style to attribute‘, ‚Prefer viewBox‘ und ‚Remove style elements‘ aktiviert werden.)
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.
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.
Analog zu Facebook, kann auch bei linkedin.com ein zuvor eingelesener Link, wenn dieser Inhaltlich geändert wurde, neu eingelesen werden.
Dies geschieht unter: https://www.linkedin.com/post-inspector/
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.
curtains.js – Einfaches WebGL-Tool zum Animieren von Bildern und Videos.
turn.js – ist eine JavaScript-Bibliothek, die Inhalte wie ein echtes Buch oder Magazin aussehen lässt und dabei alle Vorteile von HTML5 nutzt.
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
Suche nach
^([^,]*,[^,]*),.*$
und ersetze dies mit
\1
Vor jeder Zeile einfügen
Suche nach
^
und ersetze dies mit
dem gewünschten Text
Nach jeder Zeile einfügen
Suche nach
$
und ersetze dies mit
dem gewünschten Text
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:
IMGonline.com.ua – Überträgt Metadata des Originalbildes auf ein anderes.
Rauschen entfernen – Hilfreiche Infos wie man das Bildrauschen nachträglich etwas reduzieren kann.
Omatsuri.app – Webdesigner Tools
Mobilefish.com – vcards Generator
Wenn es mal vorkommt, dass sich eine Datei oder Ordner gar nicht löschen lassen und alle Möglichkeiten ausgeschöpft sind, dann hilft eventuell LockHunter.
Manche Addons, etc. benötigen die englische Version des jeweiligen Adobe Programmes, damit diese fehlerfrei funktionieren. In den Vorsteinstellungen gibt es die Möglichkeit die Programm-Sprache zu ändern, sofern diese Version installiert wurde.
Alternative: Im Photoshop-Verzeichnis unter „Locales > de_DE > Support Files“ findet man die Übersetzungsdatei „tw10428.dat“. Wenn man diese Datei vorübergehend aus dem Ordner entfernt und woanders sichert (um diese später wieder zu verwenden), anschließend das Programm neu startet, wird die englische Version geöffnet.
Um Daten auf einer Festplatte sicher löschen zu können reicht eine normale Formatierung meist nicht auf. Datenfragmete lassen sich danach oft wiederherstellen.
Besser dafür geeignet sind Programme wie Darik’s Boot and Nuke (kurz DBAN), das in der normalen Version auch kostenlos ist. Hier lässt sich einstellen, wie oft ein Datenträger überschrieben werden soll (je mehr Durchgänge, he länger dauert logischerweise der Vorgang).
Das Programm lässt sich also ISO Datei herunterladen, die dann auf einem bootfähigen Datenträger z.B. USB Stick aufgespielt wird. Sehr einfach ist dies mit dem kostenlosen Programm RUFUS möglich. Dieses erstellt nicht nur einen bootfähigen Datenträger, sondern bindet auch die entsprechende ISO Datei ein.
Dies geht ganz einfach mit dieser Erweiterung: SVG Explorer Extension
Wenn gerade kein zweiter Bildschirm zur Verfügung steht, der Bildschirm aber unbedingt geteilt werden muss, hilft folgende Windows Funktion.
Das gewünschte Fenster öffnen, die Windows Taste gedrückt halten und die Pfeiltaste links oder rechts drücken, je nachdem auf welche Seite das Fenster positioniert werden soll.
Neueste Kommentare