Hello there! This is the newest addition in a series of periodic posts where we will highlight new support documentation and/or any changes made to existing docs. This is a great way to stay up-to-date with the latest VIP coding standards.
New Updates to “Validating, Sanitizing, and Escaping”:
- Escape on String Creation
- Addition:
- It is sometimes not practical to escape late. In a few rare circumstances you cannot pass the output to wp_kses since by definition it would strip the scripts that are being generated.
In situations like this always escape while creating the string and store the value in a variable that is a postfixed with_escaped
,_safe
or_clean
. - So instead of
$variable
do$variable_escaped
or$variable_safe
. Functions must always return “safe” html that do not rely on them being late escaped. This allows you to do echomy_custom_script_code();
without needing the script tag to be passed thru a version ofWP_KSES
that would allow such tags.
- It is sometimes not practical to escape late. In a few rare circumstances you cannot pass the output to wp_kses since by definition it would strip the scripts that are being generated.
- Addition:
rawurlencode()
should be used overurlencode()
for ensure URLs are correctly encoded. Only legacy systems should useurlencode()
.<?php echo esc_url( 'http://example.com/a/safe/url?parameter=' . rawurlencode( $stored_class ) ); ?>
New Updates to “Quickstart”:
- To create unit tests for your plugin/theme
- Removal:
- Important Note: Due to the PEAR install method being at end-of-life, PHPUnit does not currently install properly on Quickstart, and so unit testing will not work. We’re working on a new install method that addresses this.
- Removal:
New Addition to “Manipulating Changes”:
- Manipulating Changes
- We also support the WebP image format—and while WebP isn’t yet supported by all browsers, we auto-detect which browsers your readers are using to make sure they can enjoy your images at the best possible quality. Our system will always serve your viewers the best image format at the highest speed possible.
New Addition to “Caching”:
- Example: Caching WP_Query
- Try and avoid cache slams when setting multiple caches by using a more random cache expiration time, using something like:
<?php $args = array( 'orderby' => 'comment_count', 'posts_per_page' => '1', 'ignore_sticky_posts' => 1 ); $query = new WP_Query( $args ); while ( $query->have_posts() ) : $query->the_post(); // do stuff endwhile;
Here’s how to modify that loop to cache the results of the WP_Query object:
// First, let's see if we have the data in the cache already $query = wp_cache_get( 'ordered_comments_query' ); // the cache key is a unique identifier for this data if( $query == false ) { // Looks like the cache didn't have our data // Let's generate the query $args = array( 'orderby' => 'comment_count', 'posts_per_page' => '1', 'ignore_sticky_posts' => 1 ); $query = new WP_Query( $args ); // Now, let's save the data to the cache // In this case, we're telling the cache to expire the data after 300 seconds wp_cache_set( 'ordered_comments_query', $query, '', 300 ); // the third parameter is $group, which can be useful if you're looking to group related cached values together } // Once we're here, the $query var will be set either from the cache or from manually generating the WP_Query object while ( $query->have_posts() ) : $query->the_post(); // do stuff endwhile;
- Try and avoid cache slams when setting multiple caches by using a more random cache expiration time, using something like:
New Additions to “Code Review: What We Look For”:
- Use
wp_json_encode()
overjson_encode()
wp_json_encode()
will take care of making sure the string is valid utf-8 while the regular function will return false if it encounters invalid utf-8. It also supports backwards compatibility for versions of PHP that do not accept all the parameters
- Use
wp_parse_url()
instead ofparsurl()
- In PHP versions lower than 5.4.7 schemeless and relative urls would not be parsed correctly by
parse_url()
we therefore recommend that you usewp_parse_url
for backwards compatibility
- In PHP versions lower than 5.4.7 schemeless and relative urls would not be parsed correctly by
- Minified Javascript files
- Javascript files that are minified should also be committed with changes to their unminified counterparts. Minified files cannot be read for review, and are much harder to work with when debugging issues.
- Inserting HTML directly into DOM with Javascript
- To avoid XSS, inserting HTML directly into the document should be avoided. Instead, DOM nodes should be programmatically created and appended to the DOM. This means avoiding
.html()
,.innerHTML()
, and other related functions, and instead using.append()
,.prepend()
,.before()
,.after()
, and so on. More information.
- To avoid XSS, inserting HTML directly into the document should be avoided. Instead, DOM nodes should be programmatically created and appended to the DOM. This means avoiding
- Use
wp_safe_redirect()
instead ofwp_redirect()
- Using
wp_safe_redirect()
, along with theallowed_redirect_hosts
filter, can help avoid any chances of malicious redirects within code. It’s also important to remember to callexit()
after a redirect so that no other unwanted code is executed.
- Using
- Mobile Detection
- When targeting mobile visitors,
jetpack_is_mobile()
should be used instead ofwp_is_mobile
. It is more robust and works better with full page caching.
- When targeting mobile visitors,
- Using
bloginfo()
without escaping- Keeping with the theme of Escaping All the Things, code that uses
bloginfo()
should useget_bloginfo()
instead so that the data can be properly late escaped on output. Sinceget_bloginfo()
can return multiple types of data, and it can be used in multiple places, it may need escaped with many different functions depending on the context:echo '<a href="' . esc_url( get_bloginfo( 'url' ) ) . '">' . esc_html( get_bloginfo( 'name' ) ) . '</a>'; echo '<meta property="og:description" content="' . esc_attr( get_bloginfo( 'description' ) ) . '">';
- Keeping with the theme of Escaping All the Things, code that uses
- Custom
wp_mail
headers- The PHP Mailer is properly escaping headers for you only in case you’re using appropriate filters inside WordPress. Every time you want to create custom headers using user supplied data (eg.: “FROM” header), make sure you’re using filters provided by WordPress for you. See https://developer.wordpress.org/reference/hooks/wp_mail_from/ and https://developer.wordpress.org/reference/hooks/wp_mail_from_name/
- Functions that use JOINS, taxonomy relation queries, -cat, -tax queries, subselects or API calls
category__not_in
,tag__not_in
, andtax_query
with NOT IN (these should never be used unless using Elasticsearch)
- reCaptcha for Share by Email
- To protect against abuse of Jetpack’s share by e-mail feature (aka Sharedaddy) it must be implemented along with reCaptcha. This helps protect against the risk of the WordPress.com network being seen as a source of e-mail spam, which would adversely affect VIP sites. This blog post explains how to implement reCaptcha.
- Using closing PHP tags
- All PHP files should omit the closing PHP tag to prevent accidental output of whitespace and other characters, which can cause issues such as ‘Headers already sent‘ errors. This is part of the WordPress Coding Standards.
New Update to “Uncached Functions”:
- get_posts()
- When using
WP_Query
instead ofget_posts
don’t forget about settingignore_sticky_posts
andno_found_rows
params appropriately (both are hardcoded inside aget_posts
function with value oftrue
)
- When using
New Update to “Term queries should consider include_children => false”:
New Update to “Gravatars and Blavatars”:
- Disabling
- If you are not using Gravatars and Blavatars and need to disable the loading of related Javascript and CSS resources, you can use
wpcom_vip_disable_hovercards()
in your theme. - You’ll also want to disable the default favicon redirect with
remove_action( 'init', 'dynamic_favicon' );
- If you are not using Gravatars and Blavatars and need to disable the loading of related Javascript and CSS resources, you can use
New Support Documentation:
That’s about it! If you have any questions, please feel free to open up a support ticket with us!