Visual Studio Code Workspaces and PHP Intelephense

When developing WordPress plugins for general use, I like to open the plugin directory itself in VS Code.

This allows me to use the git integration and terminal without wading through the wp-content/plugins/{plugin name} directory structure.

However, this results in the WordPress functions appearing as “undefined function” and the inability to jump to their definition or hover to see parameters and other details.

Here’s how I fix that annoyance:

  1. Save the open project as a workspace (File > Save As Workspace…)
  2. Add a fresh WordPress installation to the workspace, making it a multi-root workspace
  3. Go to Settings (Code > Preferences > Settings), click on the “Workspace” tab, and search for intelephense.environment.includePaths
  4. In the “Include Paths” section, add an entry for the fresh WordPress installation so Intelephense will index it

Alfred Workflows

I’ve been using Alfred on macOS for years now and it’s a wonderful productivity enhancement (on average, I use it more than 100 times a day).

Here are some of my favorite workflows:


Colors by Tyler Eich is a quick way to preview color codes and convert between formats.

Datetime Format Converter

Datetime Format Converter by Michael Waterfall is the fastest way I’ve found to convert Unix timestamps to human-readable dates, and vice versa.

Dev Doctor

Dev Doctor by Syd Lawrence provides quick-reference lookups for code documentation.


DevDocs by Yannick Galatol is another workflow that provides quick reference for documentation using

HTTP Status

HTTP Status by Marc Görtz is my preferred reference for quickly finding an HTTP status code either by number or name.

Laravel Docs

Laravel Docs by Till Krüss is amazing…it seems to have indexed most of Laravel documentation, so searching by any key word tends to bring up the best page of the documentation.

Open in VS Code

I use Visual Studio Code as my primary development tool; I created this workflow to quickly and easily open a file or directory in VS Code.

VPN Manager

VPN Manager by Dean Jackson is a great way to enable/disable VPN connections on the fly.

WordPress Developer

WordPress Developer by keesiemeijer is the fastest way to search and find functions, filters, classes, and more in the WordPress documentation.

Installing New Relic on RunCloud

Now that New Relic is offering a free tier, I’ve started using it to monitor some personal websites.

This particular server was configured using RunCloud, and the New Relic installation script didn’t automatically install New Relic monitoring for RunCloud’s PHP. Here are the steps I followed to get that working:

  1. Find the RunCloud PHP directories: /RunCloud/Packages/php7*rc/bin
  2. Set the NR_INSTALL_PATH variable to all the versions I had installed, as described here.
  3. Run newrelic-install and select all to install for all versions.
  4. Reload PHP: systemctl reload php7*rc-fpm


I found this plugin that adds WordPress-specific knowledge to New Relic reporting.

Bonus 2

New Relic allows you to specify multiple app names to group together all the sites on a server, all of one client’s sites, etc. See their documentation for more details.

The WordPress plugin provides the wp_nr_app_name filter to modify the app name.

Setting Up YouTube Live

WP YouTube Live is a free WordPress plugin to display live videos on a WordPress site.

To get started, follow these instructions:

Enable Streaming on YouTube

  1. Decide if you will stream from a personal account or a brand account. Read more about the differences in this article.
  2. Decide how you will stream video.
  3. Enable streaming for your account; see this article for details.

Set up the YouTube Data API

  1. If you don’t have a Google account already, sign up here.
  2. Log in to the Google Developers Console:
  3. Create a new project if you don’t have one already.
  4. Go to the Credentials page:
  5. Click the “Create Credentials” button at the top and choose “API key” and copy the new key
  6. Go to the Enabled APIs page:
  7. Search for Youtube Data API v3 and enable it.


Install the WordPress Plugin

  1. Go to the plugins page on the backend of your website.
  2. Press the “Add New” button and search for “WP YouTube Live.”
  3. Install and then activate the plugin.
  4. Go to Settings > YouTube, enter your channel ID and API key, and choose what to display when no video is live.
  5. Add the [youtube_live] shortcode to the page where you want the video player to appear.


For other support questions, please use the WordPress support forum.

Secondhand: Travels in the New Global Garage Sale

Secondhand: Travels in the New Global Garage Sale

Secondhand: Travels in the New Global Garage Sale by Adam Minter is a fascinating look at what happens to people’s stuff when they no longer want or need it.

The first couple of chapters discuss people decluttering on their own or disposing of a deceased family member’s belongings, often by bringing in a service to go through the stuff and determine what can be sold or donated and what should simply be thrown away.

The second part of the book goes into the global economy of second-hand stuff. For example, all the Goodwill stores in one county take unsold clothing to a Goodwill “warehouse” where clothing is sold for a dollar or two per bag; people purchase truckloads of clothing, drive over the border, and resell it at enough of a profit to make a living.


Between 1967 and 2017, the money that Americans spent annually on stuff—from sofas to cell phones—increased almost twentyfold.

Location 51

Garage sales aren’t where it’s at anymore. Half the stuff doesn’t sell because the prices are too high. Everyone thinks they’re on Antiques Roadshow.

Location 836

In the United States (and in Europe), most secondhand goods are donated rather than sold. As a result, most people lack a financial incentive to take care of their things. So instead of seeing the end of an object’s life as an opportunity to extract some last value from it (as people do with their cars), Americans view that object in philanthropic terms. It’ll help the poor; it’ll benefit the environment. For better or worse, both those reasons have proved to be little incentive to take care of stuff.

Location 1076

None of the cut-up fragments of sweatshirt through which Wilson is rummaging were used in India. Rather, they were likely made in South Asia, exported to the United States, and worn until they were donated to Goodwill, the Salvation Army, or some other thrift-based exporter. When they didn’t sell there, they were exported again, to Kandla most likely (or perhaps Mississauga, en route to Kandla), cut up, and exported again—this time to Star Wipers in Newark, Ohio. Each step of that journey makes perfect economic sense, even if the totality of it sounds ridiculous.

Location 2755

Buy the book

American Kingpin: The Epic Hunt for the Criminal Mastermind Behind the Silk Road

American Kingpin

American Kingpin: The Epic Hunt for the Criminal Mastermind Behind the Silk Road is an account of how Ross Ulbricht built the Silk Road, a marketplace for illegal drugs (the book several times compares it to “Amazon for drugs”).

It traces the history of how he built the site, and how individuals from several branches of law enforcement collaborated (or competed…) to stop him.

I thought the technical explanations were very good: accurate so a geek like me didn’t get annoyed or frustrated about incorrect descriptions, and short enough to be relevant and informative to others.

Overall I highly recommend it.

Buy it here

The Secret Life of Pronouns: What Our Words Say About Us by James W. Pennebaker


The Secret Life of Pronouns

We spend our lives communicating. In the last fifty years, we’ve zoomed through radically different forms of communication, from typewriters to tablet computers, text messages to tweets. We generate more and more words with each passing day. Hiding in that deluge of language are amazing insights into who we are, how we think, and what we feel.

In The Secret Life of Pronouns, social psychologist and language expert James W. Pennebaker uses his groundbreaking research in computational linguistics-in essence, counting the frequency of words we use-to show that our language carries secrets about our feelings, our self-concept, and our social intelligence. Our most forgettable words, such as pronouns and prepositions, can be the most revealing: their patterns are as distinctive as fingerprints. 

Using innovative analytic techniques, Pennebaker X-rays everything from Craigslist advertisements to the Federalist Papers-or your own writing, in quizzes you can take yourself-to yield unexpected insights. Who would have predicted that the high school student who uses too many verbs in her college admissions essay is likely to make lower grades in college? Or that a world leader’s use of pronouns could reliably presage whether he led his country into war? You’ll learn why it’s bad when politicians use “we” instead of “I,” what Lady Gaga and William Butler Yeats have in common, and how Ebenezer Scrooge’s syntax hints at his self-deception and repressed emotion. Barack Obama, Sylvia Plath, and King Lear are among the figures who make cameo appearances in this sprightly, surprising tour of what our words are saying-whether we mean them to or not.

My Thoughts

I thought this was a mildly interesting book explaining how people’s use of language reveals a lot about their personality and mental condition.

For instance, when speaking to a superior, people tend to use more personal pronouns, but when speaking to a person under their authority, they tend to use far fewer pronouns. This is an unconscious behavior that happens even within minutes of meeting a stranger.

However, the book didn’t seem especially practical. Many times the author reiterated that we don’t pick up on differences in pronoun usage and must rely on word-counting software to analyze text and find patterns. Because word usage is a symptom, not the cause of our behavior, changing our speech patterns won’t have much effect. Rather, it opens a window into what’s going on internally in a person’s thoughts and emotions.

WordPress and WooCommerce at Scale with 500,000 Users

WordPress generally works fairly well on small-to-medium sites; on larger sites, it can run into performance issues because of the size of the database.

A current project I’m working on for LuminFire has a WooCommerce store with potentially 270,000+ customers, and that’s causing some issues with site performance. For sake of development, our dev store has 500,000+ users.


Generating Dummy Users

First, I generated a CSV file with 50,000 fake users using and imported them using this plugin (I had to bump up my PHP memory limit to 4096MB and execution time to 240 and it still timed out a couple of times, but I deleted the users who had already been imported and then ran the import again).

Update: I have since learned about WC Smooth Generator, and it may have worked just as well or better.

I figured 50K unique users were plenty and duplicating them via MySQL queries was more efficient, so wrote these queries to do the job.

The users queries ran in seconds each, copying a batch of 50K rows at a time. The usermeta queries, not so much…they took about 11 minutes each since there were about 1.71 million rows to clone each time.

In case it’s helpful to you, here are files with the dummy users:

  • CSV with 50K users
  • MySQL dump of wp_users table (30.4MB)
    • It does include the ID field since it needs to match the usermeta table.
    • The first user ID is 510024; if you try to import and have user IDs above 510024, you’ll have errors.
    • 500,000 rows
  • MySQL dump of wp_usermeta table (148.5MB)
    • It does not include the meta_id field (so no errors trying to overwrite existing IDs).
    • 17,000,000+ rows

WordPress User Dashboard

At the top of the user dashboard, WordPress typically displays a list of the user roles on your site, as well as the number of users in each role.

user roles

The number of each users is generated by the count_users function, which uses a resource-intensive SQL query. In our dev site, it takes 15+ seconds just to run the query.

This is a known issue and should be resolved in WordPress 5.0 (currently scheduled for release in late 2018), but we need this working much sooner.

WordPress Multisite drops the number of users per role and instead shows just a list of roles; that’s how and other large multisite networks avoid this performance hit.

The proposed patch on the ticket modifies the count_users function to behave similarly to WP Multisite: if there are more than 10,000 users (modifiable with the new wp_is_large_user_count filter), it doesn’t show the number of users per role.

Since the patch is for the development version of the WP code, it doesn’t apply cleanly to a production site, so I manually patched WP core. Here are several patch files for different versions of WordPress; make sure to use the appropriate patch for your version:

Core Patch File

You can apply this patch file by downloading it, opening your WordPress installation in a terminal, and running git apply <path-to-downloaded-patch-file>.

WooCommerce User Queries

The biggest performance hit I found was searching for customers when editing an order; it took 10–15 seconds for search results to be returned.

WooCommerce user search

  • If searching by customer ID, the backend would respond pretty quickly.
  • Otherwise, it runs a full text search for the search term in the first and last name, which takes a while; see the code for full details.

Since orders aren’t manually assigned/reassigned too often, we decided this behavior was acceptable for now.

WooCommerce Customer Reports

The WooCommerce customer reports were the other major performance hit. For now, we simply disabled the customers reports since this particular customer already has a third-party system where they manage the customer data, so they’re not likely to use the WooCommerce reports.

Customers vs. Guests

Timing details:

  • Around 20–40 sec to load the page
  • Around 7 sec to get administrator users
  • Around 7 sec to get shop_manager users
  • Around 6 sec to get all other users

Here are the actual actual MySQL queries. In my staging environment, PHP ran out of memory; in my local environment, it took 305MB(!) to load the report for 1 week (the default view).

As noted above, we gave up on optimizing this report since the customer doesn’t really need it.

Customers List

This was completely unusable; it took 300 seconds to load the page.

Here are the actual MySQL queries. Two JOINs times in each query with full-text search on two columns × three queries was just too much on such a large table.

As noted above, we gave up on optimizing this report since the customer doesn’t really need it.

WordPress Posts Dashboard

Update: found another place where there’s a 15+ second wait. When bulk-editing posts (or any other post type that supports authors), an author dropdown causes a full search of the wp_usermeta table. I’ve updated the patch file in the gist above to include a fix for this.

WordPress Posts Dashboard bulk edit author dropdown


In summary, having 500,000 users on a WordPress and WooCommerce site doesn’t hurt overall performance too much, as long as you include an upcoming change in WP core and can get by without the WooCommerce customer reports.

We may explore further options to improve performance particularly when getting user roles from wp_usermeta, and I will update this post or add a new post if we find other enhancements.

The Soul of America: The Battle for Our Better Angels by Jon Meacham

The Soul of America: The Battle for Our Better Angels by Jon MeachamWritten partially in response to the 2017 white nationalist rallies in Charlottesville, this 416-page book examines a number of critical turning points in American history:

  • The Civil War, Reconstruction, and the birth of the Lost Cause
  • The backlash against immigrants in the First World War and the resurgence of the Ku Klux Klan in the 1920s
  • The fight for women’s rights
  • The demagoguery of Huey Long and Father Coughlin and the isolationist work of America First in the years before World War II
  • The anti-Communist witch-hunts led by Senator Joseph McCarthy
  • Lyndon Johnson’s crusade against Jim Crow

In each of these crises, author Jon Meacham contrasts the difference between reactionary fear holding us back and hope for a better future leading us to make positive change:

“Fear is about limits; hope is about growth. … Fear points at others, assigning blame; hope points ahead, working for a common good. Fear pushes away; hope pulls others closer. Fear divides; hope unifies.”—p16

I believe the thesis is in line with 2 Timothy 1:7: “For God hath not given us the spirit of fear; but of power, and of love, and of a sound mind.” We must not allow fear to be our motivating factor when making political—or any—choices.

While not an exhaustive history, Meacham emphasizes a number of presidents and other historical figures to illustrate his point:

  • Presidents
    • Abraham Lincoln
    • Ulysses S. Grant
    • Theodore Roosevelt
    • Woodrow Wilson
    • Franklin D. Roosevelt
    • Harry S. Truman
    • Dwight Eisenhower
    • Lyndon B. Johnson
  • Other figures
    • Martin Luther King, Jr.
    • Early suffragettes Alice Paul and Carrie Chapman Catt
    • Civil rights pioneers Rosa Parks and John Lewis
    • First Lady Eleanor Roosevelt
    • Army-McCarthy hearings lawyer Joseph N. Welch


On How We Treat Our Fellow Humans

“When the unreconstructed Southerner is the late nineteenth century or the anti-Semite of the twentieth believed—or the nativist of the globalized world believes—others to be less human, then the protocols of politics and the checks and balances of the Madisonian system of governance face formidable tests.”—p17 (emphasis in original)

I’m personally noticing this in the past couple of years: change (and fear of change) can motivate us to dehumanize others, allowing us to blame and punish them for what we fear.

“W.E.B. Du Bois understood what was happening. ‘In 1918, in order to win the war, we had to make Germans into Huns,’ he wrote. ‘In order to win [the Civil War], the South had to make Negroes into thieves, monsters, and idiots. Tomorrow, we must make Latins, South-eastern Europeans, Turks, and other Asiatics into actual “lesser breeds without the law”’—a quotation from Rudyard Kipling’s 1897 imperial poem ‘Recessional.’”—p116–117

Recent rhetoric, particularly against immigration, has this same theme of dehumanizing others not like us. By lumping them all into categories like rapists, murderers, and violent criminals, we justify treating them in ways we wouldn’t dream of treating our neighbors, friends, and loved ones.

On Private vs. Public Sector

“The American ideal of what Henry Clay had called ‘self-made men’ in 1832 is so central to the national mythology that there’s often a missing character in the story Americans like to tell about American prosperity: government, which frequently helped create the conditions for the making of those men.

“Many Americans have never liked acknowledging that the public sector has always been integral to making the private sector successful. We often approve of government’s role when we benefit from it and disapprove when others seem to be getting something we aren’t. Given the American Revolution’s origins as a rebellion against taxation and distant authority, such skepticism is understandable, even if it’s not well-founded. We have long proved ourselves quite capable of living with this contradiction, using Hamiltonian means (centralized decision-making) while speaking in Jeffersonian rhetorical terms (that government is best which governs least).”—p180

Too often we forget how much the free market depends on services provided by government, particularly for infrastructure: roads, utilities, funding for the invention and development of the internet, etc.

On Political Life

“McCarthy, though, was something new in modern political life: a freelance performer who grasped what many ordinary Americans feared and who had direct access to the media of the day. He exploited the privileges of power and prominence without regard to its responsibilities; to him politics was not about the substantive but the sensational. The country feared Communism, and McCarthy knew it, and he fed those fears with years of headlines and hearings. A master of false charges, of conspiracy-tinged rhetoric, and of calculated disrespect for conventional figures (from Truman and Eisenhower to Marshall), McCarthy could distract the public, play the press, and change the subject—all while keeping himself at center stage.”—p185

Sound familiar? Replace McCarthy’s name with Trump, change “Communism” to “immigration”, and remove the specific people mentioned, and it would remain an accurate description.


This book is a good reminder that fear is restrictive, holding us back from making any real improvement. We must look ahead with hope and work for the common good, not just for what will improve our own situation. It’s also an encouragement that as a nation, we have been through many dark times and ultimately moved past them.

Buy the book→

Menu Image Plugin + DevDmBootstrap3 Fix

This little plugin fixes the Menu Image plugin when used with the DevDmBootstrap3 theme.

Menu Image version 2.9.0 changed the way it displays images, breaking compatibility with DevDemBootstrap3. DevDmBootstrap3 uses a custom menu walker but does not use the nav_menu_item_title filter, so the plugin quit working.

One of my contract positions uses DevDmBootstrap3 for many client sites, so I wrote a basic plugin to get it working again.

Browse the code→

To use the plugin, upload the PHP file to your wp-plugins directory and activate the plugin. That’s it!