Category Archives: wordpress

Don’t forget the feed

Google killed Reader just over five years ago. This week, Digg decided to mark this Wood Anniversary by taking a club to its own Reader. Yet again, we oldsters find ourselves shaking our fists at Kids Today. See, for example, Bryan Alexander's thoughtful post on finding a way forward for RSS readers and RSS in general.

I celebrated this turn of events by struggling to set up an instance of Tiny Tiny RSS on my web server. Having finally figured it out, I'm pretty pleased with the functionality. One nice bit is the notice regarding "update errors":

Oh noes!

TT-RSS then has a tool for viewing a list of broken feeds. Looking through this list has been an interesting experience. For one thing, it's given me the opportunity to think about a few dozen people who have not otherwise entered my consciousness in a number of years.

More importantly, it's convinced me that the real threat to RSS is not the lack of reader software; you only need a couple of good ones to support an ecosystem. The bigger issue is that RSS content is disappearing.

The more mundane kind of problem is link rot and broken redirects. Many domains have gone away, some have moved in such a way that RSS links no longer work, some are now hidden behind password protection (Blogspot seems to be a particular offender). Web sites come and web sites go, so some of this is to be expected.

The more worrisome trend is content that's not available through RSS simply because there's no feed mechanism. A shamefully large number of my geekier aquantainces have moved their blogs to Jekyll and other static-site-generation tools, which don't appear to have feed support out of the box; and – this is the "shameful" part – since these folks, geeky as they may be, think so little of RSS, they don't bother setting up the secondary plugins or whatever necessary to serve feeds. I expect that kind of behavior from lock-up-my-content companies and technically-clueless organizations that rely heavily on proprietary and bespoke software, but not from people who ought to know better.

For all of its lumbering bloatedness, one of the truly wonderful things about CMSes like WordPress is that they give you things like RSS – along with a pile of other boring-but-critical-to-the-future-of-the-open-web tools – by default. You don't need to make the decision to support RSS readers (or responsive images, or markup that is accessible to assistive technologies, etc) – the system provides them for you, and you have to go out of your way to turn them off.

Those who build their own systems for old-school things like bloggish content distribution, or who rely on teh new hotness to do these tasks in ways that are slicker than the old-school tools, should beware the dangers of discarding the automated systems that are the result of many years and many minds and many mistakes. If you must reinvent the wheel, then do your due diligence. RSS feeds, like other assistive technologies, should not be an afterthought.

Handling LaTeX in WordPress and React.js

I’m in the midst of building a WordPress plugin that interfaces with WeBWorK, a web application for math and science homework. The plugin features a JavaScript app powered by React and Redux, which lives inside of a WordPress page template and communicates with WP via custom API endpoints. The project is for City Tech OpenLab and it’s pretty cool. I’ll write up some more general details when it’s closer to release.

The tool is designed for use in undergraduate math courses, so LaTeX-formatted content features heavily. LaTeX is beautiful when used on its own, but it’s hard to handle in the context of web applications. A few lessons and strategies are described below.

Delimiters

I’m dealing with “mixed” content: plain text that is interspersed with LaTeX. Some of this content is coming directly from WeBWorK, which formats LaTeX to be rendered with MathJax. WeBWorK is sending markup that, when simplified, looks like this:

[code language=”html”]
This is plain text.
Here is an inline equation:
And here is the same equation as a standalone block:

[/code]

It’s also possible for users to enter LaTeX from the front-end of the WP application. In this case, we’ve settled on the verbose delimiters \begin{math} and \end{math}, but we also support a shorthand delimiter borrowed from Jetpack’s LaTeX renderer:

[code]
This is plain text.
Here is an inline equation: \begin{math}E = mc^2\end{math}
And here is the same equation as a standalone block:
$latex E = mc^2$
[/code]

Some of these delimiter formats are more fragile than others, for various reasons – script tags that cannot be escaped, false positives due to use of literal dollar signs, etc – so I standardized on some invented delimiters for data storage. Before saving any LaTeX content to the database, I’m converting all delimiters to the following formats (of my own invention, which explains their Great Beauty):

[code]
This is plain text.
Here is an inline equation: {{{LATEX_DELIM_INLINE_OPEN}}}E = mc^2{{{LATEX_DELIM_INLINE_CLOSE}}}
And here is the same equation as a standalone block:
{{{LATEX_DELIM_DISPLAY_OPEN}}}E = mc^2{{{LATEX_DELIM_DISPLAY_CLOSE}}}
[/code]

This way, the delimiters are unique and easy to process on display.

Slashes

I’m using WordPress custom post types to store data. The lowest-level function available for saving post data is wp_insert_post(). Thanks to a glorious accident of history, this function expects data to be “slashed”, as in addslashes() and magic quotes. If you’re looking for a fun way to spend a few hours, read through this WordPress ticket and figure out a solution, please.

LaTeX uses \ as its escape character, which makes LaTeX-formatted content look “slashed” to WordPress. As such, attempting to save chunks of LaTeX using wp_insert_post() will result in slashes being removed and formatting being lost. So I had two choices: don’t use wp_insert_post(), or don’t use slashes.

I chose the latter. Before saving any content to the database, I identify text that appears between LaTeX delimiters, and I replace all slashes with a custom character. In all its glory:

[code language=”php”]
public function swap_latex_escape_characters( $text ) {
$regex = ‘;(\{\{\{LATEX_DELIM_((?:DISPLAY)|(?:INLINE))_OPEN\}\}\})(.*?)(\{\{\{LATEX_DELIM_\2_CLOSE\}\}\});s’;
$text = preg_replace_callback( $regex, function( $matches ) {
$tex = str_replace( ‘\\’, ‘{{{LATEX_ESCAPE_CHARACTER}}}’, $matches[3] );
return $matches[1] . $tex . $matches[4];
}, $text );

return $text;
}
[/code]

So a chunk of LaTeX like E = \frac{mc^2}{\sqrt{1-\frac{v^2}{c^2}}} goes into the database as

E = {{{LATEX_ESCAPE_CHARACTER}}}frac{mc^2}{{{{LATEX_ESCAPE_CHARACTER}}}sqrt{1-{{{LATEX_ESCAPE_CHARACTER}}}frac{v^2}{c^2}}}

They get converted back to slashes before being served via the API endpoints.

Rendering in a React component

I decided to stick with MathJax for rendering the LaTeX. MathJax has some preprocessors that allow you to configure custom delimiters, but I had a hard time making them work inside of my larger JavaScript framework. So I decided to skip the preprocessors and generate the <script type="math/tex"> tags myself.

React escapes output pretty aggressively. This is generally a good thing. But it makes it hard to print script tags and unescaped LaTeX characters. To make it work, I needed to live dangerously. But I didn’t want to print any more raw content than necessary. So I have two components for rendering text that may contain LaTeX. Click the links for the full source code; here’s a summary of what’s going on:

  1. FormattedProblem performs a regular expression to find pieces of text that are set off by my custom delimiters. Text within delimiters gets passed to a LaTeX component. Text between LaTeX chunks becomes a span.
  2. LaTeX puts content to be formatted as LaTeX into a script tag, as expected by MathJax. Once the component is rendered by React, I then tell MathJax to queue it for (re)processing. See how updateTex() is called both in componentDidMount() and componentDidUpdate(). Getting the MathJax queue logic correct here was hard: I spent a lot of time dealing with unrendered or double-rendered TeX, as well as slow performance when a page contains dozens of LaTeX chunks.

A reminder that React’s dangerouslySetInnerHTML is dangerous. I’m running LaTeX content through WP’s esc_html() before delivering it to the endpoint. And because I control both the endpoint and the client, I can trust that the proper escaping is happening somewhere in the chain.

I use a very slightly modified technique to provide a live preview of formatted LaTeX. Here it is in action:

output

Pretty cool TeXnology, huh? ROFLMAO

WordCamp Chicago 2016 slides

I just finished giving a talk at WordCamp Chicago titled “Backward Compatibility as a Design Principle”, in which I discussed WordPress’s approach to backward compatibility, how it’s evolved over the years, and its costs and benefits when compared to the alternatives. I’m not sure that the slides are very helpful in isolation, but someone asked me to post them, and I am not one to disappoint my Adoring Fans. Embedded below.

wc-chicago-2016

download as pdf

BuddyPress Docs 1.9.0 and Folder support

BuddyPress Docs is one of my more popular WordPress plugins. For years, one of the most popular feature requests has been the ability to sort Docs into folders. Docs 1.9.0, released earlier this week, finally introduced folder functionality.

The feature is pretty cool. When editing a Doc within the context of a group, you can select an existing folder, or create a new one, in which the Doc should appear. Folders can be nested arbitrarily. Breadcrumbs at the top of each Doc and each directory help to orient the reader. And a powerful, AJAX-powered directory interface makes it easy to drill down through the folder hierarchy. (Folders are currently limited to groups, which simplifies the question of where a given folder “lives”. An experimental plugin allows individual users to use folders to organize their personal Docs.)

docs-folders

I’ve got a couple reasons for drawing attention to this release. First, the Folders feature was developed as part of contract work I did for University of Florida Health. They use WordPress and BuddyPress for some of their internal workspaces, and the improvements to BuddyPress Docs have helped them to build a platform customized to their users’ specific needs. My partnership with UF Health is a great instance of a client commissioning a feature that then gets rolled into a publicly available tool – the type of patronage that demonstrates the best parts of free software development as well as IT in the public sector.

A bonus side note: UF Health Web Services is currently hiring a full-time web developer. If you know PHP, and want a chance to work with cool people on cool projects – including WordPress and BuddyPress – check out the job listing.

The other fun thing about this release is that it’s the first major release of Docs where I’ve worked closely with David Cavins, master luthier and BuddyPress maven. He’s a longtime contributor to Docs, and has done huge amounts of excellent work to bring 1.9.0 to fruition. Many thanks to David for his work on the release!

WordCamp NYC talk on the history of the WordPress taxonomy component

At WordCamp NYC 2015, I was pleased to present on the history of the WordPress taxonomy component. Of all the WordCamp talks I’ve given, this one was the most fun to prepare. I spent days reading through old Trac tickets, the wp-hackers archives, and interview transcripts. The jokes are mostly mediocre and the Photoshopping is (mostly intentionally) lousy, but I think the talk turned out OK. Check it out below, or on wordpress.tv.


How to cherry-pick comments using Subversion (for WordPress at least)

I generally use git-svn for my work on WordPress and related projects. On occasion, I’m forced to touch svn directly. This occurs most often when merging commits from trunk to a stable branch: it’s best to do this in a way that preserves svn:mergeinfo, and git-svn doesn’t do it properly. Nearly every time I have to do these merges, I have to relearn the process. Here’s a reminder for Future Me.

  1. Commit as you normally do to trunk. Make note of the revision number. (Say, 36040.)
  2. Create a new svn checkout of the branch, or svn up your existing one. Eg: $ svn co https://develop.svn.wordpress.org/branches/4.4 /path/to/wp44/
  3. From within the branch checkout: $ svn merge -c 36040 ^/trunk  In other words: merge the specific commit (or comma-separated commits) from trunk of the same repo.
  4. This will leave you with a dirty index (or whatever svn calls it). Use svn status to verify. Run unit tests, etc.
  5. $ svn ci. Copy the trunk commit message to EDITOR, and add a line along the lines of “Merges [36040] to the 4.4 branch”
  6. Drink 11 beers.

Very French Trip podcast

As part of my ongoing project to engage with the global WordPress community while simultaneously humbling myself, I’ve agreed to appear on the Very French Trip podcast on September 10, where I’ll be talking about how WordPress and BuddyPress get built. If you’re a French speaker, or if you like to hear me stumble, tune in for a rollicking listen.

Et si vous êtes francophone, je vous invite de poser des questions à l’avance du podcast. Vous pouvez les laisser aux commentaires de l’annonce VFT, ou sur Twitter en utilisant le hashtag #VFTPodcast. On se verra bientôt 😉

Custom version-based cache busting for WordPress CSS/JS assets

WordPress appends a query var like ?ver=4.2.1 to CSS/JS URIs when building <link> and <script> tags. When WP’s version changes (eg, from 4.2.1 to 4.2.2), the query var changes too, causing browsers to bypass their cached assets and forcing a fresh version to be requested from the server. This works well for core assets, because they generally don’t change between WP releases. But for assets loaded by plugins and themes – which don’t always provide their own ver string when enqueuing their scripts and styles – it’s not a perfect system, since browser caches will only be busted when WordPress core is updated.

I built a small filter for the CUNY Academic Commons that works around the problem by appending our custom CAC_VERSION string to all ver query vars. This ensures that users will get fresh assets after each CAC release, whether or not that release includes a WP update.

Note that this code is pretty aggressive: it busts all CSS/JS caches on every release. You could use the $handle argument to do something more fine-grained. Note also that this technique doesn’t work equally well for all caching setups; see this post for an alternative strategy, based only on filename. Proceed at your own risk.