Technote

Development workflow Practical

Series Using hooks and filters properly Part 3 of 8

Priority wars: whoever speaks last wins

Priority is a queue position, not authority. Raising your number is a move the other side can also make, and jumping behind a translation filter sends the untranslated original out.

When several callbacks are attached to the same filter, WordPress runs them from the lowest priority number upwards. Callbacks sharing a number run in registration order. The default is 10, and most plugins simply use it.

What matters is that with filters each callback receives the previous one’s result. Running later therefore means being able to overwrite what came before.

A number is a queue position, not authority

The filter chain — later is lower, and later overwrites earlier
add_filter( 'the_title', 'wper_shorten',  10 );
add_filter( 'the_title', 'wper_translate', 20 );

// wper_translate receives what wper_shorten returned.
// Slipping in at 30 overwrites an already-translated value.
add_filter( 'the_title', 'wper_decorate', 30 );

“My value is being ignored, so I will raise my number” is the natural reaction, and it does work in the moment. The trouble is that the other side can play the same card. If their next release moves to PHP_INT_MAX, you lose again. A priority race has no permanent winner.

Jumping behind a translation filter sends the original out

This is a live concern in this repository. The site translates its screens through a catalogue keyed by the Korean original, and that translator is attached to a particular filter at priority 20. The layer that supplies our copy to the same filter sits at 10.

What happens if the supplying layer moves to 20 or above? The Korean original is laid down again after the translator has already passed, and Korean titles go out in English search results. Every line of code is correct and nothing is logged — a single ordering decision undid the language.

Same code, same filter — one number decides which language ships

What to reach for instead of a race

Before raising a number, try these three. None of them competes over who stands further back in the queue.

Remove the other callback. If what it does genuinely conflicts with your work, removing it is more honest than painting over it. The mechanics and the traps are part six.

Own the source of the value. Rather than correcting at the end of a chain, put the right value in where it is produced. If it is your data, this is usually available to you.

Move to a different hook. The same outcome is frequently reachable from an earlier or later hook entirely. Finding a place where nobody is competing is the win.

Actually inspecting which callback sits at which number is the final part of this series, and if you would rather hand a review of conflicts like these over, that work is our optimization program. Related writing lives in the development workflow archive.

Next part

The next part narrows to a single hook. pre_get_posts is the most useful hook in WordPress and the one that causes the widest damage — miss two lines of guard and you rewrite the admin list tables as well.

More on this topic

All technotes

Development workflow Practical

Turning taste arguments into rule checks

"It feels a bit cramped" can be neither argued with nor fixed. Spacing off the scale, colour off the palette, contrast below threshold, missing states — four rules…

Designers 9 min read

Development workflow Practical

Do not swap everything at once

A full swap makes every problem appear at the same moment — which means none of them can be attributed. So you switch one template at a time.

Designers 6 min read

Development workflow Practical

Adding an SCSS build, and whether to commit the output

WordPress themes are expected to deploy without a build step, which leads to the opposite conclusion from ordinary application code — and to its own costs.

Developers 7 min read

₩270,000 · Join the program