Author: Mathias Lipowski

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

How to delete a single element from an array in PHP

php logo on purple background

There are multiple ways to remove an element from an array in PHP. The simplest one is the method unset().

unset()

The method unset() can be used to remove a single element of the array:

PHP
$myArray = ['apple', 'banana', 'cherry', 'date'];
unset($myArray[1]); // Remove the element at index 1 (banana)
$myArray = array_values($myArray); // Re-index the array if you want to remove the gap

print_r($myArray);

The output of print_r() is:

Array
(
    [0] => 'apple'
    [1] => 'cherry'
    [2] => 'date'
)

array_splice()

This function can be used to remove a portion of an array and replace it with something else. If you want to remove a single element, you can specify a length of 1:

PHP
$myArray = ['apple', 'banana', 'cherry', 'date'];
array_splice($myArray, 1, 1); // Remove 1 element starting from index 1

print_r($myArray);

array_diff()

You can use this function to create a new array with all the elements of the first array that are not in the other arrays:

PHP
$myArray = ['apple', 'banana', 'cherry', 'date'];
$elementToRemove = 'banana';
$myArray = array_diff($myArray, [$elementToRemove]);

print_r($myArray);

array_filter()

This function can be used with a callback function to filter elements from an array:

PHP
$myArray = ['apple', 'banana', 'cherry', 'date'];
$elementToRemove = 'banana';
$myArray = array_filter($myArray, function($value) use ($elementToRemove) {
   return $value !== $elementToRemove;
});

print_r($myArray);

unset() with array_search()

You can combine unset() with array_search() to remove an element based on its value:

PHP
$myArray = ['apple', 'banana', 'cherry', 'date'];
$elementToRemove = 'banana';
$index = array_search($elementToRemove, $myArray);
if ($index !== false) {
   unset($myArray[$index]);
}

print_r($myArray);

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

Performance improvements for GitLab on servers with limited resources

When running GitLab, the default installation enables all services by default. This might result in a poor performance, especially when the server has limited resources like RAM or CPU power.

To improve the performance of your installation, the GitLab documentation already provides some settings that can be adjusted easily.

A detailed description can be found at docs.gitlab.com.

My web server has 6GB of RAM, which results in temporary timeouts – especially when GitLab Runner executed some jobs.

I started with the changes listed below and already saw a huge reduction of loading time and UI response time on my GitLab installation. The following steps have been copied from docs.gitlab.com as a reminder for future setups.


Disable monitoring

GitLab enables all services by default to provide a complete DevOps solution without any additional configuration. Some of the default services, like monitoring, are not essential for GitLab to function and can be disabled to save memory.

In /etc/gitlab/gitlab.rb:

prometheus_monitoring['enable'] = false

We observed 200MB of memory usage reduction configuring GitLab this way.

Configure how GitLab handles memory

GitLab consists of many components (written in Ruby and Go), with GitLab Rails being the biggest one and consuming the most of memory.

GitLab Rails uses jemalloc as a memory allocator. jemalloc preallocates memory in bigger chunks that are also being held for longer periods in order to improve performance. At the expense of some performance loss, you can configure GitLab to free memory right after it is no longer needed instead of holding it for a longer periods.

In /etc/gitlab/gitlab.rb:

gitlab_rails['env'] = { 'MALLOC_CONF' => 'dirty_decay_ms:1000,muzzy_decay_ms:1000' }
gitaly['env'] = { 'MALLOC_CONF' => 'dirty_decay_ms:1000,muzzy_decay_ms:1000' }

We observed much more stable memory usage during the execution of the application.

Disable additional in-application monitoring

GitLab uses internal data structures to measure different aspects of itself. These features are no longer needed if monitoring is disabled.

To disable these features you need to go to Admin Area of GitLab and disable the Prometheus Metrics feature:

  1. On the left sidebar, at the bottom, select Admin Area.
  2. Select Settings > Metrics and profiling.
  3. Expand Metrics – Prometheus.
  4. Disable Enable Prometheus Metrics.
  5. Select Save changes.

JavaScript: how to check if a string variable is an integer value

JS on yellow background

One way to check if a variable is of type integer, Number.isInteger() can be used:

JavaScript
Number.isInteger(22); // true
Number.isInteger(22.2); // false
Number.isInteger('22'); // false

But this solution has the disadvantage, that a string with integer value like '22' will result in false.

To address this case, another solution is required:

JavaScript
function isInteger(data) {
  return +data === parseInt(data);
}

isInteger(22); // true
isInteger(22.2); // false
isInteger('22'); // true

This will result in true for integer 22 as well as a string '22'.

How to decode the exception backtrace of an ESP32

ESP32

When the execution of code on an ESP32 throws an exception, the output might look like this:

Guru Meditation Error: Core  1 panic'ed (LoadProhibited). Exception was unhandled.??
??
Core  1 register dump:??
PC      : 0x420383b2  PS      : 0x00060c30  A0      : 0x820059ec  A1      : 0x3fcebd70  ??
A2      : 0x3fc97708  A3      : 0x3fcebdcb  A4      : 0x00000001  A5      : 0x0000ff00  ??
A6      : 0x00ff0000  A7      : 0xff000000  A8      : 0x3fcecf5b  A9      : 0x0000723f  ??
A10     : 0x3fcecf5b  A11     : 0x00000001  A12     : 0x00000001  A13     : 0x3fcf06b4  ??
A14     : 0x00000001  A15     : 0x00000003  SAR     : 0x00000017  EXCCAUSE: 0x0000001c  ??
EXCVADDR: 0x0000728b  LBEG    : 0x40056f08  LEND    : 0x40056f12  LCOUNT  : 0x00000000  ??
??
??
Backtrace: 0x420383af:0x3fcebd70 0x420059e9:0x3fcebd90 0x42004e26:0x3fcebdb0 0x420035a2:0x3fcebe00 0x42003595:0x3fcebe20 0x4200542c:0x3fcebe40 0x42008891:0x3fcebe60??
...

The Espressif tools contain a binary called xtensa-esp32-elf-addr2line which will decode the backtrace addresses and return details about the source files, lines and function names, etc.

To run the tool, call:

/home/user/.espressif/tools/xtensa-esp32-elf/esp-2020r3-8.4.0/xtensa-esp32-elf/bin/xtensa-esp32-elf-addr2line -fe /path/to/build/<ELFFILE>.elf <BACKTRACE>

In the command above, simply…

  • replace the path to the xtensa-esp32-elf-addr2line binary
    (in my case the binary is located in the users home directory in the folder .espressif)
  • replace the path to your elf file
    (normally, the elf file is located in the build path and generated during compilation)
  • replace the backtrace output string
    (it’s the string that is shown after Backtrace: )

How to enter ASCII control characters with your keyboard

close photo of a macbook pro keyboard

How to enter ASCII control characters?

Entering ASCII control characters depends on the specific keyboard layout and operating system you are using. Here’s a general guide for Linux, Windows, and macOS:

Linux

In most Linux terminals, you can enter ASCII control characters using the keys Ctrl + Shift + u in combination with a letter or symbol. For example:

  • Ctrl + Shift + u and then 0 + 1: ASCII code 0x01 (Start of Heading)
  • Ctrl + Shift + u and then 0 + 2: ASCII code 0x02 (Start of Text)
  • Ctrl + Shift + u and then 0 + 3: ASCII code 0x03 (End of Text)
  • And so on…

Windows

In the Windows operating system, you can use the following steps:

  1. For characters with ASCII values 0 to 31, you can typically enter them using the Alt key and the numeric keypad. For example, to enter ASCII 0x01, press Alt + 0 + 0 + 1.
  2. For some characters, you can use the Windows Character Map utility. Press the Win key + R to open the Run dialog, type charmap, and press Enter. Select the desired character and copy/paste it.

macOS

On macOS, you can use the following steps:

  1. Character Viewer: Press Control + Command + Space to open the Character Viewer. Search for the desired control character and insert it into your document.

Note that you may have to go to the dots menu at top left and select Customize to add the Unicode category. The Unicode category is under Code Tables.

Note: The availability of these methods may vary depending on your keyboard layout and the specific software you are using. If you’re using a specific text editor or terminal, it might have its own way of entering control characters.

What are ASCII control characters?

ASCII control characters are special characters in the ASCII (American Standard Code for Information Interchange) character encoding scheme that are used to control peripheral devices such as printers and teletypewriters. They are non-printable characters and typically have specific functions rather than representing printable symbols like letters or numbers.

Here is a list of some commonly used ASCII control characters along with their decimal and hexadecimal values:

Control CharacterASCII DezimalASCII HEXDescription
NUL000null character
SOH101start of header
STX202start of text
ETX303end of text
EOT404end of transmission
ENQ505enquiry
ACK606acknowledge
BEL707bell (ring)
BS808backspace
HT909horizontal tab
LF100Aline feed
VT110Bvertical tab
FF120Cform feed
CR130Dcarriage return
SO140Eshift out
SI150Fshift in
DLE1610data link escape
DC11711device control 1
DC21812device control 2
DC31913device control 3
DC42014device control 4
NAK2115negative acknowledge
SYN2216synchronize
ETB2317end transmission block
CAN2418cancel
EM2519end of medium
SUB261Asubstitute
ESC271Bescape
FS281Cfile separator
GS291Dgroup separator
RS301Erecord separator
US311Funit separator
   
DEL1277Fdelete (rubout)

Foto von Jess Bailey auf Unsplash

FutureBuilder: handle multiple futures in a single widget

moving staircase at night

By default, FutureBuilder provides a single future parameter that handles a single Future. For multiple Futures, we can combine them into a single Future using Future.wait. Here’s a step-by-step guide on how to do this:

Create a list of Future objects

Create a list of Future objects that represent the asynchronous operations you want to perform. For example, let’s assume you have two futures:

Future<String> fetchFirstData() async {
  // Simulate a network request or other asynchronous operation.
  await Future.delayed(Duration(seconds: 2));
  return "First Data";
}

Future<int> fetchSecondData() async {
  // Simulate another asynchronous operation.
  await Future.delayed(Duration(seconds: 3));
  return 42;
}

Combine the futures using Future.wait

Use the Future.wait method to combine the individual futures into a single future. Future.wait takes a list of futures as an argument and returns a single future that completes when all the input futures have completed.

Future<void> fetchData() async {
  await Future.wait([fetchFirstData(), fetchSecondData()]);
}

Create a FutureBuilder widget

Now, use the FutureBuilder widget to handle the combined future and display the results in your widget tree. You can place this widget in your build method.

class MyWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return FutureBuilder(
      future: fetchData(),
      builder: (context, snapshot) {
        if (snapshot.connectionState == ConnectionState.done) {
          // Use the results from the futures here.
          if (snapshot.hasError) {
            return Text("Error: ${snapshot.error}");
          } else {
            return Column(
              children: [
                Text("First Data: ${snapshot.data[0]}"),
                Text("Second Data: ${snapshot.data[1]}"),
              ],
            );
          }
        } else {
          // While waiting for the futures to complete, you can show a loading indicator or placeholder.
          return CircularProgressIndicator();
        }
      },
    );
  }
}

In the code above, we use the snapshot to check the connectionState. When the connectionState is ConnectionState.done, it means that both futures have completed. You can access the results using snapshot.data.

Remember to replace the fetchFirstData and fetchSecondData functions with your actual asynchronous operations. This example demonstrates how to use FutureBuilder to handle multiple futures in a single widget in Flutter.

Foto von Tomasz Frankowski auf Unsplash