egex) { $key = $isKeyRegex ? $request->get_param('key') : $key; $value = $request->get_param('value'); if (!$this->set($key, $value)) { return new WP_Error('key_value_map_update_failed', 'Update for given key failed.', ['key' => $key, 'value' => $value]); } return new WP_REST_Response(['key' => $key, 'value' => $this->get($key)]); }, 'permission_callback' => function () use($capability) { return \current_user_can($capability); }, 'args' => ['value' => \array_merge(['required' => \true], $args)]]); }); return $this; } /** * Generate a `onclick` JavaScript coding which automatically hides the notice, sends a request via * REST API and optionally redirects to a given page. * * @param string $key * @param string $value * @param string $redirect */ public function noticeDismissOnClickHandler($key, $value, $redirect = \false) { $rest_url = Service::getUrl($this->core); $redirectStr = $redirect ? \sprintf('window.location.href= "%s";', $redirect) : ''; return \join('', ['jQuery(this).parents(".notice").remove();', \sprintf('window.fetch("%s").then(function(response){ %s });', \add_query_arg(['_method' => 'PATCH', '_wpnonce' => \wp_create_nonce('wp_rest'), 'value' => $value], \sprintf('%s%s', $rest_url, $this->getRestEndpointForKey($key))), $redirectStr)]); } /** * Generate the REST endpoint to a given key. * * @param string $key */ public function getRestEndpointForKey($key) { return \sprintf('%s/%s/%s', self::REST_NAME, $this->getName(), $key); } /** * Get value by key. * * @param string $key * @param mixed $default */ public function get($key, $default = \false) { $map = $this->getMap(); if (!isset($map[$key]) && isset($this->migrationsForKey[$key])) { $this->set($key, $this->migrationsForKey[$key]()); // Never run again unset($this->migrationsForKey[$key]); return $this->get($key, $default); } return $map[$key] ?? $default; } /** * Set value by key. * * @param string $key * @param mixed $value Use `null` to remove the key from the map */ public function set($key, $value) { $map = $this->getMap(); $changed = \false; if ($value === null) { if (isset($map[$key])) { $changed = \true; unset($map[$key]); } } elseif (isset($map[$key]) && $map[$key] !== $value || !isset($map[$key])) { $changed = \true; foreach ($this->modifiers as $modifier) { $value = $modifier($key, $value); } $map[$key] = $value; } if (!$changed) { return \true; } return $this->persistMap($map); } /** * Registers the option as autoload in database. This is not supported for site-wide options. */ protected function enableAutoload() { Utils::enableOptionAutoload($this->name, ['__created' => \true]); } /** * Persist map to `wp_options`. * * @param array $map */ protected function persistMap($map) { return $this->isSiteWide() ? \update_site_option($this->getName(), $map) : \update_option($this->getName(), $map); } /** * Get the map as array. * * @return array */ public function getMap() { $map = $this->isSiteWide() ? \get_site_option($this->getName(), []) : \get_option($this->getName(), []); if (isset($map['__created']) && $map['__created']) { foreach ($this->migrations as $migration) { $map = $migration($map); } unset($map['__created']); $this->persistMap($map); } return $map; } /** * Get an array with keys starting with a given string. * * @param string $prefix */ public function getKeysStartingWith($prefix) { $map = $this->getMap(); $result = []; foreach ($map as $key => $value) { if (\strpos($key, $prefix) === 0) { $result[\substr($key, \strlen($prefix))] = $value; } } return $result; } /** * Get option name. * * @codeCoverageIgnore */ public function getName() { return $this->name; } /** * Get if option is site-wide. * * @codeCoverageIgnore */ public function isSiteWide() { return $this->siteWide; } }