So I have created this widget which pulls a number of posts. And the query is being cached via transients. But I need the transient to be deleted whenever a post is saved so the query can be refreshed.

Have a look at this code snippet.

add_action( 'save_post', 'delete_transient' );

function delete_transient() {
     if ( $_POST['post_type'] === 'post' ) {
          // this is a hack around to delete widget transients
          $max = 20;

          for( $i = 1; $i <= $max; $i++ ) { 
           delete_transient( 'my-posts-widget-' . $i );

Ok so everything setup and working however because a widget can have multiple instances, deleting the transient is becoming an issue. Here is why. Every time you put a widget into the sidebar, the unique number WP assigns is incremented. So if someone happened to drag the widget out and then put it back again, it will increment the number again. So my $max = 20 will soon not be valid anymore as the id could then be 30... I could set the $max to 100000+ but that is not practical.

So with that in mind, you can see this is not a fully working solution. So my question is how are you guys handling this or have an idea of a work around?

Thanks for looking.

  • Why can't your widgets share a single transient? Are they saving different queries?
    – s_ha_dum
    Commented Apr 9, 2013 at 3:24
  • It can't because each widget can have different queries so if I saved it all under one transient, they will overwrite each other.
    – user23654
    Commented Apr 9, 2013 at 3:26
  • I can't help but think this could be solved by a different caching scheme but I'd have to understand how your widgets work make any progress with that idea.
    – s_ha_dum
    Commented Apr 9, 2013 at 3:47
  • Thanks for trying...I have posted a workaround solution.
    – user23654
    Commented Apr 9, 2013 at 3:57

2 Answers 2


Use a widget cache and forget the actual number of active widgets.

In your widget add this to your method widget():

public function widget( $args, $instance ) 
    // get the cache
    $cache = wp_cache_get( 'UNIQUE_WIDGET_IDENTIFIER', 'widget' );

    if ( !is_array( $cache ) )
        $cache = array();

    if ( ! isset ( $args['widget_id'] ) )
        $args['widget_id'] = $this->id;

    if ( isset ( $cache[ $args['widget_id'] ] ) )
        return print $cache[ $args['widget_id'] ];

    // go on with your widget logic, put everything into a string and …

    $cache[ $args['widget_id'] ] = $widget_string;

    wp_cache_set( 'UNIQUE_WIDGET_IDENTIFIER', $cache, 'widget' );

    print $widget_string;

And in your widget’s __construct() register the flush actions:

add_action( 'save_post',    array( $this, 'flush_widget_cache' ) );
add_action( 'deleted_post', array( $this, 'flush_widget_cache' ) );
add_action( 'switch_theme', array( $this, 'flush_widget_cache' ) );

The callback in your widget class is just a simple …

public function flush_widget_cache() 
    wp_cache_delete( 'UNIQUE_WIDGET_IDENTIFIER', 'widget' );

Transients time out even if nothing has changed. That's not what you need here.
Don’t forget to replace UNIQUE_WIDGET_IDENTIFIER with your own value. :)

  • Hey Toscho, thanks for this however I can't seem to get it to work. I put a var dump after return print, and it always executes which tells me the cache is not being set. Any ideas on that?
    – user23654
    Commented Apr 9, 2013 at 21:30
  • I ended up using transient instead because I think the query cache would benefit from persistent caching...However I will mark this as the correct answer as your idea helped me with getting rid of the "tracking active widgets" part. Thanks again!
    – user23654
    Commented Apr 9, 2013 at 23:43

So I came up with this hacky work around for now but it works.

add_action( 'save_post', 'delete_transient' );

function delete_transient() {
     if ( $_POST['post_type'] === 'post' ) {
          $ids = get_widget_id_number();

          foreach( $ids as $id ) { 
              delete_transient( 'my-posts-widget-' . $id );

function get_widget_id_number() {
    $widgets = get_option( 'sidebars_widgets' );
    $widget_ids = array();

    foreach( $widgets as $widget ) {
        if ( is_array( $widget ) ) {
            foreach( $widget as $widget_saved ) {
                $widget_saved_name = substr( $widget_saved, 0, strrpos( $widget_saved, '-' ) );
                $widget_id = substr( $widget_saved, -1, strrpos( $widget_saved, '-' ) );
                if ( $widget_saved_name === 'my-posts-widget' )
                    $widget_ids[] = $widget_id;

    array_unique( $widget_ids );

    return $widget_ids;

Hope that will help others in this situation.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.