WordPress filters and anonymous functions

Anonymous functions have been around for a long time. And since WordPress now supports php 5.6 it can be safely used.
And appears to be allowed?

Personally I’m not a fan of anonymous functions in combination with WordPress actions and filters. My main concern is you can’t remove them once registered. How ever today I found a use case which was very usefull in combination with the use

My example:

<?php
/* Template name: some-template */

// Gather all data
$condition_for_title = true;
$h1_title_override = 'very heavy and complicated check';
// the H1 also needed as the <title>

add_filter( 'pre_get_document_title', function( $title ) use ($h1_title_override, $condition_for_title) {
    if ($condition_for_title) {
        return $h1_title_override;
    }
    return $title;
}, 20, 1 );

get_header();

// start body
?>
    <h1><?php echo $h1_title_override ?>

Here I pass 2 variables h1_title_override and $condition_for_title which are created outside the function. In my case these where quite complicated and heavy checks. Of course I could put those in a function and cache the result. And call that check in the filter function. But still I need to check the current template before doing the function.

More traditional Example:

in functions.php

function complicated_check() {
    // Gather all data
    $condition_for_title = true;
    $h1_title_override   = 'very heavy and complicated check';

    return [
        'condition_for_title' => $condition_for_title,
        'h1_title_override'   => $h1_title_override,
    ];
}

function title_exception_for_template( $title ) {
    if ( ! is_page_template('clean-template.php')) {
        return $title;
    }

    $template_data = complicated_check();

    if ( $template_data['condition_for_title'] ) {
        return $template_data['h1_title_override'];
    }

    return $title;
}

add_filter( 'pre_get_document_title', 'title_exception_for_template', 20, 1 );

in clean-template.php

<?php
/* Template name: clean-template */
$template_data = complicated_check();

get_header();

// start body
?>
    <h1><?php echo $template_data['h1_title_override'] ?>

Both these approaches do the same thing. But the more traditional way is a lot more code. Although it has cleaner template.
I probably won’t use this much. If the anonymous function was more complicated it will get hard to read.

But for this case I think it was neat that I could use this little feature.

WP-cli run command over each subsite

If you use WP-cli command on a multisite it be default will only run on the mainsite.
But often you want to change a setting for all the sites.
In my case I wanted to set the timezone to Amsterdam for the whole network. That’s not hard:

wp option set timezone_string 'Europe/Amsterdam'

On a multisite this is a bit more difficult. But the script below will do the same for each site in a multisite.

wp site list --field=url | xargs -I % sh -c 'printf "%\n"; wp option set timezone_string 'Europe/Amsterdam'

–url=%’

VVV disable backups

list of vvv custom action filesVVV is great but if you have 20+ sites in it most of which are quite big doing a reload or halt can be quite slow.
Disabling it isn’t the easiest. In vagrant-root/config/homebin/ create these 3 files:

  • vagrant_destroy_custom
  • vagrant_halt_custom
  • vagrant_suspend_custom

I wish there was a way to easily disable these. The vvv-custom.yml would be great for this.
Also adding a way to exclude specific databases.

source

php array; insert new item at specific index

The php function array_splice can be used to insert new items. At specific places.

<?php
$breadcrumbs = [
    'home',
    'year',
    'month',
    'day',
];
$new_crumb = [
    'category'
];
array_splice($breadcrumbs, 1, 0, $new_crumb);

The result is that category is inserted at the second place.

array (
    0 => 'home',
    1 => 'category',
    2 => 'year',
    3 => 'month',
    4 => 'day',
);

Running php from command line

This is one of those “I know this is possible, but don’t know how”.

php -r 'echo "hello world";'

Only useful for simple onelines. You’re very likely to be better of putting code in a php file and run that script like:

php ./helloworld.php

Curl output format

A lot of usefull informatoin can be caught using curl. Formating the output can be done with the -w --write-out argument

curl -w 'Home loadtime: %{time_total}\nResponse code: %{http_code}\n' -o /dev/null -s 'https://www.janw.me/'

Output example: Bash output of curl request

This example will show the load time and response code. These 2 values are duable. But If you want more it’s more readable to pass a file.

In file: nano curlformat.txt

    time_namelookup:  %{time_namelookup}\n
       time_connect:  %{time_connect}\n
    time_appconnect:  %{time_appconnect}\n
   time_pretransfer:  %{time_pretransfer}\n
      time_redirect:  %{time_redirect}\n
 time_starttransfer:  %{time_starttransfer}\n
                    ----------\n
         time_total:  %{time_total}\n

Then pass the file to curl:

curl -w "@curl-format.txt" -o /dev/null -s "https://janw.me/"

Bash output of curl format file

A list of all avialable variables are in the man pages

Sources:

Migrate one site out a multisite.

We where asked to host a site. But then it turned out that site was part of a bigger multisite. So after I got all files & db of the complete site I needed to clean it up and only keep the requested site left.

The quick and dirty steps:

  • Don’t change the DNS until you’re done testing.

Webhosting settings

  • Import all files on the server
  • Import the database and change the db settings in wp-config.php.
  • Locally add the domain to the hosts file So I didn’t need to change urls
  • delete all sites using wp site delete SITE_ID
  • Only keep site 1 (the primary you can’t delete) and site 12 (the site ID I needed)

Rename the tables

  • Rename the site 1 tables in mysql RENAME TABLE `amsterda_db`.`wp_links` TO `amsterda_db`.`wp_BACKUP_links`;
  • Rename the site 12 tables to the normal tables RENAME TABLE `amsterda_db`.`wp_12_links` TO `amsterda_db`.`wp_links`;
  • Make sure you only rename the site tables, don’t rename wp_blogs and other multisite tables

Update the url

  • In wp_blogs delete the record of site 12 and change the name to the new main site in wp_blogs.domain. And rename the url inside wp_site.
  • Also cleanup the wp_blog_versions.
  • In wp-config.php change the constant DOMAIN_CURRENT_SITE
  • Search the database for all mentions of the old mainsite. This is a per case check what should be done.
    Links in posts are probably fine. The old url in the wp_options maybe not.

Permissions and roles

  • In the wp_options table search for wp_user_roles as option_name. If this record is not present. Search it in the wp_BACKUP_options and create the record manually.
  • Permissions are still set for site 12 fix that using wp search-replace wp_12_ wp_ wp_usermeta

Test

  • Test your site. At least test uploads, permalinks, creating/updating pages
  • The normal steps usually when deploying a new site.
  • Think about things that might differ on this inherent setup.

Live

  • switch DNS
  • SSL

After the first week

  • Delete all wp_BACKUP_* tables
  • Check for unneeded plugins
  • Check for unneeded users.
  • Possible you should cleanup the uploads folder of old sites, although there may be links to those uploads.

Of course it would be even better to remove the multisite setup. But I was out of time. And I still would have done these steps first.

Posted in TIL

PHP interface type hinting

In interfaces you can force the return type

interface InterfaceTest {
    function GetSingleEntity(): Entity;
    function GetEntitySet() : Entity[];
}

GetEntitySet should return a array containing Entities. But this kind of syntax is not allowed.
You could just change it to only return an array, but the forcing of the class is the most powerful.
The best is to create a wrapper class for the entities, best would be to use an Iterator.

sed command line tool

sed is not new for me. But it’s such a versatile tool. And I always have trouble finding the precice syntax I need. So here is a collection of examples. It probably will grow in the years.

Replace the home dir with ~.

COMPACT=$(echo ${HOME} | sed "s#${HOME}#~#g")

Replace %SALT% with the variable $SALT in the file wp-config.php

sed -i -E "s/%SALT%/$SALT/g"  "wp-config.php"