Web Server (VPS) Optimization Checklist for WordPress

I have been using VPS as web server since 2005 to host my sites. Before that, I switched among shared web hosting for many reasons. One of them is cost efficiency because I have more than one websites (using WordPress). I also want to try some thing else like Django, Flask which I cannot do with share web hosting.

If you are about to start a WordPress blog for the first time, you may want to start with shared web hosting. Below are list of shared web hosting suggested by WordPress.org

Spin up a VPS web server

I am currently using both Linode and DigitalOcean for my sites. They are all good and I want to experience with both so I keep using both till now. You can pickup one of them or one at your own choice. There are long list of VPS provider so please do some researches.

I wrote a tutorial on how to setup LEMP stack on CentOS 7. So please go ahead to check it out for basic web server setup.

VPS optimization for WordPress

Below is checklist or to-do list that we need to work on our VPS

  • Configure Nginx with HTTP 2 support
  • PHP extensions, Zend Opcache
  • Nginx GZIP Compression configuration
  • Install and configure Nginx module Brotli Compression
  • Install and configure Nginx module  Google PageSpeed
  • Use W3-Total-Cache: this is actually not server side directly related. However you cannot or hard to use W3-Total-Cache without full control web server.
  • Install and configure Memcached so you won’t get MySQL crash sometime or “Error establishing a database connection”. This one can also speed up your WordPress site since required data is already in memory & smaller PHP script needs to be executed meaning faster web site.
  • If your site already has some content with images, you may want to optimize them using optipng, jpegoptim, pngquant, etc.

web server test result

Final thought

Fast web site needs not only strong web server but also well configured. You really don’t want to pay for a super strong VPS and still see loading time of your site more than 3 seconds. All VPSs’ I used so far is $5/month (1vCPU, 1GB of RAM, 25GB SSD).

WordPress textbox autocomplete using Ajax/jQuery

This tutorial is absolutely for beginner which contains demo source code, wordy explanation. At the end, you will be able to write up a WordPress Plugin that can load data from custom database table and serve it as data source. If you learn faster by reading source code, please feel free to jump in to my github repository.

In this article, I am going to cover below topics

  1. WordPress custom database table
  2. Enqueue or load required scripts (js)
  3. Textbox autocomplete


Getting started

Before we deep dive into detail, here is couple of things that we need to do

  1. Create a folder in “\wp-content\plugins\” called “ajax-autocomplete”
  2. Create “ajax-autocomplete.php” inside above folder, this file should have below header. Check out this official document for more options

    * Plugin Name: Ajax Autocomplete
    * Plugin URI: https://www.vndeveloper.com/
    * Description: DEMO WordPress Ajax jQuery textbox autocomplete, data source from custom table.
    * Version: 0.1
    * Author: Hien D. Nguyen
    * Author URI: https://www.vndeveloper.com/
    * License: GPL2+

  3. I recommend below file folder structure. If you already have your style, keep using it.

WordPress custom database table

We will create a custom table name “testing_table” and insert some test data upon Plugin activation

register_activation_hook(basename(dirname(__FILE__)) . ‘/’ . basename( __FILE__ ), ‘activate’);
function activate() {
global $wpdb;
$charset_collate = $wpdb->get_charset_collate();
require_once(ABSPATH . ‘wp-admin/includes/upgrade.php’);

$table = $wpdb->prefix . ‘testing_table’;
$query = “CREATE TABLE IF NOT EXISTS {$table} (
name VARCHAR(128),

$wpdb->insert($table, array(‘name’=>’LogiTech’));
$wpdb->insert($table, array(‘name’=>’Apple’));
$wpdb->insert($table, array(‘name’=>’Dell’));
$wpdb->insert($table, array(‘name’=>’Google’));

Enqueue or load required scripts (js)

You might know that AutoComplete needs jQuery. You also might think that you need to download jQuery libraries and place it in your plugin, then enqueue it.

For demo purpose, we don’t have any specific requirement for jQuery version. Therefore, we are going to use “built-in” jQuery that shipped along with WordPress. You can also check out all built-in scripts or libraries such as backbone, jquery-effects-transfer…at here.

add_action(‘wp_enqueue_scripts’, ‘mysite_js’);
function mysite_js() {
$wp_scripts = wp_scripts();
wp_enqueue_script(‘mysitejs’, plugins_url(‘/assets/js/frontend.js’, __FILE__), array(‘jquery’, ‘jquery-ui-core’, ‘jquery-ui-autocomplete’));
wp_localize_script(‘mysitejs’, ‘ajax_object’, array(‘ajax_url’ => admin_url( ‘admin-ajax.php’)));

// Autocomplete style
wp_enqueue_style(‘plugin_name-admin-ui-css’,’http://ajax.googleapis.com/ajax/libs/jqueryui/’ . $wp_scripts->registered[‘jquery-ui-core’]->ver . ‘/themes/flick/jquery-ui.css’);

// If your plugin needs its own style
wp_register_style(‘mysitecss’, plugins_url(‘/assets/css/frontend.css’, __FILE__));
wp_enqueue_style(‘mysitecss’ );

Keep in mind that we’ll need to send ajax request to query data from custom database table (testing_table). That’s why we need to call wp_localize_script so that our script (JavaScript) can understand variable “ajax_url”. Basically, to send an ajax request, we send a POST request to “wp-admin/admin-ajax.php”. I personally find this article perfectly explains Ajax as well as how it handles data submission.

We also load “themes/flick/jquery-ui.css” for styling our textbox autocomplete. You can check out other styles at here.

Textbox autocomplete

First thing first, we need a textbox. In this tutorial, we’ll use shortcode called “test-form” so later on we can place it in any page or post or even widget.

add_shortcode(‘test-form’, ‘test_form’);
function test_form($args, $content=”){
include(plugin_dir_path(__FILE__) . ‘includes/forms/test-form.php’);
return ob_get_clean();

In our “test-form.php”, just create a form with a textbox with “name” attribute as “testing”. In our JavaScript, we can make use of this attribute to locate this target textbox.

<form >
<input type=”text” name=”testing”>

In our loaded script (“/assets/js/frontend.js”), it looks this

jQuery(document).ready(function($) {
source: function(request, response){
type: “POST”,
url: ajax_object.ajax_url,
data: {
action: ‘myautocomplete’,
keyword: $(‘input[name=testing]’).val(),
success:function(data) {
response(JSON.parse( data ));
error: function(errorThrown){

For further options, please check out this article. Whenever user types in, an ajax request will be sent to (url: ajax_object.ajax_url) which is “wp-admin/admin-ajax.php”, then callback action “myautocomplete” will handle this request and send a response.

add_action(‘wp_ajax_nopriv_myautocomplete’, ‘ajax_autocomplete’);
add_action(‘wp_ajax_myautocomplete’, ‘ajax_autocomplete’);
function ajax_autocomplete() {
global $wpdb;
$table = $wpdb->prefix . ‘testing_table’;
$results = $wpdb->get_results(“SELECT name FROM ” . $table . ” WHERE name LIKE ‘%” . $_POST[‘keyword’] . “%'”);
$items = array();
if ( !empty( $results) ) {
foreach ( $results as $result ) {
$items[] = $result->name;
echo json_encode($items);

Final thought

That’s it. We finished creating a WordPress Plugin that has a “testing-form” short-code. This short-code contains a form with single textbox. When user types in “l”, this textbox will load data from custom table and suggest possible value.

Technical side, we covered

  1. Creating custom table upon WordPress Plugin activation, also add some testing data
  2. Load built-in jQuery and custom scripts, styles
  3. Using Ajax/jQuery for textbox autocomplete

Please share if you find this tutorial helpful and don’t forget to leave a comment.

Add Google reCAPTCHA to WooCommerce Signup

That’s all I need “Add Google reCAPTCHA to WooCommerce Signup Form”. There are ton of plugins out there can satisfy this simple requirement. However they have more than what I need. So I googled the minimum requirement to reach the goal and try it out. Let’s check below and share if you find it helpful.

Google reCAPTCHA

Get Google reCAPTCHA Keys

Basically you need

  1. Site Key
  2. Secret Key

You can get the keys as well as learn more about Google reCAPTCHA at https://www.google.com/recaptcha/intro/index.html

Make it happens

Simply put below script into your WordPress theme’s functions.php

Final thoughts

You can replace woocommerce_register_form by register_form and woocommerce_register_post by register_post if you don’t use WooCommerce. Further customization can be found as below

There are many reasons for using WooCommerce and here are mine: E-Commerce readiness, prevent user from accessing backend.

Notify Admin On WooCommerce User Registration

As web site admin, I am so happy when receiving this kind of email, user registration notification. By default, WordPress will send web site admin notification email upon user registration. However I received none since I’ve used WooCommerce Custom Fields on REGISTER form. The web site didn’t notify admin (me) on user registration.

Notify Admin On WooCommerce User Registration

If we are using WooCommerce, user registration will done through process_registration action in WooCommerce. At that time, WordPress never send email notification to admin about new user. It only sends notification email for new orders. So to sort this out, we are going to call wp_new_user_notification WordPress notification function during new user registration by WooCommerce via woocommerce_created_customer hook.

function admin_email_on_registration( $customer_id) {
wp_new_user_notification( $customer_id );
add_action(‘woocommerce_created_customer’, ‘admin_email_on_registration’, 10 , 1);

Credit: http://sarathlal.com/send-admin-notification-on-woocommerce-user-registration/

Remove WooCommerce Password Strength Meter

One friend of mine signed up for new account. Actually, I invited him to signup for an account using “REGISTER” form that I created in this post so that we could test it one more time. He complained that I couldn’t change his password because the web site thinks his password is so weak (even it isn’t he thought). I googled and found the reason. It’s due to new feature introduced in WooCommerce 2.5: password strength meter. By default, user needs to use strong password for security purpose.

Remove WooCommerce Password Strength Meter

My very first user has priority so I need to remove it so that he can change his password. I added this function in my plugin.

function wc_ninja_remove_password_strength() {
if ( wp_script_is( ‘wc-password-strength-meter’, ‘enqueued’ ) ) {
wp_dequeue_script( ‘wc-password-strength-meter’ );
add_action( ‘wp_print_scripts’, ‘wc_ninja_remove_password_strength’, 100 );

Credit: https://nicola.blog/2016/01/27/remove-the-password-strength-meter-on-the-checkout-page/

Why WordPress Asks for Connection Information?

Why WordPress Asks for Connection Information? To perform the requested action, WordPress needs to access your web server. Please enter your FTP credentials to proceed. If you do not remember your credentials, you should contact your web host.

Why WordPress asks for Connection Information?

Why WordPress Asks for Connection Information?

I sometime get this get this dialog asks for connection information, especially when sites hosted on VPS. I think this is because agent (apache or nginx) doesn’t have necessary permissions. In other words, you didn’t give right and/or enough permissions for agent.

How to Fix WordPress Ask for FTP Credentials?

It’s simple, give necessary permissions to agent. But what agent I should give permissions to? And how to it?

Outputs the username or agent that owns the running php/httpd process

cd /var/www/vndeveloper.com/html
sudo vi info.php

Access https://vndeveloper.com/info.php and you may see this screen


I am using NGINX & FPM. You may see it slightly different on your site like “apache” or similar if you use Apache.

Give permissions to agent

chown -R php-fpm /var/www/vndeveloper.com/html/

Wrapping Up

That’s it. Quite simple huh? Don’t forget to delete info.php after finish. Leave your feedback or comment right below.