Better Human-friendly Time Ago PHP Function

Last month I posted about a Human-friendly Time Ago PHP Function. Well, I’ve come across another way of doing it. This method has less code duplication, but is harder to understand at first glance. I prefer this method though, as it seems a bit more elegant than the other method. I’ve refined the code from the Stack Overflow post, and here’s what I have now.

/**
 * Calculates a human-friendly string describing how long ago a timestamp occurred.
 *
 * @link http://stackoverflow.com/a/2916189/3923505
 *
 * @param int $timestamp The timestamp to check.
 * @param int $now       The current time reference point.
 *
 * @return string The time ago in a human-friendly format.
 *
 * @throws \Exception if the timestamp is in the future.
 */
function time_ago( $timestamp = 0, $now = 0 ) {

    // Set up an array of time intervals.
    $intervals = array(
        60 * 60 * 24 * 365 => 'year',
        60 * 60 * 24 * 30  => 'month',
        60 * 60 * 24 * 7   => 'week',
        60 * 60 * 24       => 'day',
        60 * 60            => 'hour',
        60                 => 'minute',
        1                  => 'second',
    );

    // Get the current time if a reference point has not been provided.
    if ( 0 === $now ) {
        $now = time();
    }

    // Make sure the timestamp to check predates the current time reference point.
    if ( $timestamp > $now ) {
        throw new \Exception( 'Timestamp postdates the current time reference point' );
    }

    // Calculate the time difference between the current time reference point and the timestamp we're comparing.
    $time_difference = (int) abs( $now - $timestamp );

    // Check the time difference against each item in our $intervals array. When we find an applicable interval,
    // calculate the amount of intervals represented by the the time difference and return it in a human-friendly
    // format.
    foreach ( $intervals as $interval => $label ) {

        // If the current interval is larger than our time difference, move on to the next smaller interval.
        if ( $time_difference < $interval ) {
            continue;
        }

        // Our time difference is smaller than the interval. Find the number of times our time difference will fit into
        // the interval.
        $time_difference_in_units = round( $time_difference / $interval );

        if ( $time_difference_in_units <= 1 ) {
            $time_ago = sprintf( 'one %s ago',
                $label
            );
        } else {
            $time_ago = sprintf( '%s %ss ago',
                $time_difference_in_units,
                $label
            );
        }

        return $time_ago;
    }
}

How to Delete all WordPress-generated Thumbnail Sizes

After changing the registered thumbnail sizes and regenerating your thumbnails a few times during theme development, you may have quite a few thumbnails left over from old images sizes that don’t match any of the currently registered sizes, but are just sitting there in your uploads directory taking up space. Here is a command which will delete all generated thumbnails, after which you can regenerate your thumbnails one final time and be left with only the sizes currently registered in the theme.

Navigate to your uploads directory, and run this command:
find . -name *-*x*.jpg | xargs rm -f

Note that this will delete ALL generated thumbnails, so only run this if that’s what you want. The originals will be unaffected, unless they are named like a thumbnail.

How to Make the Tab Key Indent Text in a Texarea

I recently had a situation where the user needed to be able to insert tabs into a texarea. Normally, when the cursor is inside of a textarea, pressing tab will move the cursor to the next field or button in the form. However, in this case, I needed to change that behavior and make the tab key insert a tab character into the textarea content instead. Here’s how I did it in raw Javascript, no jQuery needed.

Note: Doing this will break the accessibility of your page in a very bad way. Make sure you have a Very Good Reason to do this before implementing it, as it will make it impossible for users to tab out of the textarea.

/**
 * Hijack the tab key to insert the tab into the content rather than moving the cursor to the next field or button in
 * the form.
 */
document.getElementById( 'my-texarea' ).addEventListener( 'keydown', function( event ) {

    if ( event.keyCode === 9 ) {

        // Set up some variables. We need to know the current position of the cursor or selection.
        var selectionStartPos = this.selectionStart;
        var selectionEndPos   = this.selectionEnd;
        var oldContent        = this.value;

        // Set the new content.
        this.value = oldContent.substring( 0, selectionStartPos ) + "\t" + oldContent.substring( selectionEndPos );

        // Set the new cursor position (current position + 1 to account for the new tab character).
        this.selectionStart = this.selectionEnd = selectionStartPos + 1;

        // Prevent the default action (tabbing to the next field or control).
        event.preventDefault();
    }
});

Note: You will want to make sure this code runs after the DOM has been loaded, or it will not be able to access your textarea.

Human-friendly Time Ago PHP Function

Say you want to get the amount which has elapsed in a human-friendly format. Something like “27 minutes ago” or “3 days ago.” If you’re using WordPress, there is a handy function called human_time_diff() which does just that. But if you’re not using WordPress, here is a PHP function which will do the same.

Update: I’ve come across a slightly more elegant way of doing this.

/**
 * Generates a human-readable string describing how long ago a timestamp occurred.
 *
 * @param int $timestamp The timestamp to check.
 * @param int $now       The current time reference point.
 *
 * @return string The time ago in a human-friendly format.
 *
 * @throws Exception if the timestamp is in the future.
 */
function time_ago( $timestamp = 0, $now = 0 ) {

    // Set up our variables.
    $minute_in_seconds = 60;
    $hour_in_seconds   = $minute_in_seconds * 60;
    $day_in_seconds    = $hour_in_seconds * 24;
    $week_in_seconds   = $day_in_seconds * 7;
    $month_in_seconds  = $day_in_seconds * 30;
    $year_in_seconds   = $day_in_seconds * 365;

    // Get the current time if a reference point has not been provided.
    if ( 0 === $now ) {
        $now = time();
    }

    // Make sure the timestamp to check is in the past.
    if ( $timestamp > $now ) {
        throw new Exception( 'Timestamp is in the future' );
    }

    // Calculate the time difference between the current time reference point and the timestamp we're comparing.
    $time_difference = (int) abs( $now - $timestamp );

    // Calculate the time ago using the smallest applicable unit.
    if ( $time_difference < $hour_in_seconds ) {

        $difference_value = round( $time_difference / $minute_in_seconds );
        $difference_label = 'minute';

    } elseif ( $time_difference < $day_in_seconds ) {

        $difference_value = round( $time_difference / $hour_in_seconds );
        $difference_label = 'hour';

    } elseif ( $time_difference < $week_in_seconds ) {

        $difference_value = round( $time_difference / $day_in_seconds );
        $difference_label = 'day';

    } elseif ( $time_difference < $month_in_seconds ) {

        $difference_value = round( $time_difference / $week_in_seconds );
        $difference_label = 'minute';

    } elseif ( $time_difference < $year_in_seconds ) {

        $difference_value = round( $time_difference / $month_in_seconds );
        $difference_label = 'month';

    } else {

        $difference_value = round( $time_difference / $year_in_seconds );
        $difference_label = 'year';
    }

    if ( $difference_value <= 1 ) {
        $time_ago = sprintf( 'one %s ago',
            $difference_label
        );
    } else {
        $time_ago = sprintf( '%s %ss ago',
            $difference_value,
            $difference_label
        );
    }

    return $time_ago;
}

New Plugin Release: Customizer Framework

A lightweight and easy-to-use framework for the WordPress Customizer. Provides a simple and intuitive API for registering Customizer settings, including advanced control types. Automatically sanitizes settings based on the control type. Eliminates the tedious task of registering a setting, control, and sanitization function for each individual Customizer setting.

Homepage: http://philipnewcomer.net/wordpress-customizer-framework/
WordPress Plugin: http://wordpress.org/plugins/customizer-framework/
GitHub Project: http://github.com/philipnewcomer/Customizer-Framework

 

How to Filter the Output of any WordPress Widget

Sometimes developers need to modify the HTML output of a widget that does not have its own output filter built-in, or does not provide the necessary hooks or filters for doing so. WordPress built-in widgets, I’m looking at you! WordPress provides no native way to filter the final output of any widget, so here are some workarounds that I’ve found.

Modify the widget’s source files.
Obviously this is not a good method, as your modifications will be lost if WordPress, or the plugin creating the widget is updated.

Copy the widget into your own plugin or theme and modify it there.
You could copy the entire original widget code, creating your own new widget in the process with your own modifications, or you could copy only the widget’s display callback function into your theme or plugin, extending the original widget class. This is better than modifying the original core files, in that your code will not be overwritten by updates. You would also have complete control over the generated generated. However, this brings along its own set of problems, chiefly that you now need to maintain all of this new code, porting over updates from the original widget source into your own copy, if the original code is updated with security patches or feature additions. That could be a maintenance nightmare down the road. In addition, the use case described in this post is for relatively minor modifications to a widget’s output, such as changing a CSS class, adding some additional markup, or some other relatively minor modification. Copying the original widget’s code into your own plugin or theme, in order to make those types of minor modifications, is neither efficient nor elegant.

Use output buffering the capture the output of the entire widget area, and run filters on that.
Now we’re getting somewhere. You can use PHP output buffering to save the entire widget area output to a string, and run a filter on that. This method still has some drawbacks, but it may be suitable for some people so here’s what it would look like:

In your sidebar.php template file, this would replace the dynamic_sidebar() function:

ob_start();
dynamic_sidebar( 'my-sidebar-id' );
$sidebar_output = ob_get_clean();
echo apply_filters( 'my_sidebar_output', $sidebar_output );

Then you can do something like this in your theme’s functions.php template file, or in your own custom plugin:

function my_widget_filter( $sidebar_output ) {
 
    /**
     * Perform some kind of search and replace here on $sidebar_output.
     * Regular Expressions will likely be required in order to restrict your
     * modifications to only the widgets you wish to modify, since $sidebar_output
     * contains the output of the entire sidebar, including all widgets.
     */
 
    return $sidebar_output;
 
}
add_filter( 'my_sidebar_output', 'my_widget_filter' );

The drawbacks with this method are that it doesn’t work in the WordPress Theme Customizer, so any modifications you would make to your widgets with the widget area filter would not appear there. It also requires that the theme have this widget area filtering support built-in, so you would need to use your own custom theme, or modify your existing theme in order to add support for this method. It also requires you to use Regular Expressions in order to target only the widgets you wish to modify, because the filter is run not on individual widgets, but on the output of the entire sidebar, which contains the output from all widgets that are active there.

Replace the widget’s original display callback function with a custom function, which then runs the original display callback function, but with filters.
This is the technique that works best for me. It still seems a bit “hack-ish”, so it would be nice if WordPress provided this natively. However, this is the best we’ve got for now. Basically, the widget’s original display callback function is overridden with a new custom function, which runs the widget’s original callback function, but uses output buffering to capture the output, and run it through a filter before displaying it. This method is already used by the Widget Logic plugin in its widget_content filter, so it’s not an entirely new concept. However, there may be times that a developer needs to filter a widget’s output, but doesn’t need the widget visibility feature of Widget Logic. Additionally, plugin or theme developers requiring widget output filtering should not need to require their users to install Widget Logic in order for their theme to work properly. For those cases, here is the code which can be used in a theme or plugin, which will provide a widget_output filter, along with the widget type and unique widget ID as parameters:

First, we need to replace the widget’s original display callback function with a custom function of own:

function my_filter_dynamic_sidebar_params( $sidebar_params ) {
 
    if ( is_admin() ) {
        return $sidebar_params;
    }
 
    global $wp_registered_widgets;
    $widget_id = $sidebar_params[0]['widget_id'];
 
    $wp_registered_widgets[ $widget_id ]['original_callback'] = $wp_registered_widgets[ $widget_id ]['callback'];
    $wp_registered_widgets[ $widget_id ]['callback'] = 'my_custom_widget_callback_function';
 
    return $sidebar_params;
 
}
add_filter( 'dynamic_sidebar_params', 'my_filter_dynamic_sidebar_params' );

Next, we need to create the function referenced in the previous block of code, which will in turn run the widget’s original display callback function, but will capture its output using PHP output buffering. Then, the widget_output filter will be run on the widget’s generated HTML markup, before being output to the page:

function my_custom_widget_callback_function() {
 
    global $wp_registered_widgets;
    $original_callback_params = func_get_args();
    $widget_id = $original_callback_params[0]['widget_id'];
 
    $original_callback = $wp_registered_widgets[ $widget_id ]['original_callback'];
    $wp_registered_widgets[ $widget_id ]['callback'] = $original_callback;
 
    $widget_id_base = $wp_registered_widgets[ $widget_id ]['callback'][0]-&gt;id_base;
 
    if ( is_callable( $original_callback ) ) {
 
        ob_start();
        call_user_func_array( $original_callback, $original_callback_params );
        $widget_output = ob_get_clean();
 
        echo apply_filters( 'widget_output', $widget_output, $widget_id_base, $widget_id );
 
    }
 
}

With that in place, you can do something like this in a plugin or theme, to modify the output of any widget:

function my_widget_output_filter( $widget_output, $widget_id_base, $widget_id ) {
 
    /* To target a specific widget ID: */
    if ( 'target_widget_id' == $widget_id ) {
        // Apply your desired search and replace operations here
    }
 
    /* To target all widgets of a particular type: */
    if ( 'target_widget_type' == $widget_type ) {
        // Apply your desired search and replace operations here
    }
 
    return $widget_output;
 
}
add_filter( 'widget_output', 'my_widget_output_filter', 10, 3 );

This code can be added to a plugin or theme to enable the filtering of widget output, and is also available in plugin form in the official WordPress plugin repository.