Tag: WordPress

  • Should I move to a Hetzner VPS to improve WordPress speed?

    Interesting thread on Reddit: What makes WordPress websites super-fast nowadays?

    I plan to test drive Hetzner and move away from DigitalOcean (moving to a European service seems like a good idea in these times) so maybe a good time to try to move some WordPress instances from shared hosting to a VPS.

  • New WordPress Plugin: Photoblog

    I started a new Git Repository for a WordPress plugin I’m creating to contain the features that I want on this website related to Photoblogging.

    • I want to display a grid view of photos, in columns of 3, as I do on my photos page
    • I want to be able to add landscape and portrait photos, without breaking the grid view
    • I want to be able to navigate the photo’s with the arrow keys on the keyboard
    • I want to be able to add Galleries and make these appear as. a single image set in the grid
    • I want to enable zooming on all images by default
    • I want to display a short paragraph below the photo
    • I want to support video’s as well

    Currently only the first two bullets have been implemented. I’ve created a custom renderer for the Post Content that extracts the first image block (in the future I’ll add gallery and video blocks).

    Then I added some styling to make the images always fit within the designated grid square, without stretching it to the image’s original size.

  • Using ddev for local PHP development

    For me, one of the discoveries of 2024, has been ddev, a tool to manage PHP (and other) environments, based on Docker images.

    ddev logo
    Docker-based PHP development environments.

    In the last months I have been very happy using this project. It allows me to work locally on my source files and assets while at the same time have a specific environment with the exact server configuration that I need.

    Let me sum up some cases where it really came in a handy:

    • I ran into ddev for the first time when trying out a sample project for craft cms. The instructions to get the project up and running were surprisingly concise:
    git clone https://github.com/craftcms/europa-museum.git
    cd europa-museum
    ddev start
    ddev craft db/restore seed.sql
    • Converting an existing WordPress setup? Just run ddev config and ddev start.
    • Pull in a database dump from production? Configure a provider (ok that’s a little bit more work if you’re not on one of the predefined hosting providers)
    • want to add an extra container, say ElasticSearch? no problem.
    • Want to inspect the database? I run ddev sequelace and I’m in the database, editing the data.
    • run ddev mailpit and see the mails that have been sent out, in a Gmail like UI, or download them as a PNG screenshot
    • Boot that old Magento shop? Set the right PHP version, composer version, mysql version, run some terminal commands with ddev ssh and we’re up and running.
    • importing a database throws an error Unknown collation utf8mb4_0900_ai_ci? just switch from mariadb to mysql, run ddev restart and import again.
    • Want to run PHP with Xdebug? just drop an xdebug.ini in the correct config directory
    • I’m working on a Django setup, with extra startup scripts, an MQTT client and a Nuxt/Vue frontend and I hope to find the time to configure that for ddev as well. That would mean that starting ddev starts the full stack, all on the right ports and the paths mapped correctly

    I guess it’s clear that I’m excited about this addition to my toolchain.

    I’ve always been running Apache, MySQL, mkcert, MailHog through homebrew. And while that served my needs, I had to reconfigure quite a lot every time I ran brew upgrade.


    PS: last week I sent a toot at @atpfm suggesting ddev as a solution for Marco’s work on Overcast. I was happy to hear Casey read/butcher my name on the podcast 😄.

  • Enable compatibility mode in WooCommerce

    If you have setup a WooCommerce shop recently, or have enabled their HPOS1 you will want to enable compatibility mode as soon as you use any extension.

    I’m running into issues with WooCommerce Memberships not able to create memberships for users, because it cannot find the users related to an order:

    /**
     * Returns users IDs from orders that contain products that could grant access to a given plan.
     *
     * TODO When WooCommerce starts using alternate data stores for products (perhaps from WC 3.5+) this method may require an update as it performs a direct SQL query assuming a standard WPDB data organization {FN 2018-07-23}
     *
     * @since 1.10.6
     *
     * @param int[] $access_product_ids array of product IDs that grant access to a plan upon purchase
     * @return int[] array of user IDs
     */
    private function get_users_for_retroactive_access( array $access_product_ids ) {
    	global $wpdb;
    
    	if ( ! empty( $access_product_ids ) ) {
    
    		// get orders that contain an access granting product (or variation) to the given plan
    		$product_ids  = Strings_Helper::esc_sql_in_ids( $access_product_ids );
    		$orders_table = Framework\SV_WC_Order_Compatibility::get_orders_table();
    		$order_id_col = Framework\SV_WC_Plugin_Compatibility::is_hpos_enabled() ? 'id' : 'ID';
    		$order_ids    = $wpdb->get_col(  "
    			SELECT DISTINCT orders.{$order_id_col}
    			FROM {$wpdb->prefix}woocommerce_order_itemmeta AS order_item_meta,
    			     {$wpdb->prefix}woocommerce_order_items AS order_items,
    			     $orders_table AS orders
    			WHERE order_items.order_item_id = order_item_meta.order_item_id
    			AND order_items.order_id = orders.{$order_id_col}
    			AND ( ( order_item_meta.meta_key LIKE '_product_id'   AND order_item_meta.meta_value IN ({$product_ids}) )
    			 OR   ( order_item_meta.meta_key LIKE '_variation_id' AND order_item_meta.meta_value IN ({$product_ids}) ) )
    		" );
    
    		if ( ! empty( $order_ids ) ) {
    
    			// get user IDs for the found orders
    			$order_ids = Strings_Helper::esc_sql_in_ids( $order_ids );
    			$user_ids  = $wpdb->get_col( "
    				SELECT posts_meta.meta_value
    				FROM {$wpdb->prefix}postmeta AS posts_meta
    				WHERE posts_meta.post_id IN ({$order_ids})
    				AND posts_meta.meta_key = '_customer_user'
    			" );
    		}
    	}
    
    	return ! empty( $user_ids ) ? array_unique( array_map( 'absint', array_values( $user_ids ) ) ) : [];
    }

    With HPOS, the customer id is saved in the wp_wc_orders table instead.

    1. High-performance order storage ↩︎
  • WooCommerce Brands rollout

    With WooCommerce 9.4, WooCommerce Brands is getting rolled out to a cohort (5%) of installs.

    If you do not want to participate in this change set the option woocommerce_remote_variant_assignment to a higher value, e.g. 111

    <?php
    /**
     * Ensures that the Brands feature is released initially only to 5% of users.
     *
     * @return bool
     */
    public static function is_enabled() {
    	$assignment = get_option( 'woocommerce_remote_variant_assignment', false );
    
    	if ( false === $assignment ) {
    		return false;
    	}
    	return ( $assignment <= 6 ); // Considering 5% of the 0-120 range.
    }

    While this is a good feature, it can break your existing brands solution as it did in my case on an existing ecommerce setup.

    As a solution, set the new brands permalink to something different from brand, e.g. brands.

  • I imported my Instagram archive

    Quite a bumpy road and it took way more time than I planned, but now I have my full Instagram archive on this blog. I do not care very much about my Facebook or Twitter history, but I’m really attached to these images, that take me back to earlier years.

    The content is mine now, and I’m going to spend some time to clean things up and make the browsing more pleasant.

    Take a look

  • Added a photos page

    I just added a photos page to this site. It’s rather short and needs some optimisation, but I’m working on fixing both of theses issues.

    It’s really impressive what you can do with WordPress’ site editor today. Although I start hitting the limits of it. I’ll dive into the theming code later this week.

  • A word counter for Gutenberg blocks

    One of the main goals of – albeit slowly – setting up this blog, is writing more. And I also want to keep track of the length of the posts I make (I’d love to be able to call them articles one time 😉).

    That’s why I implemented a word counter today, that displays the words you’ve written, in the editor, as you type. I based the functionality on the code found here. It didn’t work anymore, but after some research I managed to make it work again.

    Turns out the Gutenberg editor (aka Block editor) is often running in an iframe. Which makes it a tiny bit harder to access the blocks in the editor with javascript.

    Screenshot of the editor with the counter in the top right displaying: 34 words.
    Screenshot of the Block editor with the counter in the top right displaying: 34 words.

    Download the WordPress plugin

    You can find the WordPress plugin here on Github.

    What’s next?

    I want to improve this functionality with a post-wide counter that displays the total amount of words over every block in the post.

  • AM/PM vs 24h in WordPress

    Software localization is hard. WordPress still struggles with the AM/PM vs 24h setting in some places:

    • good: the post scheduler UI on the admin post edit screen
    Screenshot with text: Publish Time 20:56
    • bad: the Publish date on the same admin post edit screen
    Screenshot with text: Publish Today at 8:56 pm
    • bad: the status text after applying the scheduling
    Screenshot with text: AM/PM vs 24h in WordPress is now scheduled. It will go live on Today at
8:56 pm.
  • new features I want to add to this blog

    While I’m slowly setting up this blog, I’m keeping track of the features that I want to add to it.

    Check the list