Category: Coding / Frameworks

WordPress: how to remove the ‘link rel=shortlink’ tag from your site

By default, WordPress adds <link rel="shortlink"> meta tag to the <head> of a website and uses the short url like https://mixable.blog/?p=12345 for this. When you already use nice slugs as permalink structure, such a tag is not necessary, because you already have unique urls.

To remove the shortlink tag, you can use an additional plugin or simply add some code to your themes functions.php:

PHP
add_filter('after_setup_theme', 'remove_redundant_shortlink');

function remove_redundant_shortlink() {
    // Remove HTML meta tag
    // <link rel='shortlink' href='http://mixable.blog/?p=12345' />
    remove_action('wp_head', 'wp_shortlink_wp_head', 10);

    // Remove HTTP header
    // Link: <https://mixable.blog/?p=12345>; rel=shortlink
    remove_action( 'template_redirect', 'wp_shortlink_header', 11);
}

This code will also remove a http header from each response.

Foto von Markus Winkler auf Unsplash

 

PHP fatal error: Uncaught TypeError: ftp_nlist(): Argument #1 ($ftp) must be of type FTP\Connection, null given

broken plate on the floor

This error happened after moving a WordPress installation to another server. The new server had a different linux distribution and a newer PHP version. In my case, the environment changed from PHP 7.4 to PHP 8.2.

I already added some missing PHP extensions and updated the configuration to match the old one, but the error still exists.

At the end, this could be solved by adding the following code in wp-config.php file:

if ( ! defined( 'FS_METHOD' ) ) define( 'FS_METHOD', 'direct' );

Source

Foto von CHUTTERSNAP auf Unsplash

 

jQuery methods in plain JavaScript

cup of coffee

Life is already very complex, so let’s simplify your projects by removing all the jQuery code. Plain JavaScript provides the same functionalities and it does not require any additional frameworks. And it’s supported by most of the modern browsers out of the box. This is a list of replacements for your daily used jQuery methods.

$() or jQuery()

Return a collection of matched elements either found in the DOM based on passed argument(s) or created by passing an HTML string.

// jQuery implementation
var element = $(selector);
// Plain JavaScript
var element = document.querySelector(selector); // Single element
var elements = document.querySelectorAll(selector); // Multiple elements

.addClass()

Adds the specified class(es) to each element in the set of matched elements.

// jQuery implementation
element.addClass('text-bold');
// Plain JavaScript
element.classList.add('text-bold');

.attr()

Adds the specified class(es) to each element in the set of matched elements.

// jQuery implementation
element.attr(attribute, value);
// Plain JavaScript
element.setAttribute(attribute, value);

.css()

Set one or more CSS properties for the set of matched elements.

// jQuery implementation
element.css(property, value);
// Plain JavaScript
element.style[property] = value;

.each()

Iterate over a jQuery object, executing a function for each matched element.

// jQuery implementation
$.each(settings, function (index, element) {
    // ...
});
// Plain JavaScript
settings.forEach((element, index) => {
    // ...
});

.empty()

Remove all child nodes of the set of matched elements from the DOM.

// jQuery implementation
container.empty();
// Plain JavaScript
container.replaceChildren();

See https://stackoverflow.com/a/65413839/768352

.extend()

Merge the contents of two or more objects together into the first object.

// jQuery implementation
const settings = $.extend(defaults, options)
// Plain JavaScript
const settings = {...defaults, ...options}

.hasClass()

Determine whether any of the matched elements are assigned the given class.

// jQuery implementation
if (element.hasClass('text-bold')) {
  // ...
}
// Plain JavaScript
if (element.classList.contains('text-bold')) {
  // ...
}

.hide()

Hide the matched elements.

// jQuery implementation
element.hide();
// Plain JavaScript
element.style.display = 'none';

.html()

Set the HTML contents of each element in the set of matched elements.

// jQuery implementation
element.html('<div>my html</div>');
// Plain JavaScript
element.style.innerHTML = '<div>my html</div>';

.map()

Translate all items in an array or object to new array of items.

// jQuery implementation
$.map(array, function (value, index) {});
// Plain JavaScript
array.map((value, index) => {});

.now()

Return a number representing the current time.

// jQuery implementation
$.now();
// Plain JavaScript
Date.now();

.removeClass()

Remove a single class or multiple classes from each element in the set of matched elements.

// jQuery implementation
element.removeClass('text-bold');
// Plain JavaScript
element.classList.remove('text-bold');

.show()

Display the matched elements.

// jQuery implementation
element.show();
// Plain JavaScript
element.style.display = 'block';

.text()

Set the content of each element in the set of matched elements to the specified text.

// jQuery implementation
element.text('my text');
// Plain JavaScript
element.textContent = 'my text';

.toggle()

Display or hide the matched elements.

// jQuery implementation
element.toggle();
// Plain JavaScript
element.style.display = element.style.display === 'none' ? 'block' : 'none';

.toggleClass()

Add or remove one or more classes from each element in the set of matched elements, depending on either the class’s presence or the value of the state argument.

// jQuery implementation
element.toggleClass('text-bold');
// Plain JavaScript
element.classList.toggle('text-bold');

.trigger()

Execute all handlers and behaviors attached to the matched elements for the given event type.

// jQuery implementation
$(document).trigger("myEvent");
$(".container").trigger("myEvent");

// Plain JavaScript
document.dispatchEvent(new Event("myEvent"));
document.querySelector(".container").dispatchEvent(new Event("myEvent"));

.val()

Get the current value of the first element in the set of matched elements.

// jQuery implementation
var val = element.val();
// Plain JavaScript
var val = element.value;

Photo by Jakub Dziubak on Unsplash

CakePHP 3: Kurzfassung zum Verwenden von Migrations

CakePHP bietet mit Migrations die Möglichkeit, Änderungen an der Datenbankstruktur einzuspielen oder rückgängig zu machen. Der typische Ablauf zur Migration ist folgender:

Generating migrations from an existing database

If you are dealing with a pre-existing database and want to start using migrations, or to version control the initial schema of your application’s database, you can run the migration_snapshot command:

bin/cake bake migration_snapshot Initial

Generating a diff between two database states

You can generate a migrations file that will group all the differences between two database states using the migration_diff bake template. To do so, you can use the following command:

bin/cake bake migration_diff NameOfTheMigrations

Applying Migrations

Once you have generated or written your migration file, you need to execute the following command to apply the changes to your database:

bin/cake migrations migrate

Migrations Status

The Status command prints a list of all migrations, along with their current status. You can use this command to determine which migrations have been run:

bin/cake migrations status

CakePHP 3: Benutzername oder Email zum Anmelden mit AuthComponent verwenden

In den Einstellungen der AuthComponent lässt sich festlegen, welches Feld der Datenbank für das Login verwendet werden soll. Hier kann allerdings nur ein einzelner Wert angegeben werden (bspw. username oder email). Um jedoch bei der Eingabe des Logins sowohl Benutzername, als auch Email zu erlauben, kann man die Einstellung zur Laufzeit (also beim Aufruf des Controllers) anpassen und das entsprechende Feld setzen. Und zwar wie folgt:

src/Controller/AppController.php

use Cake\Controller\Controller;

class AppController extends Controller
{
    public function initialize()
    {
        parent::initialize();
        $this->loadComponent('Flash');
        $this->loadComponent('Auth', [
            'authenticate' => [
                'Form' => [
                    'fields' => ['username' => 'username', 'password' => 'password'],
                ]
            ],
        ]);
    }
}

src/Controller/UsersController.php

use App\Controller\AppController;
use Cake\Validation\Validation;

class UsersController extends AppController
{
    public function login()
    {
        if ($this->request->is('post')) {

            if (Validation::email($this->request->getData('username'))) {
                $this->Auth->config('authenticate', [
                    'Form' => [
                        'fields' => ['username' => 'email']
                    ]
                ]);
                $this->Auth->constructAuthenticate();
                $this->request->data['email'] = $this->request->getData('username');
            }

            $user = $this->Auth->identify();

            if ($user) {
                $this->Auth->setUser($user);
                return $this->redirect($this->Auth->redirectUrl());
            }

            $this->Flash->error(__('Invalid combination of username/email and password.'));
        }
    }
}

src/Template/Users/login.ctp

<php
echo $this->Flash->render('auth');
echo $this->Form->create();

echo $this->Form->input('username');
echo $this->Form->input('password');

echo $this->Form->button(__('Login'));
echo $this->Form->end();
?>

CakePHP 2 Media Plugin: Media Dateien (Grafiken, …) mit verschiedenen Models nutzen

Unter http://grafikart.github.io/CakePHP-Media/index_en.html gibt es ein klasse CakePHP Plugin, mit dem sich Dateien verschiedenster Art (vorzüglich Grafiken, aber auch: png, jpg, pdf, mov, …) mit den Datensätzen anderer Models verknüpfen lassen. Im Video-Tutorial der Webseite wird ausführlichst beschrieben, wie dieses Plugin verwendet wird. Sehr zu empfehlen!

CakePHP 2: versenden von Emails (CakeEmail) debuggen

Möglichkeit 1: Debug-Einstellung setzen

Eine einfache Möglichkeit, um das Versenden von Emails in CakePHP 2.x zu testen, ist die Debug-Einstellung der Email Konfiguration. Dabei genügt das Setzen der Transport-Einstellung auf ‘Debug’ und schon wird der Inhalt der Email an der entsprechenden Stelle angezeigt:

<?php
// app/Config/email.php
class EmailConfig {
   public $default = array(
      'transport' => 'Debug',
      // ...

Dies funktioniert allerdings nur, wenn man sich die Ausgabe des aufgerufenen Scripts anzeigen lassen kann. Bei Cronjobs beispielsweise wird dies schon schwieriger.

CakePHP: Warum funktionieren Shells (bei gleichem Aufruf) nicht als Cronjob?

Shells lassen sich in CakePHP auch für den Aufruf aus Cronjobs verwenden. Dabei kann es jedoch vorkommen, dass der Aufruf einer Shell über das Terminal ohne Probleme funktioniert, aber im späteren Einsatz beim Aufruf über einen Cronjob nicht mehr so richtig will. Es hatte mich einiges an Zeit gekostet, herauszufinden warum dies passieren kann: