Category: George Lerner – Website Tech

Migrated content from website-tech.lc.lndo.site

  • Securing AI Coding Tools – How to Sandbox Devin Desktop with Bubblewrap

    Allowing an AI coding assistant or autonomous developer agent (like Devin Desktop) to run local Bash scripts, use CLI tools, and access your local development environment comes with inherent security risks. By default, these applications run with your user permissions, meaning they have unrestricted access to your private SSH keys (~/.ssh), cloud credentials (~/.aws), GPG keys (~/.gnupg), chat histories, and sensitive private documents.

    To mitigate this risk without crippling the app’s capability to code, test, and interact with your development sites, we can isolate it using Bubblewrap (bwrap)—the same lightweight containerization utility that powers Flatpak.

    Below is the production-ready sandboxing script, a detailed breakdown of its configuration items, and the exact diagnostic toolkit used to troubleshoot and lock it down.

    Tested Oct 2026 in Linux Mint 21.2 Cinnamon, Linux Kernel 6.8.0-138-generic on Devin Desktop Version: 3.10.67, VS Code OSS Version: 1.126.0, Electron: 42.2.0

    The Complete devin-sandboxed.sh Script

    save as ~/bin/devin-sandboxed.sh and then make it executable and change the System Menu (the Magic or Windows or Clover key opens it)

    # save as ~/bin/devin-sandboxed.sh
    # chmod +x ~/bin/devin-sandboxed.sh
    # In Menu, right-click Edit Menu, select Devin (in Programming), click Properties, in Command put
    #   /home/YOURNAME/bin/devin-sandboxed.sh %F
    #   NOTE: do not use ~ instead of /home/YOURNAME 
    #   /home/YOURNAME/bin/devin-sandboxed.sh %F
    #   NOTE: can not use ~ instead of /home/YOURNAME
    # To capture errors
    #   strace -f -e trace=connect,accept,socket -o ~/Documents/devin_failures.txt ~/bin/devin-sandboxed.sh
    

    The full contents of the script:

    #!/bin/bash
    
    # To capture errors for troubleshooting:
    #   strace -f -e trace=connect,accept,socket -o ~/Documents/devin_failures.txt ~/bin/devin-sandboxed.sh
    
    # Configuration: Define paths using explicit variables
    ALLOWED_SITE_DIR="$HOME/sites"
    CONFIG_DIR="$HOME/.config/devin-desktop"
    DEVIN_PROPER_CONFIG="$HOME/.config/Devin"
    LOCAL_SHARE="$HOME/.local/share/devin-desktop"
    DEVIN_HOME_CONFIG="$HOME/.devin"
    CACHE_DIR="$HOME/.cache/devin-desktop"
    
    # Additional required tool/UI paths
    VSCODE_DIR="$HOME/.vscode"
    WINDSURF_DIR="$HOME/.windsurf"
    CODEIUM_DIR="$HOME/.codeium"
    AGENTS_DIR="$HOME/.agents"
    LANDO_BIN="$HOME/.lando"
    NPM_GLOBAL="$HOME/.npm-global"
    FONT_CACHE="$HOME/.cache/fontconfig"
    THEMES_DIR="$HOME/.themes"
    
    # Ensure config/share dirs exist so they can be mounted writable
    mkdir -p "$CONFIG_DIR" "$DEVIN_PROPER_CONFIG" "$LOCAL_SHARE" "$DEVIN_HOME_CONFIG" "$CACHE_DIR" "$VSCODE_DIR" "$WINDSURF_DIR" "$CODEIUM_DIR" "$AGENTS_DIR" "$ALLOWED_SITE_DIR"
    
    # Build BWRAP flags array safely
    BWRAP_ARGS=(
        --unshare-user
        --share-net
        --uid 1000
        --gid 1000
        --clearenv
    
        # Environment Setup for Display and User
        --setenv HOME "$HOME"
        --setenv USER "$USER"
        --setenv DISPLAY "$DISPLAY"
        --setenv WAYLAND_DISPLAY "$WAYLAND_DISPLAY"
        --setenv XDG_RUNTIME_DIR "$XDG_RUNTIME_DIR"
        --setenv DBUS_SESSION_BUS_ADDRESS "$DBUS_SESSION_BUS_ADDRESS"
        --ro-bind-try "$HOME/.Xauthority" "$HOME/.Xauthority"
        --bind-try "${XDG_RUNTIME_DIR}" "${XDG_RUNTIME_DIR}"
    
        # System core read-only binds
        --ro-bind /usr /usr
        --ro-bind /lib /lib
        --ro-bind /lib64 /lib64
        --ro-bind /etc /etc
        --ro-bind /sys /sys
        --bind /dev/shm /dev/shm
        --bind-try /dev/dri /dev/dri
        --symlink usr/bin /bin
        --proc /proc
        --dev /dev
        --tmpfs /tmp
    
        # Enable machine identity for D-Bus / keyring integration
        --ro-bind-try /var/lib/dbus /var/lib/dbus
    
        # Recreate a clean home directory structure inside the sandbox
        --dir "$HOME"
    
        # Explicitly bind your allowed site directory and app configurations
        --bind "$ALLOWED_SITE_DIR" "$ALLOWED_SITE_DIR"
        --bind "$CONFIG_DIR" "$CONFIG_DIR"
        --bind "$DEVIN_PROPER_CONFIG" "$DEVIN_PROPER_CONFIG"
        --bind "$LOCAL_SHARE" "$LOCAL_SHARE"
        --bind "$DEVIN_HOME_CONFIG" "$DEVIN_HOME_CONFIG"
        --bind "$CACHE_DIR" "$CACHE_DIR"
        --bind "$VSCODE_DIR" "$VSCODE_DIR"
        --bind "$WINDSURF_DIR" "$WINDSURF_DIR"
        --bind "$CODEIUM_DIR" "$CODEIUM_DIR"
        --bind "$AGENTS_DIR" "$AGENTS_DIR"
    
        # Bind Development Tools & System UI (Read-Only where appropriate)
        --bind "$LANDO_BIN" "$LANDO_BIN"
        --bind "$NPM_GLOBAL" "$NPM_GLOBAL"
        --ro-bind-try "$HOME/.config/git/config" "$HOME/.config/git/config"
        --ro-bind-try "$FONT_CACHE" "$FONT_CACHE"
        --ro-bind-try "$THEMES_DIR" "$THEMES_DIR"
    
        # Explicitly block/hide sensitive folders by turning them into empty tmpfs mounts
        --tmpfs "$HOME/.ssh"
        --tmpfs "$HOME/Documents"
        --tmpfs "$HOME/.gnupg"
        --tmpfs "$HOME/.aws"
        --tmpfs "$HOME/.claude"
        --tmpfs "$HOME/.bash_history"
    
        # GUI / X11 / Wayland socket access
        --ro-bind /tmp/.X11-unix /tmp/.X11-unix
        --bind-try "${XDG_RUNTIME_DIR}" "${XDG_RUNTIME_DIR}"
    )
    
    exec bwrap "${BWRAP_ARGS[@]}" /usr/bin/devin-desktop "$@"

    Line-by-Line Breakdown: What Each Item Does and Fixes

    1. Namespace & Core Isolation Flags

    • --unshare-user & --uid 1000 --gid 1000: Maps your current user into an unprivileged container namespace so it cannot escalate privileges or affect the host system.
    • --share-net: Essential for Electron-based apps and deep-link handlers. Without network sharing, local TCP loopback communication breaks, and OAuth callback redirection fails to reach the app.
    • --clearenv: Wipes out inherited host environment variables to ensure a pristine, controlled launch environment.

    2. Graphics Rendering & Performance (/dev/shm, /dev/dri)

    • --bind /dev/shm /dev/shm: Chromium and Electron applications rely heavily on shared memory (/dev/shm) for inter-process communication (IPC) and rendering buffers. Without this, the UI renderer starves, resulting in blank or frozen “not responding” windows.
    • --bind-try /dev/dri /dev/dri: Passes through Direct Rendering Infrastructure nodes to enable hardware-accelerated GPU graphics pipelines.

    3. Data Privacy & Hard Blocking (--tmpfs)

    • --tmpfs "$HOME/.ssh", --tmpfs "$HOME/.aws", etc.: Instead of just restricting permissions, these directives create empty, isolated RAM-backed filesystem views (tmpfs) over your private directories. To the application, these folders appear completely empty or non-existent, shielding your credentials from exposure.

    4. Authentication & Keyring Integration (/var/lib/dbus)

    • --ro-bind-try /var/lib/dbus /var/lib/dbus: Electron and VS Code-based apps look for /var/lib/dbus/machine-id to identify the machine context. Binding this allows the app to cleanly initialize state tracking and fall back gracefully to local file-based credential storage when a full desktop secret service daemon is unavailable.

    Troubleshooting Toolkit: How We Diagnosed and Fixed It

    When building strict application sandboxes, things inevitably break on the first try. Here are the exact diagnostic utilities and grep filters used to track down hidden dependencies:

    Capturing File Access Failures (strace)

    To see every file path, library, or socket the application tried to open or touch during startup:

    strace -f -e trace=openat,access -o ~/Documents/devin_failures.txt ~/bin/devin-sandboxed.sh

    Filtering D-Bus, Sockets, and Machine IDs

    To diagnose why desktop integration or authentication handlers were failing, we filtered the strace log using grep:

    grep -i -E "dbus|bus|socket" ~/Documents/devin_failures.txt

    What it revealed: Missing access to /var/lib/dbus/machine-id, which caused authentication modules to lock up until the read-only bind was added.

  • Why Your Computer’s Apps Can See Your Secrets (And an Easy Way to Fix It)

    As a creator, coach, or entrepreneur, your computer is your digital office. It holds everything: client notes, financial records, passwords, and private SSH keys.

    For years, we operated under a comforting assumption: If I trust the company that made this app, I trust the app completely.

    Unfortunately, modern software has changed. Today, applications aren’t written by a single team—they are assembled from thousands of third-party pieces built by anonymous developers. And a new category of tools—autonomous AI coding assistants—can write and execute their own terminal commands on the fly.

    If an AI tool gets confused, or if a background component is compromised, standard computer permissions allow it to look at any file your user account owns.

    The Good News: You Don’t Need a Computer Science Degree to Stay Safe

    You don’t need to write complex security rules or stress over system files. You can protect your workspace using two effortless strategies:

    Strategy 1: Stick to Sandboxed App Stores (Flatpaks & Snaps)

    When installing desktop software on Linux Mint or Ubuntu, check if the app is available as a Flatpak or Snap in your software center.

    • Why it helps: These formats automatically place apps inside an invisible “sandbox”. A sandboxed text editor or media player literally cannot see your private documents or keys because the operating system hides them.

    Strategy 2: Use a Simple Startup Shield for Autonomous AI Tools

    For advanced AI coding software that needs to look at your project folders but nothing else, you can wrap its launch command in a tiny security script (often called a sandbox wrapper).

    Instead of letting an AI tool roam free across your entire home directory, a simple launcher script restricts it to a single designated folder (like ~/sites/) while cutting off access to sensitive areas like your .ssh or Documents folders.

    By taking these small steps, you keep your digital workspace secure without getting bogged down by technical headaches!

    How You Can Make a Sandbox Wrapper for Your Software That Needs A Startup Shield

    Here is a copy-and-paste prompt you can give to an assistant, a tech-savvy employee, or use yourself with Gemini.

    This prompt instructs Gemini to act as a Linux security guide, ask a few quick questions about your specific setup, and then output a ready-to-run Bubblewrap (bwrap) script tailored precisely to your computer.

    Act as a Linux security expert and systems administrator. I want to create a secure Bubblewrap (bwrap) sandbox script for a desktop application on Linux (such as an AI coding tool) to restrict it from accessing sensitive folders like ~/.ssh, ~/Documents, or ~/.aws, while allowing it to access a specific project folder, and its settings folder.
    
    To help me write the exact custom Bash script I need, please ask me the following 4 questions:
    1. What is the exact command or name of the application I want to sandbox (e.g., devin-desktop)?
    2. What specific folder(s) does the application need permission to read and write to (e.g., ~/sites/, and its own settings)?
    3. What is my Linux username?
    4. Are there any other specific folders I want to completely hide or block from this app?
    
    Once I answer those questions, write a complete, copy-pasteable Bash script using bwrap that I can save into my ~/bin/ folder, make executable, and run safely.
  • Setting Up User-Specific PHP Configuration in Linux

    Overview

    PHP configuration is typically managed through the php.ini file and additional configuration files. While system-wide settings are stored in /etc/php/[version]/, you may want to add your own user-specific settings without modifying system files.

    This guide demonstrates how to set up user-specific PHP configuration that works alongside the system configuration.

    Default PHP Configuration Locations

    In most Linux distributions, PHP configuration files are located in:

    • Main configuration file: /etc/php/[version]/cli/php.ini (for command-line PHP)
    • Additional configuration directory: /etc/php/[version]/cli/conf.d/ (contains module-specific settings)

    You can check your current PHP configuration paths with:

    php --ini

    Creating User-Specific PHP Configuration

    Step 1: Create a Personal Configuration Directory

    Create a directory in your home folder to store your custom PHP settings:

    mkdir -p ~/php_config

    Step 2: Create Custom Configuration Files

    Create .ini files in your personal directory with your preferred settings. For example, to set your timezone:

    echo 'date.timezone = "America/Phoenix"' > ~/php_config/timezone.ini
    

    Other common settings you might want to customize in ~/php_config/php.ini:

    ; Memory limit
    memory_limit = 256M
    
    ; Maximum execution time
    max_execution_time = 120
    
    ; Error reporting
    error_reporting = E_ALL
    display_errors = On
    

    Step 3: Configure PHP to Use Your Settings

    To make PHP recognize your custom settings alongside the system settings, set the PHP_INI_SCAN_DIR environment variable:

    version=8.4
    export PHP_INI_SCAN_DIR=/etc/php/$version/cli/conf.d:~/php_config/
    

    Replace version=8.4 with your PHP version.

    Step 4: Make the Configuration Permanent

    Add the export command to your shell configuration file (.bashrc, .zshrc, or .profile):

    version=8.4
    echo "export PHP_INI_SCAN_DIR=/etc/php/$version/cli/conf.d:~/php_config" >> ~/.bashrc
    

    Then reload your shell configuration:

    source ~/.bashrc
    

    Verifying Your Configuration

    To verify that your custom settings are being applied:

    php -r "echo 'Current timezone: ' . date_default_timezone_get() . PHP_EOL;"
    

    You can also check all loaded configuration files:

    php --ini
    

    Benefits of User-Specific Configuration

    1. Non-destructive: Doesn’t modify system files
    2. Portable: Your settings follow your user account
    3. Isolated: Doesn’t affect other users
    4. Maintainable: Easier to track your custom settings
    5. Upgradable: System updates won’t overwrite your settings

    Important Notes

    • The main php.ini file is always loaded first
    • Settings in your custom files will override the same settings from the main configuration
    • Some settings can only be set in the main php.ini file and cannot be overridden
    • Web server PHP (Apache, Nginx) uses different configuration files than CLI PHP

    Troubleshooting

    If your settings aren’t being applied:

    1. Ensure the path in PHP_INI_SCAN_DIR is correct
    2. Check that your .ini files have the correct syntax
    3. Verify file permissions (should be readable)
    4. Restart your terminal session

    For web server PHP, you’ll need to restart the web server after changing PHP settings.

    PHP Configuration in Containerized Development Environments

    Containerized development environments like Lando and Local by Flywheel use isolated PHP configurations separate from your host system. The user-specific configuration approach described above won’t automatically apply to these environments.

    Lando Configuration

    Lando provides several ways to customize PHP settings:

    Option 1: Using .lando.yml Configuration

    services:
      appserver:
        config:
          php: path/to/custom/php.ini
    

    Option 2: Inline PHP Settings in .lando.yml

    services:
      appserver:
        config:
          php: |
            date.timezone = "America/Phoenix"
            memory_limit = 256M
            display_errors = 1
            error_reporting = E_ALL
    

    Option 3: Custom php.ini with Volume Mounting

    services:
      appserver:
        volumes:
          - ./php-custom.ini:/usr/local/etc/php/conf.d/custom.ini
    

    Local by Flywheel Configuration

    Local by Flywheel also offers ways to customize PHP:

    Option 1: Using the UI

    1. Open the site’s dashboard in Local
    2. Click on “Site” → “PHP”
    3. Modify PHP settings in the interface
    4. Restart the site for changes to take effect

    Option 2: Custom php.ini File

    You can add a custom php.ini file to your site’s configuration:

    1. Locate your site’s configuration folder (typically in Local’s site directory)
    2. Add a custom php.ini file
    3. Restart the site

    Best Practices for Containerized Environments

    1. Project-specific configuration: Store a standard php-custom.ini in your project repository
    2. Documentation: Include setup instructions in your project README
    3. Version control: Track PHP configuration changes alongside code changes
    4. Consistency: Ensure all team members use the same PHP settings

    This approach ensures consistent behavior across different development environments and makes it easier to onboard new team members.

  • Display Markup on WordPress

    To display a Markup file inside a WordPress page, you can use the Markdown block or a Markdown editor plugin. For the Markdown block, navigate to the page or post editor, click the plus icon, and search for “Markdown” to add the block. Then, you can write your Markdown code directly in the block.

    Alternatively, you can use a Markdown editor plugin like WP Markdown Editor (formerly Dark Mode). To install a Markdown plugin, go to Plugins > Add New, search for “Markdown,” and install the desired plugin. Once installed, you can use the plugin to write and edit Markdown content on your posts and pages.1

    For adding schema markup, you can use custom fields. Navigate to the post or page where you want to add the schema, click on Screen Options, and check ‘Custom Fields.’ Then, create a new custom field named ‘schema’ and enter your JSON-LD code. After adding the custom field, you’ll need to edit your header.php file to ensure the schema code is loaded with your post metadata.3

    WordPress Markdown Editor
    wordpress.comMarkdown Block – WordPress.com Support
    hostinger.comWhy You Need WordPress Schema Markup and How to Add it to Your Site
    wordpress.comCustom HTML block – WordPress.com Support
    How to display Markdown files from other sites in WordPress – Christian Specht

    When I created the pages for my existing projects on this blog, I decided that I’d prefer to directly display the content of the readme files from Bitbucket (where all of my projects are hosted), instead of just copying the content.

    How to Style Using Markup

    To see the full range of Markdown formatting, see Markdown Extra.

    from https://wordpress.com/support/wordpress-editor/blocks/markdown-block/

    Markdown SyntaxOutput
    **Bold Text**Bold Text
    *Italic Text*Italic Text
    [Link](https://example.com)Link
    # Header 1Header 1
    ## Header 2Header 2
    - List Item• List Item
    1. Numbered Item1. Numbered Item
    `Inline Code`Inline Code
    `Code Block`Code Block

    For example, in Markdown, to emphasize a word, you wrap it with an asterisk on both ends, like this: *emphasized*. When your writing is published, it will look like this: emphasized. Similarly, two asterisks denote strong text: **strong** will be published as strong.

    To indicate links, use regular and square parentheses. Wrap the text you want to link in square parentheses, and immediately after it, insert the link target wrapped in regular parentheses. The actual Markdown could look like this: [WordPress.com](https://wordpress.com/). When published, it will be a standard link: WordPress.com.

    Writing with markdown. On the left: using Markdown to compose a post in the fullscreen editor. On the right: The published post.
    Examples of Markdown formatting. Note: that should be “# Writing with Markdown” to have it show as a H1

    The original Markdown text you write will always remain in Markdown, so you can go back and edit it using Markdown. Only the published document – the post or the page – will be converted. If you write a post in Markdown, it will be published as a fully formatted post on your blog, but when you go back and edit it, it’ll still be in Markdown.

    /markdown

  • Hosting Companies I Can Recommend

    There are very few hosting companies that have adequate security against hackers, and excellent page speed, and good technical support.

    You likely can’t identify the best ones yourself. So, use your local WordPress Meetup or other group where there are people who host websites for clients. These are people who have done technical support for a wide range of clients, with a wide range of WordPress expertise; they know more about the hosts they have tried than most people ever will.

    My Favorites

    I heard of most of these from my local WordPress Meetup which has many people hosting sites or developing sites for clients.

    1

    10WebSuperb page load times, excellent support

    I’m hosting now with 10Web for superb page load speed, security, and support. They also have AI-based page builder that implements via free Elementor. Mobile PageSpeed score, with WooCommerce, Elementor & Pro, Astra & Pro, many other plugins: 90. Many hosts can’t get 90 for a Desktop score.

    2

    A2 HostingTalked to them at WordCamp 2024, knowledgeable about WordPress support and page speed

    3

    SiteGroundTalked to them at WordCamp years ago, very knowledgeable about WordPress support and page speed. As a technical support person, they were the first hosting company I hosted with that often solved problems before I could solve them. At a WordCamp I talked to the SiteGround person whose job was researching global web threat boards, and adding the security rules to their dedicated hardware that blocked hackers and malware, taking him about 20 hours each week; very few hosts do that.

    4

    WordPress Support Services – OnSiteWPSupport by one of the top leaders of AZ WordPress Meetup. Server and security expertise lead to top page speed.

    5

    SiteDistrictHosted with them, very knowledgeable about WordPress support and page speed. Runs an advanced WordPress-specific firewall embedded into their web servers. Specialize in websites that have few pages, that need highest page speed. (Not recommended for large ecommerce sites, their caching isn’t designed for many occasional-use pages).

    6

    WordPress.comThis is The Only free hosting to use

    WordPress.com has excellent vetted plugins (can’t install other plugins from the WordPress Repository), superb security. You can pay to use a custom domain name or some other benefits. If you want truly free hosting, this is the only host you can use.

    7

    ClosteGreat for small, “just sits there” sites

    One WPAZ expert about Closte: “Don’t be scared of their pricing model. I have a site that just sits there. Excellent performance, much faster than SiteGround, and 10x faster than Bluehost. About $4/month. https://closte.com/ I also like Closte because you can start with paying only $10 or so. Then see how your usage goes. No need to pay for a year or more. I found their control panel clean and very well-designed. One of the better ones out there. It could be a bit prettier, and could use a designers touch, but it’s functional, pretty well organized, and does the job.

    Others I recommend from Other Experts recommending

    Pagely one of the fast hosts

    Hostinger looks low priced, full-featured for most people’s websites, proper attention to security, probably one of the hosting companies with fast page load speed.

    Managed Vultr Cloud Hosting Platform on Cloudways, one of the fast hosts.

    BlueHost is a local Phoenix host, so several people of the AZ WordPress Meetup work there, in support or development. Good for the price, not the fastest page speed, they do pay proper attention to security. Much better, I think, than GoDaddy (also a local Phoenix office).

    8

    GoDaddy (hosting or domains)Bad user interface keeps changing, push for upgrades you don’t need, charge for SSL

    GoDaddy charges for SSL, so costs more than hosting companies that have LetsEncrypt SSL (and to not reveal your admin password at login, all WordPress sites need SSL). They keep changing their user interface, so I have to re-find how to do simple things (add an add-on domain, ssh key, ftp user, etc). Technical support is not nearly as good as SiteGround’s. I wouldn’t require clients leave GD, like I would for many hosting companies; they’re very good but not “the best” for hosting, so I suggest moving 1-2 months before their current contract expires. Cloudflare has domains, often less expensive than GoDaddy’s domains, and their user interface better than GoDaddy’s for managing lots of domains.

    9

    WPEngineToo expensive for what they offer, too corporate

    Too many reports on AZ WordPress Slack channel about bad attitude towards customers, about poor user interface, and of course there is the lawsuit about promoting themselves as if they are WordPress.

    How Not to Pick a Hosting Company

    Don’t pick a host by price, nor by a recommendation from someone you don’t know on social media. There are too many mediocre or dangerous hosts out there.

    Don’t host WordPress on a company that does not specialize in WordPress. There are many more attacks on a WordPress site, because it is so popular; and there are so many plugins that a user could install which could have security holes in them. Security on a WordPress host must be a priority.

  • Git Submodule vs Composer Package for Testing Framework Integration

    Background and Decision Context

    When designing a “Separate Testing Framework Repository with Development Tools,” a key question emerged:

    Does this design work for a project where another developer, who already has their environment set up, can just get the PHPUnit part? (For experienced developers, this would be the interesting part.)

    This page explores two primary approaches to integrating a separate testing framework repository into WordPress plugin projects, with a focus on developer experience and flexibility.

    Comparison Overview

    FactorGit SubmodulesComposer Packages
    Setup ComplexityModerateHigher
    Developer ExperienceRequires Git knowledgeRequires Composer knowledge
    VersioningManual trackingAutomatic via semantic versioning
    Update Processgit submodule updatecomposer update
    Flexibility for Experienced DevsDirect access to filesAbstracted as a dependency
    Learning CurveGit commandsComposer + Package publishing

    Option A: Git Submodules

    What Are Git Submodules?

    Git submodules allow you to include one Git repository inside another as a subdirectory. This creates a link to a specific commit in the external repository rather than copying the code.

    Implementation Steps

    1. Create your testing framework repository:

      mkdir ~/sites/wp-phpunit-framework
      cd ~/sites/wp-phpunit-framework
      git init
      # Add your testing framework files
      git add .
      git commit -m "Initial commit of testing framework"
      git remote add origin https://github.com/glerner/wp-phpunit-framework.git
      git push -u origin main
    2. Add the submodule to your plugin project:

      cd ~/sites/gl-color-palette-generator
      git submodule add https://github.com/glerner/wp-phpunit-framework.git tests/framework
      git commit -m "Add testing framework as submodule"
    3. For developers cloning your plugin project:

      git clone https://github.com/glerner/gl-color-palette-generator.git
      cd gl-color-palette-generator
      git submodule init
      git submodule update
      
    4. To update the framework in your plugin:

      # In the main project
      git submodule update --remote tests/framework
      git commit -m "Update testing framework submodule"
      

    Advantages

    • Direct Access: Developers can directly access and modify framework files if needed
    • No Publishing Required: No need to publish packages to Packagist or set up private repositories
    • Version Control: Clear tracking of which framework version is being used
    • Independence: Framework can be developed independently of plugins using it
    • Simplicity: No need to understand Composer’s package system beyond basic dependencies

    Disadvantages

    • Git Knowledge Required: Developers need to understand Git submodules
    • Extra Clone Steps: Requires additional commands when cloning the repository
    • Potential Confusion: Submodules can be confusing for developers new to Git
    • Manual Updates: Updates to the framework must be manually pulled and committed

    Option B: Composer Packages

    What Are Composer Packages?

    Composer is PHP’s dependency manager. Packages are reusable libraries that can be required in projects via Composer.

    Implementation Steps

    1. Prepare your framework as a Composer package:

      • Create a proper composer.json in your framework repository:

             {
               "name": "yourusername/wp-phpunit-framework",
               "description": "WordPress PHPUnit Testing Framework",
               "type": "library",
               "require": {
                 "php": ">=7.4",
                 "phpunit/phpunit": "^9.0"
               },
               "autoload": {
                 "psr-4": {
                   "YourNamespace\\TestFramework\\": "src/"
                 }
               }
             }
    2. Use a private repository approach (simpler than Packagist):

      • In your plugin’s composer.json:

             {
               "repositories": [
                 {
                   "type": "vcs",
                   "url": "https://github.com/yourusername/wp-phpunit-framework.git"
                 }
               ],
               "require": {
                 "yourusername/wp-phpunit-framework": "dev-main"
               }
             }
    3. Install the dependency:

      composer require yourusername/wp-phpunit-framework:dev-main

    Advantages

    • Standard PHP Workflow: Follows standard PHP dependency management practices
    • Semantic Versioning: Can leverage semantic versioning for updates
    • Autoloading: Automatic class autoloading
    • Dependency Management: Handles nested dependencies automatically
    • Familiar to PHP Devs: Most PHP developers are familiar with Composer

    Disadvantages

    • Publishing Required: Requires understanding how to publish packages
    • Less Direct Access: Files are in vendor directory and shouldn’t be directly modified
    • More Complex Setup: More complex initial setup, especially for private packages
    • Learning Curve: Steeper learning curve for package maintenance

    Recommendation for WordPress Plugin Testing Frameworks

    For a WordPress plugin testing framework that needs to be accessible to developers with varying experience levels:

    Use Git Submodules When:

    • You’re still learning Git and Composer
    • You want direct control over the framework files
    • You prefer simplicity over standardization
    • You want to make frequent changes to both repositories
    • Your team is comfortable with Git but not necessarily with Composer package publishing

    Use Composer Packages When:

    • You’re comfortable with Composer package management
    • You have multiple projects that will use the framework
    • You want to leverage semantic versioning
    • Your team is already using Composer extensively
    • You want to follow PHP community standards for dependency management

    Practical Considerations for WordPress Developers

    1. WordPress Development Culture: Many WordPress developers are more familiar with Git than with Composer package publishing.

    2. Learning Path: Git submodules can be a stepping stone to learning more advanced dependency management.

    3. Team Composition: Consider the technical background of all developers who will work with the codebase.

    4. Long-term Maintenance: Composer packages may be easier to maintain across multiple projects in the long run.

    5. Hybrid Approach: You can start with Git submodules and transition to Composer packages as your team’s expertise grows.

    Conclusion

    For the specific context of a WordPress testing framework where experienced developers should be able to easily access just the PHPUnit part, Git submodules provide a more direct and accessible approach initially. As your project and team mature, you can consider transitioning to a Composer package for better standardization and dependency management.

    The most important factor is that your testing framework remains modular and well-documented, regardless of the integration method chosen.

  • Troubleshooting WooCommerce Elementor Templates

    This is using a “Classic Theme”, Astra. The details for a “Block Theme”, such as TwentyTwentyFive, will be different.

    When you are piecing together the template puzzle, with pieces from your Theme, from Elementor, and from WooCommerce, it’s common to have a mix of Theme and Elementor template configurations. Let’s focus on troubleshooting the WooCommerce main store page (/shop).

    Understanding Template Hierarchy and WooCommerce:

    WordPress (and WooCommerce) uses a template hierarchy to determine which template file to use for displaying a page. Here’s a simplified overview:

    1. Specific Templates:
      • WooCommerce has specific templates like archive-product.php (for the shop and product category pages) and single-product.php.
      • Elementor Pro Theme Builder templates, if conditions match, override theme templates.
    2. Generic Archive Templates:
      • If a specific WooCommerce template isn’t found, WordPress falls back to generic archive templates like archive.php or index.php.
    3. Page Templates:
      • For standard pages, page-{slug}.php (e.g., page-shop.php) or page.php are used.

    Troubleshooting Steps:

    1. Elementor Pro Theme Builder:
      • Check Archive Templates: Go to Templates > Theme Builder in your WordPress dashboard.
      • Display Conditions: Carefully examine your archive templates. Ensure that the “Display Conditions” include the “Shop Page” (or “Product Archive”).
      • Template Conflicts: If you have multiple archive templates, try temporarily disabling them one by one to see if one is causing a conflict.
    2. WooCommerce Status:
      • Go to WooCommerce > Status.
      • Template Overrides: Look for the “Template Overrides” section. This will show you if any WooCommerce templates are being overridden by your theme.
      • System Status: Check for any warnings or errors that might indicate a problem.
    3. Astra Customizer (WooCommerce):
      • Go to Appearance > Customize > WooCommerce > Product Catalog.
      • Shop Layout: Review the settings here. Ensure that the layout is configured correctly.
      • Archive Settings: Review the general Archive settings in the customizer.
    4. Template File Check:
      • archive-product.php: Check your Astra theme (or child theme) folder for the archive-product.php file. If it exists, it’s likely controlling the shop page.
      • If you are using a child theme, make sure that the archive-product.php file is not in your child theme, unless you intend to override the parent theme’s file.
      • page-shop.php: If you created a page with the slug “shop,” check for a page-shop.php file.
    5. Elementor Debugger:
      • Use the Elementor Debugger to see which template files are being loaded.
      • This will show you the exact template that is being used, and the order in which the templates were looked for.
    6. “Shop” Page Settings:
      • Go to Pages > Shop.
      • Page Attributes: Check the “Page Attributes” section. Make sure that the correct template is selected (if applicable).
      • Content: Temporarily add some basic text to the page content. This will help you determine if the page content is being displayed at all.
    7. Permalink Structure:
      • Go to Settings > Permalinks.
      • Ensure that your permalink structure is correct. Incorrect permalinks can sometimes cause template issues.
    8. WooCommerce Settings (Shop Page):
      • Go to WooCommerce > Settings > Products > Display.
      • Shop Page: Verify that the correct page is selected as your “Shop Page.”

    Order of Template Loading:

    • Elementor Pro Theme Builder (If Conditions Match):
    • WooCommerce Specific Templates (archive-product.php):
    • Theme Archive Templates (archive.php, index.php):
    • Page Templates (page-shop.php, page.php):

    Your Idea About “/shop”:

    • Specifying “/shop” in Astra might help, but it’s more likely a template issue.
    • The WooCommerce shop page is typically controlled by archive-product.php or Elementor’s archive templates.
    • The WooCommerce shop page is not a typical page, it is a product archive page.

    Key Takeaways:

    • Focus on Elementor Pro’s archive templates and WooCommerce’s template hierarchy.
    • Use the Elementor Debugger and WooCommerce Status to get detailed information.
    • Check for conflicting templates and ensure that the correct shop page is selected in WooCommerce settings.
  • Regenerate Image Thumbnails

    If you are changing your theme, you likely should generate images in the sizes your theme uses. Three common sizes would be the largest an image is displayed on desktop, tablet, and mobile. There is also going to be the size of image thumbnails.

    If you are using a CDN such as Cloudflare, the CDN will take care of this for you. I definitely recommend using a CDN for page caching, and image optimization, and delivering your site as fast as possible.

    If you don’t use a CDN, you can make images the sizes your theme uses, easily

    WP-CLI

    If you have SSH access, use WP-CLI:

    wp media regenerate 

    for the options see:

    wp help media regenerate

    With a Plugin

    https://wordpress.org/plugins/force-regenerate-thumbnails/ is maintained, currently says works with WP 6.7.2

  • Changing Template Header or Footer

    In Site Editor (I’m using latest WordPress 6.7.2) you can have diferent Templates, and have different Headers and Footers, and use the header you want and footer you want in each Template. You edit header and footer and template, using the Block Editor (the same editor you probably use for your pages and posts).

    Templates to Make

    Here are some ideas for different templates you can make.

    An obvious template is one with no header and no footer. This is very useful for landing pages, and for making HTML you will use on social media sites (maybe the site lets you make a custom HTML header for your account, instead of an account image).

    Make a template that doesn’t have a menu. Then you can have your landing pages have fewer distractions; they either finish signing up, or go read other pages specifically for people who haven’t signed up (reading more about your business, what you cover, what they most want to know at the beginning). Once they log in to an account, they see your normal template with your main menu.

    WooCommerce or SureCart product pages would use a different template than your articles.

    Make a template for when you are launching your course. Maybe you have a countdown timer until when your course opens for registration. Maybe you say when the course will open, and a link to the initial launch video (but the link isn’t enabled yet).

    Make a template for the speakers for your event. No page title, no featured image; you have their name as the h1 tag of the page, and their image in place of a featured image. You have a block (probably of a custom post type) that displays the sessions of the event this person will speak in.

    Make a template for your course. The lesson pages in the course have a different menu than the pages for people who haven’t registered for your course. The other pages of this part of fthe course are in a 2nd menu below the site menu.

    Changing the Header and Footer

    Header and Footer are actually “template parts”. You can create multiple headers and multiple footers, to use in different places in your site.

    Each template can use your choice of header and footer. You can have a template with no header, no footer. You can use a different template for Landing Pages (typically no header or footer), or where you want a different menu (maybe a series of articles would have a link to the site home page and to each of the articles).

    If you enter the Site Editor using Appearance, Editor, you see Design. From there, select Patterns; Header and Footer are Patterns. This is where you can “Add New Pattern” (for example have a Header with a different background color or without a menu.

    Note: This is “Edit Site” not “Edit Page” on the top bar.

    The template you are editing (seen top bar, center), is probably “Single Posts – Template” or “Pages – Template, or, if you are directly editing a template part, it will show “Header (Template Part)”

    Open the Document Overview (staggered 3 bar icon, Shift-Alt-O)

    WordPress Site Editor, with Document Overview and the Template being edited
    Document Overview’s List view showing Header, Group, Footer; “staggered 3-bar” Document Overview icon is black because it is selected. Template being edited is “Pages” at top.

    Templates for a Page or Post most likely have 3 areas, each containing blocks: Header, a Group, Footer. Template parts will have just one area.

    Sometimes when you are editing a Page (not a template) in the Site Editor (yes, you can do that!), you will see the template’s header or footer, but you won’t see the template parts in the Document Overview. To switch to editing the Template, double-click on the header area or footer area, to select it for editing.

    Select the element you want, to set the background color.
    Note: If you are editing a Page or Post, you can not set the color if you have selected “Header”; you have to select an element within the header, most likely the outermost Group.

    If you have a Row or Container within that outermost Group, you probably want to set that background color to “transparent” so the outermost Group sets the color. Alternate approach: deliberately set the boxing on the inner Row to show a different color.

    Once you have the element you want selected, set the color just like anything else in the Block Editor. The Styles panel on the right will have colors in the current palette. Set both text and background colors.

    Special Colors for Templates

    What if you want to make a header for holidays or special events? Perhaps for Halloween you want an orange and black header?

    In your theme.json file (where your theme designer set the theme’s color palette) do one of two things. Either add the specialty colors to the palette (and don’t use those special colors except in a specialty header); or configure the theme.json to allow picking colors that are not in the color palette, for pages that are in a specific Category (e.g. category Holiday) or for specific pages.

    (No, don’t let people pick colors not in your color palette “whenever they want”, only use the color palette. That makes changing your site colors much easier, you just change the palette.)

    Suggestion: copy your theme.json to another filename in the theme’s styles folder. For a Halloween-themed site, make wp-content/YOURTHEME/styles/halloween.json. Or, make a holidays theme.json, with all the special colors you will use.

    Each style variation has its own file inside a folder in the theme called styles. If you named your style variation “Variation 1”, the file [would be named] styles/variation-1.json.

    https://fullsiteediting.com/site-creators/theme-style-variations/

    Then without changing the color ‘slugs’, change the color values how you want (perhaps the site background becomes “scary black” and the text becomes “hideous orange”. Or probably better, add scary black and hideous orange to the color palette, don’t change the existing colors, and make a Template Part (header) named “Halloween Header” and edit the template for your site home page (and optionally other pages) to use that header instead of the normal one. Then when the holiday season is over, change the template so the header used is the normal one.

    Note: There is not (that I know of) a way to have a template, or template part, use a different color palette. So use Theme Variations instead, adding only the extra colors and fonts you need.

    Changing Template when Editing a Page

    If you want a page to use a different template than the default, you can set it when you are editing the page.

    In the right Settings panel (if it isn’t visible, click the icon next to Save top right), in the Post tab, you can set details like when you want to publish the post. You can also set what template this Page or Post should use. Just click next to where it says “Template” and swap the template. You can also preview what the page will look like, using the template.

    WordPress select the template to use for a post, in the Settings panel (Post tab)
  • Copying DVDs to Watch on Other Devices

    Handbrake can save a DVD (that it can read; for copy-protected DVDs need the LibDVDcss add-on that might not be automatically included)

    You can specify a common format, e.g. in Preset select Hardware > “Apple 720p30 Surround” which makes a high-quality MP4 file that pretty much plays on everything.

    If you want smaller file size, customize the settings (and save them) to Video tab RF:20 and Audio tab to use the highest quality audio available up to 320kbps, and set it to automatically include the subtitle language you want. 

    VLC Media Player is superb, plays wide range of video and audio formats, and lets you set keyboard entries so LeftArrow rewinds 10 seconds (great for “what did he say” and RightArrow is forward 1 minute. 

    Plays subtitles Cmd-V I think is the keystroke, and lets you select the subtitles you want. 

    I use VLC Media Player to play a DVD to find out what Title you want Handbrake to convert. Many copy-protected DVDs have numerous tracks, to trick you; most will be jumbled mid-scene. VLC will read the DVD menu properly to find what title to play. 

    https://www.macxdvd.com/mac-dvd-video-converter-how-to/handbrake-libdvdcss-error-fixed-windows-mac.htm

    If you want better subtitles than the crazy low-resolution ones that are on DVDs

    https://www.opensubtitles.org/en/search/subs

    Rename the subtitles to have the same filename (without changing the file extension) as the video name, in the same folder as the video. VLC Media Player (and most other players) will display the subtitles using fonts on your computer. 

  • If You Do Not See a Page Builder, Can You Add Elementor?

    For future reference, I do know of a “convert to Elementor” tool, and it is well-done and even free. It will read each page, convert it to Elementor. If the client wants to switch to Elementor, that makes it much easier to then make a page template in Elementor, and modify each page to use the template. It can even convert “pure HTML/CSS/PHP” sites. Anyone curious, can ask me about it.

    It is a “bad idea” to have multiple page builders installed (mainly the page speed is hurt by loading all those program files).

    That said, you can certainly take a WordPress site made recently (meaning, running a current version of WordPress and a theme that at least works with the current version of WordPress) that was done in the Block Editor, and add Elementor to it.

    I’ve done many sites where “only the few special pages” used Elementor, and the rest was made with the Block Editor. This works if you know how to edit “most pages” in the Block Editor.

    What if you Do have another page builder?

    As an example, let’s say you have Beaver Builder.

    (I will guess Beaver Builder is still one of the better page builders. It certainly is one I would say is okay to use; there are many I’d urge you to get that other junk builder off your site. I haven’t done a comparison in a long time so maybe BB is better than Divi (the Divi Builder, not the junk theme bundled with it, use Divi Builder with 2025 or Spectra One themes).

    What if You Like the Block Editor, Do you Need a Page Builder?

    I like the TwentyTwentyFive theme, or the Spectra One theme.

    Spectra One Theme and Spectra Builder

    Spectra is a freemium page builder that integrates with the WordPress Block Editor (Gutenberg), allowing you to create a WordPress site with ready-to-use blocks, and some great templates.

    Spectra One is a modern and versatile WordPress theme that leverages Full Site Editing (FSE), allowing for extensive customization using blocks throughout the site, from headers to footers. It was developed by Brainstorm Force, the creators of the popular Astra theme, and is available for free on WordPress.org.

    Spectra – WordPress Gutenberg Blocks generates Blocks, so it is designed to work smoothly with any theme, including the free Spectra One theme, https://wpspectra.com/ or Spectra – WordPress Gutenberg Blocks. Most of the features of full page builders, with zero page builder bloat; your site loads fast.

    Spectra One is beautiful and modern, suitable for blogs, portfolios, businesses, and more.

    It is fully compatible with WooCommerce, and has some WooCommerce-specific features that will significantly enhance the experience. If you want to set up a WooCommerce shop, or online course, or coaching program, Spectra One is a solid choice, especially if you plan to start with basic features and gradually expand.

    Spectra Pro, the premium version of Spectra, offers advanced website design options and is designed to work smoothly with any theme, including Spectra One. Start with the free version, and upgrade when you find specific features you need.

    In summary, Spectra and Spectra One are well-suited for coaches and course creators.

    Also by Brainstorm Force: Ultimate Addons for Elementor (Elementor elements much like Spectra’s blocks); Schema Pro (Schema Pro offers all major types of schema, including recipe, book, article, job posting, and a lot more.) Presto Player for embedding videos and audios in your site; SureMembers if you want to have a Membership site.

  • What is the Best Performance Plugin for Your Site?

    Never run a caching plugin on your site, it is extra work for your account that is better done elsewhere.

    Caching should be done at the hosting company level, or at the Content Delivery Network (CDN, such as Cloudflare) level.
    Cloudflare free version is excellent for all but the largest websites.

    Same answer for image optimization plugins: let free Cloudflare do it.
    Your hosting company should know exactly how to set it up for you.

    For a client’s complex Elementor/Pro and WooCommerce site, 10Web Hosting gets PageSpeed 90 for mobile.

    One speedup for Elementor is disable the elements you aren’t using, as each widget loads several files whether it is used on that page or not.