ACF load user_meta cross WordPress multisite

Users are global in a multisite. And default ACF groups are per site. So if you set a pinterest url for a user on one site it will apply it for all sites. No problem. But if you set an image it will try to find that image-id on each site.

The solution.

Step 1; Limit the user acf groups only to the main site:

<?php
function wpstarter_filter_fields_group($result, $rule, $screen) {
    if ( isset( $screen['user_id'] ) && ! is_main_site() )
        return false;

    return $result;
}
add_filter('acf/location/rule_match', 'wpstarter_filter_fields_group', 10, 3);

Step 2; Get image fields for users only from the main site:

<?php
function wpstarter_load_avatar_value_cros_site( $value, $post_id, $field ) {

    if( 0 !== strpos( $post_id, 'user_' ) || is_main_site() ) {
        return $value;
    }

    switch_to_blog( get_main_site_id() );

    $value_of_main_site = acf_get_value($post_id, $field);
    $value              = acf_format_value($value_of_main_site, $post_id, $field);

    restore_current_blog();
    return $value;
}
add_filter( 'acf/format_value/type=image', 'wpstarter_load_avatar_value_cros_site', 11, 3);

The order of arguments in an if statement

Consider this dummy snippet:

<?php
if ( true === $skip || heavy_check() ){
    continue;
}

The $skip is checked first. It is very quick as it is just a simple variable check. and since this is an ‘or’ statement. As soon as $skip is true it won’t bother with the heavy_check.

Something I always suspected but today I tested this and confirmed it.

Add custom post_meta to the WordPress rest API

So I needed some metadata to be in the rest API of a custom post_type.
The following adds the subtitle to the book post_type

<?php
add_action('rest_api_init', function () {
    register_rest_field('book', 'subtitle', [
        'get_callback'    => 'get_meta_data_for_rest',
        'update_callback' => null,
        'schema'          => null,
    ]);

});

function get_meta_data_for_rest($post, $field_name, $request)
{
    // it's not always an object
    if (isset($post->id) && ! empty($post->id)) {
        $post_id = $post->id;
    } elseif (isset($post['id']) && ! empty($post['id'])) {
        $post_id = $post['id'];
    } else {
        return null;
    }

    return get_post_meta($post_id, $field_name, true);
}

Delete all empty taxonomy terms in WordPress

The code below will find and delete all empty terms of every taxonomie, including the menu.
Think before you delete, you might want to keep some empty categories.

<?php
foreach ( get_taxonomies() as $tax_slug ) {
    $terms = get_terms( $tax_slug, array( 'hide_empty' => false ) );

    /** @var WP_Term $wp_term */
    foreach ( $terms as $wp_term ) {
        if ( 0 == $wp_term->count ) {
            wp_delete_term( $wp_term->term_id, $wp_term->taxonomy );
        }
    }
}

Regex lookahead

Regex is one of the things that I’ve always regret I didn’t learn earlier. Yes it’s complicated, but without a doubt it is worth it. There is one syntax I didn’t know yet. The lookahead

[^a]*

Match everything until you find the letter a. The a itself is not included. Should be handy to parse url’s and such

Bash script get own path and name

pathfile.bash

#!/usr/bin/env bash

# Full path to file
echo "$(cd "$(dirname "$0")"; pwd)/$(basename "$0")"

# Full path of the directory the file is in with trailing slash
echo "$( cd "$(dirname "$0")" ; pwd -P )/"

# current directory name, not the path
echo "${PWD##*/}"