2026年11月13日

2026年11月13日

Use Transients in a WordPress Plugin (set_transient, Delete, WP-CLI)

This article is a localized edition of the Japanese original. Read the Japanese original

The Transients API is the WordPress mechanism for storing things such as external API responses or the results of heavy database queries with an expiry time. You save with set_transient(), read with get_transient() and delete with delete_transient(). Because it skips repeating the work every time, it reduces the load on page rendering and on external services.

The code in this article was tested in November 2026 on WordPress 7.1 and WP-CLI 2.12.

Basic usage

<?php
// Save (name, value, expiry in seconds)
set_transient( 'myplugin_key', $data, HOUR_IN_SECONDS );

// Read (false if missing or expired)
$data = get_transient( 'myplugin_key' );

// Delete
delete_transient( 'myplugin_key' );

Key points to keep in mind:

  • Names must be 172 characters or fewer. Add a prefix such as myplugin_ so they do not clash with other plugins.
  • You can store arrays and objects as values (they are serialized automatically).
  • get_transient() returns false when the transient has expired or does not exist. So if you store false itself as the value, you cannot tell whether the cache exists.
  • A transient is a cache that is "not guaranteed to last until it expires". It can disappear early, so only store data you can rebuild if it is gone.

Cache the result of an external API

This example fetches the latest WordPress version from the WordPress.org API and caches it for 12 hours. Put it in your plugin file.

<?php
/**
 * Get the latest WordPress version from the WordPress.org API (cached for 12 hours)
 */
function myplugin_get_latest_wp_version() {
	$cache_key = 'myplugin_latest_wp_version';

	// Return the cached value if there is one
	$cached = get_transient( $cache_key );
	if ( false !== $cached ) {
		return $cached;
	}

	$response = wp_remote_get(
		'https://api.wordpress.org/core/version-check/1.7/',
		array( 'timeout' => 10 )
	);

	// Do not cache failures
	if ( is_wp_error( $response ) || 200 !== wp_remote_retrieve_response_code( $response ) ) {
		return '';
	}

	$data    = json_decode( wp_remote_retrieve_body( $response ), true );
	$version = $data['offers'][0]['version'] ?? '';

	if ( '' !== $version ) {
		set_transient( $cache_key, $version, 12 * HOUR_IN_SECONDS );
	}

	return $version;
}

In our test, the first call took about 0.6 seconds for the API request, and later calls returned instantly from the cache.

If you cache a failed connection or an error response as is, you keep returning the wrong result until it expires. As in this example, save only when the request succeeds.

Cache a heavy query and clear it on update

This example caches, for 6 hours, the IDs of popular posts sorted by a view-count custom field (here _myplugin_views). When a post is saved or deleted, the cache is cleared and rebuilt on the next call.

<?php
/**
 * Return the IDs of the most viewed posts (custom field _myplugin_views), cached for 6 hours
 */
function myplugin_get_popular_post_ids( $limit = 10 ) {
	$limit     = absint( $limit );
	$cache_key = 'myplugin_popular_' . $limit;

	$ids = get_transient( $cache_key );
	if ( false !== $ids ) {
		return $ids;
	}

	$ids = get_posts(
		array(
			'post_type'      => 'post',
			'post_status'    => 'publish',
			'posts_per_page' => $limit,
			'meta_key'       => '_myplugin_views',
			'orderby'        => 'meta_value_num',
			'order'          => 'DESC',
			'fields'         => 'ids',
			'no_found_rows'  => true,
		)
	);

	// Even zero results are saved as an empty array (not false, so it works as a cache)
	set_transient( $cache_key, $ids, 6 * HOUR_IN_SECONDS );

	return $ids;
}

// Clear the cache when a post is saved or deleted
function myplugin_flush_popular_cache( $post_id ) {
	if ( wp_is_post_revision( $post_id ) || wp_is_post_autosave( $post_id ) ) {
		return;
	}
	foreach ( array( 5, 10, 20 ) as $limit ) {
		delete_transient( 'myplugin_popular_' . $limit );
	}
}
add_action( 'save_post_post', 'myplugin_flush_popular_cache' );
add_action( 'deleted_post', 'myplugin_flush_popular_cache' );

This caches an array of IDs rather than post objects. The stored data stays small, and when displaying you can fetch the latest titles and so on.

Delete transients whose names share a prefix

If transient names include arguments and you cannot list every name to delete, you can delete them from the database by prefix. A transient is stored in the wp_options table as two rows, _transient_NAME and _transient_timeout_NAME (the expiry), so delete both.

<?php
/**
 * Delete all transients whose names start with $prefix from the database
 * (does not work when an external object cache is in use)
 */
function myplugin_delete_transients_by_prefix( $prefix ) {
	global $wpdb;

	if ( wp_using_ext_object_cache() ) {
		return 0;
	}

	return $wpdb->query(
		$wpdb->prepare(
			"DELETE FROM {$wpdb->options} WHERE option_name LIKE %s OR option_name LIKE %s",
			$wpdb->esc_like( '_transient_' . $prefix ) . '%',
			$wpdb->esc_like( '_transient_timeout_' . $prefix ) . '%'
		)
	);
}

Because this changes the database directly, old values can remain in WordPress's internal cache within the same request. (In our test, get_transient() right after the deletion returned the old value, and returned false on the next request.)

Constants for expiry times

Expiry times are given in seconds. WordPress provides the following constants.

Constant Seconds
MINUTE_IN_SECONDS 60 (1 minute)
HOUR_IN_SECONDS 3600 (1 hour)
DAY_IN_SECONDS 86400 (1 day)
WEEK_IN_SECONDS 604800 (7 days)
MONTH_IN_SECONDS 2592000 (30 days)
YEAR_IN_SECONDS 31536000 (365 days)

An expiry of 0 means no expiry. Transients with no expiry are autoloaded, meaning they are loaded on every page request. Transients with an expiry are not autoloaded. Avoid storing large data with no expiry, because it slows down loading on every page.

When expired transients are removed

Transients stored in the database are not removed the moment they expire.

  • An expired transient is deleted on the spot when you try to read it with get_transient().
  • WordPress deletes expired transients in bulk with the daily WP-Cron event delete_expired_transients (this event is scheduled when the admin screen is opened).

How transients relate to the object cache

When a persistent object cache such as Redis or Memcached (an object-cache.php drop-in) is installed, transients are stored in the object cache instead of the database. You do not need to change your code, but the following changes:

  • No transient rows are created in the wp_options table, so the prefix deletion above does not work.
  • If the cache server runs low on memory, transients may disappear before they expire.

You can check where they are stored with the WP-CLI command wp transient type.

You can also use wp_cache_get() and wp_cache_set() directly. Without a persistent object cache, values saved with wp_cache_set() only last for that request. Use transients for values that must persist across requests, and wp_cache_* for caches that avoid repeating the same work within a single request.

Check and delete transients with WP-CLI

# Check where transients are stored (database or object cache)
wp transient type

# List transients filtered by name (with readable expiry times)
wp transient list --search='myplugin_*' --human-readable

# Get, set and delete a value
wp transient get myplugin_latest_wp_version
wp transient set myplugin_test_key "test" 3600
wp transient delete myplugin_test_key

# Delete all expired transients
wp transient delete --expired

# Delete all transients
wp transient delete --all

When an external object cache is in use, wp transient list and wp transient delete --all show a warning that they only cover transients stored in the database. In that case, clear the whole cache with wp cache flush to remove the transients in the object cache.

Related articles

Questions about WordPress? The publisher of this site is based in Japan and replies in Japanese. Contact (Japanese)

お気軽にご相談ください

お見積りへ お問い合わせへ
▲