Technology Tales

Notes drawn from experiences in consumer and enterprise technology

TOPIC: AUTOMATTIC

Hardening WordPress on Ubuntu and Apache: A practical layered approach

1st March 2026

Protecting a WordPress site rarely depends on a single control. Practical hardening layers network filtering, a web application firewall (WAF), careful browser-side restrictions and sensible log-driven tuning. What follows brings together several well-tested techniques and the precise commands needed to get them working, while also calling out caveats and known changes that can catch administrators out. The focus is on Ubuntu and Apache with ModSecurity and the OWASP Core Rule Set for WordPress, but complementary measures round out a cohesive approach. These include a strict Content Security Policy, Cloudflare or Nginx rules for form spam, firewall housekeeping for UFW and Docker, targeted network blocks and automated abuse reporting with Fail2Ban. Where solutions have moved on, that is noted so you do not pursue dead ends.

The Web Application Firewall

ModSecurity and the OWASP Core Rule Set

ModSecurity remains the most widespread open-source web application firewall and has been under the custodianship of the OWASP Foundation since January 2024, having previously been stewarded by Trustwave for over a decade. It integrates closely with the OWASP Core Rule Set (CRS), which aims to shield web applications from a wide range of attacks including the OWASP Top Ten, while keeping false alerts to a minimum. There are two actively maintained engines: 2.9.x is the classic Apache module and 3.x is the newer, cross-platform variant. Whichever engine you pick, the rule set is the essential companion. One important update is worth stating at the outset: CRS 4 replaces exclusion lists with plugins, so older instructions that toggle CRS 3's exclusions no longer apply as written.

Installing ModSecurity on Ubuntu

On Ubuntu 24.04 LTS, installing the Apache module is straightforward. The universe repository ships libapache2-mod-security2 at version 2.9.7, which meets the 2.9.6 minimum required by CRS 4.x, so no third-party repository is needed. You can fetch and enable ModSecurity with the following commands:

sudo apt install libapache2-mod-security2
sudo a2enmod security2
sudo systemctl restart apache2

It is worth confirming the module is loaded before you proceed:

apache2ctl -M | grep security

The default configuration runs in detection-only mode, which does not block anything. Copy the recommended file into place and then edit it so that SecRuleEngine On replaces SecRuleEngine DetectionOnly:

sudo cp /etc/modsecurity/modsecurity.conf-recommended /etc/modsecurity/modsecurity.conf

Open /etc/modsecurity/modsecurity.conf and make the change, then restart Apache once more to apply it.

Pulling in the Core Rule Set

The next step is to pull in the latest Core Rule Set and wire it up. A typical approach is to clone the upstream repository, move the example setup into place and move the directory named rules into /etc/modsecurity:

cd
git clone https://github.com/coreruleset/coreruleset.git
cd coreruleset
sudo mv crs-setup.conf.example /etc/modsecurity/crs-setup.conf
sudo mv rules/ /etc/modsecurity/

Now adjust the Apache ModSecurity include so that the new crs-setup.conf and all files in /etc/modsecurity/rules are loaded. On Ubuntu, that is governed by /etc/apache2/mods-enabled/security2.conf. Edit this file to reference the new paths, remove any older CRS include lines that might conflict, and then run:

sudo systemctl restart apache2

On Ubuntu 26.04 (due for release in April 2026), the default installation includes a pre-existing CRS configuration at /etc/modsecurity/crs/crs-setup.conf. If this is left in place alongside your own cloned CRS, Apache will fail to start with a Found another rule with the same id error. Remove it before restarting:

sudo rm -f /etc/modsecurity/crs/crs-setup.conf

WordPress-Specific Allowances in CRS 3

WordPress tends to work far better with CRS when its application-specific allowances are enabled. With CRS 3, a variable named tx.crs_exclusions_wordpress can be set in crs-setup.conf to activate those allowances. The commented "exclusions" block in that file includes a template SecAction with ID 900130 that sets application exclusions. Uncomment it and reduce it to the single line that enables the WordPress flag:

SecAction 
 "id:900130,
  phase:1,
  nolog,
  pass,
  t:none,
  setvar:tx.crs_exclusions_wordpress=1"

Reload Apache afterwards with sudo service apache2 reload. If you are on CRS 4, do not use this older mechanism. The project has replaced exclusions with a dedicated WordPress rule exclusions plugin, so follow the CRS 4 plugin documentation instead. The WPSec guide to ModSecurity and CRS covers both the CRS 3 and CRS 4 approaches side by side if you need a reference that bridges the two versions.

Log Retention and WAF Tuning

Once the WAF is enforcing, logs become central to tuning. Retention is important for forensics as well as for understanding false positives over time, so do not settle for the default two weeks. On Ubuntu, you can extend Apache's logrotate configuration at /etc/logrotate.d/apache2 to keep weekly logs for 52 weeks, giving you a year of history to hand.

If you see Execution error – PCRE limits exceeded (-8) in the ModSecurity log, increase the following in /etc/modsecurity/modsecurity.conf to give the regular expression engine more headroom:

SecPcreMatchLimit 1000000
SecPcreMatchLimitRecursion 1000000

File uploads can generate an Access denied with code 403 (phase 2). Match of "eq 0" against "MULTIPART_UNMATCHED_BOUNDARY" required error. One remedy used in practice is to comment out the offending check around line 86 of modsecurity.conf and then reload. The built-in Theme Editor can trigger Request body no files data length is larger than the configured limit. Bumping SecRequestBodyLimit to 6000000 addresses that, again followed by a reload of Apache.

Whitelisting Rule IDs for Specific Endpoints

There are occasions where whitelisting specific rule IDs for specific WordPress endpoints is the most pragmatic way to remove false positives without weakening protection elsewhere. Creating a per-site or server-wide include works well; on Ubuntu, a common location is /etc/apache2/conf-enabled/whitelist.conf. For the Theme Editor, adding a LocationMatch block for /wp-admin/theme-editor.php that removes a small set of well-known noisy IDs can help:

<LocationMatch "/wp-admin/theme-editor.php">
  SecRuleRemoveById 300015 300016 300017 950907 950005 950006 960008 960011 960904 959006 980130
</LocationMatch>

For AJAX requests handled at /wp-admin/admin-ajax.php, the same set with 981173 added is often used. This style of targeted exclusion mirrors long-standing community advice: find the rule ID in logs, remove it only where it is truly safe to do so, and never disable ModSecurity outright. If you need help finding noisy rules, the following command (also documented by InMotion Hosting) summarises IDs, hostnames and URIs seen in errors:

grep ModSecurity /usr/local/apache/logs/error_log | grep "[id" | 
  sed -E -e 's#^.*[id "([0-9]*).*hostname "([a-z0-9-_.]*)"].*uri "(.*?)".*"#1 2 3#' | 
  cut -d" -f1 | sort -n | uniq -c | sort -n

Add a matching SecRuleRemoveById line in your include and restart Apache.

Browser-Side Controls: Content Security Policy

Beyond the WAF, browser-side controls significantly reduce the harm from injected content and cross-site scripting. A Content Security Policy (CSP) is both simple to begin and very effective when tightened. An easy starting point is a report-only header that blocks nothing but shows you what would have been stopped. Adding the following to your site lets you open the browser's developer console and watch violations scroll by as you navigate:

Content-Security-Policy-Report-Only: default-src 'self'; font-src 'self'; img-src 'self'; script-src 'self'; style-src 'self'

From there, iteratively allowlist the external origins your site legitimately uses and prefer strict matches. If a script is loaded from a CDN such as cdnjs.cloudflare.com, referencing the exact file or at least the specific directory, rather than the whole domain, reduces exposure to unrelated content hosted there. Inline code is best moved to external files. If that is not possible, hashes can allowlist specific inline blocks and nonces can authorise dynamically generated ones, though the latter must be unpredictable and unique per request. The 'unsafe-inline' escape hatch exists but undermines much of CSP's value and is best avoided.

Once the console is clean, you can add real-time reporting to a service such as URIports (their guide to building a solid CSP is also worth reading) by extending the header:

Content-Security-Policy-Report-Only: default-src 'self'; ...; report-uri https://example.uriports.com/reports/report; report-to default

Pair this with a Report-To header so that you can monitor and prioritise violations at scale. When you are satisfied, switch the key from Content-Security-Policy-Report-Only to Content-Security-Policy to enforce the policy, at which point browsers will block non-compliant content.

Server Fingerprints and Security Headers

While working on HTTPS and header hardening, it is useful to trim server fingerprints and raise other browser defences, and this Apache security headers walkthrough covers the rationale behind each directive clearly. Apache's ServerTokens directive can be set in /etc/apache2/apache.conf to mask version details. Options range from Full to Prod, with the latter sending only Server: Apache. Unsetting X-Powered-By in /etc/apache2/httpd.conf removes PHP version leakage. Adding the following headers in the same configuration file keeps responses out of hostile frames, asks browsers to block detected XSS and prevents MIME type sniffing:

X-Frame-Options SAMEORIGIN
X-XSS-Protection 1;mode=block
X-Content-Type-Options nosniff

These are not replacements for fixes in application code, but they do give the browser more to work with. If you are behind antivirus products or corporate HTTPS interception, bear in mind that these can cause certificate errors such as SEC_ERROR_UNKNOWN_ISSUER or MOZILLA_PKIX_ERROR_MITM_DETECTED in Firefox. Disabling encrypted traffic scanning in products like Avast, Bitdefender or Kaspersky, or ensuring enterprise interception certificates are correctly installed in Firefox's trust store, resolves those issues. Some errors cannot be bypassed when HSTS is used or when policies disable bypasses, which is the intended behaviour for high-value sites.

Contact Form Spam

Contact form spam is a different but common headache. Analysing access logs often reveals that many automated submissions arrive over HTTP/1.1 while legitimate traffic uses HTTP/2 with modern browser stacks, and this GridPane analysis of a real spam campaign confirms the pattern in detail. That difference gives you something to work with.

Filtering by Protocol in Cloudflare

You can block or challenge HTTP/1.x access to contact pages at the edge with Cloudflare's WAF by crafting an expression that matches both the old protocol and a target URI, while exempting major crawlers. A representative filter looks like this:

(http.request.version in {"HTTP/1.0" "HTTP/1.1" "HTTP/1.2"}
  and http.request.uri eq "/contact/"
  and not http.user_agent contains "Googlebot"
  and not http.user_agent contains "Bingbot"
  and not http.user_agent contains "DuckDuckBot"
  and not http.user_agent contains "facebot"
  and not http.user_agent contains "Slurp"
  and not http.user_agent contains "Alexa")

Set the action to block or to a managed challenge as appropriate.

Blocking Direct POST Requests Without a Valid Referrer

Another useful approach is to cut off direct POST requests to /wp-admin/admin-ajax.php and /wp-comments-post.php when the Referer does not contain your domain. In Cloudflare, this becomes:

(http.request.uri contains "/wp-admin/admin-ajax.php"
  and http.request.method eq "POST"
  and not http.referer contains "yourwebsitehere.com")
or
(http.request.uri contains "/wp-comments-post.php"
  and http.request.method eq "POST"
  and not http.referer contains "yourwebsitehere.com")

The same logic can be applied in Nginx with small site includes that set variables based on $server_protocol and $http_user_agent, then return 403 if a combination such as HTTP/1.1 on /contact/ by a non-whitelisted bot is met. It is sensible to verify with Google Search Console or similar that legitimate crawlers are not impeded once rules are live.

Complementary Mitigations Inside WordPress

Three complementary tools work well alongside the server-side measures already covered. The first is WP Armour, a free honeypot anti-spam plugin that adds a hidden field to comment forms, contact forms and registration pages using JavaScript. Because spambots cannot execute JavaScript, the field is never present in a genuine submission, and any bot that attempts to fill it is rejected silently. No CAPTCHA, API key or subscription is required, and the plugin is GDPR-compliant with no external server calls.

The second measure is entirely native to WordPress. Navigate to Settings, then Discussion and tick "Automatically close comments on articles older than X days." Spammers disproportionately target older content because it tends to be less actively monitored, so setting this to 180 days significantly reduces spam without affecting newer posts where discussion is still active. The value can be adjusted to suit the publishing cadence of the site.

The third layer is Akismet, developed by Automattic. Akismet passes each comment through its cloud-based filter and marks likely spam before it ever appears in the moderation queue. It is free for personal sites and requires an API key obtained from the Akismet website. Used alongside WP Armour, the two cover different vectors: WP Armour stops most bot submissions before they are processed at all, while Akismet catches those that reach the comment pipeline regardless of origin. Complementing both, reCAPTCHA v3 or hCaptcha (where privacy demands it) and simple "bot test" questions remain useful additions, though any solution that adds heavy database load warrants testing before large-scale deployment.

Host-Level Firewalls: UFW and Docker

Host-level firewalls remain important, particularly when Docker is in the mix. Ubuntu's UFW is convenient, but Docker's default iptables rules can bypass UFW and expose published ports to the public network even when ufw deny appears to be in place. One maintained solution uses the kernel's DOCKER-USER chain, so UFW regains control without disabling Docker's iptables management.

Appending a short block to /etc/ufw/after.rules that defines ufw-user-forward, a ufw-docker-logging-deny target and a DOCKER-USER chain, then jumps from DOCKER-USER into ufw-user-forward, allows UFW to govern forwarded traffic. Returning early for RELATED,ESTABLISHED connections, dropping invalid ones, accepting docker0-to-docker0 traffic and returning for RFC 1918 source ranges preserves internal communications. New connection attempts from public networks destined for private address ranges are logged and dropped, with a final RETURN handing off to Docker's own rules for permitted flows.

Restart UFW to activate the change:

sudo systemctl restart ufw
# or
sudo ufw reload

From that point, you can allow external access to a container's service port:

ufw route allow proto tcp from any to any port 80

Or scope to a specific container IP if needed:

ufw route allow proto tcp from any to 172.17.0.2 port 80

UDP rules follow the same pattern. If you prefer not to edit by hand, the UFW-docker helper script can install, check and manage these rules for you. It supports options to auto-detect Docker subnets, supports IPv6 by enabling ip6tables and a ULA (Unique Local Address) range in /etc/docker/daemon.json and can manage Swarm service exposure from manager nodes.

Should you instead use Firewalld, note that it provides a dynamically managed firewall with zones, a D-Bus API and runtime versus permanent configuration separation. It is the default in distributions such as RHEL, CentOS, Fedora and SUSE, and it also works with Docker's iptables backend, though the interaction model differs from UFW's.

Keeping Firewall Rules Tidy

Keeping firewall rules tidy is a small but useful habit. UFW can show verbose and numbered views of its state, as Linuxize's UFW rules guide explains in full:

sudo ufw status verbose
sudo ufw status numbered

Delete rules safely by number or by specification:

sudo ufw delete 4
sudo ufw delete allow 80/tcp

If you are scripting changes, the --force flag suppresses the interactive prompt. Take care never to remove your SSH allow rule when connected remotely, and remember that rule numbers change after deletions, so it is best to list again before removing the next one.

Logging Abusers with Fail2Ban and AbuseIPDB

Logging abusers and reporting them can reduce repeat visits. Fail2Ban watches logs for repeated failures and bans IPs by updating firewall rules for a set period. It can also report to AbuseIPDB via an action that was introduced in v0.10.0 (January 2017), which many installations have today.

Confirm that /etc/fail2ban/action.d/abuseipdb.conf exists and that your /etc/fail2ban/jail.local defines action_abuseipdb = abuseipdb. Within each jail that you want reported, add the following alongside your normal ban action, using categories that match the jail's purpose, such as SSH brute forcing:

%(action_abuseipdb)s[abuseipdb_apikey="my-api-key", abuseipdb_category="18,22"]

Reload with fail2ban-client reload and watch your AbuseIPDB reported IPs page to confirm submissions are flowing. If reports do not arrive, check /var/log/fail2ban.log for cURL errors and ensure your API key is correct, bearing in mind default API limits and throttling. Newer Fail2Ban versions (0.9.0 and above) use a persistent database, so re-reported IPs after restart are less of a concern. If you run older releases, a wrapper script can avoid duplicates by checking ban times before calling the API.

Blocking Provider Ranges

Occasionally, administrators choose to block traffic from entire provider ranges that are persistent sources of scanning or abuse. There are scripts such as the AWS-blocker tool that fetch the official AWS IPv4 and IPv6 ranges and insert iptables rules to block them all, and community posts such as this rundown of poneytelecom.eu ranges that shares specific ranges associated with problematic hosts for people who have seen repeated attacks from those networks. Measures like these are blunt instruments that can have side effects, so they warrant careful consideration and ongoing maintenance if used at all. Where possible, it is preferable to block based on behaviour, authentication failures and reputation rather than on broad ownership alone.

Final ModSecurity Notes: Chasing False Positives

Two final ModSecurity notes help when chasing false positives. First, WordPress comments and posting endpoints can trip generic SQL injection protections such as rule 300016 when text includes patterns that appear dangerous to a naive filter, a well-documented occurrence that catches many administrators out. Watching /etc/httpd/logs/modsec_audit.log or the Apache error log immediately after triggering the offending behaviour, and then scoping SecRuleRemoveById lines to the relevant WordPress locations such as /wp-comments-post.php and /wp-admin/post.php, clears real-world issues without turning off protections globally. Second, when very large responses are legitimately expected in parts of wp-admin, increasing SecResponseBodyLimit in an Apache or Nginx ModSecurity context can be more proportionate than whitelisting many checks at once. Always restart or reload Apache after changes so that your edits take effect.

Defence in Depth

Taken together, these layers complement each other well. ModSecurity with CRS gives you broad, configurable protection at the HTTP layer. CSP and security headers narrow the browser's attack surface and put guardrails in place for any client-side content issues. Targeted edge and server rules dampen automated spam without hindering real users or crawlers. Firewalls remain the bedrock, but modern container tooling means integrating UFW or Firewalld with Docker requires a small amount of extra care. Logs feed both your WAF tuning and your ban lists, and when you report abusers you contribute to a wider pool of threat intelligence. None of this removes the need to keep WordPress core, themes and plugins up to date, but it does mean the same attacks are far less likely to succeed or even to reach your application in the first place.

Rendering Markdown in WordPress without plugins by using Parsedown

4th November 2025

Much of what is generated using GenAI as articles is output as Markdown, meaning that you need to convert the content when using it in a WordPress website. Naturally, this kind of thing should be done with care to ensure that you are the creator and that it is not all the work of a machine; orchestration is fine, regurgitation does that add that much. Naturally, fact checking is another need as well.

Writing plain Markdown has secured its own following as well, with WordPress plugins switching over the editor to facilitate such a mode of editing. When I tried Markup Markdown, I found it restrictive when it came to working with images within the text, and it needed a workaround for getting links to open in new browser tabs as well. Thus, I got rid of it to realise that it had not converted any Markdown as I expected, only to provide rendering at post or page display time. Rather than attempting to update the affected text, I decided to see if another solution could be found.

This took me to Parsedown, which proved to be handy for accomplishing what I needed once I had everything set in place. First, that meant cloning its GitHub repo onto the web server. Next, I created a directory called includes under that of my theme. Into there, I copied Parsedown.php to that location. When all was done, I ensured that file and directory ownership were assigned to www-data to avoid execution issues.

Then, I could set to updating the functions.php file. The first line to get added there included the parser file:

require_once get_template_directory() . '/includes/Parsedown.php';

After that, I found that I needed to disable the WordPress rendering machinery because that got in the way of Markdown rendering:

remove_filter('the_content', 'wpautop');
remove_filter('the_content', 'wptexturize');

The last step was to add a filter that parsed the Markdown and passed its output to WordPress rendering to do the rest as usual. This was a simple affair until I needed to deal with code snippets in pre and code tags. Hopefully, the included comments tell you much of what is happening. A possible exception is $matches[0]which itself is an array of entire <pre>...</pre> blocks including the containing tags, with $i => $block doing a $key (not the same variable as in the code, by the way) => $value lookup of the values in the array nesting.

add_filter('the_content', function($content) {
    // Prepare a store for placeholders
    $placeholders = [];

    // 1. Extract pre blocks (including nested code) and replace with safe placeholders
    preg_match_all('//si', $content, $pre_matches);
    foreach ($pre_matches[0] as $i => $block) {
        $key = "§PREBLOCK{$i}§";
        $placeholders[$key] = $block;
        $content = str_replace($block, $key, $content);
    }

    // 2. Extract standalone code blocks (not inside pre)
    preg_match_all('/).*?<\/code>/si', $content, $code_matches);
    foreach ($code_matches[0] as $i => $block) {
        $key = "§CODEBLOCK{$i}§";
        $placeholders[$key] = $block;
        $content = str_replace($block, $key, $content);
    }

    // 3. Run Parsedown on the remaining content
    $Parsedown = new Parsedown();
    $content = $Parsedown->text($content);

    // 4. Restore both pre and code placeholders
    foreach ($placeholders as $key => $block) {
        $content = str_replace($key, $block, $content);
    }

    // 5. Apply paragraph formatting
    return wpautop($content);
}, 12);

All of this avoided dealing with extra plugins to produce the required result. Handily, I still use the Classic Editor, which makes this work a lot more easily. There still is a Markdown import plugin that I am tempted to remove as well to streamline things. That can wait, though. It best not add any more of them any way, not least avoid clashes between them and what is now in the theme.

Redirecting a WordPress site to its home page when its loop finds no posts

5th November 2022

Since I created a bespoke theme for this site, I have been tweaking things as I go. The basis came from the WordPress Theme Developer Handbook, which gave me a simpler starting point shorn of all sorts of complexity that is encountered with other themes. Naturally, this means that there are little rough edges that need tidying over time.

One of these is dealing with errors on the site, like when content is not found. This could be a wrong address or a search query that finds no matching posts. When that happens, there is a redirection to the home page using some simple JavaScript within the loop fallback code enclosed within script start and end tags (including the whole code triggers the action from this post so it cannot be shown here):

location.href="[blog home page ]";

The bloginfo function can be used with the url keyword to find the home page, avoiding hard-coding. For now, this works so long as JavaScript is enabled, but a more robust approach may come in time. It is not possible to do a PHP redirect because of the nature of HTTP: when headers have been sent, it is not possible to do server redirects. At this stage, things become client side, so using JavaScript is one way to go instead.

Turning off the full height editor option in WordPress 4.0

10th September 2014

Though I casually follow WordPress development, it's not nearly as rigorous as when I submitted a patch that earned me a mention on a main WordPress release's contributor list. This may explain why I barely noticed the full editor setting, which is turned on by default.

WordPress has become so mature now that I almost do not expect major revisions like the overhauls received by the administration back-end in 2008. The second interface was got so right that it still is with us, even if there were concerns in my mind at the time as to how usable it would be. Sometimes, those initial suspicions can come to nothing.

However, WordPress 4.0 introduced a major editor change that I'm not sure is successful. A full-height editor sounds good in principle, but its implementation has rough edges that make me wonder if any UX person reviewed it. Scrolling becomes strange, with the editor's toolbar fixing in place when you scroll down far enough. The sidebar then scrolls out of sync with the editor box, creating an odd sensation. Keyboard shortcuts like CTRL + HOME and CTRL + END don't work properly, which convinced me this new arrangement wasn't for me and I wanted to disable it.

A Google search found nothing useful, so I tried the WordPress.org forum. This revealed I should have looked in the screen options dropdown box for "Expand the editor to match the window height" to deselect it. Because of a Visual Editor control there, I'd checked the user profile screen but found nothing, showing the setup logic is poor. Perhaps the Visual Editor option should be a screen option too. Thankfully, the window height editor setting only needs changing once for both posts and pages, covering all situations.

With a distraction-free editing option available, I'm not sure why someone added the full height editor too. If WordPress keeps this feature, it needs refinement to behave more conventionally. I wouldn't build a website with such ill-synchronised scrolling. This needs work, as does the Visual Editor setting location. Perhaps both settings should be at the user level, rather than having one above that level. Before finding the solution, I considered using distraction-free mode permanently and installed the WP Editor plugin. I kept the plugin for its code highlighting, even though entering code view always creates a new revision. Despite this issue, things are now better.

Changing to CKEditor from FCKEditor for WordPress Content Editing

25th April 2011

The post editor that I have been using on my WordPress-powered outdoors blog has not been TinyMCE but FCKEditor. My use of that editor has meant that WordPress' autosave and word counting features have not been available to me. As strange as it may sound to some, that is my choice. Even so, there have been times when I have missed the autosaving functionality and lost work.

Since FCKEditor has been replaced by CKEditor, there are plugins available for adding that editor to WordPress' administration interface. Recently, I replaced the old FCKEditor plugin with a newer CKEditor one, which has gained me post or page autosaving. Though the more cosmetic word counting feature is not active until a draft is manually saved, I can live with that.

Other than that, the interface remains familiar with all (X)HTML tags shown in the source code view without any being hidden away from view like on WordPress' implementation of TinyMCE. That isn't to see that WordPress is doing something wrong, only that there are alternative ways of doing things, that are equally valid. After all, why would there be choices if there only ever was one right way to do anything?

Like any WordPress plugins, those replacing the default content editor on WordPress can be vulnerable to changes in the publishing platform, and there is one of those in the pipeline for 3.2: a minimalist post/page editor that is billed as being non-distracting. That planned new feature is drawing inspiration from the likes of QuietWrite, where you can write content and transfer it over to WordPress or leave it where it was written.

Even with substantial changes like this, my experience never has been that design decisions made for new WordPress releases have restricted to any great extent how I use the thing. That's not to say that my usage hasn't changed over time, yet I have felt that any decisions were mine to make and not all made for me. In that light, I can foresee CKEditor continuing to work on WordPress 3.2 along with some testing ahead of time to be sure that is the case.

Turning off the admin bar in WordPress 3.1

25th October 2010

Work on WordPress 3.1 is in full swing at the moment, though I initially thought that they were taking a little break after 3.0. From what I can see, many refinements are being made to the multi-blog functionality and behind-the-scenes work is ongoing on the administration screens too.

Another under-the-bonnet change has been to make WordPress less tied to MySQL, since the possibility of dropping in support for an alternative such as PostgreSQL is now a reality even if it isn't part of the default package. For now, it looks as if this will be plugin territory rather than default multi-database support, though that may become a sensible development in the light of Oracle's acquisition of MySQL and its sabre-rattling regarding Java patents. So far, the change to WordPress has affected my use of its database engine to power an offline version of my online photo gallery, but a quick spot of code editing sorted that issue.

One more obvious alteration will be the addition of a WordPress.com style administration bar to the top of all content and administration screens for a user who is logged into the system. Though it will be turned on by default, there will be the option of turning it off for those among who prefer things that way. All that will be needed for this is to add the following line near the top of wp-config.php:

define( "WP_SHOW_ADMIN_BAR", false);

The chance to see new additions like those above and be ready for is my main reason for following WordPress development. It's best to be ready instead of being surprised, though it has to be said that the blogging or CMS platform is a very polished one these days.

Removing a column from a MySQL data table

19th April 2010

My trying out WordPress 3.0 in advance of its final release has brought me errors on the management page for website links. After a spot of poking around the TRAC, I found that the bug already has been reported and that the cause is an extraneous column in the *_links table called link_category. The change in taxonomy handling over the years seems to have made it redundant, so I removed the said column from the database using a command like the following from both the MySQL command line and MySQL Query Browser:

alter table database.wp_links drop link_category;

That seems to have made those errors go away, and I hope that their upgrade code takes care of this before WordPress 3.0 is let loose of the general blogging public. Taking out the coding brittleness would do too.

DePo Masthead

6th November 2009

There is a place on WordPress.com where I share various odds and ends about public transport in the U.K. It's called On Trains and Buses, and I try not to go tinkering with the design side of things too much. You only can change the CSS and my previous experience of doing that with this edifice while it lived on there taught me not to expect too much even if there are sandbox themes for anyone to turn into something presentable, not that I really would want to go doing that in full view of everyone (doing if offline first and copying the CSS afterwards when it's done is my preferred way of going about it). Besides, I wanted to see how WordPress.com fares these days anyway.

While my public transport blog just been around for a little over a year, it's worn a few themes over that time, ranging from the minimalist The Journalist v1.9 and Vigilance through to Spring Reloaded. After the last of these, I am back to minimalist again with DePo Masthead, albeit with a spot of my own colouring to soften its feel a little. Though I must admit growing to like it, it came to my attention that it was a bespoke design from Derek Powazek that Automattic's Noel Jackson turned into reality. The result would appear that you cannot get it anywhere but from the WordPress.com Subversion theme repository. For those not versed in the little bit of Subversion action that is needed to get it, I did it for you and put it all into a zip file without making any changes to the original, hoping that it might make life easier for someone.

Download DePo Masthead

Going mobile

20th October 2009

Now that the mobile web is upon us, I have been wondering about making my various web presences more friendly for users of that platform, and my interest has been piqued especially by the recent addition of such capability to WordPress.com. With that in mind, I grabbed the WordPress Mobile Edition plugin and set it to work, both on this blog and my outdoors one. Well, the results certainly seem to gain a seal of approval from mobiReady so that's promising. While it comes with a version of the Carrington Mobile theme, you need to pop that into the themes directory on your web server yourself, as WordPress' plugin installation routines won't do that for you. It could be interesting to see how things go from here, and the idea of creating my own theme while using the plugin for redirection honours sounds like a way forward; I have found the place where I can make any changes as needed. Homemade variants of the methodology may find a use with my photo gallery and Textpattern sub-sites.

A self-hosted online photo album option

16th July 2009

When I was perusing a recent copy of Linux Format, I encountered a feature describing a self-hosted alternative to the likes of Flickr: Gallery. From my quick look, it looks fully featured, offering themes and even shopping cart facilities for those who want to sell their wares. The screenshots on the open-source project's website look promising but, for a fuller appraisal, I would need to spend some time trying to bend it to my will. Before anyone mentions it, I am aware that WordPress can be used for photoblogging, but this tool seems to take things a bit further. It's the sort of thing about which I might have wondered, given the pervasiveness of content management systems these days. My own custom-built photo gallery is devoid of a slick back end, hence why Gallery caught my eye, but I'll continue with it and may even get to adding the needful myself.

  • The content, images, and materials on this website are protected by copyright law and may not be reproduced, distributed, transmitted, displayed, or published in any form without the prior written permission of the copyright holder. All trademarks, logos, and brand names mentioned on this website are the property of their respective owners. Unauthorised use or duplication of these materials may violate copyright, trademark and other applicable laws, and could result in criminal or civil penalties.

  • All comments on this website are moderated and should contribute meaningfully to the discussion. We welcome diverse viewpoints expressed respectfully, but reserve the right to remove any comments containing hate speech, profanity, personal attacks, spam, promotional content or other inappropriate material without notice. Please note that comment moderation may take up to 24 hours, and that repeatedly violating these guidelines may result in being banned from future participation.

  • By submitting a comment, you grant us the right to publish and edit it as needed, whilst retaining your ownership of the content. Your email address will never be published or shared, though it is required for moderation purposes.