Idea: Uniform Resource Identifiers as an Alternative to Shortcodes

The idea is that any objects embedded in a post’s content have their own home and should be seen as separate resources. Data would be stored elsewhere.

Examples

  • https://example.com/resources/contact-forms/email-ella/
  • https://example.com/resources/charts/php-versions-wordpress/
  • https://example.com/author/iseulde/
  • https://example.com/galleries/yummy-chocolates/
  • https://example.com/surveys/wordpress-editor-2016/
  • https://external.com/some-map-or-form/

Object Types

This approach could be good for:

  • Forms such as contact forms, surveys and polls.
  • Visualised data such as diagrams, charts, graphs and tables.
  • Lists of items such as a galleries, playlists and lists of posts.
  • Albums or manually composed collections of items where the presentation is uniquely different from a normal list.
  • Any content that needs to be reused or organised separately. Anything that can be re-sourced. 😉
  • Any external resources.

This is not good for:

  • Layout.
  • Text conversions.

Inspiration

  • External embeds work similarly in WordPress through oEmbed.
  • Images, audio and video are embedded by their URL in HTML.
  • Media have their own “attachment” post type in WordPress.
  • Many plugins already have a separate post type to store their data.
  • I’ve seen some news media do this already for things for like graphs (post, resource).

Benefits

  • A URL (or “link”) is a concept that is already familiar to many users.
  • URIs are designed for these sort of things. Think about images — it would follow the same paradigm.
  • The content is treated as a separate resource, and can be reused, just like shortcodes, but it forces separation.
  • WordPress allows you to create “pretty” semantic URIs, so the resource can be described for a better experience.
  • A cool side effect is that others could embed these easily on their site through oEmbed. WordPress already supports this.
  • If there’s a problem, the URL will act as a fallback.

Implementation

A quick way to implement this for WordPress 4.4 and higher is registering a new post type. This will handle most things, you just need to provide a custom embed template with the template_include filter. An external resource can be filtered with the Embed API and TinyMCE View API, even if it doesn’t support oEmbed.

Challenge: Variants and Settings

Either each variant of an resource needs its own ID, or settings could be passed with a query string. I think the use of settings should be minimised — for example, columns for a gallery object may be better set per ID. Settings can certainly be useful for things like autoplay, for example YouTube allows you to set the start time.

Challenge: Alignment

This is great if the URL is added on a separate line, but aligning the object is not evident. This is a challenge for shortcodes too. At the moment the core galery shortcode does not allow you to allign it, and the caption shortcode has an attribute for it. Similarly the URl could have a query parameter for alignment, but that doesn’t sound ideal. Alternatively the paragraph could be floated, or it needs to be wrapped in a `div` element to float mid-text. Another approach is to always wrap the URLs in a (custom) tag that can have display information. Again, think about how images are embedded in HTML.

Challenge: Namespace

Shortcodes would have a similar problem, though slug clashes are probably more likely. Ideally plugins should use their own prefix, but this may be seen as ugly. Another way to avoid clashes with other post types is a sub type for “attachments” or “resources”.

Challenge: Extra Queries

I don’t see this exactly as a challenge, as it’s the nature of the concept, but it may be used as an argument against it. Many shortcodes already make use of custom post types to store data and embedding media (or anything else) also requires extra queries. If and how this should be cached is another problem.


I would love to hear your thoughts on this alternative, especially from those who use shortcodes for this type of objects in the post content. If you already use a custom post type, why not take advantage of embedding instead of creating shortcodes? If you want to embed external resources, why wrap it in a shortcode?

If you have other alternatives, I’d love to hear about those too!

#editor, #media, #plugins, #shortcodes

WP_Hook: Next Generation Actions and Filters

WordPress 4.7 introduces a significant reworking of action and filter iteration to address bugs that arose from recursive callbacks and from callbacks that changed the hooked callbacks on currently running actions/filters.

What does this mean for you, the plugin or theme developer? In almost all cases, nothing. Everything should continue to run as expected, and this should fix a number of hard-to-trace bugs when different plugins are stepping on each others callbacks.

Who is affected?

If your plugin directly accesses the $wp_filter global rather than using the public hooks API, you might run into compatibility issues.

Case 1: Directly setting callbacks in the $wp_filter array

$wp_filter['save_post'][10]['my_special_key'] = array( 'function' => 'my_callback_function', 'accepted_args' => 2 );

This will no longer work, and will cause a fatal error. $wp_filter['save_post'] is no longer a simple array. Rather, it is an object that implements the ArrayAccess interface.

You have two options to work around. The first (and preferred) method is to use the add_filter() or add_action() functions.

add_action( 'save_post', 'my_callback_function', 10, 2 );

If, for some reason, you absolutely cannot, you can still work around this.

if ( ! isset( $wp_filter['save_post'] ) ) {
    $wp_filter['save_post'] = new WP_Hook();
}
$wp_filter[ 'save_post' ]->callbacks[10]['my_special_key'] = array( 'function' => 'my_callback_function', 'accepted_args' => 2 );

Case 2: Directly unsetting callbacks in the $wp_filter array

unset( $wp_filter['save_post'][10][ $my_callback_id ] );

This will fail for the same reason as case one. To work around, you can use the standard remove_filter() / remove_action() functions.

remove_action( 'save_post', 'my_callback_function', 10, 2 );

Or, if you absolutely must access the array directly:

if ( isset( $wp_filter[ 'save_post' ] ) ) {
    unset( $wp_filter['save_post']->callbacks[10][ $my_callback_id ] );
}

Case 3: Checking if a hook is an array

if ( isset( $wp_filter['save_post'] ) && is_array( $wp_filter['save_post'] ) ) {
    // do something
}

This will always return false. $wp_filter['save_post'] is a WP_Hook object. To check if a hook has callbacks, use has_action() or has_filter().

if ( has_action( 'save_post' ) ) {
    // do something
}

Case 4: Moving the $wp_filter array pointer manually

If you’re calling next() or prev() on the $wp_filter array pointer to manually manage the order that callbacks are called in (or if you’re doing it to work around #17817), you will likely be unsuccessful. Use callback priorities, add_action() / add_filter(), and remove_action() / remove_filter() appropriately and let WordPress manage execution order.

Other Cases

Almost all other cases where you might manipulate the $wp_filter global directly should continue to function as expected. The WP_Hook object implements the ArrayAccess and IteratorAggregate interfaces so that, while it’s not recommended, you may continue to iterate over callbacks in $wp_filter or directly retrieve priorities from the callback array.

Props

While there were many contributors of the course of this ticket, all of whom are listed in the changeset, I’d like to especially thank @jbrinley, for his work in architecting this solution, researching and testing potential compatibility issues, and for authoring the bulk of this post.

What’s Next

We’re confident in how solid the code is for the majority of sites, and for the major edge cases, so now it’s time to add the code to the nightly build, so all y’all can test it against your sites and plugins.

This is being treated as an early commit of a feature project, so the final decision for whether this code will be kept in WordPress 4.7 will be made no later than beta 1, which gives us a month and a half to see how it effects usage in the wider world.

The current nightly build contains this update, for your testing enjoyment.

If you have any feedback on the code, please leave a comment on this post. Please post any bugs you find to Core Trac.

#4-7, #dev-notes, #feature-projects, #hooks, #plugins

Introducing admin_print_footer_scripts-$hook_suffix in 4.6

The admin_print_footer_scripts action hook is the last chance to localize admin scripts; but it is a generic one. If you ever wanted to do something for specific admin pages only, you would either have to hook into another dynamic action, or hook into admin_print_footer_scripts and check the $hook_suffix (which is not even passed, but that’s not an issue) yourself. The problem with the former is that there might be happening a lot between the chosen action and when your script gets enqueued (admin_print_footer_scripts); and maybe you need to be aware of what has happened. The problem with the latter is that you would have to register possibly a lot of functions, maybe check the current admin page inside several of these, and eventually bail most of the times. That’s why WordPress 4.6 brings the dynamic footer action admin_print_footer_scripts-$hook_suffix. See [37279].

The following pre-4.6 code

add_action( 'admin_print_footer_scripts', function() {
    global $hook_suffix;

    if ( 'some_admin_page' !== $hook_suffix ) {
        return;
    }

    // Whatever it is that you want to do...
} );

can now be simplified like this:

add_action( 'admin_print_footer_scripts-some_admin_page', function() {
    // Whatever it is that you want to do...
} );

This change brings more consistency between wp-admin/admin-footer.php and wp-admin/admin-header.php, which already fires the generic admin_print_scripts and the dynamic admin_print_scripts-$hook_suffix actions.

For more background on the change, see #34334.

#4-6, #dev-notes, #plugins, #script-loader

Changes to the Shortcode API

Earlier today, we released WordPress 4.2.3, which includes a relatively large security fix that affects the Shortcode API. Due to the nature of the fix – as is often the case with security fixes – we were unable to alert plugin authors ahead of time, however we did make efforts to scan the plugin directory for plugins that may have been affected.

With this change, every effort has been made to preserve all of the core features of the Shortcode API. That said, there are some new limitations that affect some rare uses of shortcodes.

Reminder: Never, under any circumstances, should you hack core files. This includes downgrading specific files. Doing so could have unintended consequences on your WordPress installation, including major security implications.

Basic Shortcode Usage

A brief explanation on the original purpose of shortcodes will help to explain the change. In a basic post, like this example, shortcodes are used to insert dynamic code:

Here are my images. [gallery]

Here you can see that the shortcode stands on its own as a dynamic element within the blog post content. This is the central premise of the Shortcode API: make it easy to insert blocks of dynamic code.

Shortcodes with Filtered Styles

In today’s release of WordPress 4.2.3, however, we’ve added some new limitations that affect some existing plugins. Take, for example, the following shortcode, which is no longer recognized:

<div style="background-image: url('[shortcode]');">

The shortcode in the example above appears in a context that is no longer supported. Further, this use of a shortcode stretches the imagination for how the Shortcode API was intended to be used. Fortunately, there are some workarounds still available, so that site administrators are not overly restricted in their use of HTML.

Workaround

The following example still functions as expected and is considered more acceptable:

<div [shortcode]>

Going forward, plugins implementing shortcodes for inline styles should output the entire style attribute rather than a bare value. Keep in mind that this workaround – just as the original example above – is only available to administrators and editors (i.e. only roles with unfiltered_html). Less-privileged users are still prevented from using shortcodes to output whole attributes in this manner. If a plugin is intended to work with author and contributor roles, we recommend that the plugin output an entire <div>.

Shortcodes with Bad Quotes

The following example is also no longer allowed:

<a href="/[shortcode query="?ref="]">

In the above situation, the shortcode is now properly recognized as HTML and it is rejected by the API. Apart from the example being confusing, WordPress cannot parse that shortcode.

Workaround

Instead, either of the following examples would be appropriate:

Example 1: <a href="/[shortcode query='?ref=']">
Example 2: <a href='/[shortcode query="?ref="]'>

Administrators as well as lesser-privileged authors can continue to use shortcodes in this way, as long is it conforms to the usual HTML filtering rules. However, as explained in the first example, administrators are now somewhat limited in this situation in one case: if the content in this href attribute is generated by a shortcode that does not conform to the HTML filters, then the shortcode is rejected for all users.

We do not make this change lightly and understand that it may affect some usecases. The above examples and explanations should help plugin authors make the modifications needed to support the Shortcode API.

#4-2, #4-2-3, #dev-notes, #plugins, #shortcodes

Scalable Dropdowns update

In our initial meeting on Wednesday (IRC log), we outlined some steps and a fairly aggressive timeline to get ourselves in a place where changes to wp_dropdown_users() (#19867) and wp_dropdown_pages() (#9864) are suitable for patch review.

To that end, we’ve opened a handful of issues on GitHub for work and discussion, so that we can track completion. These tasks include evaluating various accessibility areas (touch, mobile, keyboard, screen reader), creating a JS wrapper, UI skinning, and page hierarchy representation. Please check them out and participate as you are able and willing. Let’s keep those issues task-oriented, however – any other questions or comments can go here.

#4-1, #dropdowns, #plugins

Ideas for plugin/theme install/update UIs

In the last few releases, the theme and plugin installers received new UI. But the actual procedure of installing a plugin or theme is still old-school: a JavaScript alert confirms you actually did want to install something, then you get taken an ugly screen that prints out sentences of “Downloading package,” etc. If there is an error, everything stops. If it succeeds, you can activate what you just installed or go back to where you came from.

To say this is not the best experience is an understatement. We can streamline this entire flow while also adding some new functionality. Here’s the goal: Installing or updating a plugin or theme should not block you from continuing what you were doing. Secondarily: unnecessary and sub-par user interfaces should be eliminated.

Some ideas:

  • You should be able to install a plugin/theme without leaving the installer screens.
  • You should be able to continue searching and browsing for other plugins (or themes).
  • Multiple plugins/themes should be able to be queued for installation at once.
  • Progress is shown directly inside the installer. Details are only shown if there is an error.

How are we going to do this?

  • Once an install starts for an item, we can “lock” that item to the top left of the results, even if the user keeps browsing or searching for other things.
  • The plugin installer is not yet dynamic, so we’ll need to add infinite scroll and such to allow for continuous browsing (something we avoided doing in 4.0 due to time constraints).
  • We’ll need to come up with a UI for installing a plugin, such as a card-flip, a subtle progress bar, or button changes (“Install” “Installing…” “Installed!”).
  • Updating plugins, themes, and core (from the Dashboard → Updates, Plugins, and Themes screens) should be seamless and happen inline, which will be a completely different UI from installing.
  • We must make sure a user abort (leaving the page) is prevented and/or doesn’t stop the update. We must probably make sure that updates are queued (only one actually happening at once), as we have to take into account maintenance mode, conflicts, I/O operations, and such.
  • If the user is forced to enter FTP credentials, we can request it once in a modal, then send it with each Ajax request — much nicer experience.

The tracking ticket is #29820. Thoughts, ideas, challenges, suggestions, questions welcome.

#plugins, #themes, #upgrade-install

Scalable Dropdowns and More, chat on 2014/10/8

In 3.9, I started taking a look at solving some long-standing scaling issues with dropdowns, notably those for users (#19867) and pages (#9864). I arrived at a conclusion about our mixed usage of autocomplete and autosuggest far too late to make it for 3.9, and did not add it to my plate for 4.0, but would like to tackle it again for 4.1.

We can solve these issues smartly by using a combination of Ajax-powered autocomplete/suggest and smart defaults, e.g. users with the most content pre-loaded for quick access without having to run a search. As a brief overview of where I see us going with this – a roadmap, if you will: user dropdown, page dropdown, current instances of jQuery UI autocomplete (multisite users and new site), tags/nonhierarchical taxonomy UI, more built-in taxonomy UIs (#14877), and possibly more as we discover appropriate places. Not all of this will happen in 4.1 – think of this as not only a solution to long-standing, painful problems, but also a step in a series of many.

To that end, we will be holding an initial chat at 19:00 UTC on 2014/10/8 to get things moving. @ericlewis and I have begun early development as a plugin – for more, see this particular branch, which experiments with using Select 2 as a JS helper library for the UI.

#4-1, #dropdowns, #plugins

Introducing plugin icons in the plugin installer

WordPress 4.0 comes with a redesigned plugin installer. Just now we’ve added one of the finishing touches to this project — plugin icons.

Plugin authors, If your plugin is compatible with WordPress 4.0, it only takes a few moments to change a readme “Tested up to:” value to 4.0. Compatibility information is prominently shown in the new plugin installer, so you’ll definitely want to update this value. For your plugin to stand out, you’ll also want to give your plugin an icon. Read on…

Akismet

Beautiful, auto-generated icons

Default icons are generated using the GeoPattern library by Jason Long of GitHub. If you have a banner image, it is automatically sampled to determine the primary color for the pattern, using Tonesque from @matveb. (Cool, huh?)

mosiac-2

Making your own icon

Plugin icons are 128 pixels square. HiDPI (retina) icons are supported at 256 pixels square. Like banners, these go into your /assets directory and can be either a PNG or JPG. So just create assets/icon-128x128.(png|jpg) and/or assets/icon-256x256.(png|jpg) and you have an icon.

You also have another option: SVG. Vectors are perfect for icons like this, as they can be scaled to any size and the file itself is small. For an SVG file, you simply need an assets/icon.svg file.

We may implement SVG-to-images fallbacks in core for browsers that don’t support them, so if you go the SVG route, I’d suggest also turning your SVG into a PNG. (SVG takes precedence.)

Jetpack uses an SVG icon:

Some tips when designing an icon

  • Keep it simple! The Android and iOS Human Interface Guidelines both have some fantastic design tips.
  • Avoid text, especially since these may be seen at smaller sizes in other contexts (and in languages other than English). And because this is an icon, not an ad.
  • Use the right image format for what you’re doing. Don’t use JPGs for simple designs; don’t use PNGs for photos.
  • Optimize your images! Use something like ImageOptim or your favorite web app, CLI tool, etc.
  • Please no WordPress logos. Come up with your own brand. (If you already have a banner image, you likely already have a head start here.)
  • If you haven’t worked with SVGs before, they’re pretty cool. Here’s a tutorial from Chris Coyier.
  • Keep in mind this is an icon for your plugin, not a display ad.

Some examples

Akismet, Jetpack, and Hello Dolly already have icons. You can see their assets directories herehere, and here.

Thanks to the hard work of Alex Shiels (@tellyworth) for implementing this!

#4-0, #dev-notes, #plugins, #upgrade-install

Improving the Plugins Page: Follow-up

Following up on this earlier post: https://make.wordpress.org/core/2014/05/28/improving-the-plugins-page/

After chatting a bit with Alex Shiels, Nacin, and Helen, I’ve put together a first pass at what an improved “add new plugin” page could look like:

I based the new page off of the updated “add new theme” page. Instead of going with filters you can add together to search results, I’ve opted to use some broad categories. Filtering doesn’t really work with plugins, especially filters outside of different categories — if you check “backup” in security and “galleries” in media, you’re not likely to get any results. Clicking on a category would bring up results weighted by # of downloads, popularity, reviews, etc. If we did end up adding some additional filters, they could be for things like version compatibility or language.

We’ve already talked a bit about how a visual might not be the best way to scan for new plugins, and how we need to highlight plugin descriptions more. We also talked a bit about the possibility of having a better landing page if you don’t have any plugins installed on your site, that would show a mix of featured/popular plugins and categories to browse through.

This doesn’t affect installed plugin management — we were thinking that would remain mostly the same, maybe with some minor updates.

One thing we really want to nail down is the average plugin install workflow: “I want WordPress to do X. It doesn’t seem to do X. Maybe a plugin can help me! Here’s how I would look for that plugin. Here’s how I would evaluate and compare the plugins returned by how I looked for them. Here’s how I would install it/activate it.” What does your workflow look like?

#plugins

Improving the Plugins page

The WordPress Plugins page has barely changed in 5 years or more – compare WP 2.7.1 with 3.9.1.

The very first page seen by a new user who clicks on the Plugins tab is a list view showing two installed plugins. The main thing thing that has changed since 2.7 is that the way to find and install new plugins has become less obvious.

Similarly, the plugin-install page has barely changed in that time: WP 2.7.1 and 3.9.1.

The default page is very much geared towards maintenance by established users. The most common interaction is probably deactivating and reactivating plugins for troubleshooting – certainly a necessary task, but I think it misses a good opportunity for helping people to find and use the plugins they need.

There are a number of improvements that could be made with relatively minor changes:

Improve the experience for new and infrequent users.

  • The obvious fix here would be to make the path for discovering and installing new plugins much more obvious than the “Add New” link. Perhaps even go as far as making plugin-install.php the default page.
  • The Search Installed Plugins box on plugins.php is easily mistaken for a plugin directory search. Either make it less confusing, or use a unified search.
  • When searching for plugins in the directory via plugin-install.php, tailor the results to the current WP version. Give more weight to those that are compatible with the current version, and/or filter out those that are likely to be incompatible.

Help users to discover the plugins they need, especially the most robust and well-maintained.

  • On the Add New page, the most common tags in the cloud are “widget”, “post” and “plugin”. It’s next to useless. Replace it with a well-defined list of categories more in line with common needs: “contact forms”, “image galleries”, “security” and so on.
  • Improve the quality of plugin directory search results generally. Incorporate things like ratings, support stats, age, usage stats, and update frequency in the relevancy scores.
  • Augment or replace version compatibility votes with stats based on active installs per WP version.
  • Re-evaluate the tabs on the Install Plugins page. Is “Newest” helpful? Should “Popular” or “Featured” have a summary on the main page?
  • Improve the algorithm used for averaging ratings, to smooth out errors for plugins with only a handful of ratings.
  • Change the columns displayed in Search Results. “Version” doesn’t need a column; but compatibility and age ought to be shown.
  • Also show compatibility for installed plugins #27699
  • Improve the ordering and filtering possible in the plugin search API #12696 and #27316

Improve the way detailed information is given about plugins.

  • Either eliminate the thickbox for the plugin details, or make it more consistent with the theme browser (allow next/prev)
  • Add a Details view for installed plugins #17902
  • Show reviews in the detailed view #22599
  • Show contributors in the detailed view #19784
  • Show the plugin’s banner in the detailed view, and generally make it more consistent with what’s on the web site.

Help and encourage developers to publish and maintain their plugins.

  • Support screenshots, logos, or banners in the search results, installed plugin list and plugin directory.
  • Do a better job of handling ratings, reviews, updates, and support stats, especially when determining search ordering and popularity.
  • Improve the profile page to list version compatibility, support stats, and other useful info for all your plugins.
  • Add a version requirement check and/or upgrade prompt #26909 and #27323

And finally there are some other tickets suggesting improvements and fixes that could use a second look:

  • #28085 – Recently Updated plugins view (recently updated installed plugins)
  • #20578 – allow delete without uninstall
  • #27110 – allow filtering the plugin list
  • #26202 – bugfix for thickbox title truncation
  • #27623 – search results for a single space
  • #27994 – handling of automatic plugin deactivation in the event of an error

I’m working on the API side, starting with improvements to search quality. There are tickets above for many of these items already. If you’d like to help out, keep an eye on the Plugins Component in trac, open and help with tickets. Or leave a comment here with your suggestions if you’re interested.

 

 

 

 

 

#plugins