Skip to content
This repository was archived by the owner on Aug 23, 2022. It is now read-only.

Commit 1673cc7

Browse files
author
Jonny Bull
committed
WP CLI support
1 parent 95b8a16 commit 1673cc7

File tree

2 files changed

+310
-0
lines changed

2 files changed

+310
-0
lines changed

flagpole.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
}
2626

2727
use Flagpole\Flagpole;
28+
use Flagpole\CLI;
2829

2930
// Define plugin paths and url for global usage.
3031
define( 'FLAGPOLE_PLUGIN_PATH', plugin_dir_path( __FILE__ ) );
@@ -100,6 +101,10 @@ function flagpole_admin_imports( $hook ) {
100101
require plugin_dir_path( __FILE__ ) . 'includes/api/api.general.php';
101102
require plugin_dir_path( __FILE__ ) . 'includes/api/api.shortcode.php';
102103

104+
if ( defined( '\WP_CLI' ) && \WP_CLI ) {
105+
require plugin_dir_path( __FILE__ ) . 'includes/class-cli.php';
106+
}
107+
103108
/**
104109
* AJAX Action toggling features from the WP admin area.
105110
*/
@@ -338,3 +343,8 @@ function flagpole_operation_redirect( $error_code = false, $redirect = true ) {
338343
add_shortcode( 'debugFlagpole_flags', 'flagpole_shortcode_debug_flags' );
339344
add_shortcode( 'debugFlagpole_groups', 'flagpole_shortcode_debug_groups' );
340345
add_shortcode( 'debugFlagpole_db', 'flagpole_shortcode_debug_db' );
346+
347+
if ( defined( '\WP_CLI' ) && \WP_CLI ) {
348+
$flagpole_cli = new CLI();
349+
$flagpole_cli->register();
350+
}

includes/class-cli.php

Lines changed: 300 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,300 @@
1+
<?php
2+
/**
3+
* CLI Class
4+
*
5+
* Used for managing WP-CLI integration.
6+
*
7+
* @package flagpole
8+
*/
9+
10+
namespace Flagpole;
11+
12+
use Flagpole\Flagpole;
13+
use Flagpole\Flag;
14+
use WP_CLI;
15+
16+
17+
/**
18+
* Class CLI
19+
*
20+
* @package FeatureFlag
21+
*/
22+
class CLI {
23+
private const FLAGPOLE_CLI_PREFIX = 'flagpole ';
24+
25+
/**
26+
* Registers WP CLI commands.
27+
*/
28+
public function register() {
29+
WP_CLI::add_command( self::FLAGPOLE_CLI_PREFIX . 'list', [ $this, 'flag_list' ] );
30+
WP_CLI::add_command( self::FLAGPOLE_CLI_PREFIX . 'activate', [ $this, 'flag_on' ] );
31+
WP_CLI::add_command( self::FLAGPOLE_CLI_PREFIX . 'deactivate', [ $this, 'flag_off' ] );
32+
WP_CLI::add_command( self::FLAGPOLE_CLI_PREFIX . 'toggle', [ $this, 'flag_toggle' ] );
33+
}
34+
35+
private function flag_filter_enabled( $flag_item ) {
36+
if ( ( gettype( $flag_item['enabled'] ) === 'boolean') && ( $flag_item['enabled'] === true ) || ( $flag_item['enabled'] === 'true' ) ) {
37+
return $flag_item;
38+
}
39+
}
40+
41+
/**
42+
* Encodes flagpole array data in a way that is easier to read when displayed.
43+
* Specifically, we convert booleans to string equivalents and add 'enabled' data.
44+
*
45+
* @param array $data
46+
* @return array
47+
*/
48+
private function flag_list_data_encode( $data, $bool_type = 'string' ) {
49+
$encoded_data = [];
50+
51+
$true_val = 'true';
52+
$false_val = 'false';
53+
54+
if ( $bool_type == 'boolean' ) {
55+
$true_val = true;
56+
$false_val = false;
57+
}
58+
59+
foreach ( $data as $flag_key => $flag_value ) {
60+
$encoded_data[ $flag_value->get_key( false ) ] = [
61+
'key' => $flag_value->get_key( false ),
62+
'name' => $flag_value->get_name( false ),
63+
'description' => $flag_value->get_description( false ),
64+
'label' => $flag_value->get_label( false ),
65+
'activated' => $flag_value->is_enabled() ? $true_val : $false_val,
66+
'stable' => $flag_value->is_stable( false ) ? $true_val : $false_val,
67+
'enforced' => $flag_value->get_enforced() ? $true_val : $false_val,
68+
'private' => $false_val
69+
];
70+
}
71+
72+
return $encoded_data;
73+
}
74+
75+
/**
76+
* Lists all registered flags.
77+
*
78+
* ## OPTIONS
79+
*
80+
* <type>
81+
* : The type of table to display.
82+
* default: table
83+
* options:
84+
* - csv
85+
* - json
86+
* - table
87+
* - yaml
88+
*
89+
* ## EXAMPLES
90+
*
91+
* wp flagpole list
92+
* wp flagpole list csv
93+
*
94+
*/
95+
public function flag_list( $args, $assoc_args ) {
96+
/**
97+
* @todo switch to associated arguments only.
98+
* @todo filter by group/label.
99+
* @todo filter by on/off.
100+
* @todo filter fields to return.
101+
*/
102+
103+
// We don't support the 'ids' or 'count' types, as there's no real benefit to them here.
104+
$supported_render_types = [
105+
'table',
106+
'csv',
107+
'json',
108+
'yaml',
109+
];
110+
111+
$render_type = 'table';
112+
113+
if ( $args !== [] and in_array( $args[0], $supported_render_types, true ) ) {
114+
$render_type = $args[0];
115+
}
116+
117+
$flagpole_available_flags = Flagpole::init()->get_flags();
118+
119+
$fields_to_display = [
120+
'key',
121+
'name',
122+
'description',
123+
'label',
124+
'stable',
125+
'activated',
126+
'enforced',
127+
'private',
128+
];
129+
130+
$bool_type = 'boolean';
131+
132+
if ( 'table' === $render_type ) {
133+
$bool_type = 'string';
134+
}
135+
136+
$flagpole_available_flags = $this->flag_list_data_encode( $flagpole_available_flags, $bool_type );
137+
138+
$enabled_flags = array_filter( $flagpole_available_flags, [ $this, 'flag_filter_enabled' ] );
139+
140+
WP_CLI::line( 'Flags: ' . count( $flagpole_available_flags ) . ' registered. ' . count( $enabled_flags ) . ' enabled.' );
141+
WP_CLI::line();
142+
143+
if ( count( $flagpole_available_flags ) > 0 ) {
144+
WP_CLI\Utils\format_items( $render_type, $flagpole_available_flags, $fields_to_display );
145+
WP_CLI::line();
146+
}
147+
}
148+
149+
/**
150+
* Activates any given flag or a comma separated list of flags.
151+
* If any given flag is already active, its state is not changed.
152+
*
153+
* ## OPTIONS
154+
*
155+
* <flag(s)>
156+
* : The key of the flag to activate. This can be a comma separated list for multiple flags.
157+
*
158+
* ## EXAMPLES
159+
*
160+
* wp flagpole activate my-example-flag
161+
* wp flagpole activate my-example-flag,my-other-example-flag
162+
* wp flagpole on my-example-flag
163+
*
164+
* @alias on
165+
*/
166+
public function flag_on( $args, $assoc_args ) {
167+
if ( $args == [] ) {
168+
WP_CLI::error( 'Flag not provided' );
169+
return;
170+
}
171+
172+
if ( $args[0] ) {
173+
if ( strpos( $args[0], ',' ) > 0 ) {
174+
$flags = explode( ',', $args[0] );
175+
} else {
176+
$flags = [ $args[0] ];
177+
}
178+
179+
foreach( $flags as $flag ) {
180+
if ( true === $this->flag_exists_and_has_state( $flag, true ) ) {
181+
Flagpole::init()->toggle_feature_publication( $flag );
182+
WP_CLI::success( $flag . ' activated.' );
183+
}
184+
}
185+
return;
186+
}
187+
}
188+
189+
/**
190+
* Deactivates any given flag or a comma separated list of flags.
191+
* If any given flag is already deactivated, its state is not changed.
192+
*
193+
* ## OPTIONS
194+
*
195+
* <flag(s)>
196+
* : The key of the flag to activate. This can be a comma separated list for multiple flags.
197+
*
198+
* ## EXAMPLES
199+
*
200+
* wp flagpole deactivate my-example-flag
201+
* wp flagpole deactivate my-example-flag,my-other-example-flag
202+
* wp flagpole off my-example-flag
203+
*
204+
* @alias off
205+
*/
206+
public function flag_off( $args, $assoc_args ) {
207+
if ( $args == [] ) {
208+
WP_CLI::error( 'Flag not provided' );
209+
return;
210+
}
211+
212+
if ( $args[0] ) {
213+
if ( strpos( $args[0], ',' ) > 0 ) {
214+
$flags = explode( ',', $args[0] );
215+
} else {
216+
$flags = [ $args[0] ];
217+
}
218+
219+
foreach( $flags as $flag ) {
220+
if ( true === $this->flag_exists_and_has_state( $flag, false ) ) {
221+
Flagpole::init()->toggle_feature_publication( $flag );
222+
WP_CLI::success( $flag . ' deactivated.' );
223+
}
224+
}
225+
}
226+
}
227+
228+
/**
229+
* Toggles any given flag or a comma separated list of flags.
230+
*
231+
* ## OPTIONS
232+
*
233+
* <flag(s)>
234+
* : The key of the flag to toggle. This can be a comma separated list for multiple flags.
235+
*
236+
* ## EXAMPLES
237+
*
238+
* wp flagpole toggle my-example-flag
239+
* wp flagpole toggle my-example-flag,my-other-example-flag
240+
*
241+
*/
242+
public function flag_toggle( $args, $assoc_args ) {
243+
if ( $args == [] ) {
244+
WP_CLI::error( 'Flag not provided' );
245+
return;
246+
}
247+
248+
if ( $args[0] ) {
249+
if ( strpos( $args[0], ',' ) > 0 ) {
250+
$flags = explode( ',', $args[0] );
251+
} else {
252+
$flags = [ $args[0] ];
253+
}
254+
255+
foreach( $flags as $flag ) {
256+
$query_flag = Flagpole::init()->find_flag( $flag );
257+
$is_currently_enabled = $query_flag->is_enabled();
258+
259+
Flagpole::init()->toggle_feature_publication( $flag );
260+
if ( true === $is_currently_enabled ) {
261+
WP_CLI::success( $flag . ' deactivated.' );
262+
} else {
263+
WP_CLI::success( $flag . ' activated.' );
264+
}
265+
}
266+
}
267+
}
268+
269+
/**
270+
* Helper functions.
271+
*/
272+
273+
/**
274+
* Looks up a flag, checks if it exists and is of a given state.
275+
*
276+
* @param string $flag Name of the flag.
277+
* @param boolean $activated Whether the flag is activated or deactivated.
278+
* @return void
279+
*/
280+
function flag_exists_and_has_state ( $flag, $activated = true ) {
281+
$query_flag = Flagpole::init()->find_flag( $flag );
282+
283+
if ( false === $query_flag ) {
284+
WP_CLI::error( $flag . ' is not a registered flag' );
285+
return false;
286+
}
287+
288+
if ( true === $activated && true === $query_flag->is_enabled() ) {
289+
WP_CLI::success( $flag . ' is already active.' );
290+
return false;
291+
}
292+
293+
if ( false === $activated && false === $query_flag->is_enabled() ) {
294+
WP_CLI::success( $flag . ' is already deactive.' );
295+
return false;
296+
}
297+
298+
return true;
299+
}
300+
}

0 commit comments

Comments
 (0)