Make WordPress Core

Ticket #37923: 37923-phase1.diff

File 37923-phase1.diff, 39.9 KB (added by flixos90, 7 years ago)
  • src/wp-admin/includes/ms.php

     
    127127                        $wpdb->query( "DROP TABLE IF EXISTS `$table`" );
    128128                }
    129129
     130                if ( is_site_meta_supported() ) {
     131                        $blog_meta_ids = $wpdb->get_col( $wpdb->prepare( "SELECT meta_id FROM $wpdb->blogmeta WHERE blog_id = %d ", $blog_id ) );
     132                        foreach ( $blog_meta_ids as $mid ) {
     133                                delete_metadata_by_mid( 'blog', $mid );
     134                        }
     135                }
     136
    130137                $wpdb->delete( $wpdb->blogs, array( 'blog_id' => $blog_id ) );
    131138
    132139                /**
  • src/wp-admin/includes/schema.php

     
    265265  PRIMARY KEY  (blog_id),
    266266  KEY db_version (db_version)
    267267) $charset_collate;
     268CREATE TABLE $wpdb->blogmeta (
     269  meta_id bigint(20) NOT NULL auto_increment,
     270  blog_id bigint(20) NOT NULL default '0',
     271  meta_key varchar(255) default NULL,
     272  meta_value longtext,
     273  PRIMARY KEY  (meta_id),
     274  KEY meta_key (meta_key($max_index_length)),
     275  KEY blog_id (blog_id)
     276) $charset_collate;
    268277CREATE TABLE $wpdb->registration_log (
    269278  ID bigint(20) NOT NULL auto_increment,
    270279  email varchar(255) NOT NULL default '',
  • src/wp-includes/class-wp-site-query.php

     
    4242        );
    4343
    4444        /**
     45         * Metadata query container.
     46         *
     47         * @since 4.8.0
     48         * @access public
     49         * @var object WP_Meta_Query
     50         */
     51        public $meta_query = false;
     52
     53        /**
     54         * Metadata query clauses.
     55         *
     56         * @since 4.8.0
     57         * @access protected
     58         * @var array
     59         */
     60        protected $meta_query_clauses = array();
     61
     62        /**
    4563         * Date query container.
    4664         *
    4765         * @since 4.6.0
     
    99117         * Sets up the site query, based on the query vars passed.
    100118         *
    101119         * @since 4.6.0
     120         * @since 4.8.0 Introduced the `update_site_meta_cache`, `meta_query`, `meta_key`,
     121         *              `meta_value`, `meta_type` and `meta_compare` parameters.
    102122         * @access public
    103123         *
    104124         * @param string|array $query {
    105125         *     Optional. Array or query string of site query parameters. Default empty.
    106126         *
    107          *     @type array        $site__in          Array of site IDs to include. Default empty.
    108          *     @type array        $site__not_in      Array of site IDs to exclude. Default empty.
    109          *     @type bool         $count             Whether to return a site count (true) or array of site objects.
    110          *                                           Default false.
    111          *     @type array        $date_query        Date query clauses to limit sites by. See WP_Date_Query.
    112          *                                           Default null.
    113          *     @type string       $fields            Site fields to return. Accepts 'ids' (returns an array of site IDs)
    114          *                                           or empty (returns an array of complete site objects). Default empty.
    115          *     @type int          $ID                A site ID to only return that site. Default empty.
    116          *     @type int          $number            Maximum number of sites to retrieve. Default 100.
    117          *     @type int          $offset            Number of sites to offset the query. Used to build LIMIT clause.
    118          *                                           Default 0.
    119          *     @type bool         $no_found_rows     Whether to disable the `SQL_CALC_FOUND_ROWS` query. Default true.
    120          *     @type string|array $orderby           Site status or array of statuses. Accepts 'id', 'domain', 'path',
    121          *                                           'network_id', 'last_updated', 'registered', 'domain_length',
    122          *                                           'path_length', 'site__in' and 'network__in'. Also accepts false,
    123          *                                           an empty array, or 'none' to disable `ORDER BY` clause.
    124          *                                           Default 'id'.
    125          *     @type string       $order             How to order retrieved sites. Accepts 'ASC', 'DESC'. Default 'ASC'.
    126          *     @type int          $network_id        Limit results to those affiliated with a given network ID. If 0,
    127          *                                           include all networks. Default 0.
    128          *     @type array        $network__in       Array of network IDs to include affiliated sites for. Default empty.
    129          *     @type array        $network__not_in   Array of network IDs to exclude affiliated sites for. Default empty.
    130          *     @type string       $domain            Limit results to those affiliated with a given domain. Default empty.
    131          *     @type array        $domain__in        Array of domains to include affiliated sites for. Default empty.
    132          *     @type array        $domain__not_in    Array of domains to exclude affiliated sites for. Default empty.
    133          *     @type string       $path              Limit results to those affiliated with a given path. Default empty.
    134          *     @type array        $path__in          Array of paths to include affiliated sites for. Default empty.
    135          *     @type array        $path__not_in      Array of paths to exclude affiliated sites for. Default empty.
    136          *     @type int          $public            Limit results to public sites. Accepts '1' or '0'. Default empty.
    137          *     @type int          $archived          Limit results to archived sites. Accepts '1' or '0'. Default empty.
    138          *     @type int          $mature            Limit results to mature sites. Accepts '1' or '0'. Default empty.
    139          *     @type int          $spam              Limit results to spam sites. Accepts '1' or '0'. Default empty.
    140          *     @type int          $deleted           Limit results to deleted sites. Accepts '1' or '0'. Default empty.
    141          *     @type string       $search            Search term(s) to retrieve matching sites for. Default empty.
    142          *     @type array        $search_columns    Array of column names to be searched. Accepts 'domain' and 'path'.
    143          *                                           Default empty array.
    144          *     @type bool         $update_site_cache Whether to prime the cache for found sites. Default false.
     127         *     @type array        $site__in               Array of site IDs to include. Default empty.
     128         *     @type array        $site__not_in           Array of site IDs to exclude. Default empty.
     129         *     @type bool         $count                  Whether to return a site count (true) or array of site objects.
     130         *                                                Default false.
     131         *     @type array        $date_query             Date query clauses to limit sites by. See WP_Date_Query.
     132         *                                                Default null.
     133         *     @type string       $fields                 Site fields to return. Accepts 'ids' (returns an array of site IDs)
     134         *                                                or empty (returns an array of complete site objects). Default empty.
     135         *     @type int          $ID                     A site ID to only return that site. Default empty.
     136         *     @type int          $number                 Maximum number of sites to retrieve. Default 100.
     137         *     @type int          $offset                 Number of sites to offset the query. Used to build LIMIT clause.
     138         *                                                Default 0.
     139         *     @type bool         $no_found_rows          Whether to disable the `SQL_CALC_FOUND_ROWS` query. Default true.
     140         *     @type string|array $orderby                Site status or array of statuses. Accepts 'id', 'domain', 'path',
     141         *                                                'network_id', 'last_updated', 'registered', 'domain_length',
     142         *                                                'path_length', 'site__in' and 'network__in'. Also accepts false,
     143         *                                                an empty array, or 'none' to disable `ORDER BY` clause.
     144         *                                                Default 'id'.
     145         *     @type string       $order                  How to order retrieved sites. Accepts 'ASC', 'DESC'. Default 'ASC'.
     146         *     @type int          $network_id             Limit results to those affiliated with a given network ID. If 0,
     147         *                                                include all networks. Default 0.
     148         *     @type array        $network__in            Array of network IDs to include affiliated sites for. Default empty.
     149         *     @type array        $network__not_in        Array of network IDs to exclude affiliated sites for. Default empty.
     150         *     @type string       $domain                 Limit results to those affiliated with a given domain. Default empty.
     151         *     @type array        $domain__in             Array of domains to include affiliated sites for. Default empty.
     152         *     @type array        $domain__not_in         Array of domains to exclude affiliated sites for. Default empty.
     153         *     @type string       $path                   Limit results to those affiliated with a given path. Default empty.
     154         *     @type array        $path__in               Array of paths to include affiliated sites for. Default empty.
     155         *     @type array        $path__not_in           Array of paths to exclude affiliated sites for. Default empty.
     156         *     @type int          $public                 Limit results to public sites. Accepts '1' or '0'. Default empty.
     157         *     @type int          $archived               Limit results to archived sites. Accepts '1' or '0'. Default empty.
     158         *     @type int          $mature                 Limit results to mature sites. Accepts '1' or '0'. Default empty.
     159         *     @type int          $spam                   Limit results to spam sites. Accepts '1' or '0'. Default empty.
     160         *     @type int          $deleted                Limit results to deleted sites. Accepts '1' or '0'. Default empty.
     161         *     @type string       $search                 Search term(s) to retrieve matching sites for. Default empty.
     162         *     @type array        $search_columns         Array of column names to be searched. Accepts 'domain' and 'path'.
     163         *                                                Default empty array.
     164         *     @type bool         $update_site_cache      Whether to prime the cache for found sites. Default false.
     165         *     @type bool         $update_site_meta_cache Whether to prime meta caches for matched sites. Default true.
     166         *     @type array        $meta_query             Optional. Meta query clauses to limit retrieved sites by.
     167         *                                                See `WP_Meta_Query`. Default empty.
     168         *     @type string       $meta_key               Limit sites to those matching a specific metadata key.
     169         *                                                Can be used in conjunction with `$meta_value`. Default empty.
     170         *     @type string       $meta_value             Limit sites to those matching a specific metadata value.
     171         *                                                Usually used in conjunction with `$meta_key`. Default empty.
     172         *     @type string       $meta_type              Type of object metadata is for (e.g., comment, post, or user).
     173         *                                                Default empty.
     174         *     @type string       $meta_compare           Comparison operator to test the 'meta_value'. Default empty.
    145175         * }
    146176         */
    147177        public function __construct( $query = '' ) {
    148178                $this->query_var_defaults = array(
    149                         'fields'            => '',
    150                         'ID'                => '',
    151                         'site__in'          => '',
    152                         'site__not_in'      => '',
    153                         'number'            => 100,
    154                         'offset'            => '',
    155                         'no_found_rows'     => true,
    156                         'orderby'           => 'id',
    157                         'order'             => 'ASC',
    158                         'network_id'        => 0,
    159                         'network__in'       => '',
    160                         'network__not_in'   => '',
    161                         'domain'            => '',
    162                         'domain__in'        => '',
    163                         'domain__not_in'    => '',
    164                         'path'              => '',
    165                         'path__in'          => '',
    166                         'path__not_in'      => '',
    167                         'public'            => null,
    168                         'archived'          => null,
    169                         'mature'            => null,
    170                         'spam'              => null,
    171                         'deleted'           => null,
    172                         'search'            => '',
    173                         'search_columns'    => array(),
    174                         'count'             => false,
    175                         'date_query'        => null, // See WP_Date_Query
    176                         'update_site_cache' => true,
     179                        'fields'                 => '',
     180                        'ID'                     => '',
     181                        'site__in'               => '',
     182                        'site__not_in'           => '',
     183                        'number'                 => 100,
     184                        'offset'                 => '',
     185                        'no_found_rows'          => true,
     186                        'orderby'                => 'id',
     187                        'order'                  => 'ASC',
     188                        'network_id'             => 0,
     189                        'network__in'            => '',
     190                        'network__not_in'        => '',
     191                        'domain'                 => '',
     192                        'domain__in'             => '',
     193                        'domain__not_in'         => '',
     194                        'path'                   => '',
     195                        'path__in'               => '',
     196                        'path__not_in'           => '',
     197                        'public'                 => null,
     198                        'archived'               => null,
     199                        'mature'                 => null,
     200                        'spam'                   => null,
     201                        'deleted'                => null,
     202                        'search'                 => '',
     203                        'search_columns'         => array(),
     204                        'count'                  => false,
     205                        'date_query'             => null, // See WP_Date_Query
     206                        'update_site_cache'      => true,
     207                        'update_site_meta_cache' => true,
     208                        'meta_query'             => '',
     209                        'meta_key'               => '',
     210                        'meta_value'             => '',
     211                        'meta_type'              => '',
     212                        'meta_compare'           => '',
    177213                );
    178214
    179215                if ( ! empty( $query ) ) {
     
    229265         * @since 4.6.0
    230266         * @access public
    231267         *
     268         * @global wpdb $wpdb WordPress database abstraction object.
     269         *
    232270         * @return array|int List of sites, or number of sites when 'count' is passed as a query var.
    233271         */
    234272        public function get_sites() {
     273                global $wpdb;
     274
    235275                $this->parse_query();
    236276
     277                // Set up meta_query so it's available to 'pre_get_sites'.
     278                if ( class_exists( 'WP_Meta_Query' ) ) {
     279                        $this->meta_query = new WP_Meta_Query();
     280                        $this->meta_query->parse_query_vars( $this->query_vars );
     281                }
     282
    237283                /**
    238284                 * Fires before sites are retrieved.
    239285                 *
     
    243289                 */
    244290                do_action_ref_array( 'pre_get_sites', array( &$this ) );
    245291
     292                // Reparse query vars, in case they were modified in a 'pre_get_comments' callback.
     293                if ( $this->meta_query ) {
     294                        $this->meta_query->parse_query_vars( $this->query_vars );
     295                        if ( is_site_meta_supported() && ! empty( $this->meta_query->queries ) ) {
     296                                $this->meta_query_clauses = $this->meta_query->get_sql( 'blog', $wpdb->blogs, 'blog_id', $this );
     297                        }
     298                }
     299
    246300                // $args can include anything. Only use the args defined in the query_var_defaults to compute the key.
    247301                $key = md5( serialize( wp_array_slice_assoc( $this->query_vars, array_keys( $this->query_var_defaults ) ) ) );
    248302                $last_changed = wp_cache_get_last_changed( 'sites' );
     
    286340
    287341                // Prime site network caches.
    288342                if ( $this->query_vars['update_site_cache'] ) {
    289                         _prime_site_caches( $site_ids );
     343                        if ( $this->meta_query ) {
     344                                _prime_site_caches( $site_ids, $this->query_vars['update_site_meta_cache'] );
     345                        } else {
     346                                _prime_site_caches( $site_ids, false );
     347                        }
    290348                }
    291349
    292350                // Fetch full site objects from the primed cache.
     
    366424
    367425                        $orderby = implode( ', ', $orderby_array );
    368426                } else {
    369                         $orderby = "blog_id $order";
     427                        $orderby = "$wpdb->blogs.blog_id $order";
    370428                }
    371429
    372430                $number = absint( $this->query_vars['number'] );
     
    383441                if ( $this->query_vars['count'] ) {
    384442                        $fields = 'COUNT(*)';
    385443                } else {
    386                         $fields = 'blog_id';
     444                        $fields = "$wpdb->blogs.blog_id";
    387445                }
    388446
    389447                // Parse site IDs for an IN clause.
    390448                $site_id = absint( $this->query_vars['ID'] );
    391449                if ( ! empty( $site_id ) ) {
    392                         $this->sql_clauses['where']['ID'] = $wpdb->prepare( 'blog_id = %d', $site_id );
     450                        $this->sql_clauses['where']['ID'] = $wpdb->prepare( "$wpdb->blogs.blog_id = %d", $site_id );
    393451                }
    394452
    395453                // Parse site IDs for an IN clause.
    396454                if ( ! empty( $this->query_vars['site__in'] ) ) {
    397                         $this->sql_clauses['where']['site__in'] = "blog_id IN ( " . implode( ',', wp_parse_id_list( $this->query_vars['site__in'] ) ) . ' )';
     455                        $this->sql_clauses['where']['site__in'] = "$wpdb->blogs.blog_id IN ( " . implode( ',', wp_parse_id_list( $this->query_vars['site__in'] ) ) . ' )';
    398456                }
    399457
    400458                // Parse site IDs for a NOT IN clause.
    401459                if ( ! empty( $this->query_vars['site__not_in'] ) ) {
    402                         $this->sql_clauses['where']['site__not_in'] = "blog_id NOT IN ( " . implode( ',', wp_parse_id_list( $this->query_vars['site__not_in'] ) ) . ' )';
     460                        $this->sql_clauses['where']['site__not_in'] = "$wpdb->blogs.blog_id NOT IN ( " . implode( ',', wp_parse_id_list( $this->query_vars['site__not_in'] ) ) . ' )';
    403461                }
    404462
    405463                $network_id = absint( $this->query_vars['network_id'] );
     
    507565
    508566                $join = '';
    509567
     568                if ( ! empty( $this->meta_query_clauses ) ) {
     569                        $join .= $this->meta_query_clauses['join'];
     570
     571                        // Strip leading 'AND'.
     572                        $this->sql_clauses['where']['meta_query'] = preg_replace( '/^\s*AND\s*/', '', $this->meta_query_clauses['where'] );
     573
     574                        if ( ! $this->query_vars['count'] ) {
     575                                $groupby = "{$wpdb->blogs}.blog_id";
     576                        }
     577                }
     578
    510579                $where = implode( ' AND ', $this->sql_clauses['where'] );
    511580
    512581                $pieces = array( 'fields', 'join', 'where', 'orderby', 'limits', 'groupby' );
     
    659728                                $parsed = 'CHAR_LENGTH(path)';
    660729                                break;
    661730                        case 'id':
    662                                 $parsed = 'blog_id';
     731                                $parsed = "$wpdb->blogs.blog_id";
    663732                                break;
    664733                }
    665734
     735                if ( ! $parsed && is_site_meta_supported() && $this->meta_query ) {
     736                        switch ( $orderby ) {
     737                                case $this->query_vars['meta_key']:
     738                                case 'meta_value':
     739                                        $parsed = "$wpdb->blogmeta.meta_value";
     740                                        break;
     741                                case 'meta_value_num':
     742                                        $parsed = "$wpdb->blogmeta.meta_value+0";
     743                                        break;
     744                                default:
     745                                        $meta_query_clauses = $this->meta_query->get_clauses();
     746                                        if ( $meta_query_clauses && isset( $meta_query_clauses[ $orderby ] ) ) {
     747                                                $meta_clause = $meta_query_clauses[ $orderby ];
     748                                                $parsed = sprintf( "CAST(%s.meta_value AS %s)", esc_sql( $meta_clause['alias'] ), esc_sql( $meta_clause['cast'] ) );
     749                                        }
     750                        }
     751                }
     752
    666753                return $parsed;
    667754        }
    668755
  • src/wp-includes/load.php

     
    515515        }
    516516
    517517        if ( function_exists( 'wp_cache_add_global_groups' ) ) {
    518                 wp_cache_add_global_groups( array( 'users', 'userlogins', 'usermeta', 'user_meta', 'useremail', 'userslugs', 'site-transient', 'site-options', 'site-lookup', 'blog-lookup', 'blog-details', 'site-details', 'rss', 'global-posts', 'blog-id-cache', 'networks', 'sites' ) );
     518                wp_cache_add_global_groups( array( 'users', 'userlogins', 'usermeta', 'user_meta', 'useremail', 'userslugs', 'site-transient', 'site-options', 'site-lookup', 'blog-lookup', 'blog-details', 'site-details', 'rss', 'global-posts', 'blog-id-cache', 'networks', 'sites', 'blog_meta' ) );
    519519                wp_cache_add_non_persistent_groups( array( 'counts', 'plugins' ) );
    520520        }
    521521}
  • src/wp-includes/ms-blogs.php

     
    457457        wp_cache_delete( 'current_blog_' . $blog->domain, 'site-options' );
    458458        wp_cache_delete( 'current_blog_' . $blog->domain . $blog->path, 'site-options' );
    459459        wp_cache_delete( $domain_path_key, 'blog-id-cache' );
     460        wp_cache_delete( $blog_id, 'blog_meta' );
    460461
    461462        /**
    462463         * Fires immediately after a site has been removed from the object cache.
     
    534535 * Adds any sites from the given ids to the cache that do not already exist in cache.
    535536 *
    536537 * @since 4.6.0
     538 * @since 4.8.0 The $update_meta_cache parameter was added.
    537539 * @access private
    538540 *
    539541 * @see update_site_cache()
     542 * @see update_sitemeta_cache()
     543 *
    540544 * @global wpdb $wpdb WordPress database abstraction object.
    541545 *
    542  * @param array $ids ID list.
     546 * @param array $ids               ID list.
     547 * @param bool  $update_meta_cache Optional. Whether to update the meta cache. Default true.
    543548 */
    544 function _prime_site_caches( $ids ) {
     549function _prime_site_caches( $ids, $update_meta_cache = true ) {
    545550        global $wpdb;
    546551
    547552        $non_cached_ids = _get_non_cached_ids( $ids, 'sites' );
     
    549554                $fresh_sites = $wpdb->get_results( sprintf( "SELECT * FROM $wpdb->blogs WHERE blog_id IN (%s)", join( ",", array_map( 'intval', $non_cached_ids ) ) ) );
    550555
    551556                update_site_cache( $fresh_sites );
     557
     558                if ( $update_meta_cache ) {
     559                        update_sitemeta_cache( $non_cached_ids );
     560                }
    552561        }
    553562}
    554563
     
    571580}
    572581
    573582/**
     583 * Updates metadata cache for list of site IDs.
     584 *
     585 * Performs SQL query to retrieve all metadata for the sites matching `$site_ids` and stores them in the cache.
     586 * Subsequent calls to `get_site_meta()` will not need to query the database.
     587 *
     588 * @since 4.8.0
     589 *
     590 * @param array $site_ids List of site IDs.
     591 * @return array|false Returns false if there is nothing to update. Returns an array of metadata on success.
     592 */
     593function update_sitemeta_cache( $site_ids ) {
     594        // Bail if site meta table is not installed.
     595        if ( ! is_site_meta_supported() ) {
     596                return;
     597        }
     598
     599        return update_meta_cache( 'blog', $site_ids );
     600}
     601
     602/**
    574603 * Retrieves a list of sites matching requested arguments.
    575604 *
    576605 * @since 4.6.0
     
    628657}
    629658
    630659/**
     660 * Add meta data field to a site.
     661 *
     662 * Site meta data is called "Custom Fields" on the Administration Screen.
     663 *
     664 * @since 4.8.0
     665 *
     666 * @param int    $site_id    Site ID.
     667 * @param string $meta_key   Metadata name.
     668 * @param mixed  $meta_value Metadata value. Must be serializable if non-scalar.
     669 * @param bool   $unique     Optional. Whether the same key should not be added.
     670 *                           Default false.
     671 * @return int|false Meta ID on success, false on failure.
     672 */
     673function add_site_meta( $site_id, $meta_key, $meta_value, $unique = false ) {
     674        if ( ! is_site_meta_supported() || is_core_site_meta_key( $meta_key ) ) {
     675                return false;
     676        }
     677
     678        $added = add_metadata( 'blog', $site_id, $meta_key, $meta_value, $unique );
     679
     680        // Bust site query cache.
     681        if ( $added ) {
     682                wp_cache_set( 'last_changed', microtime(), 'sites' );
     683        }
     684
     685        return $added;
     686}
     687
     688/**
     689 * Remove metadata matching criteria from a site.
     690 *
     691 * You can match based on the key, or key and value. Removing based on key and
     692 * value, will keep from removing duplicate metadata with the same key. It also
     693 * allows removing all metadata matching key, if needed.
     694 *
     695 * @since 4.8.0
     696 *
     697 * @param int    $site_id    Site ID.
     698 * @param string $meta_key   Metadata name.
     699 * @param mixed  $meta_value Optional. Metadata value. Must be serializable if
     700 *                           non-scalar. Default empty.
     701 * @return bool True on success, false on failure.
     702 */
     703function delete_site_meta( $site_id, $meta_key, $meta_value = '' ) {
     704        if ( ! is_site_meta_supported() || is_core_site_meta_key( $meta_key ) ) {
     705                return false;
     706        }
     707
     708        $deleted = delete_metadata( 'blog', $site_id, $meta_key, $meta_value );
     709
     710        // Bust site query cache.
     711        if ( $deleted ) {
     712                wp_cache_set( 'last_changed', microtime(), 'sites' );
     713        }
     714
     715        return $deleted;
     716}
     717
     718/**
     719 * Retrieve site meta field for a site.
     720 *
     721 * @since 4.8.0
     722 *
     723 * @param int    $site_id Site ID.
     724 * @param string $key     Optional. The meta key to retrieve. By default, returns
     725 *                        data for all keys. Default empty.
     726 * @param bool   $single  Optional. Whether to return a single value. Default false.
     727 * @return mixed Will be an array if $single is false. Will be value of meta data
     728 *               field if $single is true.
     729 */
     730function get_site_meta( $site_id, $key = '', $single = false ) {
     731        if ( ! is_site_meta_supported() ) {
     732                if ( ! empty( $key ) && $single ) {
     733                        return '';
     734                }
     735
     736                return array();
     737        }
     738
     739        return get_metadata( 'blog', $site_id, $key, $single );
     740}
     741
     742/**
     743 * Update site meta field based on site ID.
     744 *
     745 * Use the $prev_value parameter to differentiate between meta fields with the
     746 * same key and site ID.
     747 *
     748 * If the meta field for the site does not exist, it will be added.
     749 *
     750 * @since 4.8.0
     751 *
     752 * @param int    $site_id    Site ID.
     753 * @param string $meta_key   Metadata key.
     754 * @param mixed  $meta_value Metadata value. Must be serializable if non-scalar.
     755 * @param mixed  $prev_value Optional. Previous value to check before removing.
     756 *                           Default empty.
     757 * @return int|bool Meta ID if the key didn't exist, true on successful update,
     758 *                  false on failure.
     759 */
     760function update_site_meta( $site_id, $meta_key, $meta_value, $prev_value = '' ) {
     761        if ( ! is_site_meta_supported() || is_core_site_meta_key( $meta_key ) ) {
     762                return false;
     763        }
     764
     765        $updated = update_metadata( 'blog', $site_id, $meta_key, $meta_value, $prev_value );
     766
     767        // Bust site query cache.
     768        if ( $updated ) {
     769                wp_cache_set( 'last_changed', microtime(), 'sites' );
     770        }
     771
     772        return $updated;
     773}
     774
     775/**
     776 * Delete everything from site meta matching meta key.
     777 *
     778 * @since 4.8.0
     779 *
     780 * @param string $meta_key Metadata key to search for when deleting.
     781 * @return bool Whether the site meta key was deleted from the database.
     782 */
     783function delete_site_meta_by_key( $meta_key ) {
     784        if ( ! is_site_meta_supported() || is_core_site_meta_key( $meta_key ) ) {
     785                return false;
     786        }
     787
     788        return delete_metadata( 'blog', null, $meta_key, '', true );
     789}
     790
     791/**
     792 * Returns whether a given site meta key is one of the core site meta keys.
     793 *
     794 * @since 4.8.0
     795 *
     796 * @param string $meta_key Metadata key to check.
     797 * @return bool True if the metadata key is one of the core site meta keys,
     798 *              otherwise false.
     799 */
     800function is_core_site_meta_key( $meta_key ) {
     801        return in_array( $meta_key, get_core_site_meta_keys(), true );
     802}
     803
     804/**
     805 * Returns the list of core site meta keys.
     806 *
     807 * @since 4.8.0
     808 *
     809 * @return array Core site meta keys.
     810 */
     811function get_core_site_meta_keys() {
     812        return array(
     813                 'blogname',
     814                 'siteurl',
     815                 'post_count',
     816                 'home',
     817                 'blog_public',
     818                 'WPLANG',
     819                 'blogdescription',
     820                 'admin_email',
     821                 'db_version'
     822        );
     823}
     824
     825/**
     826 * Returns whether site meta is supported by this installation.
     827 *
     828 * By default this depends on the database version, however site meta can
     829 * optionally be disabled completely using the {@see 'site_meta_supported'}
     830 * filter.
     831 *
     832 * @since 4.8.0
     833 *
     834 * @return bool True if site meta is supported, otherwise false.
     835 */
     836function is_site_meta_supported() {
     837        $supported = get_option( 'db_version' ) >= 40000;
     838
     839        /**
     840         * Filters whether site meta is supported by this installation.
     841         *
     842         * @since 4.8.0
     843         *
     844         * @param bool $supported Whether site meta is supported.
     845         */
     846        return apply_filters( 'site_meta_supported', $supported );
     847}
     848
     849/**
    631850 * Retrieve option value for a given blog id based on name of option.
    632851 *
    633852 * If the option does not exist or does not have a value, then the return value
     
    8311050                        if ( is_array( $global_groups ) ) {
    8321051                                wp_cache_add_global_groups( $global_groups );
    8331052                        } else {
    834                                 wp_cache_add_global_groups( array( 'users', 'userlogins', 'usermeta', 'user_meta', 'useremail', 'userslugs', 'site-transient', 'site-options', 'site-lookup', 'blog-lookup', 'blog-details', 'rss', 'global-posts', 'blog-id-cache', 'networks', 'sites', 'site-details' ) );
     1053                                wp_cache_add_global_groups( array( 'users', 'userlogins', 'usermeta', 'user_meta', 'useremail', 'userslugs', 'site-transient', 'site-options', 'site-lookup', 'blog-lookup', 'blog-details', 'rss', 'global-posts', 'blog-id-cache', 'networks', 'sites', 'site-details', 'blog_meta' ) );
    8351054                        }
    8361055                        wp_cache_add_non_persistent_groups( array( 'counts', 'plugins' ) );
    8371056                }
     
    9051124                        if ( is_array( $global_groups ) ) {
    9061125                                wp_cache_add_global_groups( $global_groups );
    9071126                        } else {
    908                                 wp_cache_add_global_groups( array( 'users', 'userlogins', 'usermeta', 'user_meta', 'useremail', 'userslugs', 'site-transient', 'site-options', 'site-lookup', 'blog-lookup', 'blog-details', 'rss', 'global-posts', 'blog-id-cache', 'networks', 'sites', 'site-details' ) );
     1127                                wp_cache_add_global_groups( array( 'users', 'userlogins', 'usermeta', 'user_meta', 'useremail', 'userslugs', 'site-transient', 'site-options', 'site-lookup', 'blog-lookup', 'blog-details', 'rss', 'global-posts', 'blog-id-cache', 'networks', 'sites', 'site-details', 'blog_meta' ) );
    9091128                        }
    9101129                        wp_cache_add_non_persistent_groups( array( 'counts', 'plugins' ) );
    9111130                }
  • src/wp-includes/version.php

     
    1111 *
    1212 * @global int $wp_db_version
    1313 */
    14 $wp_db_version = 38590;
     14$wp_db_version = 40000;
    1515
    1616/**
    1717 * Holds the TinyMCE version
  • src/wp-includes/wp-db.php

     
    298298         * @see wpdb::tables()
    299299         * @var array
    300300         */
    301         var $ms_global_tables = array( 'blogs', 'signups', 'site', 'sitemeta',
     301        var $ms_global_tables = array( 'blogs', 'blogmeta', 'signups', 'site', 'sitemeta',
    302302                'sitecategories', 'registration_log', 'blog_versions' );
    303303
    304304        /**
     
    423423        public $blogs;
    424424
    425425        /**
     426         * Multisite Blog Metadata table
     427         *
     428         * @since 4.8.0
     429         * @access public
     430         * @var string
     431         */
     432        public $blogmeta;
     433
     434        /**
    426435         * Multisite Blog Versions table
    427436         *
    428437         * @since 3.0.0
  • tests/phpunit/tests/multisite/siteMeta.php

     
     1<?php
     2
     3if ( is_multisite() ) :
     4/**
     5 * @group ms-site
     6 * @group multisite
     7 * @group meta
     8 * @ticket 37923
     9 */
     10class Tests_Multisite_Site_Meta extends WP_UnitTestCase {
     11        protected static $site_id;
     12        protected static $site_id2;
     13
     14        public static function wpSetUpBeforeClass( $factory ) {
     15                self::$site_id = $factory->blog->create( array( 'domain' => 'wordpress.org', 'path' => '/' ) );
     16                self::$site_id2 = $factory->blog->create( array( 'domain' => 'wordpress.org', 'path' => '/foo/' ) );
     17        }
     18
     19        public static function wpTearDownAfterClass() {
     20                wpmu_delete_blog( self::$site_id, true );
     21                wpmu_delete_blog( self::$site_id2, true );
     22
     23                wp_update_network_site_counts();
     24        }
     25
     26        public function test_add() {
     27                if ( ! is_site_meta_supported() ) {
     28                        $this->markTestSkipped( 'Test only runs when site meta is supported' );
     29                }
     30
     31                $this->assertNotEmpty( add_site_meta( self::$site_id, 'foo', 'bar' ) );
     32        }
     33
     34        public function test_add_unique() {
     35                if ( ! is_site_meta_supported() ) {
     36                        $this->markTestSkipped( 'Test only runs when site meta is supported' );
     37                }
     38
     39                $this->assertNotEmpty( add_site_meta( self::$site_id, 'foo', 'bar' ) );
     40                $this->assertFalse( add_site_meta( self::$site_id, 'foo', 'bar', true ) );
     41        }
     42
     43        public function test_delete() {
     44                if ( ! is_site_meta_supported() ) {
     45                        $this->markTestSkipped( 'Test only runs when site meta is supported' );
     46                }
     47
     48                add_site_meta( self::$site_id, 'foo', 'bar' );
     49
     50                $this->assertTrue( delete_site_meta( self::$site_id, 'foo' ) );
     51        }
     52
     53        public function test_delete_with_invalid_meta_key_should_return_false() {
     54                if ( ! is_site_meta_supported() ) {
     55                        $this->markTestSkipped( 'Test only runs when site meta is supported' );
     56                }
     57
     58                $this->assertFalse( delete_site_meta( self::$site_id, 'foo' ) );
     59        }
     60
     61        public function test_delete_should_respect_meta_value() {
     62                if ( ! is_site_meta_supported() ) {
     63                        $this->markTestSkipped( 'Test only runs when site meta is supported' );
     64                }
     65
     66                add_site_meta( self::$site_id, 'foo', 'bar' );
     67                add_site_meta( self::$site_id, 'foo', 'baz' );
     68
     69                $this->assertTrue( delete_site_meta( self::$site_id, 'foo', 'bar' ) );
     70
     71                $metas = get_site_meta( self::$site_id, 'foo', false );
     72                $this->assertSame( array( 'baz' ), $metas );
     73        }
     74
     75        public function test_get_with_no_key_should_fetch_all_keys() {
     76                if ( ! is_site_meta_supported() ) {
     77                        $this->markTestSkipped( 'Test only runs when site meta is supported' );
     78                }
     79
     80                add_site_meta( self::$site_id, 'foo', 'bar' );
     81                add_site_meta( self::$site_id, 'foo1', 'baz' );
     82
     83                $found = get_site_meta( self::$site_id );
     84                $expected = array(
     85                        'foo' => array( 'bar' ),
     86                        'foo1' => array( 'baz' ),
     87                );
     88
     89                $this->assertEqualSets( $expected, $found );
     90        }
     91
     92        public function test_get_with_key_should_fetch_all_for_key() {
     93                if ( ! is_site_meta_supported() ) {
     94                        $this->markTestSkipped( 'Test only runs when site meta is supported' );
     95                }
     96
     97                add_site_meta( self::$site_id, 'foo', 'bar' );
     98                add_site_meta( self::$site_id, 'foo', 'baz' );
     99                add_site_meta( self::$site_id, 'foo1', 'baz' );
     100
     101                $found = get_site_meta( self::$site_id, 'foo' );
     102                $expected = array( 'bar', 'baz' );
     103
     104                $this->assertEqualSets( $expected, $found );
     105        }
     106
     107        public function test_get_should_respect_single_true() {
     108                if ( ! is_site_meta_supported() ) {
     109                        $this->markTestSkipped( 'Test only runs when site meta is supported' );
     110                }
     111
     112                add_site_meta( self::$site_id, 'foo', 'bar' );
     113                add_site_meta( self::$site_id, 'foo', 'baz' );
     114
     115                $found = get_site_meta( self::$site_id, 'foo', true );
     116                $this->assertEquals( 'bar', $found );
     117        }
     118
     119        public function test_update_should_pass_to_add_when_no_value_exists_for_key() {
     120                if ( ! is_site_meta_supported() ) {
     121                        $this->markTestSkipped( 'Test only runs when site meta is supported' );
     122                }
     123
     124                $actual = update_site_meta( self::$site_id, 'foo', 'bar' );
     125                $this->assertInternalType( 'int', $actual );
     126                $this->assertNotEmpty( $actual );
     127
     128                $meta = get_site_meta( self::$site_id, 'foo', true );
     129                $this->assertSame( 'bar', $meta );
     130        }
     131
     132        public function test_update_should_return_true_when_updating_existing_value_for_key() {
     133                if ( ! is_site_meta_supported() ) {
     134                        $this->markTestSkipped( 'Test only runs when site meta is supported' );
     135                }
     136
     137                add_site_meta( self::$site_id, 'foo', 'bar' );
     138
     139                $actual = update_site_meta( self::$site_id, 'foo', 'baz' );
     140                $this->assertTrue( $actual );
     141
     142                $meta = get_site_meta( self::$site_id, 'foo', true );
     143                $this->assertSame( 'baz', $meta );
     144        }
     145
     146        public function test_delete_by_key() {
     147                if ( ! is_site_meta_supported() ) {
     148                        $this->markTestSkipped( 'Test only runs when site meta is supported' );
     149                }
     150
     151                add_site_meta( self::$site_id, 'unique_delete_by_key', 'value', true );
     152                add_site_meta( self::$site_id2, 'unique_delete_by_key', 'value', true );
     153
     154                $this->assertEquals( 'value', get_site_meta( self::$site_id, 'unique_delete_by_key', true ) );
     155                $this->assertEquals( 'value', get_site_meta( self::$site_id2, 'unique_delete_by_key', true ) );
     156
     157                $this->assertTrue( delete_site_meta_by_key( 'unique_delete_by_key' ) );
     158
     159                $this->assertEquals( '', get_site_meta( self::$site_id, 'unique_delete_by_key', true ) );
     160                $this->assertEquals( '', get_site_meta( self::$site_id2, 'unique_delete_by_key', true ) );
     161        }
     162
     163        /**
     164         * @dataProvider data_get_core_keys
     165         */
     166        public function test_add_fails_for_core_key( $key ) {
     167                if ( ! is_site_meta_supported() ) {
     168                        $this->markTestSkipped( 'Test only runs when site meta is supported' );
     169                }
     170
     171                $this->assertFalse( add_site_meta( self::$site_id, $key, 'foo' ) );
     172        }
     173
     174        /**
     175         * @dataProvider data_get_core_keys
     176         */
     177        public function test_update_fails_for_core_key( $key ) {
     178                if ( ! is_site_meta_supported() ) {
     179                        $this->markTestSkipped( 'Test only runs when site meta is supported' );
     180                }
     181
     182                $this->assertFalse( update_site_meta( self::$site_id, $key, 'foo' ) );
     183        }
     184
     185        /**
     186         * @dataProvider data_get_core_keys
     187         */
     188        public function test_delete_fails_for_core_key( $key ) {
     189                if ( ! is_site_meta_supported() ) {
     190                        $this->markTestSkipped( 'Test only runs when site meta is supported' );
     191                }
     192
     193                $this->assertFalse( delete_site_meta( self::$site_id, $key ) );
     194        }
     195
     196        /**
     197         * @dataProvider data_get_core_keys
     198         */
     199        public function test_delete_by_key_fails_for_core_key( $key ) {
     200                if ( ! is_site_meta_supported() ) {
     201                        $this->markTestSkipped( 'Test only runs when site meta is supported' );
     202                }
     203
     204                $this->assertFalse( delete_site_meta_by_key( $key ) );
     205        }
     206
     207        public function data_get_core_keys() {
     208                return array(
     209                        array( 'blogname' ),
     210                        array( 'siteurl' ),
     211                        array( 'post_count' ),
     212                        array( 'home' ),
     213                        array( 'blog_public' ),
     214                        array( 'WPLANG' ),
     215                        array( 'blogdescription' ),
     216                        array( 'admin_email' ),
     217                        array( 'db_version' ),
     218                );
     219        }
     220
     221        public function test_adding_site_meta_should_bust_get_sites_cache() {
     222                if ( ! is_site_meta_supported() ) {
     223                        $this->markTestSkipped( 'Test only runs when site meta is supported' );
     224                }
     225
     226                add_site_meta( self::$site_id, 'foo', 'bar' );
     227
     228                // Prime cache.
     229                $found = get_sites( array(
     230                        'fields' => 'ids',
     231                        'meta_query' => array(
     232                                array(
     233                                        'key' => 'foo',
     234                                        'value' => 'bar',
     235                                ),
     236                        ),
     237                ) );
     238
     239                $this->assertEqualSets( array( self::$site_id ), $found );
     240
     241                add_site_meta( self::$site_id2, 'foo', 'bar' );
     242
     243                $found = get_sites( array(
     244                        'fields' => 'ids',
     245                        'meta_query' => array(
     246                                array(
     247                                        'key' => 'foo',
     248                                        'value' => 'bar',
     249                                ),
     250                        ),
     251                ) );
     252
     253                $this->assertEqualSets( array( self::$site_id, self::$site_id2 ), $found );
     254        }
     255
     256        public function test_updating_site_meta_should_bust_get_sites_cache() {
     257                if ( ! is_site_meta_supported() ) {
     258                        $this->markTestSkipped( 'Test only runs when site meta is supported' );
     259                }
     260
     261                add_site_meta( self::$site_id, 'foo', 'bar' );
     262                add_site_meta( self::$site_id2, 'foo', 'baz' );
     263
     264                // Prime cache.
     265                $found = get_sites( array(
     266                        'fields' => 'ids',
     267                        'meta_query' => array(
     268                                array(
     269                                        'key' => 'foo',
     270                                        'value' => 'bar',
     271                                ),
     272                        ),
     273                ) );
     274
     275                $this->assertEqualSets( array( self::$site_id ), $found );
     276
     277                update_site_meta( self::$site_id2, 'foo', 'bar' );
     278
     279                $found = get_sites( array(
     280                        'fields' => 'ids',
     281                        'meta_query' => array(
     282                                array(
     283                                        'key' => 'foo',
     284                                        'value' => 'bar',
     285                                ),
     286                        ),
     287                ) );
     288
     289                $this->assertEqualSets( array( self::$site_id, self::$site_id2 ), $found );
     290        }
     291
     292        public function test_deleting_site_meta_should_bust_get_sites_cache() {
     293                if ( ! is_site_meta_supported() ) {
     294                        $this->markTestSkipped( 'Test only runs when site meta is supported' );
     295                }
     296
     297                add_site_meta( self::$site_id, 'foo', 'bar' );
     298                add_site_meta( self::$site_id2, 'foo', 'bar' );
     299
     300                // Prime cache.
     301                $found = get_sites( array(
     302                        'fields' => 'ids',
     303                        'meta_query' => array(
     304                                array(
     305                                        'key' => 'foo',
     306                                        'value' => 'bar',
     307                                ),
     308                        ),
     309                ) );
     310
     311                $this->assertEqualSets( array( self::$site_id, self::$site_id2 ), $found );
     312
     313                delete_site_meta( self::$site_id2, 'foo', 'bar' );
     314
     315                $found = get_sites( array(
     316                        'fields' => 'ids',
     317                        'meta_query' => array(
     318                                array(
     319                                        'key' => 'foo',
     320                                        'value' => 'bar',
     321                                ),
     322                        ),
     323                ) );
     324
     325                $this->assertEqualSets( array( self::$site_id ), $found );
     326        }
     327
     328        public function test_get_sites_bypass_meta_query_without_site_meta_support() {
     329                add_filter( 'site_meta_supported', '__return_false' );
     330
     331                $found = get_sites( array(
     332                        'fields' => 'ids',
     333                        'domain' => 'wordpress.org',
     334                        'path'   => '/',
     335                        'meta_query' => array(
     336                                array(
     337                                        'key' => 'foo',
     338                                        'value' => 'baz',
     339                                ),
     340                        ),
     341                ) );
     342
     343                remove_filter( 'site_meta_supported', '__return_false' );
     344
     345                $this->assertEqualSets( array( self::$site_id ), $found );
     346        }
     347
     348        public function test_site_meta_should_be_deleted_when_term_is_deleted() {
     349                $site_id = self::factory()->blog->create( array( 'domain' => 'foo.org', 'path' => '/' ) );
     350
     351                add_site_meta( $site_id, 'foo', 'bar' );
     352                add_site_meta( $site_id, 'foo1', 'bar' );
     353
     354                $this->assertSame( 'bar', get_site_meta( $site_id, 'foo', true ) );
     355                $this->assertSame( 'bar', get_site_meta( $site_id, 'foo1', true ) );
     356
     357                wpmu_delete_blog( $site_id, true );
     358
     359                $this->assertSame( '', get_site_meta( $site_id, 'foo', true ) );
     360                $this->assertSame( '', get_site_meta( $site_id, 'foo1', true ) );
     361        }
     362
     363        public function test_site_meta_supported() {
     364                add_filter( 'site_meta_supported', '__return_false' );
     365
     366                $result = is_site_meta_supported();
     367
     368                remove_filter( 'site_meta_supported', '__return_false' );
     369
     370                $this->assertFalse( $result );
     371        }
     372}
     373
     374endif;