-
Notifications
You must be signed in to change notification settings - Fork 441
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
a66f3e1
commit c5ec8ed
Showing
7 changed files
with
662 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
<?php | ||
/** | ||
* WordPress Dashboard functionality for Experiments. | ||
* | ||
* @package WPGraphQL\Experimental | ||
*/ | ||
|
||
namespace WPGraphQL\Experimental; | ||
|
||
/** | ||
* Class - Admin | ||
*/ | ||
class Admin { | ||
/** | ||
* The name of the option group | ||
* | ||
* @var string | ||
*/ | ||
public static $option_group = 'graphql_experiments_settings'; | ||
|
||
/** | ||
* Initialize Admin functionality for Experiments | ||
*/ | ||
public function init(): void { | ||
$this->register_settings(); | ||
} | ||
|
||
/** | ||
* Registers the Experiments section to the WPGraphQL Settings page. | ||
*/ | ||
private function register_settings(): void { | ||
// Register the section. | ||
register_graphql_settings_section( | ||
self::$option_group, | ||
[ | ||
'title' => __( 'Experiments 🧪', 'wp-graphql' ), | ||
'desc' => __( 'WPGraphQL Experiments are experimental features that are under active development. They may change, break, or disappear at any time.', 'wp-graphql' ), | ||
] | ||
); | ||
|
||
$experiments = ExperimentRegistry::get_experiments(); | ||
|
||
// If there are no experiments to register, display a message. | ||
if ( empty( $experiments ) ) { | ||
register_graphql_settings_field( | ||
self::$option_group, | ||
[ | ||
'label' => __( 'No Experiments Available', 'wp-graphql' ), | ||
'desc' => __( 'There are no experiments available at this time.', 'wp-graphql' ), | ||
'type' => 'html', | ||
] | ||
); | ||
return; | ||
} | ||
|
||
// Register the toggle for each Experiment. | ||
$toggle_fields = []; | ||
|
||
foreach ( $experiments as $experiment ) { | ||
$config = $experiment->get_config(); | ||
|
||
$toggle_fields[] = [ | ||
'name' => $experiment->get_slug() . '_enabled', | ||
'label' => $config['title'], | ||
'desc' => $config['description'], | ||
'type' => 'checkbox', // @todo we probably want a better type callback. | ||
'default' => 'off', | ||
'value' => $experiment->is_active() ? 'on' : 'off', | ||
'disabled' => defined( 'GRAPHQL_EXPERIMENTAL_FEATURES' ), | ||
]; | ||
} | ||
|
||
register_graphql_settings_fields( | ||
self::$option_group, | ||
$toggle_fields | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,204 @@ | ||
<?php | ||
/** | ||
* Abstract class for creating new experiments. | ||
* | ||
* ALL experiments should extend this class. | ||
* | ||
* @package WPGraphQL\Experimental\Experiment | ||
* @since @todo | ||
*/ | ||
|
||
namespace WPGraphQL\Experimental\Experiment; | ||
|
||
use WPGraphQL\Experimental\Admin; | ||
|
||
/** | ||
* Class - Abstract Experiment | ||
*/ | ||
abstract class AbstractExperiment { | ||
/** | ||
* The experiment unique slug. | ||
* | ||
* @var ?string | ||
*/ | ||
protected static $slug; | ||
/** | ||
* The experiment's configuration. | ||
* | ||
* @var ?array{title:string,description:string} | ||
*/ | ||
protected static $config; | ||
|
||
/** | ||
* Whether the experiment is active. | ||
* | ||
* @var ?bool | ||
*/ | ||
protected $is_active; | ||
|
||
/** | ||
* Defines the experiment slug. | ||
*/ | ||
abstract protected static function slug(): string; | ||
|
||
/** | ||
* Defines the experiment configuration. | ||
* | ||
* @return array{title:string,description:string} | ||
*/ | ||
abstract protected function config(): array; | ||
|
||
/** | ||
* Initializes the experiment. | ||
* | ||
* I.e where you put your hooks. | ||
*/ | ||
abstract protected function init(): void; | ||
|
||
/** | ||
* Loads the experiment. | ||
* | ||
* @uses AbstractExperiment::init() to initialize the experiment. | ||
*/ | ||
public function load(): void { | ||
if ( ! $this->is_active() ) { | ||
return; | ||
} | ||
|
||
$this->init(); | ||
|
||
/** | ||
* Fires after the experiment is loaded. | ||
* | ||
* @param \WPGraphQL\Experimental\Experiment\AbstractExperiment $instance The experiment instance. | ||
*/ | ||
do_action( 'wp_graphql_experiment_' . $this->get_slug() . '_loaded', $this ); | ||
} | ||
|
||
/** | ||
* Gets the experiment's configuration array. | ||
* | ||
* @return array{title:string,description:string} | ||
*/ | ||
public function get_config(): array { | ||
if ( ! isset( $this->config ) ) { | ||
$this->config = $this->prepare_config(); | ||
} | ||
|
||
return $this->config; | ||
} | ||
|
||
/** | ||
* Returns the experiment's slug. | ||
* | ||
* This is static so it can be accessed outside of the class instantiation. | ||
* | ||
* @throws \Exception If the experiment is missing a slug. | ||
*/ | ||
public static function get_slug(): string { | ||
if ( ! isset( static::$slug ) ) { | ||
$slug = static::slug(); | ||
|
||
if ( empty( $slug ) ) { | ||
throw new \Exception( | ||
sprintf( | ||
/* translators: %s: The experiment's class name. */ | ||
esc_html__( 'The experiment %s is missing a slug. Ensure a valid `slug` is defined in the ::slug() method.', 'wp-graphql' ), | ||
static::class | ||
) | ||
); | ||
} | ||
|
||
static::$slug = $slug; | ||
} | ||
|
||
return static::$slug; | ||
} | ||
|
||
/** | ||
* Whether the experiment is active. | ||
*/ | ||
public function is_active(): bool { | ||
if ( isset( $this->is_active ) ) { | ||
return $this->is_active; | ||
} | ||
|
||
// See if the experiment is set via the constant. | ||
$is_active = defined( 'GRAPHQL_EXPERIMENTAL_FEATURES' ) && is_array( GRAPHQL_EXPERIMENTAL_FEATURES ) && isset( GRAPHQL_EXPERIMENTAL_FEATURES[ static::get_slug() ] ) ? (bool) GRAPHQL_EXPERIMENTAL_FEATURES[ static::get_slug() ] : null; | ||
|
||
if ( ! isset( $is_active ) ) { | ||
$setting_key = static::get_slug() . '_enabled'; | ||
|
||
$is_active = 'on' === get_graphql_setting( $setting_key, 'off', Admin::$option_group ); | ||
} | ||
|
||
$this->is_active = $is_active; | ||
|
||
return $this->is_active; | ||
} | ||
|
||
/** | ||
* Prepares the configuration. | ||
* | ||
* @return array{title:string,description:string} | ||
* | ||
* @throws \Exception If the experiment is missing a slug. | ||
*/ | ||
protected function prepare_config(): array { | ||
$slug = static::get_slug(); | ||
$config = $this->config(); | ||
|
||
/** | ||
* Filters the experiment configuration. | ||
* | ||
* @param array{title:string,description:string} $config The experiment configuration. | ||
* @param string $slug The experiment's slug. | ||
*/ | ||
$config = apply_filters( 'wp_graphql_experiment_config', $config, $slug ); | ||
$config = apply_filters( 'wp_graphql_experiment_' . $slug . '_config', $config ); | ||
|
||
// Validate the config. | ||
$this->validate_config( $config ); | ||
|
||
return $config; | ||
} | ||
|
||
/** | ||
* Validates the $config array, throwing an exception if it's invalid. | ||
* | ||
* @param array<string,mixed> $config The experiment configuration. | ||
* | ||
* @throws \Exception If the config is invalid. | ||
*/ | ||
protected function validate_config( array $config ): void { | ||
if ( empty( $config ) ) { | ||
throw new \Exception( | ||
sprintf( | ||
/* translators: %s: The experiment's class name. */ | ||
esc_html__( 'The experiment %s is missing a configuration. Ensure a valid `config` is defined in the ::config() method.', 'wp-graphql' ), | ||
static::class | ||
) | ||
); | ||
} | ||
|
||
if ( ! isset( $config['title'] ) || ! is_string( $config['title'] ) ) { | ||
throw new \Exception( | ||
sprintf( | ||
/* translators: %s: The experiment's class name. */ | ||
esc_html__( 'The experiment %s is missing a title in the configuration. Ensure a valid `title` is defined in the ::config() method.', 'wp-graphql' ), | ||
static::class | ||
) | ||
); | ||
} | ||
|
||
if ( ! isset( $config['description'] ) || ! is_string( $config['description'] ) ) { | ||
throw new \Exception( | ||
sprintf( | ||
/* translators: %s: The experiment's class name. */ | ||
esc_html__( 'The experiment %s is missing a description in the configuration. Ensure a valid `description` is defined in the ::config() method.', 'wp-graphql' ), | ||
static::class | ||
) | ||
); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
<?php | ||
/** | ||
* An Example Experiment | ||
* | ||
* @package WPGraphQL\Experimental\Experiment | ||
*/ | ||
|
||
namespace WPGraphQL\Experimental\Experiment; | ||
|
||
use WPGraphQL\Experimental\Experiment\AbstractExperiment; | ||
|
||
/** | ||
* Class - TestExperiment | ||
*/ | ||
class TestExperiment extends AbstractExperiment { | ||
/** | ||
* {@inheritDoc} | ||
*/ | ||
protected static function slug(): string { | ||
return 'test_experiment'; | ||
} | ||
|
||
/** | ||
* {@inheritDoc} | ||
*/ | ||
protected function config(): array { | ||
return [ | ||
'title' => __( 'Test Experiment', 'wp-graphql' ), | ||
'description' => __( 'A test experiment for WPGraphQL. Registers the `RootQuery.testExperiment` field to the schema.', 'wp-graphql' ), | ||
]; | ||
} | ||
|
||
/** | ||
* Initializes the experiment. | ||
* | ||
* I.e where you put your hooks. | ||
*/ | ||
public function init(): void { | ||
add_action( 'graphql_init', [ $this, 'register_field' ] ); | ||
} | ||
|
||
/** | ||
* Registers the field for the experiment. | ||
*/ | ||
public function register_field(): void { | ||
register_graphql_field( | ||
'RootQuery', | ||
'testExperiment', | ||
[ | ||
'type' => 'String', | ||
'description' => 'A test field for the Test Experiment.', | ||
'resolve' => static function () { | ||
return 'This is a test field for the Test Experiment.'; | ||
}, | ||
] | ||
); | ||
} | ||
} |
Oops, something went wrong.