10 things to to after installing WordPress blog

This guide provides a list of 7 things that you should do after installing a new WordPress site. Some of the steps are optional, but many others are essential if you want to comply with GDPR and Google AdSense policy, to have at least basic on-site SEO and manage the updates easier.

This guide provides links to other articles which will aid in your learning of WordPress content management system. Many of the steps refer to 3rd party sites where you can find more information on a particular topic.

After you have finished this guide, you will have easy to maintain SEO optimized website that complies to GDPR and Google AdSense policy.

1. Setup domain

In order to avoid Google penalty for content duplication, you should setup your domain properly. According to Matt Cutts blog, it is necessary to redirect non-www to www or vice versa. it is a good idea to check which domain has more links indexed: if the www has more links – redirect the non-www to the www, otherwise, I suggest the opposite (www to the non-www). Check your web server documentation for more information on how to do it.

Do not forget to redirect non-https version to https, too!

2. Hardening admin panel to prevent Brute-force attack

If you check your server access logs, you will notice an enormous amount of requests to /wp-login.php. Most of these requests are performed by bots, trying to Brute-force the login form. There is a pretty easy and elegant solution to harden these attacks. Just add basic HTTP authentication for /wp-login.php URL. The bots should brute force two logins instead of one, but most probably they will fail on the first one – most of the bots are not programmed to expect basic HTTP authentication. You can add optionally IP restriction, too.

3. Install plugins

This step is not absolutely necessary, but my experience is that you most likely will need if not all the most of plugins I recommend bellow because almost nobody use vanilla WordPress. Nowadays, the SEO is essential to be properly indexed on Google and the social media are a most used channel to drive targeted traffic to your site and so you need plugins for them.

  • Classic Editor – enables the WordPress classic editor and the old-style Edit Post screen with TinyMCE, Meta Boxes, etc. If you have troubles running Guttenberg, this plugin is a life saver.
  • Code Snippets – An easy, clean and simple way to add code snippets to your site. The best thing is that you do not need to edit to your theme’s functions.php file again and your changes are persisted even if you change the theme you use.
  • Conditional CAPTCHAplugin that serves a CAPTCHA to new commenters, or if Akismet thinks their comment is spam. All other commenters never see a CAPTCHA. You need to obtain reCAPTCHA v2 API keys in order to use it. It is really easy – you need to log in with your Google credentials here.
  • Cookie Notice – allows you to elegantly inform users that your site uses cookies and to comply with the EU cookie law GDPR regulations.
  • Google XML Sitemapsthis plugin improves SEO using sitemaps for best indexation by search engines like Google, Bing, Yahoo, and others.
  • Share Buttons by AddThis – the official AddThis plugin that allows you to easily configure and place different social media buttons and widgets. It is free and provides nice usage stats.
  • SyntaxHighlighter Evolved – one of the first plugins of its kind to add Gutenberg support via its own block. SyntaxHighlighter Evolved allows you to easily post syntax-highlighted code to your site without losing its formatting or making any manual changes. It uses the SyntaxHighlighter JavaScript package by Alex Gorbatchev.
  • WP Post Signature – this plugin allows you to append a signature after every post. Some variables can be used, such as %post_title%, %post_link%, %bloginfo_name%, %bloginfo_url%, and so on. It supports multiuser.
  • WP Updates Notifier – easiest way to be notified by email when a plugin, a theme or WordPress core gets a new version. It will help you to maintain an up-to-date site and so reduce the chance to be hacked.

4. Disable cron jobs

Long story short: WordPress does not use Linux crontab, but its own pseudo cron system implementation that works right after installation and does not need server configuration. It sends an HTTP request on every page request of your website to wp-cron.php and executes scheduled events of the core and plugins. This way planned posts are published, system updates are received and pingbacks are triggered for example. The huge problem is that this is a pseudo cron system that relies on visitors – you need somebody to hit the site at a particular time in order to execute the scheduled tasks for that particular moment. There is even a website dedicated to this problem – https://wp-cron.org/. Check it out for more detailed information on how to migrate to a real, reliable cron job system.

5. SEO

Search Engine Optimization (SEO) is something so essential for a successful blog, so you just can’t skip it. There is plenty of articles on the topic, so I will not go into details here. I will only mention the most important (and easy to do) steps to ensure basic on-site optimization.

  • robots.txt – ensure that Settings -> Reading -> Search Engine Visibility checkbox is unticked. Otherwise, WordPress will generate a robots.txt record that discourages the search engines of indexing the blog.
  • Register the site in Google Webmaster Tools (a.k.a. Google Search Console) in order to receive updates related to SEO, indexing, and security. You can even submit your sitemap and check for errors.
  • Use a plugin to generate sitemap – it will speed up the process of discovering new or changed pages by search engines.
  • Signup for Google Analytics, really. Yeah, there are some cool FOSS alternatives to it such as Piwiki (Matomo) and Open Web Analytics, but they have one big issue – do not provide search keywords statistics.

6. Legal

In order to run Google AdSense, comply with GDPR and avoid legal problems, it is recommended to have Privacy Policy page and Cookie consent badge (notification). Version 5 of WordPress ships with template of Privacy Policy page you can customize and publish. For cockie consent badge, you can use third party plugin such as Cookie Notice or just include the js code of this.


WP-CLI is the command-line interface for WordPress. You can update plugins, configure multisite installs and much more, without using a web browser, right from the terminal. You can use it to auto-update the core, plugins, and themes, automate the deployment process or perform repetitive tasks to multiple WP installations. Try it and you will love it!

Batch rename files with Cyrillic filenames to Latin ones (transliterate file names)

If you have bunch of files with Cyrillic file names, there is a chance that some old devices such as TV embedded players, car audio systems, mp3 players may not recognize them or fail to read. The quick and dirty solution is to rename these files to Latin only characters. In order to save some time I use this handy bash script. It works flawlessly on both Windows (Git Bash) and native Linux systems. Continue reading

This machine ID is already enabled with a different key or is non-unique

I have purchased new VPS and I wanted to enable Ubuntu live patch service for it. Unfortunately, the command canonical-livepatch enable [TOKEN] failed with this ugly error message:

This machine ID is already enabled with a different key or is non-unique.
Either “sudo canonical-livepatch disable” on the other machine, or regenerate a
unique /etc/machine-id on this machine with
“sudo rm /etc/machine-id /var/lib/dbus/machine-id && sudo systemd-machine-id-setup” :
{“error”: “Conflicting machine-id”}

I thought to myself “Ok, lets try the suggested solution”. What I did was to backup the file /etc/machine-id, than delete it and run suggested systemd command. I was surprised to see the newly generated UUID was the same! Consulting with man page of systemd-machine-id-setup command revealed that “If run inside a KVM virtual machine and a UUID is configured (via the -uuid option), this UUID is used to initialize the machine ID. The caller must ensure that the UUID passed is sufficiently unique and is different for every booted instance of the VM.”. Obviously, my new VPS provider did not ensure that and somebody else have the same machine ID on his/her VPS and enabled Ubuntu live patch for it.

Continue reading

Vagrant: Authentication failure. Retrying…

I recently bought a newer laptop. It had Windows 8 preinstalled which I wiped immediately in order to install Linux Mint 19.1 and started to migrate data from my old machine. I packaged my vagrant box and transferred it to the new machine. Once imported the box back and issued vagrant up command I was surprised by the following errors:

Continue reading

Control screen backlight brightness from the command line

I have a Dell Latitude E5430 running Linux Mint 19 Tara. In Cinnamon, my function keys for brightness work correctly, but that was not the case with i3wm session. My first bet was to bind shortcuts executing xbacklight command but it doesn’t work because of this bug. So, I started to research for workaround and I found brightlight – “a program that can get and
set the screen backlight brightness on Linux systems using the kernel sysfs
interface.”. Sounds perfect but there are no prebuild binaries so you need to do it by yourself. The following steps are short guide how to build and install brightlight on Ubuntu and Ubuntu derivatives.

Continue reading

Putting HTML in inline JavaScript

A tag inside inline JavaScript string literal is interpreted by the HTML parser as a closing tag, causing syntax errors.
According to w3.org

Although the STYLE and SCRIPT elements use CDATA for their data model, for these elements, CDATA must be handled differently by user agents. Markup and entities must be treated as raw text and passed to the application as is. The first occurrence of the character sequence “</” (end-tag open delimiter) is treated as terminating the end of the element’s content. In valid documents, this would be the end tag for the element.

In real world scenario web browsers only end parsing a CDATA script block on an actual close-tag.
Unfortunately, there is no such special handling for script blocks in XHTML, causing < (or &) character to generate syntax errors if it is not properly escaped (i.e. HTML entity encoded).
There are different approaches to avoid such problems:

1) Encode the HTML string in base64 and decode it when reading
2) Split the <script> tag like that

var str = '</' + 'script' + '>';

3) Use CDATA

<script type="text/javascript">

How to install PHP Data Structures (DS) extension on Ubuntu 16.04

First, you will need to install PEAR via apt-get to get the necessary package and distribution system that both PEAR and PECL use. From a shell prompt enter:

sudo apt-get install php-pear

You will be prompted to confirm the install. Just press “y” and enter. If all goes well you should see it download and install the php-pear package.

Now you will need to install the php-dev package to get the necessary PHP7 source files to compile additional modules. Enter the following from a shell prompt:

sudo apt-get install php-dev

If you do not install the php-dev package and try to install a PECL extension using “pear install”, you will get the following error:

sh: phpize: not found
ERROR: `phpize’ failed

The PECL_HTTP extension requires an additional dependency package to be installed. You can probably skip this for other extensions:

sudo apt-get install libcurl4-openssl-dev

Now we are finally ready to actually install the extension. From a shell prompt enter following:

sudo pecl install ds

The installer may ask you about some specific options for the extension you are installing.  Just accept the defaults and go ahead.

Once the install is complete, it’s time to enable the extension.
First, edit the following file (create it if it does not exist already):

sudo vi /etc/php/7.0/mods-available/ds.ini

and change it’s contents to:

; configuration for php ds module
; priority=30

Than check and remove any symbolic links to 20-ds.ini file, such as:

sudo rm /etc/php/7.0/fpm/conf.d/20-ds.ini
sudo rm /etc/php7.0/apache2/conf.d/20-ds.ini
sudo rm /etc/php7.0/cli/conf.d/20-ds.ini

You need to remove above listed symlinks because of bug: there is hard dependency on the json extension. DS extension shouldn’t try to implement JsonSerializable if the json extension is not loaded, but actually do it and it will complain with exception if it is not found:

PHP Warning:  PHP Startup: Unable to load dynamic library '/usr/lib/php/20151012/ds.so'
 - /usr/lib/php/20151012/ds.so: undefined symbol: php_json_serializable_ce in Unknown on line 0

That’s why we removed 20-ds.ini symlinks and specified ds.so to load after json is already enabled.

Now, disable and then re-enable the extension:

sudo phpdismod ds
sudo phpenmod ds

You may need to restart your HTTP server:

# If you are on apache
sudo service apache2 restart
# if you are on nginx
sudo service nginx restart

My favorite programming quotes

“90% of coding is debugging. The other 10% is writing bugs”
Bram Cohen (the author of the peer-to-peer BitTorrent protocol)

“The programmer who refuses to keep exploring will surely stagnate, forget his joy, lose the will to program (and become a manager).”
Marijn Haverbeke

“The more I learn, the more I realize
how much I don’t know.”
Albert Einstein

“Never memorize something that
you can look up.”
Albert Einstein

How to parse a csv file in php when the delimiter is unknown

There are plenty of MS Excel alternatives out there – OpenOffice, LibreOffice, Kingsoft, Google Spreadsheets and many more. The problem is that CSV files created by different softwares may vary (, or ; to name a few options). If you need to process CSV files exported from different systems and software and handle the delimiter automatically, you can benefit from using SplFileObject::getCsvControl method.

Example usage:

<?php $csvFileObject = new SplFileObject($_FILES["csv"]["tmp_name"]); list($delimiter, $enclosure) = $csvFileObject->getCsvControl();

$lines = fopen($_FILES["csv"]["tmp_name"], 'r');
if($lines) {
while (($line = fgetcsv($lines, 4096, $delimiter, $enclosure)) !== false) {
//do something

Reference: http://php.net/manual/en/splfileobject.getcsvcontrol.php

How to setup Pure-FTPd server on OpenWRT enabled router

I am proud owner of TP-Link TL-WDR3500 router flashed with OpenWRT, which is really good custom firmware offering countless possibilities. Recently I’ve installed FTP server on it so I can access the attached external HDD drive remotely. This how-to is simple guide showing you to configure Pure-FTPd with TLS support on your OpenWRT enabled router, too.

Why Pure-FTPd

There are many reasons to prefer Pure-FTPd over other FTP servers available as OpenWRT packages:

  • It is a secure FTP server
  • It has FTPS support (offers optional TLS Encryption)
  • You can use both real user accounts and virtual ones
  • You can put every user in a chroot jail

Continue reading