Ben Lobaugh Online

I think, therefore I am. I am, therefore I sail

Category: Web Development Page 2 of 30

Find and update WordPress posts with comments older than NNN days

I have a use case where I need to disable comments on posts in WordPress where the last comment was more than one year, or 365 days, ago.

Posts can be found with this query:

SELECT p.ID, p.post_title, p.post_date, p.comment_status, p.`ping_status`
FROM wp_posts AS p
     SELECT c.comment_post_ID
     FROM wp_comments AS c
     WHERE DATEDIFF( curdate(), c.comment_date ) <= 365

The outer query takes the inner query as the search parameter. The inner query is finding the latest comment for each post based on the number in the WHERE condition. 365 represents 365 days, or 1 year.

Therefore, this query is getting the latest comment for post where the comment is less than 1 year old.

Now let’s say you need to update the posts to disable comments. The goal is to disable commenting for all posts that have not had a comment within the last year. It can be accomplished with the following:

UPDATE wp_posts
SET comment_status='closed', ping_status='closed'
		SELECT c.comment_post_ID
		FROM wp_comments AS c
		WHERE DATEDIFF( curdate(), c.comment_date ) >= 365

Here again the number 365 represents the number of days.

Check the posts and you should see the comments have been closed.

WordPress Multisite: Global options that can be overridden per site

I recently ran into a situation where a WordPress Multisite install needed to have some options replicated across each site, both new and existing. It also needed to be able to override the options per site if so desired. The solution is fairly trivial.

  • Setup the options page in wp-admin. Ensure it exists on all subsites
  • On the main site fill in the values that should be defaulted across all sites
  • Drop the following code into your site and replace the placeholder with your own option name
  • Freely use the values from the main site or alter the options on a subsite

All you need to do to get this working is drop the following code into your site and change the placeholder to be the same as the option name that should be replicated.

add_filter( 'option_{OPTION_NAME}', 'my_option_settings', 10, 2 );
add_filter( 'default_option_{OPTION_NAME}', 'my_option_settings', 10, 2 );

function my_option_settings( $value, $option_name ) {
  // Do not loop on ourself
  if( 1 == get_current_blog_id() ) {
    // Bail out
    return $value;
  if( ! $value ) {
    $value = get_blog_option( 1, $option_name );
  return $value;

WordPress: Add category to permalink and redirect old permalinks

Occasionally you run across a situation where a website permalink structure needs to be changed from what it has been to a new structure. Most sites that have been public will have links to them from other websites that need to properly redirect to the new permalink structure. Removing an element from the permalink structure and redirecting old links is trivial, however adding an additional element to the url structure can be difficult. For example:

A fairly typical structure is: /%year%/%month%/%day%/%postname%/

Lets use a simple example of adding the category to the permalink structure: /%category%/%year%/%month%/%day%/%postname%/

To provide a more useful example:

With category:

The original url is going to display the 404 page. I am going to provide an example that you can use in your own site to capture the url causing the 404 and attempt to locate the new post permalink. If none can be found it will fallback to the 404 page. As long as there is something in the original url you can use to locate a post (like the  %postname%) this method will work with minor tweaks.

add_action( 'template_redirect', 'maybe_redirect_404_old_permalink' );
 * Attempts to forward old permalinks to the new permalink structure
 * @author Ben Lobaugh
function maybe_redirect_404_old_permalink() {
    // Only run this function if we are on a 404
    if( ! is_404() ) {
    // "trick" to get the full URL
    $url = add_query_arg( '', '' );

     * Pull the URL path apart to find a slug (post_name)
     * The final segment should be the slug
    $parts = explode( '/', $url );
    $parts = array_filter( $parts );
    $size = count( $parts );
    $maybe_slug = $parts[ $size ]; // We use size here because the filter turned 1 based

    // Attempt to locate corresponding post in the database
    $args = array(
        'name'        => $maybe_slug,
        'post_type'   => 'post',
        'post_status' => 'publish',
        'numberposts' => 1,

    $posts = get_posts( $args );

    // Identify a found post
    if( $posts && ! empty( $posts[0]->ID ) ) {
        $post_id = $posts[0]->ID;

        $post_url = get_permalink( $post_id );

        // Attempt to forward to the new post permalink
        if( $post_url ) {
            wp_safe_redirect( $post_url, 301 ); // Permanent redirect

     * If we made it down here then we could not find a matching post in
     * the database. No biggie, simply do nothing and display the 404 page
     * as normal 🙂

Prevent WordPress plugins from requesting updates

Ever need to “lock” a plugin into a specific version and do not want it showing in the updates list and getting accidentally updated?

This quick snippet allows you to specify a plugin(s) that should not appear in the update list. This will effectively block them from updating through WordPress itself. Manual updates/changes to the plugin(s) is still possible however.

add_filter( 'site_transient_update_plugins', array( 'no_updates_for_you' ) );

function no_updates_for_you( $value ) {
    $plugin = '[plugin_folder]/[plugin_file].php';
    if ( empty( $value ) || empty( $value->response[$plugin] ) ) {
      return $value;
    unset( $value->response[$plugin] );
    return $value;

Be sure to change [plugin_folder]/[plugin_file].php to the plugin you want to prevent updating.

Getting social media shares with php

Quick snippets to help me (and maybe you!) remember how to quickly and easily get share counts from social networks.

What other networks would you like to see?


function facebook_share_count( $post_id ) {
  $api = "";
  $url = $api . urlencode( get_permalink( $post_id ) );
  $response = wp_remote_get( $url );
  if( is_wp_error( $response ) ) {
    return 0;
  if( '200' != wp_remote_retrieve_response_code( $response ) ) {
    // Bad url
    return 0;
  $body = wp_remote_retrieve_body( $response );
  $body = json_decode( $body );
  if( isset( $body->shares ) ) {
    // Shares will not be set if there are none!
    return $body->shares;
  return 0;


NOTE: ***Twitter will be shutting down this API*** No replacement has been announced.

function twitter_share_count( $post_id ) {
  // Check for transient
  if ( ! ( $count = get_transient( 'twitter_count' . $post_id ) ) ) {
    // Do API call
    $response = wp_remote_retrieve_body( wp_remote_get( '' . urlencode( get_permalink( $post_id ) ) ) );
    // If error in API call, stop and don't store transient
    if ( is_wp_error( $response ) )
      return 'error';
    // Decode JSON
    $json = json_decode( $response );
    // Set total count
    $count = absint( $json->count );
    // Set transient to expire every 30 minutes
    set_transient( 'twitter_count' . $post_id, absint( $count ), 30 * MINUTE_IN_SECONDS );
 return absint( $count );


function linkedin_share_count( $post_id ) {
  $api = ';url=';
  $api .= urlencode( get_permalink( $post_id ) );
  if ( ! ( $count = get_transient( 'linkedin_count' . $post_id ) ) ) {
    $response = wp_remote_get( $api );
    if( is_wp_error( $response ) ) {
      // eat it
      return 0;
    // Should verify the correct json is returned
    $json = json_decode( wp_remote_retrieve_body( $response ) );
    $count = (int) $json->count;
    set_transient( 'linkedin_count' . $post_id, absint( $count ), 30 * MINUTE_IN_SECONDS );
  return $count;

Page 2 of 30