Delete Media Files from WordPress Database

DELETE FROM wp_posts WHERE post_type = 'attachment';
DELETE FROM wp_postmeta WHERE meta_key = '_wp_attached_file';
DELETE FROM wp_postmeta WHERE meta_key = '_wp_attachment_metadata';

Defer Loading Background Images

Add this to your <head> section...

<style id="defer-style">
  .selector {
    background-image: none !important;
  }
</style>

...and this before </body> tag...

<script>
  document.addEventListener('DOMContentLoaded', function () {
    var deferStyle = document.getElementById('defer-style');

    if (null !== deferStyle) {
      deferStyle.parentElement.removeChild(deferStyle);
    }
  });
</script>

Preload Fonts for Google PageSpeed Insights

<link rel="preload" href="/path/font.woff2" as="font" type="font/woff2" crossorigin>

Javascript Browser Check

Google Chrome

window.navigator.userAgent.indexOf('Chrome') > -1

Microsoft Internet Explorer

window.navigator.userAgent.indexOf('MSIE') > -1 || !!navigator.userAgent.match(/Trident.*rv\:11\./)

Microsoft Edge

window.navigator.userAgent.indexOf('Edge') > -1

Safari

window.navigator.userAgent.indexOf('Safari') > -1 && window.navigator.userAgent.indexOf('Chrome') == -1

Mozilla Firefox

window.navigator.userAgent.indexOf('Firefox') > -1

Chromium Edge

window.navigator.userAgent.indexOf('Edg/') > -1

Redirect all URLs to another Domain

<IfModule mod_rewrite.c>
    RewriteEngine on
    RewriteRule ^(.*)$ https://www.domain.com/$1 [R=302,L]
</IfModule>

Show Future Posts in Frontend

add_action('pre_get_posts', function ($query) {
  if (false === is_user_logged_in() && $query->is_main_query() && $query->is_single()) {
    $query->set('post_status', [
      'publish',
      'future'
    ]);
  }
});

Disable WordPress Updates

Add this to your wp-config.php

define('WP_AUTO_UPDATE_CORE', false);

Remove Google Fonts from Elementor completely

add_action('wp_print_styles', function () {
  wp_dequeue_style('google-fonts-1');
});

Fix Autoscroll on Elementor

If you use a sticky header with anchor links, there is one problem since Elementor 3.0 was released. Everything is fine, if you have a single one page layout. But when you have subpages and use your anchor links also in the main navigation, then you will have some trouble.

You're on a subpage and want to jump to an anchor link on another page. You scroll automatically to the anchor, but now the sticky header is placed over it.

Copy and paste the following snippet and the problem will solved.

add_action('wp_footer', function () {
    ?>
    <script>
        var hash = window.location.hash.replace('#', '');
        var scrollToElement = document.getElementById(hash);
        var header = document.querySelector('[data-elementor-type="header"]');
        var headerHeight = header.offsetHeight;

        if (null !== scrollToElement) {
            var style = document.createElement('style');
            style.innerText = '#' + hash + ':before { content: ""; display:block; height: ' + headerHeight + 'px; margin: ' + (-1 * headerHeight) + 'px 0 0; visibility: hidden; pointer-events: none; }';
            document.head.appendChild(style);

            document.addEventListener('DOMContentLoaded', function() {
                setTimeout(function () {
                    document.head.removeChild(style);
                }, 1000);
            });
        }
    </script>
    <?php
}, 1);

Overwrite Stylesheets in WordPress

Use these methods to overwrite existing stylesheets and you no longer have to use !important for your sections.

Header Scripts

add_action('wp_enqueue_scripts', function () {
    wp_enqueue_style('new', 'css/new.css', ['old'], false);
}, 99);

Footer Scripts

add_action('get_footer', function () {
    wp_enqueue_style('new', 'css/new.css', ['old'], false);
}, 99);

Ultimate WordPress .htaccess File

The ultimate .htaccess of WordPress looks like this one.

# BEGIN WordPress
<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteBase /
    RewriteRule ^index\.php$ - [L]
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule . /index.php [L]
</IfModule>
# END WordPress

# BEGIN SSL Forwarding
<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteCond %{HTTPS} !=on
    RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
</IfModule>
# END SSL Forwarding

# BEGIN CORS Security
<IfModule mod_headers.c>
    <FilesMatch "\.(ttf|ttc|otf|eot|woff|woff2|font.css|css|js|gif|png|jpe?g|svg|svgz|ico|webp)$">
        Header set Access-Control-Allow-Origin "*"
    </FilesMatch>
</IfModule>
# END CORS Security

# BEGIN Browser Caching
<IfModule mod_expires.c>
    ExpiresActive on
    ExpiresDefault "access plus 1 month"

    # CSS
    ExpiresByType text/css "access plus 1 year"

    # Data
    ExpiresByType application/atom+xml "access plus 1 hour"
    ExpiresByType application/rdf+xml "access plus 1 hour"
    ExpiresByType application/rss+xml "access plus 1 hour"

    ExpiresByType application/json "access plus 0 seconds"
    ExpiresByType application/ld+json "access plus 0 seconds"
    ExpiresByType application/schema+json "access plus 0 seconds"
    ExpiresByType application/vnd.geo+json "access plus 0 seconds"
    ExpiresByType application/xml "access plus 0 seconds"
    ExpiresByType text/xml "access plus 0 seconds"

    # Favicon (cannot be renamed!) and cursor images
    ExpiresByType image/vnd.microsoft.icon "access plus 1 week"
    ExpiresByType image/x-icon "access plus 1 week"

    # HTML
    ExpiresByType text/html "access plus 0 seconds"

    # JavaScript
    ExpiresByType application/javascript "access plus 1 year"
    ExpiresByType application/x-javascript "access plus 1 year"
    ExpiresByType text/javascript "access plus 1 year"

    # Manifest files
    ExpiresByType application/manifest+json "access plus 1 week"
    ExpiresByType application/x-web-app-manifest+json "access plus 0 seconds"
    ExpiresByType text/cache-manifest "access plus 0 seconds"

    # Media files
    ExpiresByType audio/ogg "access plus 1 year"
    ExpiresByType image/bmp "access plus 1 year"
    ExpiresByType image/gif "access plus 1 year"
    ExpiresByType image/jpeg "access plus 1 year"
    ExpiresByType image/png "access plus 1 year"
    ExpiresByType image/svg+xml "access plus 1 year"
    ExpiresByType image/webp "access plus 1 year"
    ExpiresByType video/mp4 "access plus 1 year"
    ExpiresByType video/ogg "access plus 1 year"
    ExpiresByType video/webm "access plus 1 year"

    # Web Fonts

    # Embedded OpenType (EOT)
    ExpiresByType application/vnd.ms-fontobject "access plus 1 year"
    ExpiresByType font/eot "access plus 1 year"

    # OpenType
    ExpiresByType font/opentype "access plus 1 year"

    # TrueType
    ExpiresByType application/x-font-ttf "access plus 1 year"

    # Web Open Font Format (WOFF) 1.0
    ExpiresByType application/font-woff "access plus 1 year"
    ExpiresByType application/x-font-woff "access plus 1 year"
    ExpiresByType font/woff "access plus 1 year"

    # Web Open Font Format (WOFF) 2.0
    ExpiresByType application/font-woff2 "access plus 1 year"

    # Other
    ExpiresByType text/x-cross-domain-policy "access plus 1 week"
</IfModule>
# END Browser Caching

# BEGIN Compression
<IfModule mod_deflate.c>
    AddOutputFilterByType DEFLATE text/plain
    AddOutputFilterByType DEFLATE text/html
    AddOutputFilterByType DEFLATE text/xml
    AddOutputFilterByType DEFLATE text/css
    AddOutputFilterByType DEFLATE text/vtt
    AddOutputFilterByType DEFLATE text/x-component
    AddOutputFilterByType DEFLATE application/xml
    AddOutputFilterByType DEFLATE application/xhtml+xml
    AddOutputFilterByType DEFLATE application/rss+xml
    AddOutputFilterByType DEFLATE application/js
    AddOutputFilterByType DEFLATE application/javascript
    AddOutputFilterByType DEFLATE application/x-javascript
    AddOutputFilterByType DEFLATE application/x-httpd-php
    AddOutputFilterByType DEFLATE application/x-httpd-fastphp
    AddOutputFilterByType DEFLATE application/atom+xml
    AddOutputFilterByType DEFLATE application/json
    AddOutputFilterByType DEFLATE application/ld+json
    AddOutputFilterByType DEFLATE application/vnd.ms-fontobject
    AddOutputFilterByType DEFLATE application/x-font-ttf
    AddOutputFilterByType DEFLATE application/font-woff2
    AddOutputFilterByType DEFLATE application/x-font-woff
    AddOutputFilterByType DEFLATE application/x-web-app-manifest+json font/woff
    AddOutputFilterByType DEFLATE font/woff
    AddOutputFilterByType DEFLATE font/opentype
    AddOutputFilterByType DEFLATE image/svg+xml
    AddOutputFilterByType DEFLATE image/x-icon

    # Exception: Images
    SetEnvIfNoCase REQUEST_URI \.(?:gif|jpg|jpeg|png|svg)$ no-gzip dont-vary

    # Drop problematic browsers
    BrowserMatch ^Mozilla/4 gzip-only-text/html
    BrowserMatch ^Mozilla/4\.0[678] no-gzip
    BrowserMatch \bMSI[E] !no-gzip !gzip-only-text/html

    # Make sure proxies don't deliver the wrong content
    Header append Vary User-Agent env=!dont-vary
</IfModule>
# END Compression

# BEGIN Caching on Apache
<IfModule mod_headers.c>
    <FilesMatch "\.(ico|pdf|flv|swf|js|css|gif|png|jpg|jpeg|txt|woff2|woff)$">
        Header set Cache-Control "max-age=31536000, public"
    </FilesMatch>
</IfModule>

<IfModule mod_headers.c>
    <FilesMatch "\.(js|css|xml|gz)$">
        Header append Vary Accept-Encoding
    </FilesMatch>
</IfModule>
# END Caching on Apache

# BEGIN Keep-Alive Header
<IfModule mod_headers.c>
    Header set Connection keep-alive
</IfModule>
# END Keep-Alive Header

# BEGIN Disable ETags
<IfModule mod_expires.c>
    <IfModule mod_headers.c>
        Header unset ETag
    </IfModule>

    FileETag None
</IfModule>

<IfModule mod_headers.c>
    <FilesMatch ".(js|css|xml|gz|html|woff|woff2|ttf)$">
        Header append Vary: Accept-Encoding
    </FilesMatch>
</IfModule>
# END Disable ETags

# BEIGN Protection
<Files install.php>
    Order allow,deny
    Deny from all
</Files>

<Files wp-config.php>
    Order allow,deny
    Deny from all
</Files>

<Files readme.html>
    Order allow,deny
    Deny from all
    Satisfy all
</Files>

<Files liesmich.html>
    Order allow,deny
    Deny from all
    Satisfy all
</Files>

<Files error_log>
    Order allow,deny
    Deny from all
</Files>

<FilesMatch "(\.htaccess|\.htpasswd)">
    Order deny,allow
    Deny from all
</FilesMatch>

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

<Files xmlrpc.php>
    Order deny,allow
    Deny from all
</Files>
# END Protection

Optional Snippets

# BEGIN No-Referrer Header
<IfModule mod_headers.c>
    Header set Referrer-Policy "no-referrer"
</IfModule>
# END No-Referrer Header

# BEGIN X-Frame-Options Header
<IfModule mod_headers.c>
    Header set X-Frame-Options "sameorigin"
</IfModule>
# END X-Frame-Options Header

# BEGIN X-XSS-Protection Header
<IfModule mod_headers.c>
    Header set X-XSS-Protection "1; mode=block"
</IfModule>
# END X-XSS-Protection Header

# BEGIN X-Content-Type-Options Header
<IfModule mod_headers.c>
    Header set X-Content-Type-Options "nosniff"
</IfModule>
# END X-Content-Type-Options Header

# BEGIN Strict-Transport-Security Header
<IfModule mod_headers.c>
    Header set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
</IfModule>
# END Strict-Transport-Security Header

Zoom-In Animation… One by One

Ok, put that Javascript snippet on your site.

$(window).on('scroll', function () {
        var scrollPosition = $(window).scrollTop() + $(window).height();
        var timeout = 100;

        $('.ws-post').each(function () {
            var element = $(this);
            var elementPosition = element.offset().top;

            if (false === element.hasClass('ws-post--ready') && scrollPosition >= elementPosition) {
                setTimeout(function () {
                    element.addClass('ws-post--ready');
                }, timeout += 100);
            }
        });
    });

The code above will add a class on your elements, if the user scroll down on your site and the element is in the viewport.
Don't forget to style the elements, to make the effect more fancy.

.ws-post {
    transform: scale(0);
    -webkit-transform: scale(0);
    visibility: hidden;
    opacity: 0;
    transition: transform 100ms cubic-bezier(0, 0, 1, 1), visibility 0ms linear, opacity 100ms cubic-bezier(0, 0, 1, 1);
    -webkit-transition: transform 100ms cubic-bezier(0, 0, 1, 1), visibility 0ms linear, opacity 100ms cubic-bezier(0, 0, 1, 1);
}

.ws-post.ws-post--ready {
    transform: scale(1);
    -webkit-transform: scale(1);
    visibility: visible;
    opacity: 1;
}

Human Readability Time Function

You need a function to publish your date like "1 hour ago", "3 days ago" or something like that? No problem. Here is my way to do that.

function ws_format_time($datetime, $full = false)
{
    $now = new DateTime;
    $ago = new DateTime($datetime);
    $diff = $now->diff($ago);

    $diff->w = floor($diff->d / 7);
    $diff->d -= $diff->w * 7;
    $diff = (array) $diff;

    $string = [
        'y' => 'year',
        'm' => 'month',
        'w' => 'week',
        'd' => 'day',
        'h' => 'hour',
        'i' => 'minute',
        's' => 'second',
    ];

    foreach ($string as $key => $value) {
        if ($diff[$key]) {
            $prefix = 's';
            $string[$key] = $diff[$key] . ' ' . $value . ($diff[$key] > 1 ? $prefix : '');
        } else {
            unset($string[$key]);
        }
    }

    if (!$full) {
        $string = array_slice($string, 0, 1);
    }

    return $string ? implode(', ', $string) . ' ago' : 'just now';
}

Elementor Font Awesome 5 Pro Support (Self-Hosted)

Actually, this variant is already obsolete, if not already deprecated. However, I use this method in some projects. If e.g. Font Awesome 5 Pro has already been purchased and there is no access to the CDN. With the integration of the u.g. Code snippets in the functions.php, there is still the possibility to use the premium icons in Elementor.

In Elementor, the Font Awesome 5 CDN can only be used with the license key.

function enqueue_icon_font() {
    wp_enqueue_style('font-awesome-5', 'https://use.fontawesome.com/releases/v5.1.0/css/all.css');
}

add_action('wp_enqueue_scripts', 'enqueue_icon_font', 1);
add_action('elementor/editor/before_enqueue_styles', 'enqueue_icon_font', 1);

add_action('elementor/controls/controls_registered', function ($controls_registry) {
    $icons = $controls_registry->get_control('icon')->get_settings('options');
    $new_icons = array_merge(
        array(
            'fab fa-elementor' => 'elementor',
        ),
        $icons
    );

    $controls_registry->get_control('icon')->set_settings('options', $new_icons);
}, 10, 1);

CSS Flip Animation

Here is a little flip animation that I like to use in dropdowns at my navigations.

selector {
    animation: ws-flip-rotation 500ms ease-in-out forwards;
    -webkit-animation: ws-flip-rotation 500ms ease-in-out forwards;
}

@keyframes ws-flip-rotation {
    0% {
        opacity: 0;
        transform: translateY(45px) rotate3d(1, 1, 0, 45deg);
    }
    
    100% {
        opacity: 1;
        transform: translateY(0);
    }
}

@-webkit-keyframes ws-flip-rotation {
    0% {
        opacity: 0;
        -webkit-transform: translateY(45px) rotate3d(1, 1, 0, 45deg);
    }
    
    100% {
        opacity: 1;
        -webkit-transform: translateY(0);
    }
}

CSS Hamburger Menu

A really nice Hamburg menu button. Simple and yet so brilliant.
First the basic framework with HTML:

<button class="ws-navigation__button">
    <span class="ws-navigation__hamburger">
        <span class="ws-navigation__button-line"></span>
        <span class="ws-navigation__button-line"></span>
        <span class="ws-navigation__button-line"></span>
    </span>
    <span class="ws-navigation__cross">
        <span class="ws-navigation__button-line"></span>
        <span class="ws-navigation__button-line"></span>
    </span> 
</button>

… and then a little bit of CSS:

<style>
    selector {
        z-index: 99;
    }
    
    .ws-navigation__button {
        display: block;
        width: 40px;
        height: 40px;
        position: relative;
        border: none;
        padding: 0;
        background: none;
        cursor: pointer;
    }
    
    .ws-navigation__hamburger,
    .ws-navigation__cross {
        display: block;
        width: 60%;
        height: 60%;
        position: absolute;
        top: 20%;
        left: 20%;
    }
    
    .ws-navigation__button-line {
        display: block;
        width: 100%;
        height: 2px;
        position: absolute;
        background-color: #000;
    }
    
    .ws-navigation__hamburger .ws-navigation__button-line:nth-child(2) {
        width: 75%;
    }
    
    .ws-navigation__hamburger .ws-navigation__button-line:nth-child(1),
    .ws-navigation__hamburger .ws-navigation__button-line:nth-child(2),
    .ws-navigation__hamburger .ws-navigation__button-line:nth-child(3) {
        right: 0;
        transform: translateY(-50%);
        -webkit-transform: translateY(-50%);
        transition: width 0.15s ease-in-out;
        -webkit-transition: width 0.15s ease-in-out;
    }
    
    .ws-navigation__hamburger .ws-navigation__button-line:nth-child(1) {
        top: calc(50% - 4px);
        transition-delay: 0.4s;
        -webkit-transition-delay: 0.4s;
    }
    
    .ws-navigation__hamburger .ws-navigation__button-line:nth-child(2) {
        top: 50%;
        transition-delay: 0.5s;
        -webkit-transition-delay: 0.5s;
    }
    
    .ws-navigation__hamburger .ws-navigation__button-line:nth-child(3) {
        top: calc(50% + 4px);
        transition-delay: 0.6s;
        -webkit-transition-delay: 0.6s;
    }
    
    .ws-navigation__button--clicked .ws-navigation__hamburger .ws-navigation__button-line {
        width: 0;
    }
    
    .ws-navigation__button--clicked .ws-navigation__hamburger .ws-navigation__button-line:nth-child(1) {
        transition-delay: 0.1s;
        -webkit-transition-delay: 0.1s;
    }
    
    .ws-navigation__button--clicked .ws-navigation__hamburger .ws-navigation__button-line:nth-child(2) {
        transition-delay: 0.2s;
        -webkit-transition-delay: 0.2s;
    }
    
    .ws-navigation__button--clicked .ws-navigation__hamburger .ws-navigation__button-line:nth-child(3) {
        transition-delay: 0.3s;
        -webkit-transition-delay: 0.3s;
    }
    
    .ws-navigation__cross {
        transform: rotate(45deg);
        -webkit-transform: rotate(45deg);
    }
    
    .ws-navigation__cross .ws-navigation__button-line:nth-child(1) {
        width: 0;
        top: 50%;
        left: 0;
        transform: translateY(-50%);
        -webkit-transform: translateY(-50%);
        transition: width 0.15s ease-in-out;
        -webkit-transition: width 0.15s ease-in-out;
        transition-delay: 0.1s;
        -webkit-transition-delay: 0.1s;
    }
    
    .ws-navigation__cross .ws-navigation__button-line:nth-child(2) {
        width: 2px;
        height: 0;
        top: 0;
        left: 50%;
        transform: translateX(-50%);
        -webkit-transform: translateX(-50%);
        transition: height 0.15s ease-in-out;
        -webkit-transition: height 0.15s ease-in-out;
        transition-delay: 0.2s;
        -webkit-transition-delay: 0.2s;
    }
    
    .ws-navigation__button--clicked .ws-navigation__cross .ws-navigation__button-line:nth-child(1) {
        width: 100%;
        transition-delay: 0.5s;
        -webkit-transition-delay: 0.5s;
    }
    
    .ws-navigation__button--clicked .ws-navigation__cross .ws-navigation__button-line:nth-child(2) {
        height: 100%;
        transition-delay: 0.6s;
        -webkit-transition-delay: 0.6s;
    }
</style>

Now we can simply swap classes with the OnClick event via jQuery and marvel at the magic. Mmh, yummi. 🙂

WordPress Rest API

First we need to add the following code to our functions.php.

add_action('rest_api_init', function () {
    register_rest_route('namespace', '/path', [
        'methods' => 'GET',
        'callback' => function () {
            return $_GET;
        }
    ]);
});

Then we can create a simple form and process the request via Javascript.

$('form').on('submit', function (e) {
    e.preventDefault();

    $.ajax({
        type: 'GET',
        url: '/wp-json/namespace/path',
        data: $('form').serialize()
    }).done(function (response) {
        console.log(response);
    });
});

Alternatively, you can also call the following URL directly in the browser:
https://www.domain.com/wp-json/namespace/path?parameter=value

Custom Cursor with CSS

Sometimes a simple mouse pointer (cursor) is not enough. Then something of your own has to be found. Replacing the cursors with another graphic is in many cases insufficient or leads to compatibility problems in other browsers. We need something better!

First of all we need some HTML code:

<div class="cursor">
    <div class="cursor-pointer"></div>
    <div class="cursor-effect"></div>
</div>

Then we give the elements their essential attributes and design them according to our ideas:

.cursor--ready,
.cursor--ready *,
.cursor--ready *:hover {
    cursor: none;
}

.cursor {
    display: block;
    box-sizing: border-box;
    -webkit-box-sizing: border-box;
    width: 100vw;
    height: 100vh;
    position: fixed;
    top: 0;
    left: 0;
    z-index: 99999;
    pointer-events: none;
}

.cursor-pointer {
    position: absolute;
    top: -100%;
    left: -100%;
}
	
.cursor-pointer:before {
    content: '';
    display: block;
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    -webkit-transform: translate(-50%, -50%);
    width: 4px;
    height: 4px;
    border-radius: 100%;
    background-color: #a3ff12;
    opacity: 1;
    transition: all 256ms ease;
    -webkit-transition: all 265ms ease;
}
	
.cursor--active .cursor-pointer:before {
    width: 16px;
    height: 16px;
    box-shadow: 0 0 16px #a3ff12;
    opacity: 0.64;
}
	
.cursor-effect {
    position: absolute;
    top: -100%;
    left: -100%;
    transition: top 100ms ease, left 100ms ease;
    -webkit-transition: top 100ms ease, left 100ms ease;
}
	
.cursor-effect:before {
    content: '';
    display: block;
    width: 24px;
    height: 24px;
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    -webkit-transform: translate(-50%, -50%);
    border: 1px solid rgba(163, 255, 18, 0.48);
    border-radius: 100%;
    opacity: 1;
    transition: all 256ms ease;
    -webkit-transition: all 256ms ease;
}
	
.cursor--active .cursor-effect:before {
    width: 0;
    height: 0;
    opacity: 0;
}
	
@media (max-width: 768px) {
    .cursor {
        display: none;
    }
}

So that everything works properly, a little bit of Javascript is missing at the end:

(function($) {
    var cursorPointer = $('.cursor-pointer');
    var cursorEffect = $('.cursor-effect');
    var cursorEffectOffsetTop = (cursorEffect.height() / 2) - (cursorPointer.height() / 2);
    var cursorEffectOffsetLeft = (cursorEffect.width() / 2) - (cursorPointer.width() / 2);
			
    $('body').addClass('cursor--ready');
			
    $(document).on('mousemove', function (e) {
        cursorPointer.css({
            'top': e.pageY + 'px',
            'left': e.pageX + 'px'
        });
				
        cursorEffect.css({
            'top': (e.pageY - cursorEffectOffsetTop) + 'px',
            'left': (e.pageX - cursorEffectOffsetLeft) + 'px'
        });
    });
			
    $(document).on('mouseenter', 'a, label, input, button', function () {
	$('.cursor').addClass('cursor--active');
    });
			
    $(document).on('mouseleave', 'a, label, input, button', function () {
        $('.cursor').removeClass('cursor--active');
    });
})(jQuery);

Force WWW Redirect with SSL

If the domain is called without SSL (i.e. "https: //") or no "www." before that, the forwarding takes place to an SSL domain with WWW.

RewriteCond %{HTTPS} off [OR]
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteCond %{HTTP_HOST} ^(.*)$  [NC]
RewriteRule (.*) https://www.%1/$1 [R=302,L]

Popup with Cookie Timeout

We need a popup. After it has been closed, it should no longer be displayed for the next hour. So the problem could be solved relatively easily.

$(function () {
    var now = new Date();
    var myCookies = {};
    var browserCookies = document.cookie.split('; ');

    for (var i = 0; i < browserCookies.length; i++) {
        var cookieChunks = browserCookies[i].split('=');
        myCookies[cookieChunks[0]] = cookieChunks[1];
    }

    var cookieTimeout = (now.getHours() + 1) + '' + now.getMinutes();

    if ('undefined' !== myCookies['WS_POPUP_CLOSED'] && cookieTimeout >= myCookies['WS_POPUP_CLOSED']) {
        return;
    }

    setTimeout(function () {
        $('.ws-popup').addClass('ws-popup--visible');
    }, 1000);

    $('.ws-popup__button-close').on('click', function () {
        document.cookie = 'WS_POPUP_CLOSED=' + now.getHours() + '' + now.getMinutes() + ';';
        $('.ws-popup').removeClass('ws-popup--visible');
    });
});

Export Construct 2 Project as Android APK

In order to export a project from Construct 2 as an APK under Windows, the following steps are necessary.

  1. First we have to (if not already available) Android Studio, NodeJS and the Java SE Runtime Environment to install.
  2. After the installation we open the command line CMD, change to our hard drive "C: \" and execute the following command: npm install -g cordova
  3. Then we create a new project with the following command:
    cordova create demo com.wossi.demo demo
    The word demo is of course my project name here.
  4. Now we switch to our new directory with cd demo and execute the following command:
    cordova platform add android
  5. Then we open Android Studio and select the menu item "Import Project (Gradle, Eclipse, ADT, etc.)"
  6. Then we choose the point android in our project directory C:/demo/platforms/android and confirm our selection with OK. The following message is also simply confirmed with OK.
  7. In the emulator we can now check whether Cordova is running.
  8. We are now switching to the Construct 2 application and exporting our project with Cordova. In the exported project folder, we now copy the entire content of the www folder and paste it into Android Studio under app/assets/www.
    We overwrite all existing files!
  9. Now we can test our app again using the emulator, change the app icon under app/res/mipmap/ic_launcher/ic_launcher.png or make further settings in app/manifests/AndroidManifest.xml. If necessary, we can also activate the full-screen mode in app/res/xml/config.xml
  10. Finally, we export the APK to Android Studio at Build > Build Bundle(s) / APK(s) > Build APK(s). The unsigned APK can then be found atC:/demo/platforms/android/app/build/outputs/apk/debug/app-debug.apk

Cordova Fullscreen App in Android Studio

I have just generated my first APK for Android and now I want to use my app in full screen mode. However, I have the problem that I cannot hide the navigation bar of the device.
The solution is relatively simple. A small adjustment in app/res/xml/config.xml should solve the problem. Just add the following code.

<preference name="Fullscreen" value="true" />

In addition, I use the following line in my app/manifests/AndroidManifest.xml:

android:theme="@android:style/Theme.NoTitleBar.Fullscreen"

Allow WordPress Editors to edit Menus

It often happens that customers want to do their own thing in the dashboard (or backend) of WordPress. In the course of this, it may be necessary to enable the editor to edit menus. All you have to do is add the following lines to your functions.php.

$role_object = get_role('editor');
$role_object->add_cap('edit_theme_options');

Get WordPress Menu Items as Array

That is my solution! 😉

function getNavigationItemsArray(array $menuItems)
{
    $navigationItems = [];
    $parentPackages = [];

    foreach ($menuItems as $menuItem) {
        if ($menuItem->menu_item_parent == 0) {
            continue;
        }

        if (!isset($parentPackages[$menuItem->menu_item_parent])) {
            $parentPackages[$menuItem->menu_item_parent] = [$menuItem];
        } else {
            $parentPackages[$menuItem->menu_item_parent][] = $menuItem;
        }
    }

    foreach ($menuItems as $menuItem) {
        if (isset($parentPackages[$menuItem->ID])) {
            $menuItem->children = $parentPackages[$menuItem->ID];
        } else {
            $menuItem->children = [];
        }

        if ($menuItem->menu_item_parent == 0) {
            $navigationItems[] = $menuItem;
        }
    }

    return $navigationItems;
}

Rename WordPress Database after Domain Transfer

It happens that you have to transfer a WordPress project into the live environment after development. After the move you are faced with the problem that the old URL is still in the database. The project is therefore not accessible via the new domain. However, it is relatively easy to replace the old domain with the new domain. To do this, you have to execute the following SQL commands in PHPMyAdmin.

UPDATE wp_options SET option_value = replace(option_value, 'http://www.old.com', 'http://www.new.com') WHERE option_name = 'home' OR option_name = 'siteurl';
UPDATE wp_posts SET guid = replace(guid, 'http://www.old.com', 'http://www.new.com');
UPDATE wp_posts SET post_content = replace(post_content, 'http://www.old.com', 'http://www.new.com');
UPDATE wp_postmeta SET meta_value = replace(meta_value, 'http://www.old.com', 'http://www.new.com');

The names of the tables should of course be adjusted accordingly.

Use ACF fields in Yoast SEO as template variable

If you want to use the content of a user-defined field of the ACF plugin (Advanced Custom Fields) in the Yoast SEO Plugin, you can easily pass the value to Yoast as a template variable. It is therefore possible to use the content of the field in the SEO snippet as a title or meta description.

add_action('wpseo_register_extra_replacements', function () {
    wpseo_register_var_replacement('%%custom_template_variable%%', function () {
        global $post;

        $field = get_field_object('acf_field_name', $post->ID);

        return $field['value']->name;
    }, 'advanced', __('ACF Field Description'));
});

Show custom field in SEO snippet

Then you can use the template variable %%custom_template_variable%% to edit the SEO snippet in Yoast plugin.

WordPress Post Query

Show posts in WordPress … probably the best option!

$query = [
    'post_type' => 'post',
    'post_status' => 'publish',
    'orderby' => 'date',
    'order' => 'DESC',
    'posts_per_page' => -1,
    'cat' => 1,
];

$posts = get_posts($query);

foreach ($posts as $post) {
    setup_postdata($post);
    
    the_title();
    the_content('', false);
}

wp_reset_postdata();

Filter by taxonomy

If you want to filter by taxonomy, you can add the following code before passing the query variable to get_posts.

$query['tax_query'] = [
    [
        'taxonomy' => 'my_custom_taxonomy',
        'field' => 'term_id',
        'terms' => 1
    ]
];

My WordPress Plugins

I work a lot professionally and also in my free time with WordPress. I have known this CMS since the release of version 2.3 in 2007. In the meantime, I cannot imagine a better system for myself and my customers. It can be easily and quickly expanded using plugins. If you have the certain technical know-how, this opens up unlimited possibilities … I love it and have already been able to implement a number of projects.

I am always asked which plugins I use or would use myself. The function and when which plugin is used, I just now assume. So here are my personal recommendations:

iOS Hover Fix / Double-Tap Problem

iPad and iPhone sometimes have the so-called "Double tap" problem. The problem occurs together with the CSS selector ": hover". The iOS interprets the mouseover effect, which actually does not exist on mobile devices. There is a simple solution: just copy the following code into the <head> area of the page. Alternatively, the two snippets can also be stored in separate files.

<script type="text/javascript">
    document.addEventListener('touchstart', function() {}, true);
</script>

<style>
    *:hover,
    *:active {
        -webkit-user-select: none;
        -webkit-touch-callout: none;
    }
</style>

CSS Selector Hack for Internet Explorer 11

If the properties of a CSS selector should only be valid for Internet Explorer 11, then we use the following instruction …

_:-ms-fullscreen,
:root .selector {
    property: value;
}

CSS Selector Hack for Microsoft Edge Browser

If the properties of a CSS selector should only be valid for the Microsoft Edge browser, then we use the following instruction …

:-ms-lang(x),
:-webkit-full-screen,
.selector {
    property: value;
}

WordPress Login without Database Access

Ok, the following scenario:

We received a wordpress project from a customer. The customer does not have administrator access to the backend. The former developer of the project is no longer available and the password for the database is not known. The only access is the connection to the FTP server.

How can you still get full access to WordPress Backend?

We only need to add the following lines to the functions.php in the activated theme:

add_action('init', function (){
    $user = 'USERNAME';
    $pass = 'PASSWORD';
    $mail = 'USER@MAIL.COM';

    if (!username_exists($user)  && !email_exists($mail)) {
        $user_id = wp_create_user($user, $pass, $mail);
        $user = new WP_User($user_id);
        $user->set_role('administrator');
    }
});

After that, the website just has to be called up. The corresponding user is thus automatically created in the database.

CSS Transition Callback

Call a Javascript function as soon as CSS transition has ended …

$('.selector').one('transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd', function () {
    ...
});

… or, wait until CSS animation has run through …

$('.selector').one('animationend webkitAnimationEnd oAnimationEnd MSAnimationEnd', function () {
    ...
});

Phonetic Alphabet

When I want to spell a word on the phone, in most cases I use words that come to mind. All well and good … well, maybe not! The Phonetic Alphabet is actually meant for this.

So that I always have my personal spelling board or radio alphabet at hand, here is the complete list. I chose the NATO variant here because it sounds much more groovy than the normal German version. 🙂

AAlfa
BBravo
CCharlie
DDelta
EEcho
FFoxtrot
GGolf
HHotel
IIndia
JJuliet
KKilo
LLima
MMike
NNovember
OOscar
PPapa
QQuebec
RRomeo
SSierra
TTango
UUniform
VVictor
WWhiskey
XX-Ray
YYankee
ZZulu
Phonetisches Alphabet

CSS Font Weights

The "font-weight" attribute defines the thickness of the font in CSS. Some fonts can only be displayed in bold or normal. Other fonts provide a more precise definition with a numeric value.

The following list shows the numerical value for the appropriate keyword:

  • 100 Thin, Hairline, Ultra-light, Extra-light
  • 200 Light
  • 300 Book
  • 400 Regular, Normal, Plain, Roman, Standard
  • 500 Medium
  • 600 Semi-bold, Demi-bold
  • 700 Bold
  • 800 Heavy, Black, Extra-bold
  • 900 Ultra-black, Extra-black, Ultra-bold, Heavy-black, Fat, Poster

1 Pixel Transparent GIF

Somehow I always used a transparent pixel … no idea why?! Before you start your CorelDraw (or Photoshop), here is a solution in base64 format.

<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7">

base64 Scanlines

Sometimes you can use scanlines quite well … but in most cases you would have to use a graphics program to create the things. Fortunately, this can also be done with a few lines of code.

Black Scanlines

1 Pixel Version

background-image: url('data:image/gif;base64,R0lGODlhAQACAPAAAAAAAAAAACH5BAEAAAEALAAAAAABAAIAAAICRAoAOw==');

1 Pixel Version

background-image: url('data:image/gif;base64,R0lGODlhAQAEAPAAAAAAAAAAACH5BAEAAAEALAAAAAABAAQAAAIDBBIFADs=');

White Scanlines

2 Pixel Version

background-image: url('data:image/gif;base64,R0lGODlhAQACAPAAAP///wAAACH5BAEAAAEALAAAAAABAAIAAAICRAoAOw==');

2 Pixel Version

background-image: url('data:image/gif;base64,R0lGODlhAQAEAPAAAP///wAAACH5BAEAAAEALAAAAAABAAQAAAIDBBIFADs=');

Don't forget to repeat the pixels horizontally!

Responsive Images

My default styles for images...

<style>
    img {
        display: block;
        width: 100%;
        height: auto;
        margin: auto;
    }
</style>

The HTML part...

<picture>
    <source media="(min-width: 1025px)" srcset="image-1260px.jpg">
    <source media="(min-width: 769px) and (max-width: 1024px)" srcset="image-1024px.jpg">
    <source media="(min-width: 481px) and (max-width: 768px)" srcset="image-768px.jpg">
    <source media="(max-width: 480px)" srcset="image-480px.jpg">
    <img src="image-1260px.jpg">                   
</picture>

Clear DNS Cache in Google Chrome Browser

Sometimes it is helpful to clear the DNS cache in the browser. In Google Chrome you just have to open a new tab, enter the following in the address bar and confirm with ENTER. Then simply click on the button and empty the DNS cache.

chrome://net-internals/#dns

Blank HTML5 Template (Boilerplate)

A useful HTML5 boilerplate...

<!DOCTYPE html>
<html lang="de">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1.0, user-scalable=no">
    <title>Default Page Title</title>
    <link rel="icon" href="favicon.png">
    <link rel="stylesheet" type="text/css" href="css/style.css">
</head>
<body>
    <p>Hello World!</p>
    <script src="js/script.js"></script>
</body>
</html>

Hardware Setup [WiP]

… for everyone who is interested. Here you can find my current hardware.

Internal

External