Encoding serialized attributes for Gutenberg blocks in PHP

I stumbled backwards into this and didn’t see it discussed anywhere else yet, so here’s a path for anyone else finding themselves temporarily confused and internet searching.

Say you’ve created a custom block for the WordPress block editor, Gutenberg. In addition to regular content, there are one or more attributes associated with the block:

<!-- wp:jf/custom { "data":"Some data assigned as an attribute." } /-->

Now that you have the block in place, you want to migrate the meta from thousands of posts into this structure and inject it into the post content. This data can contain all sorts of characters, including quotes and HTML markup.

If you enter quotes and HTML markup directly into Gutenberg, the content is saved like so:

<!-- wp:jf/custom { "data":"Hey, a \u003Ca href=\u0022http:s\/\/jeremyfelt.com\/\u0022\u003Elink to my website\u003C\/a\u003E." } /-->

This works because the Block API replaces a handful of special characters via regex after JSON.stringify()has done the initial translation.

WordPress does not have a PHP mirror of the Block API’s serializeAttributes(), but the existing functions for encoding JSON are really flexible. Per the documentation for json_encode(), which itself is used by wp_json_encode(), a handful of constants are available to apply as a bitmask to ensure specific characters are encoded in a specific way.

So we end up with this:

// String from non-Gutenberg data source.
$string = 'Hey, a <a href="https://jeremyfelt.com/">link to my website</a>.';

$attribute = wp_json_encode( $string, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP | JSON_UNESCAPED_UNICODE );

// And $attribute is now:
// "Hey, a \u003Ca href=\u0022https:\/\/jeremyfelt.com\/\u0022\u003Elink to my website\u003C\/a\u003E."

// If storing with wp_insert_post(), etc...
$attribute = addslashes( $attribute );

$block = '<!-- wp:jf/custom { "data":' . $attribute . ' } /-->';

And the block string can now be stored as part of the post content.

Note: addslashes() is needed if storing the data with wp_insert_post(), etc… because those strip slashes and \u003Ca looks like a slash that needs to be stripped unless it itself is slashed.

Some thoughts on plugins, Jetpack, advertisements, and things

A series of loose thoughts I’ve been trying to work through over the last couple days in response to Jetpack adding feature suggestions to plugin search results in the WordPress dashboard.

I think injecting promotions into the current plugin search interface is not a great idea. I understand why it’s appealing, and I imagine that it will be helpful for many WordPress site owners. However, it opens an ambiguously regulated door to something that should really be part of a designed system.

I don’t think it would be horrible to have some sort of interface in the plugin search, via a WordPress core API, that allows plugins you have installed to promote their other work based on predefined keywords.

Discoverability of safe and performant plugins by WordPress site owners has always been a hard task to solve.

Which I think is why a large plugin of plugins like Jetpack exists. If it doesn’t—in the world we’ve had—the site owner goes somewhere else (Wix, Squarespace, etc…) or installs a series of plugins that do not have the same resources as the team behind Jetpack.

This series of plugins—one plugin, one feature, all safe and performant—is a vision of WordPress that I’ve always preferred. And I’d love if plugin developers I trust could highlight their other plugins when I search for something new.

Overall, this is something that has gotten much better over the years thanks to the plugin review team and tools that make it easier to apply WordPress coding standards.

But! In the past, installing this series of plugins has led to hacked sites. Hacked sites lead to a lack of trust in the WordPress core project and other plugins. A lack of trust leads to a lack of growth.

Which is where my thoughts often end up and are in some ways still muddled.

If the primary goal for WordPress.org is to increase market share, then it’s probably good to have something like Jetpack around until that ideal discoverability catches up.

If the primary goal for WordPress.org is individual ownership, then plugins of plugins should be broken apart into individual features and we should figure out how to better guarantee security across the ecosystem.

In reality, these aren’t exclusive of each other and they aren’t the only possible goals. That’s the part I’m still trying to work through. Why is it important that WordPress powers more than a third of the web? What are the consequences of slowing down growth? Are there ways to refocus our efforts to help better balance the two? Are there better models for plugins?

Still thinking!

A personal history of tracking people on websites

This is me trying to figure out why.

In the earlier days of the web—that I remember—we all used counter scripts. I don’t know where they came from, but every place that hosted sites seemed to also have a cgi-bin directory. If you were lucky, you could find some sort of count.cgi script written in Perl that would just work. If you reloaded the page over and over again, the number would increase.

Of course, this wasn’t really reliable. If you didn’t understand Perl, and I didn’t know anybody that did at the time, it could be hard to make things work. Those cgi-bin directories differed in permissibility and, sooner or later, someone was going to exploit a vulnerability in your copy/pasted code.

Where did I even find that code!

A bit later. I don’t remember anything about signing up for this, but there was a service called “Webdigits” or “Web Counter” that offered a hosted tracker. This is the first time that I outsourced tracking the tracking of people to someone else.

A page of mine from January 1998 had the following:

<LAYER ID=counter TOP=975 LEFT=10>
<font size = 4>
<a href = http://www.digits.com>Web Counter</a> says you are the 
<IMG SRC="http://counter.digits.com/wc/-d/8/-c/8/-z/oldemail@isp.com" 
person to access this page.

Retro HTML!

I have a feeling this was similar to the self-hosted script in that you could reload the page over and over again and the counter would just go up. Still nothing granular, but you (and everyone else) could see how many visits had accumulated.

The next tracker I remember was the very popular and now defunct Site Meter. This moved the web from tracking via an image to tracking via Javascript:

<!--WEBBOT bot="HTMLMarkup" startspan ALT="Site Meter" -->
<script type="text/javascript" language="JavaScript">
    var site="sm5accountname"
<script type="text/javascript" language="JavaScript1.2" 

Much more information about people was suddenly available—where they were from, how much time they spent on pages, and what sites led to their visit.

Here’s the amazing part: I have at least 27 receipts in my email over a 2.5 year period at $6.95/month. I paid for a service to track analytics!

At some point in 2007 Site Meter started injecting another script on behalf of a shady looking 3rd party company and the Blogosphere was up in arms. (Oh, we were still so young…)

Luckily (ha!), I got my invite to Google Analytics in March of 2006, so I was already using multiple trackers on my site when the Site Meter debacle happened.

It was during this period that Google Analytics really started to take over the analytics world. The interface was nicer, the data was probably more accurate, people were (supposedly) making a ton of money gaming AdWords, and this was your way in! I can see the spread in my email archive as I started adding analytics to any site I was involved with, convinced that it was good to know who was doing what and where on your slice of the web.

And it was all a lot of fun. There was a thrill to watching the numbers climb throughout the day if you wrote a post that a couple other bloggers picked up on or hit the first page of search results for a recent event.

The next few years (2007-2012) seem to have been relatively uneventful for me in analytics. I played with Piwik for a few months on a custom domain, but for some reason it didn’t stick. And in 2011 or 2012 I started using WordPress.com stats via the Jetpack plugin in addition to Google Analytics. These were nice in that straight-forward were available without effort in the WordPress admin.

And now.

Over the last few years my thinking has shifted.

When I first setup the global analytics dashboard at WSU, I was pretty excited. It achieved that goal of having a fun display to watch numbers on throughout the day as different events happened. But when you start digging through the available data that Google provides, it gets a little creepy. Visitor profiles are only non-identifying until you stare close enough. It doesn’t take long to take a guess at what department a person might be from. If you stared at the data for a few days, you could probably tell someone on campus that you knew what grad program they were interested in.

All the while, there was no investment in the actual use of analytics. The web team tracked them, the data was available, but often nobody looked at it, let alone tried to use it for anything purposeful.

At some point I was on a call with a company that was walking through their “simple” “retargeting” “conversion” “pixel”—I loathe the way that word is used—that they wanted to put on all university pages to track the success of a marketing campaign. We were easily able to talk things down to a single landing page, but during that conversation the guy bragged about how creepy they could get in tracking people on the web.

If you ever start digging into the mechanics of that “pixel”, things feel even uglier. This marketing company sells you the pixel that they source from this 3rd party that sources their platform from another. The opportunity for someone to misuse or mishandle the data just keeps growing the more you look at that pixel.


That conversation really planted a seed—why does a university need to track people? Why does anyone need to track people?

I’m still on board with tracking visits. I like to see how many people view content. If they choose to pass the info on, I like to see what referred them to the site.

I don’t think data about individual people actually matters for the overwhelming majority of the web.

So I made a few adjustments based on this.

  • I removed Google Analytics. (also from VVV)
  • I disabled Jetpack, which removed the WordPress.com tracker. I tried to disable via filter first, but it kept going.
  • I setup a self-hosted installation of Matomo, an open source analytics platform (formerly Piwik) and I’ve anonymized IP addresses down to two octets.

I’m still working out how I use Matomo. As with many things, I did this on a weekend morning and haven’t looped back around to it yet. I hope to find an accurate enough mix of useful data and privacy. I’ll work on turning that into a framework and policy that I can use on any site I manage.

And I’m still working through how I feel about everything. When building the web with others as a partner, I don’t want to be dismissive towards current or future practices around analytics without having something constructive to offer. I do want to make sure that we keep people as part of the conversation rather than pixels and users.

And of course, I’m very open to conversation. I’m still a beginner in being mindful about this, even if I’ve been tracking people for over 20 years! 😂