codeprofessor
codeprofessor

Secure Your WordPress and ClassicPress Development

If you develop WordPress or ClassicPress plugins professionally or as a side hustle, it is important to recognize security issues. With WordPress powering large swaths of the internet, code security should be a vital part of your development.

In this light, I wanted to share several key areas of security that every WordPress and ClassicPress developer should be mindful of during their development of code projects.

Don’t Let Direct Access Occur

While many web hosts are built around allowing access to files that reside on the server, we shouldn’t allow our plugin files to be accessed directly.  We need to make sure that its only “WordPress itself” that is accessing the plugin files.

The best way to handle this is to perform a conditional check at the top of the plugin files that makes sure the file isn’t being accessed from outside WordPress or ClassicPress.

<?php
if ( ! defined('ABSPATH') ) exit;

Escape the Data Anytime Output Happens

It is very important that any time we are fetching data out of the WordPress database that the data is clean and valid and isn’t going to cause harm due to unexpected output results. This security aspect goes hand-in-hand with input sanitization (talked about next). So that if we are diligent in sanitizing the input and escaping the output we can prevent vulnerabilities like XSS attacks.

WordPress is a great codebase to develop on top of because of the many functions that exist to assist in the escaping of data output.

  • wp_kses() and wp_kses_post() will strip out any untrusted HTML that might exist in the outputted data.
  • esc_attr() will encode the outputted text for use in HTML attributes.
  • esc_html() will encode the brackets/quotes/etc when outputting HTML data.
  • esc_textarea() will encode the text that is used inside textarea HTML elements.
  • esc_url() will properly encode URLs and reject invalid URLs.
  • esc_js() will escape and properly encode text string characters being echoed for Javascript.

If the heavy lifting of creating escaped and valid output data is already done with the functions listed above, there is no excuse for not taking advantage of these tools.

A quick example of functionality…

<a href="<?php echo esc_url($url_var); ?>"><?php echo esc_html($textblock); ?></a>

Sanitize Everything Being Inputted to the Site

There is a saying that any time you allow a user to input whatever they want into a form… they will do exactly that.  If we don’t sanitize inputs then we are opening our site up to XSS attacks by allowing others to manipulate posted data whether on purpose or by accident.  Therefore, we must sanitize all data that is gathered from $_GET$_POST, and $_REQUEST.

WordPress has a number of sanitization functions that should be used by all developers. You can see the list here in addition to the popular ones below:

  • sanitize_title() – Makes sure that HTML and PHP tags are stripped out of the title. (Note: this can be modified.)
  • is_email() – Makes sure the email is valid or it returns as false.
  • sanitize_text_field() – Checks to make sure its valid UTF-8, converts single characters (<) to entities, strips out all the tags, removes line breaks, tabs, and extra whitespace, and even strips octets.

Always Always Always Debug

WordPress is so large and constantly moving systems that its hard for everyone to keep up with all the deprecation notices and changes in code.  Plus, I don’t think I’ve met a single developer that has never done a “typo” or forgotten a semi-colon or just plain fell asleep during the middle of a coding marathon.  WordPress provides a debugging environment by simply adding the following line to your wp-config.php file.

define( 'WP_DEBUG', true );

But, you will notice that when you turn on debugging it will also reveal server information like file paths and other bits of knowledge that can be used by parties looking to do harm to your server/site.  We can hide the display of the notifications, warnings, and errors that WP_DEBUG provides by adding an additional line to the wp-config.php.

define( 'WP_DEBUG_DISPLAY', false );

Nonce is Your Friend

One vector of attack bad actors attempt on many websites are CSRF (Cross Site Request Forgeries) that trick site request into doing a function that wasn’t intended.  The way to combat this issue is using a nonce (Number used once). A nonce is a unique token that gets generated at the beginning of each action and timestamped so that an action can be verified both against the action request and the timestamp.

WordPress provides nonce functions like wp_nonce_url() and wp_nonce_field() that can be used on any type of form input field.  We can also verify that the nonce is valid and thereby accepting the input by using the wp_verify_nonce() function.

CURL Up and Die

If you are developing inside WordPress there is really no reason to use PHP CURL to fetching remote data because WordPress has two great functions called wp_safe_remote_get() and wp_safe_remote_post().  The best part is that not only do these functions take care of all the encoding of the data, but they also have built-in fallbacks that CURL does not.

An example of using wp_safe_remote_get() function:

<?php
$request = wp_safe_remote_get( 'https://example.com/file.json' );
if ( is_wp_error( $request )){
    return false;
}
$body = wp_remote_retrieve_body( $request );
$json = json_decode( $body );

Prepare Your Database Query

WordPress provides a database abstraction class ($wpdb) that is meant to reduce risks introduced by SQL Injection attacks.  The $wpdb class has insert() and update() methods that already escape and safely insert data into the database.

But what about getting things OUT of the database.  Most developers who are used to working with MySQL databases understand the complexity of the query() function.  So it should be a relief to all to know that WordPress provides a method of pre-preparing the query to ensure that the query is safe and escapes the variables.

An example method of using the query  and the prepare capabilities together:

<?php
$wpdb->query ( $wpdb->prepare( "DELETE FROM $wpdb->posts WHERE ID = %d;", $post_id ) );

Security is Your Responsibility

Yes, the above areas of responsible security are meant for developers. But they should also be understood by users of WordPress.  When we begin to grow beyond simply installing a plugin or theme to starting to customizing a site, it is important that we all take security seriously.  Nobody is perfect, but at least we can begin working towards getting into better habits of escaping and sanitizing data.  Or becoming more diligent in preventing unauthorized access by using built-in conditional logic statements in WordPress like current_user_can().

Do you have a security “pet peeve”? What areas of security do you find yourself wrestling with?  When was the last time you turned on WP_DEBUG on one of your sites?

Require a Specific Password Length

Many of the leading WordPress security plugins have the ability to force/require strong passwords for users. But one of the requests I’ve received from people is if there is a way to require passwords to be of a certain length. It seems that some users who work with clients are finding that some clients will reset a password to something “easier to remember” but not entirely secure, or the developer is trying to enforce a specific “password policy” and one of the aspects of a policy specifies a certain number of characters.

How to Set a Password Length Requirement

Setting a password length requirement is fairly easy since WordPress already provides a hook that occurs before a password is actually reset.  The hook is validate_password_reset, and it allows developers to verify aspects of the user-entered password before passing it through the password reset function.

Here is an example code snippet:

add_action('validate_password_reset', 'wps_password_min_length_val', 10, 2);
function wps_password_min_length_val($errors, $user){
    if( strlen($_POST['pass1-text']) < 12 ){
        $errors->add('password_too_short', 'ERROR: Password is too short.');
    }
}

The basics of this function (which can be placed in an active theme’s functions.php file or a custom plugin) are as follows:

  • The WordPress hook being used is validate_password_reset.
  • The function is comparing the value entered into the password reset box (pass1-text) and checking the length of that string (strlen) and making sure that if the entered password value is less than 12, then the following $errors will be rendered out on the screen.
  • And since there are “errors” in the password reset process, the process does not continue and returns to the screen to allow the user to try again to create a password that “passes the test.”

You can try this out on your own site by creating a test user, then proceed to reset the password with a shorter password value.

While there are plugins that may perform this functionality, if you can do it with this simple code snippet, why clutter the plugins area with unnecessary plugins.

If you enjoy or find these types of posts useful, please let me know or request a type of tutorial/code solution in the comments below.

Using Dashicons in WordPress Themes

Many WordPress users learn about using Dashicons when they go to create their first Custom Post Type and assign a Dashicon to represent that Custom Post Type in the Admin menu.  But then the frustration begins as soon as you attempt to use a Dashicon on the frontend of the site.

The developer resources at WordPress.org make it extremely easy to copy/paste either the Glyph, HTML, or CSS version of a Dashicon.  But if you have ever tried to copy/paste a Dashicon into a widget area or a post you would have experienced the frustration of nothing showing up.

Why Dashicons?

The reason the Dashicon doesn’t show up on the frontend is that the Dashicon stylesheet is not being enqueued to be used on the frontend.  So here are two code snippets you can use to start using Dashicons on your WordPress website immediately.

Add Dashicons as a Dependency

function load_my_styles(){
    wp_enqueue_style( 'mycustomstyle', get_stylesheet_uri(), 'dashicons' );
}
add_action( 'wp_enqueue_scripts', 'load_my_styles' );

Simply Enqueue Dashicon Stylesheet

function enqueue_dashicons(){
    wp_enqueue_style( 'dashicons' );
}
add_action( 'wp_enqueue_scripts', 'enqueue_dashicons' );

I hope this helps you take advantage of Dashicons in your WordPress site.  Let me know how you utilize font icons in your web development.

The Power of the Body Class in WordPress

For many WordPress users who are stepping beyond the basics of WordPress and starting to customize different parts of a site based on the site’s template hierarchy, it can get pretty daunting to figure out WHICH page template is being used to render WHICH part.  The heart of this answer is in understanding more about WordPress template hierarchy. There is even a very useful visual map to help find your way to the right template.

But this post is focused on another seldom talked about feature in WordPress that works with every properly coded theme.  I’m talking about the body class.

<body <?php body_class(); ?>>

The above code can be found in almost all WordPress themes and will output the multiple classes being used on a specific page in the HTML body element.  For example, if you were to visit a blog post page and look at the source code, you might see the HTML body element and corresponding classes that look like this:

<body class="post-template-default single single-post postid-2675 single-format-aside logged-in admin-bar no-customize-support one-col c1">

This long string of classes actually tells us a LOT about what area of a site the visitor is viewing along with other bits of information.  Now since the above example is fairly long, I’m going to pull out several of the classes to go into a deeper explanation.

  • single – This class tells us we are in a singular post.  It could be a standard blog post; it could be a single post from a custom post type.  This also tells us that the web page is not a feed or archive view.
  •  single-post – This class tells me we are on a singular post from the “post” custom post type.  If we had a custom post type called “reports”, this class would appear as single-reports.
  • postid-2675 – This class is generated by the actual Post ID of the post.  For example, if you wanted to apply some CSS style to this specific post, you could target .postid-2675{color:#ff2200;} (or something along those lines).
  • single-format-aside – This class indicates that the post being displayed is a single post that is using the Post Format Aside.
  • logged_in – This class will show up in the body class for any user that is actively logged into the site.

There are also additional classes in the above HTML body element example that are more theme specific to indicate the number of columns, custom layout options, and more.  Other types of classes you might see, depending on the page being referenced: homepageblogarchivecategoryauthor, etc.

The ability to identify and decode the information contained within the string of HTML body element classes can assist any developer in not only being able to target specific views but also can grant knowledge as to which template file a view is using within the theme.

Helpful Information for the Voce Theme

The Voce Theme has a custom solution based on a conditional logic that helps serve up different template files based upon core WordPress template hierarchy.  The simple response is that everything, every view and location on the site, is served through the index.php template file in the theme folder. But if you were to dig into the actual PHP files, you would see that there is a solitary function in the index.php file…. wpsvoce().  While this post won’t go into how this function works, I will say that this function builds and renders the layout structure that you see and use for your WordPress sites.

At this point, we as WordPress developers, really need to understand the basics of template hierarchy.  But for the purpose of this post, I’ll be focusing solely on how this relates to the Voce Theme and how we can interpret the above HTML body element classes to find the correct page template to edit.

Reminder: Never edit the /voce-theme/ (parent theme) files.  Always copy a page template file to your child theme’s /templates/ folder.  If no /templates/ folder exists in the child theme you can simply create one.

Hierarchy is important in any WordPress theme and especially with the Voce Theme.  At the base level, everything falls to the content.php file in the templates directory.  All the other content-***.php files are based on several conditions.

  • Sometimes the theme will look for Post Formats being used.  Example: content-quote.php would be used to display any post that contains the Quote post format option.  If a post contains the Quote post format option and WordPress is unable to find a content-quote.php file, then it will attempt to display the post using the base content.php file.
  • Sometimes the theme will be displaying an Archive page, and in this example, WordPress will be looking for the content-archive.php template file.  If that file is not found, then the post will be displayed using the content.php file.
  • Sometimes the theme will be on a WordPress Page, and so WordPress will be looking for the content-page.php template file.  If that file is not found, then the page will be displayed using the content.php template file.

If you want to dig a little deeper and see exactly how the Voce Theme makes a choice as to which template part is loaded, you can look at the loops.php file in the parent theme folder.  You can look for the get_template_part(‘template/content’, **********); code to identify which conditional is loading which template file.

So what does this mean for customizing the look of content?

If you were to look at the HTML body element list of classes and see a CSS class of single-post.  You can be sure that WordPress will be looking for the content-single.php template file to render that content.  And the way template hierarchy works is that WordPress will first look in the child theme for that /templates/content-single.php template file and if it doesn’t find that template file in the child theme, WordPress will look for the /templates/content-single.php template file in the parent theme.

Now, this is where it gets a little more complicated because if both of those file locations are not found, the Voce Theme then starts looking in the child theme for /templates/content.php and if not found look for the /templates/content.php in the parent theme.

What template files are included by default in the Voce Theme?

  • content.php – Lowest level fallback method of displaying content if no other template file is found.
  • content-archive.php – This is used by any archive view.
  • content-aside.php – This is used when a specific post has the Post Format Aside assigned to it.
  • content-attachment.php – This is used to display a specific attachment page.
  • content-page.php – This is used to display any page (WordPress Pages).
  • content-quote.php – This is used when a specific post has the Post format Quote assigned to it.
  • content-search.php – This is used when a search result is rendered.
  • content-single.php – This is used for single post pages.
  • content-status.php – This is used when a specific post has the Post Format Status assigned to it.
  • no-results.php –  When no post is found from the query (but the URL is valid) this template is used.
  • 404.php – This is used when an invalid URL is used. 404 Error.

Anytime you want to make modifications to any of these files; you should copy/paste a copy of that file into your child theme’s /templates/ folder.

Eliminate the JUMP from WordPress Read More Link

WordPress has a method of splitting your content to only show the “top half” on the is_home() conditional location.  (This is normally the “Blog” feed page in WordPress.  It could be your homepage, or it could be a custom page depending on your theme and setup.)  This “splitting method” is called the “Read More” link.

The “Read More” link is identified as <!--more-->  in the code/content area of your WordPress post/page.  The location in your post content that contains this “Read More” link will return an active link from the blog feed to the full post page.  What happens next when a reader clicks on the “Read More” link presents the “issue” that WordPress owners experience.

The “Read More” link jumps to the place in the code where the <!–more–> tag had been placed, essentially chopping off the top of the post.  While some themes and designs may not be bothered by this experience, many developers create custom user experiences that differ from the blog feed and the individual post page.  Therefore the “Read More” link jump can be a jolting feeling for the readers.

The following piece of code can be placed in the active theme’s functions.php file and will remove the jumping element of the “Read More” link.  This code snippet will provide a straight link directly to the post page allowing for the intended theme experience to occur.

function eliminate_readmore_jump( $link ){
    $offset = strpos( $link, '#more-' );
    if ($offset) {
        $end = strpos($link, '"', $offset);
    }
    if ($end) {
        $link = substr_replace($link, '', $offset, $end-$offset);
    }
    return $link;
}
add_filter('the_content_more_link', 'eliminate_readmore_jump');

An example of when this code might be useful would be when a featured image is only used on the full single post page but not on the blog feed.  If the “Read More” jump process bypasses the visual experience of the featured image the effect of the blog could be diminished.

Take Control of the WordPress Auto-Paragraph Tag

WordPress has a function called wpautop() that very kindly “autowraps” and adds paragraph tags (<p></p>) around elements of your content.  While this is extremely helpful for users, those that may be more unfamiliar with HTML and those that only want to use WordPress as a content publishing platform.  Those users that desire more control over the structure of the site may want to manage what elements exist or don’t exist in the content structure.

For a long time, WordPress users have had access to filtering out the wpautop() function by adding a simple line of code to their functions.php file of their active theme folder.

remove_filter( 'the_content', 'wpautop' );

But the above code can also leave users with an unintended issue.  This code snippet will remove ALL the auto-inserted paragraph tags.  To truly have control over when and where this wpautop() function interacts with content, we need to be able to manage this on an individual post/page level.

This is where WordPress’ Custom Fields come to the rescue. If you do not see a metabox on your post/page editor screen, you may need to enable the metabox to be visible from within the Screen Options located inside the drop-down tab in the upper right of your screen window.

Once you enable Custom Fields by checking the box, you will see a new metabox appear in the edit post/page area.

custom fields

From within this metabox, we can press the “Enter New” link to create a newly named unique field. In the “Name” input box enter the text wpautop.  (Side Note: After your initial time of adding the wpautop value to the Name input box, all proceeding attempts to add this field can be done through the drop-down box.) Then in the corresponding value box located to the right, enter the text false.  Now the metabox name and value should look like the following image.

Once you save your post/page this Custom Field value is now stored in the postmeta of this specific post ID… which means that in our code we can identify whether a certain post ID has a Custom Field that is declaring wpautop => false.  We do this “conditional check” in a small function that is placed in the functions.php file of your active WordPress theme folder.

function wpautop_filter_control( $content ){
    if ( get_post_meta( get_the_ID(), 'wpautop', true) == 'false' ){
        return $content;
    } else {
        return wpautop($content);
    }
}
remove_filter( 'the_content', 'wpautop' );
add_filter( 'the_content', 'wpautop_filter_control' );

The above code snippet will now check to see whether the active post ID has the wpautop custom field value set to false.  If it finds that particular custom field setting exists, it will return the_content without the wpautop() function running on the content.  If that exact custom field setting is not found, then the_content is returned after running wpautop on the content.

Now you have complete control over disabling wpautop() function on a per-post basis.

Use CSS Columns for Better Content Layout

Have you ever been browsing a website and wonder… how did they do that?  This is one of the things that are asked a lot in the WPStudio membership.  This past week one of our members was on a British news site and asked if the section displayed in the image below could be done in CSS?

There are three CSS properties that allow developers to take a straight block of code and allow it to display like the above image.

  • column-count –  this property specifies the number of columns an element should be divided into.  By setting this property with a number, CSS will auto-divide the element (unless additional properties like column-width are declared).
  • column-gap – this property specifies the gap (spacing) between the columns.
  • column-rule – this property can set the width, style, and color of the rule (line) that appears between the columns (in the gap).
    • width – Options include: medium, thin, thick, and length (pixel width etc)
    • style – Options include: none, hidden, dotted, dashed, solid, double, groove, ridge, inset, outset.
    • color – Options include any CSS color value.

Now let us look at a piece of example CSS that would be applied to the “content” area to make any wrapped code layout like the above screenshot image.

.content {
  background-color: #00ffff;
  padding: 15px;
  column-count: 2;
  column-gap: 50px;
  column-rule-style: solid;
  column-rule-width: 1px;
}

Yes, it is as simple as that.  But if you really want to utilize these CSS columns in your site’s content it is important to also consider the responsive requirements for mobile devices.  If you were to leave these column-count declarations the display of the content area would have multiple columns on your mobile device making the content difficult to read.  You can use media queries to adjust the column-count to make the content’s readability much better.

@media screen and (max-width:480px){
  .content {
    column-count: 1;
  }
}

By setting the column-count property to 1 the other column properties are no longer necessary since no gaps exist.  The content that displayed in columns for regular browsers now will show as a single column on a mobile device.  Remember that the same concept can be applied to media-queries that target extremely large screens as you can add even more columns.

How do you use CSS column properties?  And if you want to read more about different CSS properties and different ways to use them in layout design, let me know in the comments below.

Create a Shortcode for Mobile Content

Recently it was asked if there was an easy way to use a WordPress shortcode to easily hide or show wrapped content on mobile devices.  While there are numerous plugins and even a few themes that offer this functionality out of the box, there can be issues when you change a plugin or theme.  So I put together some basic code that can be placed in either the active theme’s functions.php file or placed in a plugin you may use on your WordPress website.

The two pieces of code below will enable two shortcodes to be used on your WordPress sites:

[hide_from_mobile]Content you want hidden from mobile browsers.[/hide_from_mobile]

&

[show_if_mobile]This content will only show on mobile browsers.[/show_if_mobile]

The two pieces of code are as follows:

function wps_hide_from_mobile_shortcode( $atts, $content = '' ){
  if ( wp_is_mobile() === true ) {
    $content = '';
  }
  return $content;
}
add_shortcode( 'hide_from_mobile', 'wps_hide_from_mobile_shortcode' );

and

function wps_show_if_mobile_shortcode( $atts, $content = '' ){
  if ( ! wp_is_mobile() === true ) {
    $content = '';
  }
  return $content;
}
add_shortcode( 'show_if_mobile', 'wps_show_if_mobile_shortcode' );

 

Only Allow Administrators Access to Admin Area

For many WordPress developers, building a website where there is only a content producer who is going to access the Admin area of WordPress is fairly easy.  You know beforehand which users will have access and you can prepare and lock down the site accordingly.  The “fun” begins with you begin allowing visitors / users / customers / clients to register for accounts on the WordPress site.

That’s when THIS begins to happen for users…

 

Why should your subscribers even be allowed to see the “underbelly” of WordPress (as described by my older neighbor).  Yes, you probably want to offer the ability to update the profile information for subscribers, but most developers are going to do that on the front end of the site, in an area that is much easier to style.  And while most “front end user profile” WordPress plugins may redirect logged-in users to their new better looking profile/account pages, many of them don’t block access to the Admin area.

This where the good stuff happens.  The following code does two things.  It first checks to make sure the current user is NOT an Administrator and checks to see if that current user is trying to access any of the Admin pages in WordPress (essentially the /wp-admin/ folder).  If the code decides you shouldn’t have access it simply redirects the page load to go to the homepage.

function wps_redirect_non_admin_users(){
  if ( !current_user_can('manage_options') && '/wp-admin/admin-ajax.php' != $_SERVER['PHP_SELF'] ){
    wp_redirect(home_url());
    exit;
  }
}
add_action('admin_init', 'wps_redirect_non_admin_users');

You can adjust the “location” of the redirection by changing the home_url() to a different URL.

This is an excellent code snippet to save and/or use for all your sites that you are working to “lock down” and protect your users from having access to the admin areas of WordPress.