Make WordPress Core

Changeset 56717


Ignore:
Timestamp:
09/26/2023 03:53:39 PM (3 years ago)
Author:
flixos90
Message:

Options, Meta APIs: Fix follow up bug when comparing values for options using the pre_option_{$option} filter.

This fix is relevant for options such as gmt_offset that use a filter to force a specific value regardless of what is stored in the database.

Props mamaduka, flixos90, mukesh27, spacedmonkey.
See #22192.

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/option.php

    r56681 r56717  
    777777        $value = apply_filters( 'pre_update_option', $value, $option, $old_value );
    778778
     779        /*
     780         * To get the actual raw old value from the database, any existing pre filters need to be temporarily disabled.
     781         * Immediately after getting the raw value, they are reinstated.
     782         * The raw value is only used to determine whether a value is present in the database. It is not used anywhere
     783         * else, and is not passed to any of the hooks either.
     784         */
     785        if ( has_filter( "pre_option_{$option}" ) ) {
     786                global $wp_filter;
     787
     788                $old_filters = $wp_filter[ "pre_option_{$option}" ];
     789                unset( $wp_filter[ "pre_option_{$option}" ] );
     790
     791                $raw_old_value                       = get_option( $option );
     792                $wp_filter[ "pre_option_{$option}" ] = $old_filters;
     793        } else {
     794                $raw_old_value = $old_value;
     795        }
     796
    779797        /** This filter is documented in wp-includes/option.php */
    780798        $default_value = apply_filters( "default_option_{$option}", false, $option, false );
     
    788806         * See https://core.trac.wordpress.org/ticket/38903 and https://core.trac.wordpress.org/ticket/22192.
    789807         */
    790         if ( $old_value !== $default_value && _is_equal_database_value( $old_value, $value ) ) {
     808        if ( $raw_old_value !== $default_value && _is_equal_database_value( $raw_old_value, $value ) ) {
    791809                return false;
    792810        }
    793811
    794         if ( $old_value === $default_value ) {
     812        if ( $raw_old_value === $default_value ) {
    795813
    796814                // Default setting for new options is 'yes'.
  • trunk/tests/phpunit/tests/option/option.php

    r56681 r56717  
    439439                }
    440440        }
    441 
    442441
    443442        /**
     
    582581                $this->assertSame( 1, $actual );
    583582        }
     583
     584        /**
     585         * Tests that a non-existing option is added even when its pre filter returns a value.
     586         *
     587         * @ticket 22192
     588         *
     589         * @covers ::update_option
     590         */
     591        public function test_update_option_with_pre_filter_adds_missing_option() {
     592                // Force a return value of integer 0.
     593                add_filter( 'pre_option_foo', '__return_zero' );
     594
     595                /*
     596                 * This should succeed, since the 'foo' option does not exist in the database.
     597                 * The default value is false, so it differs from 0.
     598                 */
     599                $this->assertTrue( update_option( 'foo', 0 ) );
     600        }
     601
     602        /**
     603         * Tests that an existing option is updated even when its pre filter returns the same value.
     604         *
     605         * @ticket 22192
     606         *
     607         * @covers ::update_option
     608         */
     609        public function test_update_option_with_pre_filter_updates_option_with_different_value() {
     610                // Add the option with a value of 1 to the database.
     611                add_option( 'foo', 1 );
     612
     613                // Force a return value of integer 0.
     614                add_filter( 'pre_option_foo', '__return_zero' );
     615
     616                /*
     617                 * This should succeed, since the 'foo' option has a value of 1 in the database.
     618                 * Therefore it differs from 0 and should be updated.
     619                 */
     620                $this->assertTrue( update_option( 'foo', 0 ) );
     621        }
     622
     623        /**
     624         * Tests that calling update_option() does not permanently remove pre filters.
     625         *
     626         * @ticket 22192
     627         *
     628         * @covers ::update_option
     629         */
     630        public function test_update_option_maintains_pre_filters() {
     631                add_filter( 'pre_option_foo', '__return_zero' );
     632                update_option( 'foo', 0 );
     633
     634                // Assert that the filter is still present.
     635                $this->assertSame( 10, has_filter( 'pre_option_foo', '__return_zero' ) );
     636        }
    584637}
Note: See TracChangeset for help on using the changeset viewer.