Support Documentation Updates

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 echo my_custom_script_code(); without needing the script tag to be passed thru a version of WP_KSES that would allow such tags.
  • rawurlencode() should be used over urlencode() for ensure URLs are correctly encoded. Only legacy systems should use urlencode().
    <?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.

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;
      

New Additions to “Code Review: What We Look For”:

  • Use wp_json_encode() over json_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 of parsurl()
    • 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 use wp_parse_url for backwards compatibility
  • 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.
  • Use wp_safe_redirect() instead of wp_redirect()
    • Using wp_safe_redirect(), along with the allowed_redirect_hosts filter, can help avoid any chances of malicious redirects within code. It’s also important to remember to call exit() after a redirect so that no other unwanted code is executed.
  • Mobile Detection
    • When targeting mobile visitors, jetpack_is_mobile() should be used instead of wp_is_mobile. It is more robust and works better with full page caching.
  • Using bloginfo() without escaping
    • Keeping with the theme of Escaping All the Things, code that uses bloginfo() should use get_bloginfo() instead so that the data can be properly late escaped on output. Since get_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' ) ) . '">';
      
  • Custom wp_mail headers
  • 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 of get_posts don’t forget about setting ignore_sticky_posts and no_found_rows params appropriately (both are hardcoded inside a get_posts function with value of true )

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' );

New Support Documentation:

That’s about it! If you have any questions, please feel free to open up a support ticket with us!