Note to self: WordPress comments are loaded in comments_tempate() not in WP_Query

This had somehow escaped my notice, but recently I was experimenting with a DRYing out my WordPress base theme and wanted to create some custom display logic for comments so I removed the call to comments_template() from my single post template.

I had assumed that all it really did was load the comments.php template from the theme or a fallback when needed. What I didn’t realise is that the comments for a given post or page are not loaded during the main query, but are queried directly in the comments_template() function. (The only exception is for RSS comment feeds which are loaded as part of the main query.)

The function is also responsible for stuffing the comments into the $wp_query global and setting the cpage query variables correctly.  It is a little frustrating as it means the theme must either some comment.php template even if it’s empty or recreate the comment display logic from comments_template().

Note to self: pseudo elements, line-height, rem and IE

It seems there is a bug in IE9-11 which causes line-height to collapse in psuedo-elements when the line height is set in rems.

The bug was reported by Matt Stow over a year ago in relation to IE10 but nothing seems to have been done to rectify the issue.

The best workaround is to set the line height in an equivalent px value instead.

Flexbox, clear fix and pseudo elements in Safari and Chrome

If you are progressively enhancing a layout with flexbox, remember that when you apply display: flex to an element, the flex layout applies to all its children including any pseudo elements.

This can occasionally cause issues in some browsers if you already have a clear fix in place to ensure the height of the element respects any floated children. One of the most common ways of doing this is to set the pseudo elements ::before and ::after to force the parent element to wrap:

.clear-fix:before,
.clear-fix:after {
    content: "";
    display: table;
}

.clear-fix:after {
    clear: both;
}

But applying flexbox can cause these elements to obtain small width of 1px in some browsers which looks ugly and probably isn’t what you want. Here’s a pen to test it out for yourself.

The fix

To hide the pseudo element, we need to tell the flexbox algorithm that they should definitely have zero width by using the flex-basis property which sets the initial size of the flexitem.

However, for some reason (I think to do with the fact the pseudo-elements are display: table) that isn’t enough. The ::after element shrinks away to nothing, but the ::before remains. The only way I have found to fix this is by explicitly setting the order property to something other than the default 0. The seems to give flexbox the kick it needs to force apply the flex-basis to both pseudo-elements:

.clear-fix:before,
.clear-fix:after {
  flex-basis: 0;
  order: 1;
}

Because these properties are only available in browsers which support flexbox, they shouldn’t interfere with the styles in older browsers, so you don’t need to test with Modernizr before using it.

The culprits

I haven’t tested extensively but this is what I’ve found so far:

Browser Chrome Safari Firefox
Version 33 6.1.1 27.0.1
Display Incorrect Incorrect Correct

The flexbox spec is still settling down so this kind of anomaly is to be expected. Still it’s good to know there is a fix for it.

Note to self: Old Safari, Android 2.3 and max-width: none

It seems some older browsers don’t correctly interpret element widths when both width: 100% and max-width: none are set.

I created a quick pen on CodePen to test this out. The test has two examples.

The first example should show the placeholder image at it’s natural width (300px). All browsers seems to get this right.

The second example with width: 100%; max-width: none; should show the image stretched to the full width of the red container. The value none is the default for max-width so the image should obey the 100% width declaration.

max width test: correct

However in some browsers (notably Safari before version 5.1) the image will revert to its natural size. This is a screenshot from Safari 4.0.5 for example:

max width test: incorrect

This seems to affect at least: IE6, Safari <5.1, and Android 2.3.

The solution seems to be to set: max-width: 100% on the child element to force it to occupy the full width on all browsers.

Old version of Safari make up a very small percentage of global usage but Android 2.3 is still pretty common so it’s worth watching out for.

Related:

Note to self: String.prototype.trim() is not universal

If you want to strip whitespace from a string in JavaScript then the simplest way is:

"  My string with some extra whitespace   ".trim();

which should just give you

"My string with some extra whitespace"

Unfortunately the trim() was introduced in ECMAScript 5.1 and is only available in newer browsers. Here’s the support table for major desktop browsers.

Chrome Firefox Internet Explorer Opera Safari
All 3.5 9 10.5 5

Source: MDN

This means you will either need to polyfill the String prototype or use jQuery’s trim() method if that is available.

More information on MDN

Note to self: Firefox handles inherited height differently

Unlike Chrome and Safari, elements in Firefox don’t automatically inherit their heights from the containing element. So elements with implicit height (eg. images) will stretch the containing element to to their full height.

To prevent this happening, each descendant element of a container with a height must have either and explicit heigh (probably height: 100% or height: inherit. Note that IE7 doesn’t support inherit as a value for height.

See this pen for a test case.

I’m not clear which browser is out of spec on this.

Note to self: user_has_cap doesn’t do what you think it does.

The WordPress filter user_has_cap is a bit misleading. It doesn’t (as the name suggested to me) return a boolean indicating whether the user has a given capability. Instead it allows last minute filtering of the capabilities that a user has, allowing you to add and remove caps just before they are checked against those required for the particular action.

The arguments are:

  • $allcaps
    • The array of caps that the given user has assigned to them
  • $caps
    • The array of caps required for the current action
    • Has already been filtered through map_meta_caps
  • $args
    • Additional arguments passed to the has_cap() method of the user object
    • May contain post ID or other info needed for cap check

A user_has_cap filter might make additional checks against the user and then set or unset the relevant capability in the $allcaps array before returning it.

Note to self: the map_meta_cap conversation

The WordPress function current_user_can() calls $user->has_cap() which calls the map_meta_cap filter.

The purpose of map_meta_cap is to filter and return the list of capabilities that a user needs to complete a task. Essentially, the conversation goes something like this:

has_cap: “Hey, user ‘Dan’ would like to read_post 342. What caps will he need?”

map_meta_cap: “He’ll need read, read_post and read_published_posts

has_cap: “Cool. Let me see if he has all of those. … Looks like he does! I’ll let current_user_can() know.”

The other thing to remember is that capabilities are cumulative. Each additional cap that map_meta_cap returns makes the permission more restrictive: has_cap() will check each one in turn against the capabilities that the user has and bail out immediately if any are not present.