| [ Index ] |
PHP Cross Reference of WordPress Trunk (Updated Daily) |
[Summary view] [Print] [Text view]
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 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated : Wed Oct 14 08:20:33 2026 | Cross-referenced by PHPXref |