Tag Archives: php

How To Easily Put A Form On Your Website

forms

Contact Forms. Everyone wants them on their website. It seems like quite a standard component that anybody should know about like the back of their hand. But it’s not true. Time and again I run into people who are pulling their hair out trying to get a simple contact form (or any type of form) on their site, or accomplishing it in a very long-winded and inefficient manner. This guide will teach you how to use the best tools to quickly create forms and embed them on your website, whether it’s a plain HTML / PHP website or a WordPress…

The post How To Easily Put A Form On Your Website appeared first on The Daily Egg.

Read more – 

How To Easily Put A Form On Your Website

Advanced WordPress Management With WP-CLI


The command-line interface has always been popular in the world of developers, because it provides tools that boost productivity and speed up the development process. At first sight, it might seem hard to believe that using the command line to perform certain tasks is getting easier than using a graphical interface. The purpose of this article is to clear up your doubts about that, at least concerning WordPress tasks.

Advanced WordPress Management With WP-CLI

WordPress provides a graphical user interface for every administrative task, and this has helped to make it the most popular content management system on the web. But in terms of productivity, working with the command line enables you to accomplish many such tasks more efficiently and quickly.

The post Advanced WordPress Management With WP-CLI appeared first on Smashing Magazine.

This article:

Advanced WordPress Management With WP-CLI

A Simple Workflow From Development To Deployment

In this article I’ll be taking a look at how to build a simple yet robust workflow for developing sites that require PHP and MySQL. I’ll show you how to use Vagrant51 to create and run a web server on your own computer, with the version of PHP your live site runs. I also demonstrate a process for using a hosted service to deploy files in a robust way to your live server.

This article is for you if you currently have no way to test your PHP and MySQL sites locally, or use something like MAMP2 or XAMPP3. The second half of the article will help you move away from uploading files using FTP to a process that is far less likely to cause you problems.

The Aim Of A Local Development Environment

When designing and developing your website, you should try to match the live web server as much as possible. This should include ensuring that paths from root don’t change between local and live versions, and that PHP modules and permissions are the same in both places. This approach will reduce the possibility of something going wrong as you push the site live. It should also enable you to come back to a site to make changes and updates and know that you can then deploy those changes without breaking the running site.

A good local development environment saves you time and stress. It gives you a place to test things out. It means that you can pick up a project, make some changes, deploy them and bill your client for another job well done.

Disaster-Free Deployments

If you keep a list of changes made to your site and then transfer the files one by one, you leave yourself open to difficulties caused by human error and connectivity problems. Many issues we see supporting our products are down to failed FTP transfers. A key file has failed to upload, and it is deep in the core product. It’s easy to forget to transfer a file, and it’s also easy to leave old files lying around. If the software you use has removed some files to resolve a security issue, leaving them on the server could leave you at risk even if you have upgraded.

A good deployment method ensures that the files on your live server exactly match those locally. If anything fails to deploy, you should be notified so you can fix the issue before your client or their customers see it first!

Step 1: Grab Some Tools

We’re going to be using some free tools to create our development environment. First, download VirtualBox4, a free application which allows you to run a virtual machine on your computer. You may have already come across virtual machines if you work on a Mac and use a Windows virtual machine for testing. A virtual machine is exactly as the name suggests, a complete virtual OS running on your computer.

Install the version of VirtualBox for your operating system.

Now download and install Vagrant51. Vagrant is an application that helps you manage virtual machines.

Screenshot of Vagrant homepage.6
The Vagrant homepage. (View large version7)

It’s possible to work with virtual machines without using Vagrant. However, each time you want to set up a new VM you have to go through the process of installing web server software and configuring the server. Vagrant helps you automate that process so that within a few minutes you can have a local web server running your site.

If you are on Mac OS X or Linux, at the command line run the following command:

sudo vagrant plugin install vagrant-bindfs

For all operating systems, run the next command to install Vagrant Host Manager8 to save you editing your hosts file by hand.

sudo vagrant plugin install vagrant-hostmanager

Vagrant requires a project folder with a text file saved with the name Vagrantfile in the root. In the Vagrantfile you specify how the VM should be set up. You can write your own configuration scripts for Vagrant, but for most cases you don’t need to as someone else has already done the hard work for you. Here we’re going to use a tool called PuPHPet9.

Screenshot of PuPHPet website.10
The PuPHPet website. (View large version11)

PuPHPet

PuPHPet is an online configuration tool that helps you configure a Vagrant project. You work through a form on the website, selecting options for your site, and then download a package containing a Vagrantfile and other scripts to set up a virtual machine.

Step 2: Discover What Is On Your Live Server

To use PuPHPet to set up a development server that is as close as possible to the hosting you will use for the site, first find out what is on the live server. You want to know:

  1. Type of Linux
  2. Web server: Apache or Nginx (probably Apache if shared hosting)
  3. PHP version: this will be something like PHP 5.4 or 5.5, etc.
  4. The configured resource limits for file upload, memory and so on
  5. Installed PHP modules; for example: gd, curl
  6. MySQL version

If you don’t yet have access to the hosting then you will need to ask the host these questions. If you do have access then you can find out for yourself.

Upload a file to the server named info.php that contains the following PHP function:

<?php phpinfo(); ?>

With your web browser you can visit http://yourdomain.com/info.php12 and see all kinds of information about PHP on the server.

1. Type Of Linux

You should see an indication of the base operating system in the first line of the report “System”. Knowing that you have a Debian, Ubuntu or CentOS system might be helpful for more advanced configurations.

2. Web Server

This is probably Apache. If you see any mention of Apache in the initial section or in the headings below, it’s Apache. The most likely alternative is Nginx. For simple sites the biggest difference between web servers is the fact that rewrite rules are different, so if you are creating friendly URLs you need to know the correct syntax to use.

3. PHP Version

The version of PHP will be right at the top of the document next to the PHP logo. It might be a long string — you are mostly interested in one number after the dot. So if you see “PHP Version 5.4.4-14+deb7u14,” all you need to note down is PHP 5.4.

4. PHP Modules

PuPHPet will install some default modules for you. If you want to be sure certain things are present, however, you can specify them. The PHP modules are listed, with details about them, after the “Core” section of the report. Common modules to look out for are:

  • curl: for making requests to other servers
  • gd and/or imagemagick: used for image manipulation
  • mysql, mysqli and pdo: methods of connecting to the database. You should probably be using mysqli or pdo at this point
5. Resource Limits And Configuration Options

Under the section “Core” you will find all kinds of information about PHP. Useful settings to note down are:

  • max_execution_time: how long a script may run for
  • max_file_uploads: how many files may be uploaded at once
  • max_input_vars: how many fields a form is limited to
  • post_max_size: the maximum size of a form post
  • upload_max_filesize: file upload limit

Depending on your hosting, some of these might be able to be changed. For example, you can usually increase the size of files that can be uploaded.

6. MySQL Version

Under the PHP module information for mysql, mysqli and pdo_mysql you should see a value for “Client Library Version”: this is your MySQL version. Again, knowing just one value after the dot is fine.

Beware Of Old PHP!

On doing this test, if you discover that the server is running anything older than PHP 5.4 — stop now and find out how to upgrade the hosting to a more recent PHP version. For a new site I’d suggest ensuring you are on at least PHP 5.5. Version 5.6 is even better.

PHP5.3 is not only end-of-life, it’s also really slow in comparison to newer PHP versions. It’s a good plan to make sure you are using a supported version of a core technology on your site. Through helping customers at Perch we’ve found that, in general, hosts are happy to upgrade you to a newer server if you put in a request. If they are not, I’d seriously consider moving hosts13.

Step 3: Build A Project With PuPHPet

Now that you have your information to hand, you can use it to build a project with PuPHPet that reasonably closely mirrors your environment. I’ll walk you through the interface. If I don’t mention a setting and you don’t have an opinion about it, then leave the default value.

Deploy Target

On the PuPHPet website14, choose Deploy Target → Locally in the sidebar. In the main screen select VirtualBox as the provider.

Under Distro you can select the type of Linux you are using, if it is listed. If it isn’t listed I would suggest using the default Ubuntu.

The IP address needs to be something unique on your network, not a real external IP. I tend to use IP addresses with the format 10.1.0.130 for VMs.

The hostname identifies your server. Again this can be something made up.

Shared Folders is an important setting. When you use a virtual machine you are running an entirely new computer with its own file system on your computer. If you want to continue editing files in the usual place on your computer — and not have to transfer them into the VM to view them — you need to map the drive on your own machine to one on the VM. That’s what we are doing when we create a shared folder.

On my Mac, inside /Users/rachel/Sites I have a folder called vm. This is where I place a folder for each of my projects. When I set up a VM I use the path /Users/rachel/Sites/vm as the folder source, mapped to /var/www as the folder target.

Screenshot of PuPHPet configuration screen.15
Setting up shared folders on PuPHPet. (View large version16)

If this is a new site and you don’t already have files created, at this point I’d suggest creating a folder for the project you are setting up the virtual machine for, and pop an index.html into that folder with <h1>It works!</h1> in it. Just so you can see that things are working after running setup.

Finally, if you are on Mac OS X or Linux, select NFS as the shared folder type.

System

You can probably leave everything here as the default. It’s worth knowing that under this option you can configure cron jobs for scheduled tasks and add system packages if you have certain things you want to install.

Web Servers

Unless you have identified that you have Nginx, select Apache and check Install Apache. This will open up a further set of options. Here is where you configure your virtual hosts.

A virtual host means that instead of having one website per server you can have multiple websites on a server. With virtual machines you can create as many as you like, so it’s up to you whether you configure a single virtual host or more. What you should not do is configure one virtual host and then stick multiple websites into subfolders of that host. Each site needs either its own VM or a virtual host on a VM so that the path of your files from root does not change when you go live.

The basic settings for a virtual host are as follows:

Server name: clientname.dev or any made up domain you like.

Document root: from /var/www. If you have shared a folder in the way I suggested, /var/www is that directory on your computer — the directory with all your project folders in it — so you can specify /var/www/clientname here.

Screenshot of virtual host setup.17
Configuring a virtual host with PuPHPet. (View large version18)

If you want to add another host, scroll down to Add an Apache vhost and create your next one.

Languages

Select PHP and check Install PHP.

Screenshot of language setup.19
Setting up languages on PuPHPet. (View large version20)

Under PHP Version select the version you identified as being on your host.

Under PHP Modules add any specific modules (for example, “gd” and “curl”) that you identified as present on your hosting.

Databases

Select MySQL and if you know the version of MySQL select it here.

You can now create a database user with a password. I tend to just use the name “vagrant” for both on local development machines.

You can also create a database ready to use for your site. Remember these details as you’ll need them to install your CMS or use in your own custom code that connects to MySQL.

Mail Tools

If you are using a CMS then it’s a good idea to have some way of looking at the emails it sends. PuPHPet suggests you install MailCatcher21 locally for this task as it saves configuring a mail server.

That should be it for setup. Select Create Archive from the sidebar and download your file. Unzip the file and put it somewhere on your system — mine all live in my home directory in a subdirectory called vagrant.

Your First Virtual Machine

You are almost ready to go. Open up a terminal window and change into the folder where you unzipped your project.

cd /Users/rachel/vagrant/mynewproject

Now run the command:

vagrant up
Screenshot of terminal window.22
Running the vagrant up command. (View large version23)

The first time you do this it will take a while. Vagrant will see that you don’t already have the base operating system downloaded so it will download it. When you create a new project in the future and use the same version of Linux, Vagrant will copy the box so this will be quicker.

You will see a lot of stuff scrolling by — don’t worry about it; it will take a few minutes to get everything set up for you. If you are using NFS you will be prompted for your password during the process to allow Vagrant to edit your exports file.

Once Vagrant has finished you should be able to go to the domain you set up for your virtual host using your web browser and see your site! If you make changes to your files and reload the browser, you will see your changes.

Basic Vagrant Commands

Vagrant is controlled with a few simple commands from the command line. We’ve already used vagrant up which will start up a VM. If the VM is brand-new it will also provision it — setting up the packages you configured to be installed, creating your virtual hosts, and so on. If you run vagrant up on a VM that has already been provisioned, Vagrant will not reprovision it.

Understanding the commands and what they will do is important, but if you prefer to stay out of the command line, take a look at Vagrant Manager24. Vagrant Manager is an application for Mac OS X and Windows that gives you a nice way to manage your VMs and also see which are running at any one time.

Screenshot of Vagrant Manager website.25
The Vagrant Manager website. (View large version26)

If you want to reprovision a VM, first make sure it is running with vagrant up, then type:

vagrant provision

To stop a VM from running you can use:

vagrant suspend

This will pause the box and give back your host machine the memory it uses, but it won’t delete anything on the VM or shut down the operating system. If you run vagrant up again, it will come back just as it was before you paused it.

To shut down the operating system on a VM use:

vagrant halt

Running vagrant up on a halted box boots up the system again.

If you want to set your virtual machine right back to its initial state, run:

vagrant destroy

This will delete anything you installed on the server. It won’t touch the files in your mapped drive as those are hosted on the host computer, but it will delete MySQL databases, for example. If you want the data from those, export it first.

To access the command line on the VM type:

vagrant ssh

You will then be on your VM and can run any commands. A common thing you might do is import or export a database file.

Importing A Database File

Our process creates an empty database. If you are installing a CMS or some other software, it is likely that it will create the tables for you. If you want to import a file exported from your live server, you can do that at the command line.

Use vagrant ssh to reach the command line of your VM. Make sure your exported database SQL script is in the root of your site, within the shared folder. Then, type the following (I’m assuming a database name of dbMySite, username and password both set to “vagrant”.

mysql -u vagrant -p dbMySite < /var/www/clientname/db.sql

You will then be prompted for the password. Type your password and the database will be imported.

Deploying Live

After following these steps you should have a nice way to work locally on one or more projects at a time. You can set up virtual machines that are similar to live, and you are not developing in subfolders. We can continue to enhance our workflow by moving away from FTP to using a deployment service.

Get Files Into Source Control

If you are already using Git, then you are part of the way to simple deployments. If not, that is the first thing we need to do. Our process will be to commit files into Git on our own computer, then create an account on a hosted Git repository and push our files to the live server from there.

If you don’t already have Git running locally, download and install Git27.

At the command line, give Git your name using the following command:

git config --global user.name "YOUR NAME"

Use the next command to give Git your email address. We are going to use a hosted repository, so use the email address here that you will use to sign up.

git config --global user.email "YOUR EMAIL ADDRESS"

Stay on the command line and change to the directory where you keep your site files. If your files are in /Users/rachel/Sites/vm/clientname, you would type:

cd /Users/rachel/Sites/vm/clientname

The next command tells Git that we want to create a new Git repository here:

git init

We then add our files:

git add .

Then commit the files:

git commit -m "Adding initial files"

The comment in quotes after -m is a message describing the commit. Your local files are now in Git! As you work you can add and commit files.

If you would rather not work in the command line, there are plenty of applications to help you work with Git. Tower28 is a popular choice. The people who develop Tower have also produced a great book on learning version control with Git29. You can read online free or purchase an ebook version.

Screenshot of Tower website.30
The Tower website. (View large version31)

Create A Hosted Repository

To make deployments easy we are going to use a hosted Git repository that will securely store your files and allow you to deploy them live. The hosted service I’m suggesting here is Beanstalk32, because it does both hosted Git and deployment. There are other services that will deploy from a GitHub account or other hosted Git service; Beanstalk bundles them together which makes things straightforward.

Screenshot of Beanstalk website.33
Beanstalk’s website. (View large version34)

After setting up your Beanstalk account, create a repository there. You now need to push your files to that repository. At the command line, make sure you are inside the directory that contains your files, and type:

git remote add beanstalk git@accountname.beanstalkapp.com35:/gitreponame.git
git push beanstalk

Your files will now be transmitted to Beanstalk. You should be able to see and browse around them there.

We can now edit our files, previewing them on our own web server. We can commit them locally and push the changes to Beanstalk. Our final step is to make them live.

Deployment

Deployments on Beanstalk can be manual or automatic. An automatic deployment would happen when you pushed some code into your branch on GitHub. Typically, you’d do this on a staging environment where it wouldn’t matter if the code you pushed broke things.

For a live site, especially working in our simple way, you’ll want to do a manual deployment. You will log into Beanstalk and trigger the deployment yourself.

When you deploy, Beanstalk will make sure that the files on the server are identical to the files in Git. If a new file is present, it will be added, changed files will be updated, and any files deleted from Git will be removed from the server.

To get started deploying your files, go to the repository that you created on Beanstalk and select Deployments. Here you can create a new environment and server. If you are creating a deployment to the live server, name it “Live” or “Production,” keep Deployment Mode as Manual and specify the master branch.

You can then add a server type. If you are deploying to shared hosting, that type would ideally be SFTP, but could also be FTP. On the next screen you then add your server details. These are exactly what you would use to connect with an FTP client.

Screenshot of server types on Beanstalk.36
Selecting a server type on Beanstalk. (View large version37)

Beanstalk allows you to run a test to check that your server can be connected to. Once you have your server set up, and have verified the connection, you are all set to deploy your files to your live site. It’s as simple as clicking a button and waiting. Once you deploy, Beanstalk will do the following:

  • Connect to your server.
  • Ensure that the files on the server match the files in the branch you are deploying.
  • On initial deploy, all existing files on the server have to be checked. Your first deploy will be slow!
  • Subsequent deploys only change things that have changed in Git.

Deployment Tips

Here are a few suggestions to make deploying your sites in this way easier.

Create A Multiple-Server Config File

Working across a few environments means you are going to need to manage things that are specific to each environment, such as database settings or file paths. I like to create a config file that switches on host name, so the same file can be everywhere and you can’t accidentally replace your live details with the development server ones. You can see an example for Perch38, but you could do the same for any other system that has a config file as part of the code.

Use .gitignore To Keep Things Out Of Beanstalk

There are likely to be files and assets that you don’t want to push to Beanstalk. You can use a .gitignore file to make Git ignore them. There are some good starting point files39 for various systems on GitHub.

Exclude Files And Folders On GitHub

If you want files and folders to end up on Beanstalk as part of the repository but not be deployed onto your server, you can also exclude them from the deployment. Perhaps you have some source assets you want to manage in Git along with the site, but don’t want to deploy. You can configure patterns, specific files or directories when setting up or editing your deployment.

Edit Files On Beanstalk In Emergencies

When you are away from your desk and need to fix a problem, Beanstalk can save the day. You can edit a file directly on Beanstalk using the web interface and push it live.

This is not as good as testing locally before deploying but handy in an emergency. Unlike editing directly on the server, you have the safety net of being able to roll back to a previous version if it all goes wrong. You also have the changed file in Git so you don’t overwrite the change next time you deploy.

Use Navicat To Sync Database Changes

One of the biggest problems of deploying changes can arise if you need to make changes to the live database to keep it in sync with your local one. Navicat40 can help with that job. You can select a source and target, compare differences and run queries to make changes.

Your New Workflow

If you’ve followed this article you should now be in a position to develop one or many sites locally, using a setup similar to how the site will run on the live server.

Your files are now version-controlled and are pushed to a remote Git repository.

You can deploy in the confidence that what ends up on the live server is exactly what should be on that server — no more, no less.

When you need to make changes to a project in the future, you can make sure you have the latest files from Beanstalk, make your changes, test, commit and deploy, and not worry that you might break something. The time you have spent getting your workflow straight should pay off the first time you need to make updates to a running site that you haven’t touched for a few weeks.

This isn’t the only way to achieve a solid development environment and deployment process, but it’s a reasonably straightforward one. Once you understand this type of workflow, you can explore how to streamline it further, making time to do more interesting things than fight with servers and hosting!

(vf, ml, og)

Footnotes

  1. 1 https://www.vagrantup.com/
  2. 2 https://www.mamp.info/
  3. 3 https://www.apachefriends.org/
  4. 4 https://www.virtualbox.org/
  5. 5 https://www.vagrantup.com/
  6. 6 http://www.smashingmagazine.com/wp-content/uploads/2015/07/01-vagrant-opt.png
  7. 7 http://www.smashingmagazine.com/wp-content/uploads/2015/07/01-vagrant-opt.png
  8. 8 https://github.com/smdahlen/vagrant-hostmanager
  9. 9 https://puphpet.com
  10. 10 http://www.smashingmagazine.com/wp-content/uploads/2015/07/02-puphpet-opt.png
  11. 11 http://www.smashingmagazine.com/wp-content/uploads/2015/07/02-puphpet-opt.png
  12. 12 http://yourdomain.com/info.php
  13. 13 http://www.lornajane.net/posts/2014/how-to-choose-php-hosting
  14. 14 https://puphpet.com
  15. 15 http://www.smashingmagazine.com/wp-content/uploads/2015/07/03-nfs-opt.png
  16. 16 http://www.smashingmagazine.com/wp-content/uploads/2015/07/03-nfs-opt.png
  17. 17 http://www.smashingmagazine.com/wp-content/uploads/2015/07/04-vhosts-opt.png
  18. 18 http://www.smashingmagazine.com/wp-content/uploads/2015/07/04-vhosts-opt.png
  19. 19 http://www.smashingmagazine.com/wp-content/uploads/2015/07/05-puphpet-php-opt.png
  20. 20 http://www.smashingmagazine.com/wp-content/uploads/2015/07/05-puphpet-php-opt.png
  21. 21 http://mailcatcher.me/
  22. 22 http://www.smashingmagazine.com/wp-content/uploads/2015/07/06-vagrant-up-opt.png
  23. 23 http://www.smashingmagazine.com/wp-content/uploads/2015/07/06-vagrant-up-opt.png
  24. 24 http://vagrantmanager.com/
  25. 25 http://www.smashingmagazine.com/wp-content/uploads/2015/07/07-vagrant-manager-opt.png
  26. 26 http://www.smashingmagazine.com/wp-content/uploads/2015/07/07-vagrant-manager-opt.png
  27. 27 http://git-scm.com/downloads
  28. 28 http://www.git-tower.com/
  29. 29 http://www.git-tower.com/learn/ebook
  30. 30 http://www.smashingmagazine.com/wp-content/uploads/2015/07/08-git-tower-opt.png
  31. 31 http://www.smashingmagazine.com/wp-content/uploads/2015/07/08-git-tower-opt.png
  32. 32 http://beanstalkapp.com
  33. 33 http://www.smashingmagazine.com/wp-content/uploads/2015/07/09-beanstalk-opt.png
  34. 34 http://www.smashingmagazine.com/wp-content/uploads/2015/07/09-beanstalk-opt.png
  35. 35 mailto:git@accountname.beanstalkapp.com
  36. 36 http://www.smashingmagazine.com/wp-content/uploads/2015/07/10-add-server-opt.png
  37. 37 http://www.smashingmagazine.com/wp-content/uploads/2015/07/10-add-server-opt.png
  38. 38 http://solutions.grabaperch.com/development/multiple-server-config
  39. 39 https://github.com/github/gitignore
  40. 40 http://www.navicat.com/products/navicat-for-mysql

The post A Simple Workflow From Development To Deployment appeared first on Smashing Magazine.

See original article: 

A Simple Workflow From Development To Deployment

How To Use Autoloading And A Plugin Container In WordPress Plugins

Building and maintaining1 a WordPress plugin can be a daunting task. The bigger the codebase, the harder it is to keep track of all the working parts and their relationship to one another. And you can add to that the limitations imposed by working in an antiquated version of PHP, 5.2.

In this article we will explore an alternative way of developing WordPress plugins, using the lessons learned from the greater PHP community, the world outside WordPress. We will walk through the steps of creating a plugin and investigate the use of autoloading and a plugin container.

Let’s Begin

The first thing you need to do when creating a plugin is to give it a unique name. The name is important as it will be the basis for all our unique identifiers (function prefix, class prefix, textdomain, option prefix, etc.). The name should also be unique across the wordpress.org space. It won’t hurt if we make the name catchy. For our sample plugin I chose the name Simplarity, a play on the words “simple” and “clarity”.

We’ll assume you have a working WordPress installation already.

Folder Structure

First, create a directory named simplarity inside wp-content/plugins. Inside it create the following structure:

  • simplarity.php: our main plugin file
  • css/: directory containing our styles
  • js/: directory containing JavaScript files
  • languages/: directory that will contain translation files
  • src/: directory containing our classes
  • views/: directory that will contain our plugin view files

The Main Plugin File

Open the main plugin file, simplarity.php, and add the plugin information header:

<?php
/*
Plugin Name: Simplarity
Description: A plugin for smashingmagazine.com
Version: 1.0.0
License: GPL-2.0+
*/

This information is enough for now. The plugin name, description, and version will show up in the plugins area of WordPress admin. The license details are important to let your users know that this is an open source plugin. A full list of header information can found in the WordPress codex2.

Autoloading

Autoloading allows you to automatically load classes using an autoloader so you don’t have to manually include the files containing the class definitions. For example, whenever you need to use a class, you need to do the following:

require_once '/path/to/classes/class-container.php';
require_once '/path/to/classes/class-view.php';
require_once '/path/to/classes/class-settings-page.php';

$plugin = new Container();
$view = new View();
$settings_page = new SettingsPage();

With autoloading, you can use an autoloader instead of multiple require_once3 statements. It also eliminates the need to update these require statements whenever you add, rename, or change the location of your classes. That’s a big plus for maintainability.

Adopting The PEAR Naming Convention For Class Names

Before we create our autoloader we need to create a convention for our class names and their location in the file system. This will aid the autoloader in mapping out the class to its source file.

For our class names we will adopt the PEAR naming convention4. The gist is that class names are alphabetic characters in StudlyCaps. Each level of the hierarchy is separated with a single underscore. Class names will directly map to the directories in which they are stored.

It’s easier to illustrate it using examples:

  • A class named Simplarity_Plugin would be defined in the file src/Simplarity/Plugin.php.
  • A class named Simplarity_SettingsPage would be defined in src/Simplarity/SettingsPage.php.

As you can see with this convention, the autoloader will just replace the underscores with directory separators to locate the class definition.

What About The WordPress Coding Standards For Class Names?

As you might be aware, WordPress has its own naming convention5 for class names. It states:

Class names should use capitalized words separated by underscores. Any acronyms should be all upper case. […] Class file names should be based on the class name with class- prepended and the underscores in the class name replaced with hyphens, for example WP_Error becomes class-wp-error.php

I know that we should follow the standards of the platform that we are developing on. However, we suggest using the PEAR naming convention because:

  • WP coding standards do not cover autoloading.
  • WP does not follow its own coding standards. Examples: class.wp-scripts.php and SimplePie. This is understandable since WordPress grew organically.
  • Interoperability allows you to easily use third-party libraries that follow the PEAR naming convention, like Twig. And conversely, you can easily port your code to other libraries sharing the same convention.
  • It’s important your autoloader is future-ready. When WordPress decides to up the ante and finally move to PHP 5.3 as its minimum requirement, you can easily update the code to be PSR-0 or PSR-4-compatible and take advantage of the built-in namespaces instead of using prefixes. This is a big plus for interoperability.

Note that we are only using this naming convention for classes. The rest of our code will still follow the WordPress coding standards. It’s important to follow and respect the standards of the platform that we are developing on.

Now that we have fully covered the naming convention, we can finally build our autoloader.

Building Our Autoloader

Open our main plugin file and add the following code below the plugin information header:

spl_autoload_register( 'simplarity_autoloader' );
function simplarity_autoloader( $class_name ) 
  if ( false !== strpos( $class_name, 'Simplarity' ) ) 
    $classes_dir = realpath( plugin_dir_path( __FILE__ ) ) . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR;
    $class_file = str_replace( '_', DIRECTORY_SEPARATOR, $class_name ) . '.php';
    require_once $classes_dir . $class_file;
  
}

At the heart of our autoloading mechanism is PHP’s built in spl_autoload_register6 function. All it does is register a function to be called automatically when your code references a class that hasn’t been loaded yet.

The first line tells spl_autoload_register to register our function named simplarity_autoloader:

spl_autoload_register( 'simplarity_autoloader' );

Next we define the simplarity_autoloader function:

function simplarity_autoloader( $class_name ) 
  …

Notice that it accepts a $class_name parameter. This parameter holds the class name. For example when you instantiate a class using $plugin = new Simplarity_Plugin(), $class_name will contain the string “Simplarity_Plugin”. Since we are adding this function in the global space, it’s important that we have it prefixed with simplarity_.

The next line checks if $classname contains the string “Simplarity” which is our top level namespace:

if ( false !== strpos( $class_name, 'Simplarity' ) ) 

This will ensure that the autoloader will only run on our classes. Without this check, our autoloader will run every time an unloaded class is referenced, even if the class is not ours, which is not ideal.

The next line constructs the path to the directory where our classes reside:

$classes_dir = realpath( plugin_dir_path( __FILE__ ) ) . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR;

It uses WP’s plugin_dir_path7 to get the plugin root directory. __FILE__ is a magic constant8 that contains the full path and filename of the current file. DIRECTORY_SEPARATOR is a predefined constant that contains either a forward slash or backslash depending on the OS your web server is on. We also use realpath9 to normalize the file path.

This line resolves the path to the class definition file:

$class_file = str_replace( '_', DIRECTORY_SEPARATOR, $class_name ) . '.php';

It replaces the underscore (_) in $class_name with the directory separator and appends .php.

Finally, this line builds the file path to the definition and includes the file using require_once:

require_once $classes_dir . $class_file;

That’s it! You now have an autoloader. Say goodbye to long lines of require_once statements.

Plugin Container

A plugin container is a special class that holds together our plugin code. It simplifies the interaction between the many working parts of your code by providing a centralized location to manage the configuration and objects.

Uses Of Our Plugin Container

Here are the things we can expect from the plugin container:

  • Store global parameters in a single location

    Often you’ll find this code in plugins:

    define( 'SIMPLARITY_VERSION', '1.0.0' );
    define( 'SIMPLARITY_PATH', realpath( plugin_dir_path( __FILE__ ) ) . DIRECTORY_SEPARATOR );
    define( 'SIMPLARITY_URL', plugin_dir_url( __FILE__ ) );
    

    Instead of doing that, we could do this instead:

    $plugin = new Simplarity_Plugin();
    $plugin['version] = '1.0.0';
    $plugin['path'] = realpath( plugin_dir_path( __FILE__ ) ) . DIRECTORY_SEPARATOR;
    $plugin['url'] = plugin_dir_url( __FILE__ );
    

    This has the added benefit of not polluting the global namespace with our plugin’s constants, which in most cases aren’t needed by other plugins.

  • Store objects in a single location

    Instead of scattering our class instantiations everywhere in our codebase we can just do this in a single location:

    $plugin = new Simplarity_Plugin();
    /…/
    $plugin['scripts'] = new Simplarity_Scripts(); // A class that loads javascript files
    
  • Service definitions

    This is the most powerful feature of the container. A service is an object that does something as part of a larger system. Services are defined by functions that return an instance of an object. Almost any global object can be a service.

    $plugin['settings_page'] = function ( $plugin ) 
      return new SettingsPage( $plugin['settings_page_properties'] );
    ;
    

    Services result in lazy initialization whereby objects are only instantiated and initialized when needed.

    It also allows us to easily implement a self-resolving dependency injection design. An example:

    $plugin = new Plugin();
    $plugin['door_width'] = 100;
    $plugin['door_height'] = 500;
    $plugin['door_size'] = function ( $plugin ) 
      return new DoorSize( $plugin['door_width'], $plugin['door_height'] );
    ;
    $plugin['door'] = function ( $plugin ) 
      return new Door( $plugin['door_size'] );
    ;
    $plugin['window'] = function ( $plugin ) 
      return new Window();
    ;
    $plugin['house'] = function ( $plugin ) 
      return new House( $plugin['door'], $plugin['window'] );
    ;
    $house = $plugin['house'];

    This is roughly equivalent to:

    $door_width = 100;
    $door_height = 500;
    $door_size = new DoorSize( $door_width, $door_height );
    $door = new Door( $door_size );
    $window = new Window();
    $house = new House( $door, $window );

    Whenever we get an object, as in $house = $plugin['house']; , the object is created (lazy initialization) and dependencies are resolved automatically.

Building The Plugin Container

Let’s start by creating the plugin container class. We will name it “Simplarity_Plugin”. As our naming convention dictates, we should create a corresponding file: src/Simplarity/Plugin.php.

Open Plugin.php and add the following code:

<?php
class Simplarity_Plugin implements ArrayAccess 
  protected $contents;
    
  public function __construct() 
    $this->contents = array();
  
  
  public function offsetSet( $offset, $value ) 
    $this->contents[$offset] = $value;
  

  public function offsetExists($offset) 
    return isset( $this->contents[$offset] );
  

  public function offsetUnset($offset) 
    unset( $this->contents[$offset] );
  

  public function offsetGet($offset) 
    if( is_callable($this->contents[$offset]) )
      return call_user_func( $this->contents[$offset], $this );
    
    return isset( $this->contents[$offset] ) ? $this->contents[$offset] : null;
  }
  
  public function run() 
    foreach( $this->contents as $key => $content ) // Loop on contents
      if( is_callable($content) )
        $content = $this[$key];
      
      if( is_object( $content ) )
        $reflection = new ReflectionClass( $content );
        if( $reflection->hasMethod( 'run' ) )
          $content->run(); // Call run method on object
        
      }
    }
  }
}

The class implements the ArrayAccess interface:

class Simplarity_Plugin implements ArrayAccess 

This allows us to use it like PHP’s array:

$plugin = new Simplarity_Plugin();
$plugin['version'] = '1.0.0'; // Simplicity is beauty

The functions offsetSet, offsetExists, offsetUnset and offsetGet are required by ArrayAccess to be implemented. The run function will loop through the contents of the container and run the runnable objects.

To better illustrate our plugin container, let’s start by building a sample plugin.

Example Plugin: A Settings Page

This plugin will add a settings page named “Simplarity” under WordPress Admin → Settings.

Let’s go back to the main plugin file. Open up simplarity.php and add the following code. Add this below the autoloader code:

add_action( 'plugins_loaded', 'simplarity_init' ); // Hook initialization function
function simplarity_init() 
  $plugin = new Simplarity_Plugin(); // Create container
  $plugin['path'] = realpath( plugin_dir_path( __FILE__ ) ) . DIRECTORY_SEPARATOR;
  $plugin['url'] = plugin_dir_url( __FILE__ );
  $plugin['version'] = '1.0.0';
  $plugin['settings_page_properties'] = array( 
    'parent_slug' => 'options-general.php',
    'page_title' =>  'Simplarity',
    'menu_title' =>  'Simplarity',
    'capability' => 'manage_options',
    'menu_slug' => 'simplarity-settings',
    'option_group' => 'simplarity_option_group',
    'option_name' => 'simplarity_option_name'
  );
  $plugin['settings_page'] = new Simplarity_SettingsPage( $plugin['settings_page_properties'] );
  $plugin->run();

Here we use WP’s add_action to hook our function simplarity_init into plugins_loaded:

add_action( 'plugins_loaded', 'simplarity_init' );

This is important as this will make our plugin overridable by using remove_action. An example use case would be a premium plugin overriding the free version.

Function simplarity_init contains our plugin’s initialization code. At the start, we simply instantiate our plugin container:

$plugin = new Simplarity_Plugin();

These lines assign global configuration data:

$plugin['path'] = realpath( plugin_dir_path( __FILE__ ) ) . DIRECTORY_SEPARATOR;
$plugin['url'] = plugin_dir_url( __FILE__ );
$plugin['version'] = '1.0.0';

The plugin path contains the full path to our plugin, the url contains the URL to our plugin directory. They will come in handy whenever we need to include files and assets. version contains the current version of the plugin that should match the one in the header info. Useful whenever you need to use the version in code.

This next code assigns various configuration data to settings_page_properties:

$plugin['settings_page_properties'] = array(
  'parent_slug' => 'options-general.php',
  'page_title' =>  'Simplarity',
  'menu_title' =>  'Simplarity',
  'capability' => 'manage_options',
  'menu_slug' => 'simplarity-settings',
  'option_group' => 'simplarity_option_group',
  'option_name' => 'simplarity_option_name'
);

These configuration data are related to WP settings API10.

This next code instantiates the settings page, passing along settings_page_properties:

$plugin['settings_page'] = new Simplarity_SettingsPage( $plugin['settings_page_properties'] );

The run method is where the fun starts:

$plugin->run();

It will call Simplarity_SettingsPage‘s own run method.

The Simplarity_SettingsPage Class

Now we need to create the Simplarity_SettingsPage class. It’s a class that groups together the settings API functions.

Create a file named SettingsPage.php in src/Simplarity/. Open it and add the following code:

<?php
class Simplarity_SettingsPage 
  protected $settings_page_properties;

  public function __construct( $settings_page_properties )
    $this->settings_page_properties = $settings_page_properties;
  

  public function run() 
    add_action( 'admin_menu', array( $this, 'add_menu_and_page' ) );
    add_action( 'admin_init', array( $this, 'register_settings' ) );
  

  public function add_menu_and_page()  

    add_submenu_page(
      $this->settings_page_properties['parent_slug'],
      $this->settings_page_properties['page_title'],
      $this->settings_page_properties['menu_title'], 
      $this->settings_page_properties['capability'],
      $this->settings_page_properties['menu_slug'],
      array( $this, 'render_settings_page' )
    );
  
    
  public function register_settings()  
    
    register_setting(
      $this->settings_page_properties['option_group'],
      $this->settings_page_properties['option_name']
    );   
  
   
  public function get_settings_data()
    return get_option( $this->settings_page_properties['option_name'], $this->get_default_settings_data() );
  
    
  public function render_settings_page() 
    $option_name = $this->settings_page_properties['option_name'];
    $option_group = $this->settings_page_properties['option_group'];
    $settings_data = $this->get_settings_data();
    ?>
    <div class="wrap">
      <h2>Simplarity</h2>
      <p>This plugin is using the settings API.</p>
      <form method="post" action="options.php">
        <?php
        settings_fields( $this->plugin['settings_page_properties']['option_group']);
        ?>
        <table class="form-table">
          <tr>
              <th><label for="textbox">Textbox:</label></th>
              <td>
                <input type="text" id="textbox"
                  name="<?php echo esc_attr( $option_name."[textbox]" ); ?>"
                  value="<?php echo esc_attr( $settings_data['textbox'] ); ?>" />
              </td>
          </tr>
        </table>
        <input type="submit" name="submit" id="submit" class="button button-primary" value="Save Options">
      </form>
    </div>
    <?php
  
   
  public function get_default_settings_data() 
    $defaults = array();
    $defaults['textbox'] = '';
      
    return $defaults;
  
}

The class property $settings_page_properties stores the settings related to WP settings API:

<?php
class Simplarity_SettingsPage 
  protected $settings_page_properties;

The constructor function accepts the settings_page_properties and stores it:

public function __construct( $settings_page_properties )
  $this->settings_page_properties = $settings_page_properties;

The values are passed from this line in the main plugin file:

$plugin['settings_page'] = new Simplarity_SettingsPage( $plugin['settings_page_properties'] );

The run function is use to run startup code:

public function run() 
  add_action( 'admin_menu', array( $this, 'add_menu_and_page' ) );
  add_action( 'admin_init', array( $this, 'register_settings' ) );

The most likely candidate for startup code are filters11 and action hooks12. Here we add the action hooks related to our settings page.
Do not confuse this run method with the run method of the plugin container. This run method belongs to the settings page class.

This line hooks the add_menu_and_page function on to the admin_menu action:

add_action( 'admin_menu', array( $this, 'add_menu_and_page' ) );

Function add_submenu_page in turn calls WP’s add_submenu_page13 function to add a link under the WP Admin → Settings:

public function add_menu_and_page()  

  add_submenu_page(
    $this->settings_page_properties['parent_slug'],
    $this->settings_page_properties['page_title'],
    $this->settings_page_properties['menu_title'], 
    $this->settings_page_properties['capability'],
    $this->settings_page_properties['menu_slug'],
    array( $this, 'render_settings_page' )
  );


As you can see, we are pulling the info from our class property $settings_page_properties which we specified in the main plugin file.

The parameters for add_submenu_page are:

  • parent_slug: slug name for the parent menu
  • page_title: text to be displayed in the <title> element of the page when the menu is selected
  • menu_title: text to be used for the menu
  • capability: the capability required for this menu to be displayed to the user
  • menu_slug: slug name to refer to this menu by (should be unique for this menu)
  • function: function to be called to output the content for this page

This line hooks the register_settings function on to the admin_init action:

add_action( 'admin_init', array( $this, 'register_settings' ) );

array( $this, 'register_settings' ) means to call register_settings on $this, which points to our SettingsPage instance.

The register_settings then calls WP’s register_setting to register a setting:

public function register_settings()  

  register_setting(
    $this->settings_page_properties['option_group'],
    $this->settings_page_properties['option_name']
  );

Function render_settings_page is responsible for rendering the page:

public function render_settings_page() 
  $option_name = $this->settings_page_properties['option_name'];
  $option_group = $this->settings_page_properties['option_group'];
  $settings_data = $this->get_settings_data();
  ?>
  <div class="wrap">
    <h2>Simplarity</h2>
    <p>This plugin is using the settings API.</p>
    <form method="post" action="options.php">
      <?php
      settings_fields( $option_group );
      ?>
      <table class="form-table">
        <tr>
          <th><label for="textbox">Textbox:</label></th>
          <td>
            <input type="text" id="textbox"
              name="<?php echo esc_attr( $option_name."[textbox]" ); ?>"
              value="<?php echo esc_attr( $settings_data['textbox'] ); ?>" />
          </td>
        </tr>
      </table>
      <input type="submit" name="submit" id="submit" class="button button-primary" value="Save Options">
    </form>
  </div>
  <?php

We hooked render_settings_page earlier using add_submenu_page.

Function get_settings_data is a wrapper function for get_option:

public function get_settings_data()
    return get_option( $this->plugin['settings_page_properties']['option_name'] );

This is to easily get the settings data with a single function call.

Function get_default_settings_data is use to supply us with our own default values:

public function get_default_settings_data() 
  $defaults = array();
  $defaults['textbox'] = '';
  
  return $defaults;

Abstracting Our Settings Page Class

Right now our settings page class cannot be reused if you want to create another subpage. Let’s move the reusable code for the settings page to another class.

Let’s call this class Simplarity_WpSubPage. Go ahead and create the file src/Simplarity/WpSubPage.php.

Now add the code below:

<?php
abstract class Simplarity_WpSubPage 
  protected $settings_page_properties;
   
  public function __construct( $settings_page_properties )
    $this->settings_page_properties = $settings_page_properties;
  
   
  public function run() 
    add_action( 'admin_menu', array( $this, 'add_menu_and_page' ) );
    add_action( 'admin_init', array( $this, 'register_settings' ) );
  
    
  public function add_menu_and_page()  

    add_submenu_page(
      $this->settings_page_properties['parent_slug'],
      $this->settings_page_properties['page_title'],
      $this->settings_page_properties['menu_title'],
      $this->settings_page_properties['capability'],
      $this->settings_page_properties['menu_slug'],
        array( $this, 'render_settings_page' )
    );
    
  
    
  public function register_settings()  
  
    register_setting(
      $this->settings_page_properties['option_group'],
      $this->settings_page_properties['option_name']
    );
  
  
   
  public function get_settings_data()
    return get_option( $this->settings_page_properties['option_name'], $this->get_default_settings_data() );
  
   
  public function render_settings_page()
      
  
   
  public function get_default_settings_data() 
    $defaults = array();
      
    return $defaults;
  
}

Notice that it is an abstract class. This will prevent intantiating this class directly. To use it you need to extend it first with another class, which in our case is Simplarity_SettingsPage:

<?php
class Simplarity_SettingsPage extends Simplarity_WpSubPage 
    
  public function render_settings_page() 
    $option_name = $this->settings_page_properties['option_name'];
    $option_group = $this->settings_page_properties['option_group'];
    $settings_data = $this->get_settings_data();
    ?>
    <div class="wrap">
      <h2>Simplarity</h2>
      <p>This plugin is using the settings API.</p>
      <form method="post" action="options.php">
        <?php
        settings_fields( $option_group );
        ?>
        <table class="form-table">
          <tr>
              <th><label for="textbox">Textbox:</label></th>
              <td>
                  <input type="text" id="textbox"
                      name="<?php echo esc_attr( $option_name."[textbox]" ); ?>"
                      value="<?php echo esc_attr( $settings_data['textbox'] ); ?>" />
              </td>
          </tr>
        </table>
        <input type="submit" name="submit" id="submit" class="button button-primary" value="Save Options">
      </form>
    </div>
    <?php
  
   
  public function get_default_settings_data() 
    $defaults = array();
    defaults['textbox'] = '';
      
    return $defaults;
  
}

The only functions we have implemented are render_settings_page and get_default_settings_data, which are customized to this settings page.

To create another WP settings page you’ll just need to create a class and extend the Simplarity_WpSubPage. And implement your own render_settings_page and get_default_settings_data.

Defining A Service

The power of the plugin container is in defining services. A service is a function that contains instantiation and initialization code that will return an object. Whenever we pull a service from our container, the service function is called and will create the object for you. The object is only created when needed. This is called lazy initialization.

To better illustrate this, let’s define a service for our settings page.

Open simplarity.php and add this function below the Simplarity code:

function simplarity_service_settings( $plugin )
   
  $object = new Simplarity_SettingsPage( $plugin['settings_page_properties'] );
  return $object;

Notice that our service function has a $plugin parameter which contains our plugin container. This allows us to access all configuration, objects, and services that have been stored in our plugin container. We can see that the Simplarity_SettingsPage has a dependency on $plugin['settings_page_properties']. We inject this dependency to Simplarity_SettingsPage here. This is an example of dependency injection. Dependency injection is a practice where objects are designed in a manner where they receive instances of the objects from other pieces of code, instead of constructing them internally. This improves decoupling of code.

Now let’s replace this line in simplarity_init:

$plugin['settings_page'] = new Simplarity_SettingsPage( $plugin['settings_page_properties'] );

with a service definition assignment:

$plugin['settings_page'] = 'simplarity_service_settings'

So instead of assigning our object instance directly, we assign the name of our function as string. Our container handles the rest.

Defining A Shared Service

Right now, every time we get $plugin['settings_page'], a new instance of Simplarity_SettingsPage is returned. Ideally, Simplarity_SettingsPage should only be instantiated once as we are using WP hooks, which in turn should only be registered once.

To solve this we use a shared service. A shared service will return a new instance of an object on first call, on succeeding calls it will return the same instance.

Let’s create a shared service using a static variable:

function simplarity_service_settings( $plugin )
  static $object;

  if (null !== $object) 
    return $object;
  
    
  $object = new Simplarity_SettingsPage( $plugin['settings_page_properties'] );
  return $object;
}

On first call, $object is null, and on succeeding calls it will contain the instance of the object created on first call. Notice that we are using a static variable. A static variable exists only in a local function scope, but it does not lose its value when program execution leaves this scope.

That’s it.

Now if you activate the plugin, an admin menu will appear in Admin → Settings named “Simplarity”. Click on it and you will be taken to the settings page we have created.

Settings Page In Action14
Settings Page In Action

The Future: PHP 5.3+

Earlier we mentioned that our class naming convention was future-ready. In this section we will discuss how our codebase will work in PHP version 5.3 and up. Two of the best features that have graced the PHP world are namespaces and anonymous functions.

Namespaces

PHP does not allow two classes or functions to share the same name. When this happens, a name collision occurs and causes a nasty error.

With namespaces you can have the same class names as long as they live in their own namespace. A good analogy for namespaces are the folders you have in your OS. You cannot have files with the same name in one folder. However, you can have the same filenames in different folders.

With namespaces, class and function names won’t need unique prefixes anymore.

Anonymous Functions

Anonymous functions, also known as closures, allow the creation of functions which have no specified name. They are most useful as the value of callback parameters, but they have many other uses. You can also store closures in variables.

Here’s an example of closure:

<?php
$greet = function($name) 
  printf("Hello %srn", $name);
;

$greet('World');
$greet('PHP');

Using Namespaces In Classes

Let’s go ahead and use namespaces in our class definitions. Open up the following files in src/Simplarity:

  • Plugin.php
  • SettingsPage.php
  • WpSubPage.php

In each of these files, add a namespace declaration on top and remove the “Simplarity_” prefix on class names:

// Plugin.php
namespace Simplarity;

class Plugin 
...

// SettingsPage.php
namespace Simplarity;

class SettingsPage extends WpSubPage 
...

// WpSubPage.php
namespace Simplarity;

abstract class WpSubPage 
...

Since we have updated our class names we also need to update our class instantiations in simplarity.php. We do this by deleting the prefixes:

function simplarity_init() 
  $plugin = new Plugin();
  ...

...
function simplarity_service_settings( $plugin )

  ...
    
  $object = new SettingsPage( $plugin['settings_page_properties'] );
  return $object;

By default, PHP will try to load the class from the root namespace so we need to tell it about our namespaced classes. We add this to the top of simplarity.php just above the autoloader code:

use SimplarityPlugin;
use SimplaritySettingsPage;

This is called importing/aliasing with the use operator15.

Updating The Autoloader

Open up simplarity.php and change this line in the autoloader from:

$class_file = str_replace( '_', DIRECTORY_SEPARATOR, $class_name ) . '.php';

to:

$class_file = str_replace( '\', DIRECTORY_SEPARATOR, $class_name ) . '.php';

Remember that in 5.2 code we are using underscores as hierarchy separators. For 5.3+ we are using namespaces which use backslash “” as hierarchy separators. Thus we simply swap “_” for “”. We use another backslash to escape the original one: “\”.

Updating Our Service Definitions To Use Anonymous Functions

We can now replace the global functions we created for our service definitions with anonymous functions. So instead of doing this:

function simplarity_init() 
  ...
  $plugin['settings_page'] = 'simplarity_service_settings';
  ...

...
function simplarity_service_settings( $plugin )
  static $object;

  if (null !== $object) 
    return $object;
  
   
  $object = new Simplarity_SettingsPage( $plugin['settings_page_properties'] );
  return $object;
}

we can just replace this with an inline anonymous function:

function simplarity_init() 
  $plugin = new Plugin();
  ...
  $plugin['settings_page'] = function ( $plugin ) 
    static $object;
  
    if (null !== $object) 
      return $object;
    
    return new SettingsPage( $plugin['settings_page_properties'] );
  };
  ...
}

Using Pimple As A Plugin Container

Pimple is a small dependency injection (DI) container for PHP 5.3+. Pimple has the same syntax as our simple plugin container. In fact our plugin container was inspired by Pimple. In this part, we will extend Pimple and use it.

Download Pimple container from GitHub16 and save it in src/Simplarity/Pimple.php.

Open up Pimple.php and replace the namespace and the classname to:

...
namespace Simplarity;

/**
 * Container main class.
 *
 * @author  Fabien Potencier
 */
class Pimple implements ArrayAccess
...

Open up Plugin.php and replace all the code with:

<?php
namespace Simplarity;

class Plugin extends Pimple 
    
  public function run() 
    foreach( $this->values as $key => $content ) // Loop on contents
      $content = $this[$key];
      
      if( is_object( $content ) )
        $reflection = new ReflectionClass( $content );
        if( $reflection->hasMethod( 'run' ) )
            $content->run(); // Call run method on object
        
      }
    }
  }
}

Now let’s change the service definition in simplarity.php to:

$plugin['settings_page'] = function ( $plugin ) 
  return new SettingsPage( $plugin['settings_page_properties'] );
;

By default, each time you get a service, Pimple returns the same instance of it. If you want a different instance to be returned for all calls, wrap your anonymous function with the factory() method:

$plugin['image_resizer'] = $plugin->factory(function ( $plugin ) 
  return new ImageResizer( $plugin['image_dir'] );
);

Conclusion

The PHP community is big. A lot of best practices have been learned over the years. It’s good to always look beyond the walled garden of WordPress to look for answers. With autoloading and a plugin container we are one step closer to better code.

Code Samples

Resources

(dp, og, il)

Footnotes

  1. 1 https://shop.smashingmagazine.com/products/wordpress-maintenance-keeping-your-website-safe-and-efficient
  2. 2 http://codex.wordpress.org/Writing_a_Plugin
  3. 3 http://php.net/manual/en/function.require-once.php
  4. 4 http://pear.php.net/manual/en/standards.naming.php
  5. 5 https://make.wordpress.org/core/handbook/coding-standards/php/#naming-conventions
  6. 6 http://php.net/manual/en/function.spl-autoload-register.php
  7. 7 http://codex.wordpress.org/Function_Reference/plugin_dir_path
  8. 8 http://php.net/manual/en/language.constants.predefined.php
  9. 9 http://php.net/manual/en/function.realpath.php
  10. 10 http://codex.wordpress.org/Settings_API
  11. 11 http://codex.wordpress.org/Plugin_API/Filter_Reference
  12. 12 http://codex.wordpress.org/Plugin_API/Hooks
  13. 13 http://codex.wordpress.org/add_submenu_page
  14. 14 http://www.kosinix.com/wp-content/uploads/2015/02/simplarity1.png
  15. 15 http://php.net/manual/en/language.namespaces.importing.php
  16. 16 https://raw.githubusercontent.com/silexphp/Pimple/master/src/Pimple/Container.php
  17. 17 https://github.com/kosinix/simplarity
  18. 18 https://github.com/kosinix/simplarity-php53
  19. 19 http://pear.php.net/manual/en/standards.naming.php
  20. 20 http://daylerees.com/php-namespaces-explained
  21. 21 https://github.com/silexphp/Pimple

The post How To Use Autoloading And A Plugin Container In WordPress Plugins appeared first on Smashing Magazine.

Credit: 

How To Use Autoloading And A Plugin Container In WordPress Plugins

Thumbnail

Encrypting Blacklisted Words In WordPress With ROT13

Countless algorithms for encrypting data exist in computer science. One of the lesser known and less common encryptions is ROT13, a derivative of the Caesar cypher1 encryption technique.

In this tutorial, we’ll learn about ROT13 encryption and how it works. We’ll see how text (or strings) can be programmatically encoded in ROT13 using PHP. Finally, we’ll code a WordPress plugin that scans a post for blacklisted words and replaces any in ROT13 encryption.

If you own a blog on which multiple authors or certain group of people have the privilege of publishing posts, then a plugin that encrypts or totally removes inappropriate words might come in handy

Introduction

ROT13 (short for “rotate by 13 places,” sometimes abbreviated as ROT-13) is a simple encryption technique for English that replaces each letter with the one 13 places forward or back along the alphabet. So, A becomes N, B becomes O and so on up to M, which becomes Z. Then, the sequence continues at the beginning of the alphabet: N becomes A, O becomes B and so on up to Z, which becomes M.

A major advantage of ROT13 over other rot(N) techniques (where “N” is an integer that denotes the number of places down the alphabet in a Caesar cypher encryption) is that it is “self-inverse,” meaning that the same algorithm is applied to encrypt and decrypt data.

Below is a ROT13 table for easy reference.

| A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z |
--------------------------------------------------------------------------------------------------------  
| N | O | P | Q | R | S | T | U | V | W | X | Y | Z | A | B | C | D | E | F | G | H | I | J | K | L | M |

If we encrypted the domain smashingmagazine.com in ROT13, the result would be fznfuvatzntnmvar.pbz, and the sentence “Why did the chicken cross the road?” would become “Jul qvq gur puvpxra pebff gur ebnq?”

Note that only letters in the alphabet are affected by ROT13. Numbers, symbols, white space and all other characters are left unchanged.

Transforming Strings To ROT13 In PHP

PHP includes a function, str_rot13(), for converting a string to its ROT13-encoded value. To encode text in ROT13 using this function, pass the text as an argument to the function.

<?php

echo str_rot13('smashingmagazine.com'); // fznfuvatzntnmvar.pbz

echo str_rot13('The best web design and development blog'); // Gur orfg jro qrfvta naq qrirybczrag oybt

Using ROT13 In WordPress

Armed with this knowledge, I thought of ways it might be handy in WordPress. I ended up creating a plugin that encodes blacklisted words found in posts using ROT13.

The plugin consists of a textearea field (located in the plugin’s settings page) in which you input blacklisted words, which are then saved to the database for later reuse in WordPress posts.

Without further fussing, let’s start coding the plugin.

Setting Up the Plugin

First, include the plugin’s file header2.

<?php

/*
Plugin Name: Rot13 Words Blacklist
Plugin URI: http://smashingmagazine.com/
Description: A simple plugin that detects and encrypts blacklisted words in ROT13
Version: 1.0
Author: Agbonghama Collins
Author URI: http://w3guy.com
Text Domain: rot13
Domain Path: /lang/
License: GPL2
*/

As mentioned, the plugin will have a settings page with a textarea field that collects and saves blacklisted words to WordPress’ database (specifically the options table).

Below is a screenshot of what the plugin’s settings (or admin) page will look like.

Settings page of the plugin.3
(See large version4)

Now that we know what the options page will look like, let’s build it using WordPress’ Settings API5

Building the Settings Page

First, we create a submenu item in the main “Settings” menu by using add_options_page(), with its parent function hooked to admin_menu action.

add_action( 'admin_menu', 'rot13_plugin_menu' );

/**
 * Add submenu to main Settings menu
 */
function rot13_plugin_menu() 
	add_options_page(
		__( 'Rot13 Blacklisted Words', 'rot13' ),
		__( 'Rot13 Blacklisted Words', 'rot13' ),
		'manage_options',
		'rot13-words-blacklist',
		'rot13_plugin_settings_page'
	);

The fifth parameter of add_options_page() is the function’s name (rot13_plugin_settings_page), which is called to output the contents of the page.

Below is the code for rot13_plugin_settings_page().

/**
 * Output the contents of the settings page.
 */
function rot13_plugin_settings_page() 
	echo '<div class="wrap">';
	echo '<h2>', __( 'Rot13 Blacklisted Words', 'rot13' ), '</h2>';
	echo '<form action="options.php" method="post">';
	do_settings_sections( 'rot13-words-blacklist' );
	settings_fields( 'rot13_settings_group' );
	submit_button();

Next, we add a new section to the “Settings” page with add_settings_section(). The textarea field we mentioned earlier will be added to this section with add_settings_field(). Finally, the settings are registered with register_setting().

Below is the code for add_settings_section(), add_settings_field() and register_setting().

	// Add the section
	add_settings_section(
		'rot13_setting_section',
		'',
		'rot13_setting_section_callback_function',
		'rot13-words-blacklist'
	);


	// Add the textarea field to the section.
	add_settings_field(
		'blacklisted_words',
		__( 'Blacklisted words', 'rot13' ),
		'rot13_setting_callback_function',
		'rot13-words-blacklist',
		'rot13_setting_section'
	);

	// Register our setting so that $_POST handling is done for us
	register_setting( 'rot13_settings_group', 'rot13_plugin_option', 'sanitize_text_field' );

The three functions above must be enclosed in a function and hooked to the admin_init action, like so:

/**
 * Hook the Settings API to 'admin_init' action
 */
function rot13_settings_api_init() 
	// Add the section
	add_settings_section(
		'rot13_setting_section',
		'',
		'rot13_setting_section_callback_function',
		'rot13-words-blacklist'
	);


	// Add the textarea field to the section
	add_settings_field(
		'blacklisted_words',
		__( 'Blacklisted words', 'rot13' ),
		'rot13_setting_callback_function',
		'rot13-words-blacklist',
		'rot13_setting_section'
	);

	// Register our setting so that $_POST handling is done for us
	register_setting( 'rot13_settings_group', 'rot13_plugin_option', 'sanitize_text_field' );


add_action( 'admin_init', 'rot13_settings_api_init' );

Lest I forget, here is the code for the rot13_setting_callback_function() and rot13_setting_section_callback_function() functions, which will output the textarea field and the description of the field (at the top of the section), respectively.

/**
 * Add a description of the field to the top of the section
 */
function rot13_setting_section_callback_function() 
	echo '<p>' . __( 'Enter a list of words to blacklist, separated by commas (,)', 'rot13' ) . '</p>';


/**
 * Callback function to output the textarea form field
 */
function rot13_setting_callback_function() 
	echo '<textarea rows="10" cols="60" name="rot13_plugin_option" class="code">' . esc_textarea( get_option( 'rot13_plugin_option' ) ) . '</textarea>';

At this point, we are done building the settings page for the plugin.

Up next is getting the plugin to detect blacklisted words and encrypt them with ROT13.

Detecting Blacklisted Words and Encrypting in ROT13

Here is an overview of how we will detect blacklisted words in a WordPress post:

  • A post’s contents are broken down into individual words and saved to an array ($post_words).
  • The blacklisted words that were saved by the plugin to the database are retrieved. They, too, are broken down into individual words and saved to an array ($blacklisted_words).
  • We iterate over the $post_words arrays and check for any word that is on the blacklist.
  • If a blacklisted word is found, then str_rot13() encodes it in ROT13.

It’s time to create the PHP function (rot13_filter_post_content()) that filters the contents of a post and then actually detects blacklisted words and encrypts them in ROT13.

Below is the code for the post’s filter.

/**
 * Encrypt every blacklisted word in ROT13
 *
 * @param $content string post content to filter
 *
 * @return string
 */
function rot13_filter_post_content( $content ) 

	// Get the words marked as blacklisted by the plugin
	$blacklisted_words = esc_textarea( get_option( 'rot13_plugin_option' ) );

    // If no blacklisted word are defined, return the post's content.
	if ( empty( $blacklisted_words ) ) 
		return $content;
	

	else 

		// Ensure we are dealing with "posts", not "pages" or any other content type.
		if ( is_singular( 'post' ) ) 

			// Confine each word in a post to an array
			$post_words = preg_split( "/b/", $content );

			// Break down the post's contents into individual words
			$blacklisted_words = explode( ',', $blacklisted_words );

			// Remove any leading or trailing white space
			$blacklisted_words = array_map(
				function ( $arg ) 
					return trim( $arg );
				,

				$blacklisted_words
			);


			// Iterate over the array of words in the post
			foreach ( $post_words as $key => $value ) 

				// Iterate over the array of blacklisted words
				foreach ( $blacklisted_words as $words ) 

					// Compare the words, being case-insensitive
					if ( strcasecmp( $post_words[ $key ], $words ) == 0 ) 

						// Encrypt any blacklisted word
						$post_words[ $key ] = '<del>' . str_rot13( $value ) . '</del>';
					
				}
			}

			// Convert the individual words in the post back into a string or text
			$content = implode( '', $post_words );
		}

		return $content;
	}
}


add_filter( 'the_content', 'rot13_filter_post_content' );

While the code above for the filter function is quite easy to understand, especially because it is so heavily commented, I’ll explain a bit more anyway.

The is_singular( 'post' ) conditional tag ensures that we are dealing with a post, and not a page or any other content type.

With preg_split(), we are breaking down the post’s contents into individual words and saving them as an array by searching for the RegEx pattern b, which matches word boundaries6.

The list of blacklisted words is retrieved from the database using get_option(), with rot13_plugin_option as the option’s name.

From the screenshot of the plugin’s settings page above and the description of the textarea field, we can see that the blacklisted words are separated by commas, our delimiter. The explode PHP function breaks down the blacklisted words into an array by searching for those commas.

A closure7 is applied to the $blacklisted_words array via array_map() that will trim leading and trailing white spaces from the array values (the individual blacklisted words).

The foreach construct iterates over the post’s words and check whether any word is in the array of blacklisted words. Any blacklisted word that gets detected is encrypted in ROT13 and enclosed in a <del> tag.

The $post_words array is converted back to a string or text and subsequently returned.

Finally, the function is hooked to the the_content filter action.

Below is a screenshot of a post with the words “love” and “forever” blacklisted.

A post with the blacklisted word love encoded in ROT138

Wrapping Up

ROT13 is a simple encryption technique that can be easily decrypted. Thus, you should never use it for serious data encryption.

Even if you don’t end up using the plugin, the concepts you’ve learned in creating it can be applied to many situations, such as obfuscating or encrypting inappropriate words (such as profanities) in ROT13, which would be a nice feature in a forum where people have the freedom to post anything.

Hopefully, you have learned a thing or two from this tutorial. If you have any question or a contribution, please let us know in the comments.

(dp, al, il)

Front page image credit: Wikipedia9.

Footnotes

  1. 1 http://en.wikipedia.org/wiki/Caesar_cipher
  2. 2 http://codex.wordpress.org/File_Header
  3. 3 http://www.smashingmagazine.com/wp-content/uploads/2014/12/rot13-plugin-settings-page-large-opt.jpg
  4. 4 http://www.smashingmagazine.com/wp-content/uploads/2014/12/rot13-plugin-settings-page-large-opt.jpg
  5. 5 http://codex.wordpress.org/Settings_API
  6. 6 http://www.regular-expressions.info/wordboundaries.html
  7. 7 php.net/manual/en/functions.anonymous.php
  8. 8 http://www.smashingmagazine.com/wp-content/uploads/2014/11/post-with-blacklisted-word-opt.jpg
  9. 9 http://en.wikipedia.org/wiki/Caesar_cipher

The post Encrypting Blacklisted Words In WordPress With ROT13 appeared first on Smashing Magazine.

Continue reading here:  

Encrypting Blacklisted Words In WordPress With ROT13

Thumbnail

Obfuscating Blacklisted Words In WordPress With ROT13

Countless algorithms for encrypting data exist in computer science. One of the lesser known and less common encryptions is ROT13, a derivative of the Caesar cypher1 encryption technique.

In this tutorial, we’ll learn about ROT13 encryption and how it works. We’ll see how text (or strings) can be programmatically encoded in ROT13 using PHP. Finally, we’ll code a WordPress plugin that scans a post for blacklisted words and replaces any in ROT13 encryption.

If you own a blog on which multiple authors or certain group of people have the privilege of publishing posts, then a plugin that encrypts or totally removes inappropriate words might come in handy

Introduction

ROT13 (short for “rotate by 13 places,” sometimes abbreviated as ROT-13) is a simple encryption technique for English that replaces each letter with the one 13 places forward or back along the alphabet. So, A becomes N, B becomes O and so on up to M, which becomes Z. Then, the sequence continues at the beginning of the alphabet: N becomes A, O becomes B and so on up to Z, which becomes M.

A major advantage of ROT13 over other rot(N) techniques (where “N” is an integer that denotes the number of places down the alphabet in a Caesar cypher encryption) is that it is “self-inverse,” meaning that the same algorithm is applied to encrypt and decrypt data.

Below is a ROT13 table for easy reference.

| A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z |
--------------------------------------------------------------------------------------------------------  
| N | O | P | Q | R | S | T | U | V | W | X | Y | Z | A | B | C | D | E | F | G | H | I | J | K | L | M |

If we encrypted the domain smashingmagazine.com in ROT13, the result would be fznfuvatzntnmvar.pbz, and the sentence “Why did the chicken cross the road?” would become “Jul qvq gur puvpxra pebff gur ebnq?”

Note that only letters in the alphabet are affected by ROT13. Numbers, symbols, white space and all other characters are left unchanged.

Transforming Strings To ROT13 In PHP

PHP includes a function, str_rot13(), for converting a string to its ROT13-encoded value. To encode text in ROT13 using this function, pass the text as an argument to the function.

<?php

echo str_rot13('smashingmagazine.com'); // fznfuvatzntnmvar.pbz

echo str_rot13('The best web design and development blog'); // Gur orfg jro qrfvta naq qrirybczrag oybt

Using ROT13 In WordPress

Armed with this knowledge, I thought of ways it might be handy in WordPress. I ended up creating a plugin that encodes blacklisted words found in posts using ROT13.

The plugin consists of a textearea field (located in the plugin’s settings page) in which you input blacklisted words, which are then saved to the database for later reuse in WordPress posts.

Without further fussing, let’s start coding the plugin.

Setting Up the Plugin

First, include the plugin’s file header2.

<?php

/*
Plugin Name: Rot13 Words Blacklist
Plugin URI: http://smashingmagazine.com/
Description: A simple plugin that detects and encrypts blacklisted words in ROT13
Version: 1.0
Author: Agbonghama Collins
Author URI: http://w3guy.com
Text Domain: rot13
Domain Path: /lang/
License: GPL2
*/

As mentioned, the plugin will have a settings page with a textarea field that collects and saves blacklisted words to WordPress’ database (specifically the options table).

Below is a screenshot of what the plugin’s settings (or admin) page will look like.

Settings page of the plugin.3
(See large version4)

Now that we know what the options page will look like, let’s build it using WordPress’ Settings API5

Building the Settings Page

First, we create a submenu item in the main “Settings” menu by using add_options_page(), with its parent function hooked to admin_menu action.

add_action( 'admin_menu', 'rot13_plugin_menu' );

/**
 * Add submenu to main Settings menu
 */
function rot13_plugin_menu() 
	add_options_page(
		__( 'Rot13 Blacklisted Words', 'rot13' ),
		__( 'Rot13 Blacklisted Words', 'rot13' ),
		'manage_options',
		'rot13-words-blacklist',
		'rot13_plugin_settings_page'
	);

The fifth parameter of add_options_page() is the function’s name (rot13_plugin_settings_page), which is called to output the contents of the page.

Below is the code for rot13_plugin_settings_page().

/**
 * Output the contents of the settings page.
 */
function rot13_plugin_settings_page() 
	echo '<div class="wrap">';
	echo '<h2>', __( 'Rot13 Blacklisted Words', 'rot13' ), '</h2>';
	echo '<form action="options.php" method="post">';
	do_settings_sections( 'rot13-words-blacklist' );
	settings_fields( 'rot13_settings_group' );
	submit_button();

Next, we add a new section to the “Settings” page with add_settings_section(). The textarea field we mentioned earlier will be added to this section with add_settings_field(). Finally, the settings are registered with register_setting().

Below is the code for add_settings_section(), add_settings_field() and register_setting().

	// Add the section
	add_settings_section(
		'rot13_setting_section',
		'',
		'rot13_setting_section_callback_function',
		'rot13-words-blacklist'
	);


	// Add the textarea field to the section.
	add_settings_field(
		'blacklisted_words',
		__( 'Blacklisted words', 'rot13' ),
		'rot13_setting_callback_function',
		'rot13-words-blacklist',
		'rot13_setting_section'
	);

	// Register our setting so that $_POST handling is done for us
	register_setting( 'rot13_settings_group', 'rot13_plugin_option', 'sanitize_text_field' );

The three functions above must be enclosed in a function and hooked to the admin_init action, like so:

/**
 * Hook the Settings API to 'admin_init' action
 */
function rot13_settings_api_init() 
	// Add the section
	add_settings_section(
		'rot13_setting_section',
		'',
		'rot13_setting_section_callback_function',
		'rot13-words-blacklist'
	);


	// Add the textarea field to the section
	add_settings_field(
		'blacklisted_words',
		__( 'Blacklisted words', 'rot13' ),
		'rot13_setting_callback_function',
		'rot13-words-blacklist',
		'rot13_setting_section'
	);

	// Register our setting so that $_POST handling is done for us
	register_setting( 'rot13_settings_group', 'rot13_plugin_option', 'sanitize_text_field' );


add_action( 'admin_init', 'rot13_settings_api_init' );

Lest I forget, here is the code for the rot13_setting_callback_function() and rot13_setting_section_callback_function() functions, which will output the textarea field and the description of the field (at the top of the section), respectively.

/**
 * Add a description of the field to the top of the section
 */
function rot13_setting_section_callback_function() 
	echo '<p>' . __( 'Enter a list of words to blacklist, separated by commas (,)', 'rot13' ) . '</p>';


/**
 * Callback function to output the textarea form field
 */
function rot13_setting_callback_function() 
	echo '<textarea rows="10" cols="60" name="rot13_plugin_option" class="code">' . esc_textarea( get_option( 'rot13_plugin_option' ) ) . '</textarea>';

At this point, we are done building the settings page for the plugin.

Up next is getting the plugin to detect blacklisted words and encrypt them with ROT13.

Detecting Blacklisted Words and Encrypting in ROT13

Here is an overview of how we will detect blacklisted words in a WordPress post:

  • A post’s contents are broken down into individual words and saved to an array ($post_words).
  • The blacklisted words that were saved by the plugin to the database are retrieved. They, too, are broken down into individual words and saved to an array ($blacklisted_words).
  • We iterate over the $post_words arrays and check for any word that is on the blacklist.
  • If a blacklisted word is found, then str_rot13() encodes it in ROT13.

It’s time to create the PHP function (rot13_filter_post_content()) that filters the contents of a post and then actually detects blacklisted words and encrypts them in ROT13.

Below is the code for the post’s filter.

/**
 * Encrypt every blacklisted word in ROT13
 *
 * @param $content string post content to filter
 *
 * @return string
 */
function rot13_filter_post_content( $content ) 

	// Get the words marked as blacklisted by the plugin
	$blacklisted_words = esc_textarea( get_option( 'rot13_plugin_option' ) );

    // If no blacklisted word are defined, return the post's content.
	if ( empty( $blacklisted_words ) ) 
		return $content;
	

	else 

		// Ensure we are dealing with "posts", not "pages" or any other content type.
		if ( is_singular( 'post' ) ) 

			// Confine each word in a post to an array
			$post_words = preg_split( "/b/", $content );

			// Break down the post's contents into individual words
			$blacklisted_words = explode( ',', $blacklisted_words );

			// Remove any leading or trailing white space
			$blacklisted_words = array_map(
				function ( $arg ) 
					return trim( $arg );
				,

				$blacklisted_words
			);


			// Iterate over the array of words in the post
			foreach ( $post_words as $key => $value ) 

				// Iterate over the array of blacklisted words
				foreach ( $blacklisted_words as $words ) 

					// Compare the words, being case-insensitive
					if ( strcasecmp( $post_words[ $key ], $words ) == 0 ) 

						// Encrypt any blacklisted word
						$post_words[ $key ] = '<del>' . str_rot13( $value ) . '</del>';
					
				}
			}

			// Convert the individual words in the post back into a string or text
			$content = implode( '', $post_words );
		}

		return $content;
	}
}


add_filter( 'the_content', 'rot13_filter_post_content' );

While the code above for the filter function is quite easy to understand, especially because it is so heavily commented, I’ll explain a bit more anyway.

The is_singular( 'post' ) conditional tag ensures that we are dealing with a post, and not a page or any other content type.

With preg_split(), we are breaking down the post’s contents into individual words and saving them as an array by searching for the RegEx pattern b, which matches word boundaries6.

The list of blacklisted words is retrieved from the database using get_option(), with rot13_plugin_option as the option’s name.

From the screenshot of the plugin’s settings page above and the description of the textarea field, we can see that the blacklisted words are separated by commas, our delimiter. The explode PHP function breaks down the blacklisted words into an array by searching for those commas.

A closure7 is applied to the $blacklisted_words array via array_map() that will trim leading and trailing white spaces from the array values (the individual blacklisted words).

The foreach construct iterates over the post’s words and check whether any word is in the array of blacklisted words. Any blacklisted word that gets detected is encrypted in ROT13 and enclosed in a <del> tag.

The $post_words array is converted back to a string or text and subsequently returned.

Finally, the function is hooked to the the_content filter action.

Below is a screenshot of a post with the words “love” and “forever” blacklisted.

A post with the blacklisted word love encoded in ROT138

Wrapping Up

ROT13 is a simple encryption technique that can be easily decrypted. Thus, you should never use it for serious data encryption.

Even if you don’t end up using the plugin, the concepts you’ve learned in creating it can be applied to many situations, such as obfuscating or encrypting inappropriate words (such as profanities) in ROT13, which would be a nice feature in a forum where people have the freedom to post anything.

Hopefully, you have learned a thing or two from this tutorial. If you have any question or a contribution, please let us know in the comments.

(dp, al, il)

Front page image credit: Wikipedia9.

Footnotes

  1. 1 http://en.wikipedia.org/wiki/Caesar_cipher
  2. 2 http://codex.wordpress.org/File_Header
  3. 3 http://www.smashingmagazine.com/wp-content/uploads/2014/12/rot13-plugin-settings-page-large-opt.jpg
  4. 4 http://www.smashingmagazine.com/wp-content/uploads/2014/12/rot13-plugin-settings-page-large-opt.jpg
  5. 5 http://codex.wordpress.org/Settings_API
  6. 6 http://www.regular-expressions.info/wordboundaries.html
  7. 7 php.net/manual/en/functions.anonymous.php
  8. 8 http://www.smashingmagazine.com/wp-content/uploads/2014/11/post-with-blacklisted-word-opt.jpg
  9. 9 http://en.wikipedia.org/wiki/Caesar_cipher

The post Obfuscating Blacklisted Words In WordPress With ROT13 appeared first on Smashing Magazine.

View this article – 

Obfuscating Blacklisted Words In WordPress With ROT13