ClassicPress Plugin Development: Develop for Accessibility

ClassicPress PluginsThis post is part of the ClassicPress Plugin Development series n which I am going to look at both best practice for developing plugins and how I approach some requirements as well as some of the functions I commonly use.

in the last post, I discussed how plugins should be developed for them to be translated (internationalization); you should also develop for accessibility (often abbreviated as a11y as there are 11 letters between the letters l and n.

The A11y Project website has a lot of good resources which can help get you started with developing for accessibility and as they say, on their about page, "[a]ccessibility is incredibly important, yet often overlooked in traditional digital design and development education...".

Unfortunately, this post is more of a "do as I say, not as I do" because I have nt been developing with accessibility in mind. There are certain ways of coding which I have picked up in the past whic do fit the accessibility patterns, but this is more fortuitous happenstance than deliberate design. It recently came up on the ClassicPress Forum when Marco Zehe joined the community.

Reading an interview he did with Deborah Edwards-Onoro of Lireo Designs this reiterated that accessibility should not just be a nice to have, but a requirement as without it, sites will not be accessible to many users. One of the reasons he gave for looking at ClassicPress is the forced introduction of the block editor (formerly Gutenburg editor) into WordPress which has many series accessibility problems.

Plugins form a major part of the ClassicPress, and WordPress, ecosystems with many of them outputting content to users and this should always be done in an accessible way; it's not just the front end content which needs to be accessible, it is also the settings pages in the admin dashboard.

As with internationalization, adding accessibility to an existing plugin will take a lot more effort than designing and coding the plugin for accessibility from the start. This is a task which I have added to my development list to look at as soon as possible; unfortunately with a lot of ClassicPress plugins this is not going to be a small task.

The A11Y Project website has links to a lot of resources to help with accessibility design including a checklist.

ClassicPress Plugin Development: Develop for Translation

ClassicPress PluginsThis post is part of the ClassicPress Plugin Development series in which I am going to look at both best practice for developing plugins and how I approach some requirements as well as some of the functions I commonly use.

When developing plugins for ClassicPress, you should plan and develop for the plugin to be translatable. There are many posts on translation of plugins for WordPress which will also apply to ClassicPress. I did a series in late 2019 on ClassicPress Plugin Development where I covered the why and how of developing plugins so they can be translated.

Two key terms in this process are internationalization (often abbreviated as i18n as there are 18 letters between the letters i and n) which is the process of developing a plugin so it can easily be translated into other languages and localization (often abbreviated as l10n as there are 10 letters between the letters l and n) is the process of translating an internationalized plugin.

Developing your plugins using the principles of internationalization, allows other to localize your plugin by translating it into their language. Plugins I develop are all in English, as that is my primary language, but having internationalized them during developed, anyone can now translate them into the language used by their site without needing to modify any code.

As I noted in this post, when I started developing plugins I did not internationalize any of the strings and then had to go back and find every single string in all the plugins, but new plugins I internationalize from the start and this takes far less effort overall.

Internationalizing your plugins will widen the market for your plugin to countries outside of those which use your language.

ClassicPress Plugin Development: Add an index.php to Every Folder

ClassicPress PluginsThis post is part of the ClassicPress Plugin Development series in which I am going to look at both best practice for developing plugins and how I approach some requirements as well as some of the functions I commonly use.

Putting an index.php in every folder is technically required and websites should be configured to disallow directory browsing anyway, but as plugins will e used by many different people, I would generally call putting one into every folder best practice as your plugin could be installed on a website which is allowing directory browsing and this will stop people seeing a list of the files.

Classicpress itself uses an index.php file to stop directory browsing:

<?php
// Silence is golden.

There is no requirement for the file to include any code or text, but in all of my plugins I use a file similar to the above in every folder.

ClassicPress Plugin Development: Format of a Plugin Header

ClassicPress PluginsThis post is part of the ClassicPress Plugin Development series in which I am going to look at both best practice for developing plugins and how I approach some requirements as well as some of the functions I commonly use.

As with the readme.txt file, the main plugin file needs a header containing information related to the plugin. The bare minimum which is needed in the header is the plugin name:

/**
 * Plugin Name: {plugin name}
 */

The fields which can be used are:

  • Plugin Name: The name of your plugin, which will be displayed in the Plugins list in the ClassicPress admin dashboard.
  • Plugin URI: The unique home page of the plugin
  • Description: A short description of the plugin which will be displayed in the Plugins section in the admin dashboard. It should be shorter than 140 characters.
  • Version: The current version number of the plugin, such as 1.0.0 or 1.0.3.
  • Requires at least: The lowest ClassicPress version that the plugin will work on.
  • Requires PHP: The minimum required PHP version.
  • Author: The name of the plugin author (separate multiple authors with commas).
  • Author URI: The author’s website or profile on another website.
  • License: The short name (slug) of the plugin’s license (e.g. GPLv2).
  • License URI: A link to the full text of the license (e.g. https://www.gnu.org/licenses/gpl-2.0.html).
  • Text Domain: The gettext text domain of the plugin. More information can be found in the Text Domain section of the How to Internationalize your Plugin page.
  • Domain Path: The domain path tells ClassicPress where to find the translations.

The below example is what I use for my plugins:

/**
 * ------------------------------------------------------------------------------
 * Plugin Name: {plugin name}
 * Description: {short description}
 * Version: {version}
 * Author: {author}
 * Author URI: {author url}
 * Plugin URI: {plugin url}
 * Text Domain: {text domain}
 * Domain Path: {domain path}
 * ------------------------------------------------------------------------------
 * This is free software released under the terms of the General Public License,
 * version 2, or later. It is distributed WITHOUT ANY WARRANTY; without even the
 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Full
 * text of the license is available at https://www.gnu.org/licenses/gpl-2.0.html.
 * ------------------------------------------------------------------------------
 */

In the above example, the text in braces {} would be replaced with the required text.

ClassicPress Plugin Development: Format of a Plugin readme.txt

ClassicPress PluginsThis post is part of the ClassicPress Plugin Development series in which I am going to look at both best practice for developing plugins and how I approach some requirements as well as some of the functions I commonly use.

A ClassicPress plugin should have a readme.txt file. A readme file is where you "sell" your plugin, it's features and benefits and why users would want to use it over the competition. Being clear and concise in your explanations will be of benefit.

This file explains what the plugin does, what features it has and is used to present this and other information to the users when they view the plugin details page through their ClassicPress site. This is an example of the plugin details for my SMTP plugin:

Plugin details page

As you can see the user first sees the description, but there are a number of other tabs available as well, which are configured in the readme file which are created using a form of Markdown which allows the file to be human readable no matter how it is viewed (unlike HTML markup).

At the basic level, a plugin file does not need to contain much information. Below is an example of the template used by the Update Manager I use for updating my plugins (while the ClassicPress Directory is in development:

=== Plugin Name Here ===

Version:           1.0.0
Requires:          1.0.0
Download link:     https://

== Description ==

This text displays in the modal windows; it is required. Write something!

Continue reading "ClassicPress Plugin Development: Format of a Plugin readme.txt"

ClassicPress Plugin Development: Structure of a Plugin

ClassicPress PluginsThis post is part of the ClassicPress Plugin Development series in which I am going to look at both best practice for developing plugins and how I approach some requirements as well as some of the functions I commonly use.

Before you start developing a plugin, I'd recommend deciding on the plugin structure you want to use. At the simplest level, a plugin only actually requires the file which holds enough code for the plugin and the folder it sits within, but in reality you will have other files which are needed as well, such as style sheets, language files, images and so on.

Planning a structure for the plugin will ensure your plugin files are well organised which will make it easier to work with both now and again in future.

John Alarcon of Code Potent, did a blog post on this subject a while ago. I use a structure fairly similar to the one he described, and have used the same format for showing the structure I use.

Continue reading "ClassicPress Plugin Development: Structure of a Plugin"

ClassicPress Plugin Development: Using Namespaces

ClassicPress PluginsThis post is part of the ClassicPress Plugin Development series in which I am going to look at both best practice for developing plugins and how I approach some requirements as well as some of the functions I commonly use.

In the last post in this series, on whether to use namespaces, I discussed whether they should be used or not and noted that I do not currently use them, but am debating whether I should.

At present, the azrcrv_tt_post_tweet function in my To Twitter plugin is called from a few other plugins in order to send a tweet; the function calls looks like this:

$tweet_result = azrcrv_tt_post_tweet($parameters);

This calls this function:

function azrcrv_tt_post_tweet($parameters){

If I was to update my plugins to use namespaces, in the To Twitter plugin a namespace would be added to the top of the PHP file (only the opening PHP tags and any comments should be before the namespace declaration). If I do make this change, I would use a developer and plugin specific namespace:

namespace azurecurve\ToTwitter;

The function to post the tweet, and all other functions, could then be renamed to remove the current developer and plugin specific prefixes thusly:

function post_tweet($parameters){

The other plugins which call this function, would need the function call to be amended to include the namespace:

$tweet_result = \azurecurve\ToTwitter\post_tweet($parameters);

With namespaces, it is possible to use a function name which matches that in the global namespace. For example, the get_option function is a standard ClassicPress function used to get the options for a plugin. I can create a function with the same name in a plugin without a conflict.

Calling the below will call the function in the plugin:

$options = get_option('azrcrv-tt');

To call the standard ClassicPress version in the global namespace I would prefix the function call with a \:

$options = \get_option('azrcrv-tt');

The final point to handle, is if you are using a ClassicPress hook such as add_action you are passing a string which will be executed in the global namespace so you need to pass the namespace of your plugin as part of the hook:

add_action('admin_menu', 'azurecurve\ToTwitter\create_admin_menu');

There is a predefined PHP constant available which you can use to avoid putting your namespace in many parts of your plugin; this can be useful in future if you need to change your namespace, as you then ony need to change the declaration at the top of the plugin:

add_action('admin_menu', __NAMESPACE__.'\create_admin_menu');

The same principles would apply PHP classes as well, but as I said in the coding paradigms blog post, I am not developing using object oriented programming and so am not covering classes.

ClassicPress Plugin Development: To Use Namepsaces or Not

ClassicPress PluginsThis post is part of the ClassicPress Plugin Development series in which I am going to look at both best practice for developing plugins and how I approach some requirements as well as some of the functions I commonly use.

Namespaces are a standard feature of PHP, post version 5.2. A namespace is a way of addressing the problem of isolation. For example, if you have a function called load_cs in one part of your code, then you cannot use the same name elsewhere. For ClassicPress this also means that having that function in one plugin, you cannot have the same name in another plugin.

To avoid this problem with ClassicPress, the common approach is to prefix function names (and class names) with a developer and plugin specific prefix; I typically use azrcrv_{nn}_ where the highlighted section is one to four letters to represent the specific plugin (e.g. e for Events, uam for Update Admin Menu or smtp for SMTP).

John Alarcon, Code Potent, uses namespaces in all of his plugins so does not need to use developer and plugin specific prefixes; instead he uses a developer and plugin name namespace. For example, the PHP Error Log Viewer uses the following namespace declaration:

// Declare the namespace.
namespace CodePotent\PhpErrorLogViewer;

I started developing plugins for WordPress (back in 2013) before namespaces were introduced to PHP and have never adopted them. I rewrote my WordPress plugins specifically for ClassicPress in 2019 after I migrated all of my sites, but did not adopt namespaces. Partly this was to maintain some backward compatibility as some of the plugins have functions which are intended to be called from outside the plugin (such as URL Shortener which is typically called to display the shortlink in a theme) and partly because at the time I didn't especially see the benefit.

As time has passed and I've created more plugins, I am thinking that was a mistake and I should have introduced namespaces when I did the ClassicPress rewrite; if I make this change now to existing plugins, this would, under semver, be a breaking change necessitating a major version number increase.

If you are starting off developing for ClassicPress, I would encourage you to seriously consider using namespaces in your development of plugins.

ClassicPress Plugin Development: Coding Standards

ClassicPress PluginsThis post is part of the ClassicPress Plugin Development series in which I am going to look at both best practice for developing plugins and how I approach some requirements as well as some of the functions I commonly use.

In the last post, I covered using semantic versioning or (semver) when developing plugins for ClassicPress.

When developing plugins, ClassicPress largely uses the same coding standards as WordPress:

From the coding standard links above, I do follow the ones for HTML and CSS pretty much 100%, but the PHP one has a few items for which I take a slightly different approach. The idea behind coding standards is to make code readable to other people, so I largely take the view that if there is part of the standard you don't like, then as long as you're consistent in how you break the standard, code will still be readable.

The above opinion on adhering to coding standards is in reference to greenfield development; if contributing to an existing plugin, code to the standards used for that plugin. If contributing to core, then adhere to the standards as written.

ClassicPress Plugin Development: Semantic Versioning 2.0

ClassicPress PluginsThis post is part of the ClassicPress Plugin Development series in which I am going to look at both best practice for developing plugins and how I approach some requirements as well as some of the functions I commonly use.

When developing plugins for ClassicPress, you need to develop using semantic versioning (or semver) as this will be a requirement of the ClassicPress Directory.

Semantic Versioning is a versioning scheme for using meaningful version numbers which can be used to avoid incompatibilities.

semver version numbering works using three segments:

  1. MAJOR version when you make breaking changes where users will need to take some action during an upgrade.
  2. MINOR version when you add functionality in a backwards compatible manner which users can simply apply without taking any other action.
  3. PATCH version when you make backwards compatible bug fixes which, like MINOR versions users can apply without taking any other action.

One key point to note when using semver, is that when a versioned release has been made, nothing in that release can be changed; a new version with incremented number must be released instead.

Additional labels for pre-release and build metadata are available as extensions to the MAJOR.MINOR.PATCH format; pre-release versions often have a MAJOR version number of 0. When a plugin is ready for release to production it should be released as version 1.0.0.

Continue reading "ClassicPress Plugin Development: Semantic Versioning 2.0"