Make WordPress Core

Opened 16 months ago

Last modified 12 months ago

#55969 new enhancement

The function set_transient should have the autoload argument

Reported by: giuse's profile giuse Owned by:
Milestone: Awaiting Review Priority: normal
Severity: normal Version: 6.0
Component: Options, Meta APIs Keywords: needs-patch
Focuses: performance Cc:

Description

The function set_transient should have an argument to decide if a specific transient should be autoloaded or not so.
At the moment every transient that is set with the function set_transient is autoloaded.
Not all the transients have the need to be autoloaded. For example, many times transients that are used only in the backend don't need the autoload, but they slow down the frontend in some cases.

Change History (8)

#1 @galbaras
16 months ago

The set_transient() manual states:

NB: transients that never expire are autoloaded, whereas transients with an expiration time are not autoloaded. Consider this when adding transients that may not be needed on every page, and thus do not need to be autoloaded, impacting page performance.

This seems to make sense. Temporary values should definitely not be autoloaded, but permanent ones can help save some time by being autoloaded.

I've just checked one of my sites and it has 14 autoloaded transients vs. 138 that aren't autoloaded.

You can find out about your own site using the following SQL query:

SELECT autoload, count(*) FROM wp_options WHERE option_name LIKE '_transient_%' group by autoload

#2 @giuse
16 months ago

Temporary values should definitely not be autoloaded

It makes sense, I would totally agree if the sentence was without "definitely". You may have some rare situations where you want the autoload also for this kind of transients. Why don't give me the possibility to choose? Imagine transients that expire after 1-2 months. For 1-2 months I want them autoloaded.
You can't predict all the cases. It's perfect to have as default the autoload that has a sense for most cases, but why don't give the possibility to choose?
If I don't explicitly assign the autoload parameter it would be as it is now, and if I assign it, it means that I need to assign it.

Should permanent transients always be autoloaded? Also in this case, as a default yes, but you should be able to choose. You may need permanent transients that are not autoloaded. For example, permanent transients that run in the backend.

I would assign it as a default as it is now, but give the possibility to change the autoload if needed. The same as you do with normal options.

#3 @galbaras
16 months ago

Since this is all done in code, you can create a transient without expiry and manage updates to it yourself.

I'm wondering about the use case of this, though. Why do you need this, specifically?

On the other hand, to prevent autoloading, you can use 100 years (3153600000) for the expiration value.

Last edited 16 months ago by galbaras (previous) (diff)

#4 @giuse
16 months ago

Do you see any downsides in modifying the function with something like this?

<?php
function set_transient( $transient, $value, $expiration = 0,$custom_autoload = null ) {
 
    $expiration = (int) $expiration;
 
    /**
     * Filters a specific transient before its value is set.
     *
     * The dynamic portion of the hook name, `$transient`, refers to the transient name.
     *
     * @since 3.0.0
     * @since 4.2.0 The `$expiration` parameter was added.
     * @since 4.4.0 The `$transient` parameter was added.
     *
     * @param mixed  $value      New value of transient.
     * @param int    $expiration Time until expiration in seconds.
     * @param string $transient  Transient name.
     */
    $value = apply_filters( "pre_set_transient_{$transient}", $value, $expiration, $transient );
 
    /**
     * Filters the expiration for a transient before its value is set.
     *
     * The dynamic portion of the hook name, `$transient`, refers to the transient name.
     *
     * @since 4.4.0
     *
     * @param int    $expiration Time until expiration in seconds. Use 0 for no expiration.
     * @param mixed  $value      New value of transient.
     * @param string $transient  Transient name.
     */
    $expiration = apply_filters( "expiration_of_transient_{$transient}", $expiration, $value, $transient );
 
    if ( wp_using_ext_object_cache() || wp_installing() ) {
        $result = wp_cache_set( $transient, $value, 'transient', $expiration );
    } else {
        $transient_timeout = '_transient_timeout_' . $transient;
        $transient_option  = '_transient_' . $transient;
        $custom_autoload_is_valid = null !== $custom_autoload && in_array( $custom_autoload,array( 'no','yes',true,false ) );
 
        if ( false === get_option( $transient_option ) ) {

            $autoload = $custom_autoload_is_valid ? $custom_autoload : 'yes';
            if ( $expiration ) {
                $autoload = $ccustom_autoload_is_valid ? $custom_autoload : 'no';
                add_option( $transient_timeout, time() + $expiration, '', $autoload );
            }
            $result = add_option( $transient_option, $value, '', $autoload );
        } else {
            // If expiration is requested, but the transient has no timeout option,
            // delete, then re-create transient rather than update.
            $update = true;
 
            if ( $expiration ) {
                $autoload = $ccustom_autoload_is_valid ? $custom_autoload : 'no';
                if ( false === get_option( $transient_timeout ) ) {
                    delete_option( $transient_option );
                    add_option( $transient_timeout, time() + $expiration, '', $autoload );
                    $result = add_option( $transient_option, $value, '', $autoload );
                    $update = false;
                } else {
                    update_option( $transient_timeout, time() + $expiration,$autoload );
                }
            }
 
            if ( $update ) {
                $result = update_option( $transient_option, $value );
            }
        }
    }
 
    if ( $result ) {
 
        /**
         * Fires after the value for a specific transient has been set.
         *
         * The dynamic portion of the hook name, `$transient`, refers to the transient name.
         *
         * @since 3.0.0
         * @since 3.6.0 The `$value` and `$expiration` parameters were added.
         * @since 4.4.0 The `$transient` parameter was added.
         *
         * @param mixed  $value      Transient value.
         * @param int    $expiration Time until expiration in seconds.
         * @param string $transient  The name of the transient.
         */
        do_action( "set_transient_{$transient}", $value, $expiration, $transient );
 
        /**
         * Fires after the value for a transient has been set.
         *
         * @since 3.0.0
         * @since 3.6.0 The `$value` and `$expiration` parameters were added.
         *
         * @param string $transient  The name of the transient.
         * @param mixed  $value      Transient value.
         * @param int    $expiration Time until expiration in seconds.
         */
        do_action( 'setted_transient', $transient, $value, $expiration );
    }
 
    return $result;
}

Then, if I want to set a transient that expires for instance in 90 days, and I want the autoload (e.g. for a transient that is needed for 90 days and has to be autoloaded:

<?php
set_transient( 'my_transient',$my_value, 60*60*24*90,'yes' );

Without any workaround and any additional code.

IF I want a transient without expiration but also without autoload (e.g. for a transient that is needed only in the backend:

<?php
set_transient( 'my_transient',$my_value,false,'yes' );

Without workarounds and without additional code.

Last edited 16 months ago by giuse (previous) (diff)

#5 @desrosj
15 months ago

  • Keywords needs-patch added

@giuse if you could, please attach your suggested changes in the form of a patch or a pull request on GitHub. It's very difficult to see what is being changed from a full snippet.

#6 @desrosj
15 months ago

  • Component changed from Database to Options, Meta APIs

#7 @iandunn
12 months ago

Related: #54221 is one example of where this might be useful in Core.

Temporary values should definitely not be autoloaded, but permanent ones can help save some time by being autoloaded.

The correlation between expiration of a transient and how many pages it's used on isn't obvious to me; can you articulate it?

#8 @iandunn
12 months ago

ticket:22844#comment:6 alludes to a discussion in the 2.8 development phase. I searched around, though, and didn't find anything on Make/Core or wp-hackers. The logs for #wordpress-dev only go back to 2009-05-14 (2.7 was released on 2008-12-10, and 2.8 on 2009-6-11).


The new Optimized Autoloaded Options proposal is related.

Note: See TracTickets for help on using tickets.