[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

Search

title

Body

[close]

/wp-includes/secrets/ -> class-wp-secrets-option-store.php (source)

   1  <?php
   2  /**
   3   * Secrets API: WP_Secrets_Option_Store class
   4   *
   5   * @package WordPress
   6   * @subpackage Secrets
   7   * @since 7.2.0
   8   */
   9  
  10  /**
  11   * The default secret store.
  12   *
  13   * Keeps records as rows in the options tables, always with autoload disabled, and
  14   * always excluded from options.php and the REST settings endpoint.
  15   *
  16   * Site-scope secrets live under '_wp_secret_{name}' via get_option()/update_option().
  17   * Network-scope secrets live under '_wp_network_secret_{name}' via the *_site_option()
  18   * functions, which on a non-multisite install are themselves backed by wp_options –
  19   * so on a single site, site- and network-scope secrets differ only by prefix, in the
  20   * same table; on a real network, network-scope rows live in wp_sitemeta instead.
  21   *
  22   * @since 7.2.0
  23   */
  24  final class WP_Secrets_Option_Store implements WP_Secrets_Store {
  25  
  26      /**
  27       * Option name prefix for site-scope secrets.
  28       *
  29       * @since 7.2.0
  30       * @var string
  31       */
  32      const SITE_PREFIX = '_wp_secret_';
  33  
  34      /**
  35       * Option name prefix for network-scope secrets.
  36       *
  37       * @since 7.2.0
  38       * @var string
  39       */
  40      const NETWORK_PREFIX = '_wp_network_secret_';
  41  
  42      /**
  43       * Reads a secret's stored record.
  44       *
  45       * @since 7.2.0
  46       *
  47       * @param string $name    The secret's namespaced name.
  48       * @param bool   $network Whether this is a network-scope secret.
  49       * @return array<mixed>|null|WP_Error
  50       */
  51  	public function get( string $name, bool $network = false ) {
  52          $option_name = $this->option_name( $name, $network );
  53          $value       = $network ? get_site_option( $option_name, null ) : get_option( $option_name, null );
  54  
  55          if ( null === $value ) {
  56              return null;
  57          }
  58  
  59          if ( ! is_array( $value ) ) {
  60              return new WP_Error(
  61                  WP_SECRETS_ERROR_RECORD_MALFORMED,
  62                  __( 'The stored secret record is not an array.' )
  63              );
  64          }
  65  
  66          return $value;
  67      }
  68  
  69      /**
  70       * Writes a secret's record.
  71       *
  72       * @since 7.2.0
  73       *
  74       * @param string       $name    The secret's namespaced name.
  75       * @param array<mixed> $record  The record to store.
  76       * @param bool         $network Whether this is a network-scope secret.
  77       * @return true|WP_Error
  78       */
  79  	public function set( string $name, array $record, bool $network = false ) {
  80          $option_name = $this->option_name( $name, $network );
  81  
  82          if ( $network ) {
  83              $updated = update_site_option( $option_name, $record );
  84          } else {
  85              $updated = update_option( $option_name, $record, false );
  86          }
  87  
  88          if ( $updated ) {
  89              return true;
  90          }
  91  
  92          /*
  93           * update_option()/update_site_option() return false both on genuine
  94           * failure and when the new value already equals the stored one – a
  95           * documented ambiguity in the Options API. Read back and compare rather
  96           * than treating every false as a failure.
  97           */
  98          $current = $network ? get_site_option( $option_name ) : get_option( $option_name );
  99  
 100          if ( $current === $record ) {
 101              return true;
 102          }
 103  
 104          return new WP_Error(
 105              WP_SECRETS_ERROR_STORE_UNAVAILABLE,
 106              __( 'The secret record could not be written.' )
 107          );
 108      }
 109  
 110      /**
 111       * Deletes a secret's record.
 112       *
 113       * @since 7.2.0
 114       *
 115       * @param string $name    The secret's namespaced name.
 116       * @param bool   $network Whether this is a network-scope secret.
 117       * @return true|WP_Error
 118       */
 119  	public function delete( string $name, bool $network = false ) {
 120          $option_name = $this->option_name( $name, $network );
 121          $deleted     = $network ? delete_site_option( $option_name ) : delete_option( $option_name );
 122  
 123          if ( $deleted ) {
 124              return true;
 125          }
 126  
 127          // delete_*_option() also returns false when the option never existed.
 128          // Deleting something already absent is not a failure.
 129          $still_exists = null !== ( $network ? get_site_option( $option_name, null ) : get_option( $option_name, null ) );
 130  
 131          if ( ! $still_exists ) {
 132              return true;
 133          }
 134  
 135          return new WP_Error(
 136              WP_SECRETS_ERROR_STORE_UNAVAILABLE,
 137              __( 'The secret record could not be deleted.' )
 138          );
 139      }
 140  
 141      /**
 142       * Lists the names of every secret in this store, for this scope.
 143       *
 144       * @since 7.2.0
 145       *
 146       * @global wpdb $wpdb WordPress database abstraction object.
 147       *
 148       * @param bool $network Whether to list network-scope secrets.
 149       * @return string[]|WP_Error
 150       */
 151  	public function list_names( bool $network = false ) {
 152          global $wpdb;
 153  
 154          $prefix  = $network ? self::NETWORK_PREFIX : self::SITE_PREFIX;
 155          $pattern = $wpdb->esc_like( $prefix ) . '%';
 156  
 157          if ( $network && is_multisite() ) {
 158              $option_names = $wpdb->get_col(
 159                  $wpdb->prepare(
 160                      "SELECT meta_key FROM {$wpdb->sitemeta} WHERE meta_key LIKE %s AND site_id = %d",
 161                      $pattern,
 162                      get_current_network_id()
 163                  )
 164              );
 165          } else {
 166              $option_names = $wpdb->get_col(
 167                  $wpdb->prepare(
 168                      "SELECT option_name FROM {$wpdb->options} WHERE option_name LIKE %s",
 169                      $pattern
 170                  )
 171              );
 172          }
 173  
 174          if ( ! is_array( $option_names ) ) {
 175              return new WP_Error(
 176                  WP_SECRETS_ERROR_STORE_UNAVAILABLE,
 177                  __( 'Could not list secrets.' )
 178              );
 179          }
 180  
 181          $names = array();
 182  
 183          foreach ( $option_names as $option_name ) {
 184              if ( ! is_string( $option_name ) ) {
 185                  continue;
 186              }
 187  
 188              $names[] = substr( $option_name, strlen( $prefix ) );
 189          }
 190  
 191          return $names;
 192      }
 193  
 194  
 195      /**
 196       * Builds the option name a secret is stored under.
 197       *
 198       * @since 7.2.0
 199       *
 200       * @param string $name    The secret's namespaced name.
 201       * @param bool   $network Whether this is a network-scope secret.
 202       * @return string
 203       */
 204  	private function option_name( string $name, bool $network ): string {
 205          return ( $network ? self::NETWORK_PREFIX : self::SITE_PREFIX ) . $name;
 206      }
 207  }


Generated : Wed Oct 14 08:20:33 2026 Cross-referenced by PHPXref