PluginProbe
Edit Flow / trunk
Edit Flow vtrunk
0.11.1 0.11.0 0.7.2 0.7.3 0.7.4 0.7.5 0.7.6 0.8 0.8.1 0.8.2 0.9 0.9.1 0.9.2 0.9.3 0.9.4 0.9.5 0.9.6 0.9.7 0.9.8 0.9.9 trunk 0.1.5 0.10.0 0.10.1 0.10.2 All 44 releases
edit-flow / edit_flow.php

edit_flow.php in Edit Flow trunk, at edit_flow.php

463 lines 14.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Plugin Name: Edit Flow
4 * Plugin URI: http://editflow.org/
5 * Description: Remixing the WordPress admin for better editorial workflow options.
6 * Author: Daniel Bachhuber, Scott Bressler, Mohammad Jangda, Automattic, and others
7 * Version: 0.11.1
8 * Requires at least: 6.4
9 * Requires PHP: 7.4
10 * License: GPLv2 or later
11 * License URI: https://www.gnu.org/licenses/gpl-2.0.html
12 *
13 * Copyright 2009-2019 Mohammad Jangda, Daniel Bachhuber, Automattic, et al.
14 *
15 * @package EditFlow
16 */
17
18 defined( 'ABSPATH' ) || exit;
19
20 /**
21 * Print admin notice regarding having an old version of PHP.
22 *
23 * @since 0.9
24 */
25 function _ef_print_php_version_admin_notice() {
26 ?>
27 <div class="notice notice-error">
28 <p><?php esc_html_e( 'Edit Flow requires PHP 7.4+. Please contact your host to update your PHP version.', 'edit-flow' ); ?></p>
29 </div>
30 <?php
31 }
32
33 if ( version_compare( phpversion(), '7.4', '<' ) ) {
34 add_action( 'admin_notices', '_ef_print_php_version_admin_notice' );
35 return;
36 }
37
38 // Define constants.
39 define( 'EDIT_FLOW_VERSION', '0.11.1' );
40 define( 'EDIT_FLOW_ROOT', __DIR__ );
41 define( 'EDIT_FLOW_FILE_PATH', EDIT_FLOW_ROOT . '/' . basename( __FILE__ ) );
42 define( 'EDIT_FLOW_URL', plugins_url( '/', __FILE__ ) );
43 define( 'EDIT_FLOW_SETTINGS_PAGE', add_query_arg( 'page', 'ef-settings', get_admin_url( null, 'admin.php' ) ) );
44
45 /**
46 * Core Edit Flow class.
47 */
48 #[\AllowDynamicProperties]
49 class edit_flow {
50
51 /**
52 * Options group prefix.
53 *
54 * @var string
55 */
56 public $options_group = 'edit_flow_';
57
58 /**
59 * Options group name.
60 *
61 * @var string
62 */
63 public $options_group_name = 'edit_flow_options';
64
65 /**
66 * The one true EditFlow instance.
67 *
68 * @var edit_flow
69 */
70 private static $instance;
71
72 /**
73 * Active modules.
74 *
75 * @var \stdClass
76 */
77 public $modules;
78
79 /**
80 * Number of active modules.
81 *
82 * @var int
83 */
84 public $modules_count;
85
86 /**
87 * Helper modules.
88 *
89 * @var EF_Module
90 */
91 public $helpers;
92
93 /**
94 * Main EditFlow Instance.
95 *
96 * Insures that only one instance of EditFlow exists in memory at any one
97 * time. Also prevents needing to define globals all over the place.
98 *
99 * @since EditFlow 0.7.4
100 * @staticvar array $instance
101 * @uses EditFlow::setup_globals() Setup the globals needed.
102 * @uses EditFlow::includes() Include the required files.
103 * @uses EditFlow::setup_actions() Setup the hooks and actions.
104 * @see EditFlow()
105 * @return edit_flow The one true EditFlow.
106 */
107 public static function instance() {
108 if ( ! isset( self::$instance ) ) {
109 self::$instance = new edit_flow();
110 self::$instance->setup_globals();
111 self::$instance->setup_actions();
112 // Backwards compat for when we promoted use of the $edit_flow global.
113 global $edit_flow;
114 $edit_flow = self::$instance;
115 }
116 return self::$instance;
117 }
118
119 /**
120 * Constructor.
121 */
122 private function __construct() {
123 // Do nothing.
124 }
125
126 /**
127 * Set up global variables.
128 */
129 private function setup_globals() {
130 $this->modules = new stdClass();
131 $this->modules_count = 0;
132 }
133
134 /**
135 * Include the common resources to Edit Flow and dynamically load the modules.
136 */
137 private function load_modules() {
138
139 // We use the WP_List_Table API for some of the table gen.
140 if ( ! class_exists( 'WP_List_Table' ) ) {
141 require_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php';
142 }
143
144 // Edit Flow base module.
145 require_once EDIT_FLOW_ROOT . '/common/php/class-module.php';
146
147 // Scan the modules directory and include any modules that exist there.
148 $module_dirs = scandir( EDIT_FLOW_ROOT . '/modules/' );
149 $class_names = array();
150 foreach ( $module_dirs as $module_dir ) {
151 if ( file_exists( EDIT_FLOW_ROOT . "/modules/{$module_dir}/$module_dir.php" ) ) {
152 include_once EDIT_FLOW_ROOT . "/modules/{$module_dir}/$module_dir.php";
153
154 // Prepare the class name because it should be standardized.
155 $tmp = explode( '-', $module_dir );
156 $class_name = '';
157 $slug_name = '';
158 foreach ( $tmp as $word ) {
159 $class_name .= ucfirst( $word ) . '_';
160 $slug_name .= $word . '_';
161 }
162 $slug_name = rtrim( $slug_name, '_' );
163 $class_names[ $slug_name ] = 'EF_' . rtrim( $class_name, '_' );
164 }
165 }
166
167 // Instantiate EF_Module as $helpers for back compat and so we can use it in this class.
168 $this->helpers = new EF_Module();
169
170 // Other utils.
171 require_once EDIT_FLOW_ROOT . '/common/php/util.php';
172
173 // Instantiate all of our classes onto the Edit Flow object but make sure they exist too.
174 foreach ( $class_names as $slug => $class_name ) {
175 if ( class_exists( $class_name ) ) {
176 $this->$slug = new $class_name();
177 }
178 }
179
180 /**
181 * Fires after edit_flow has loaded all Edit Flow internal modules.
182 *
183 * Plugin authors can hook into this action, include their own modules add them to the $edit_flow object
184 */
185 do_action( 'ef_modules_loaded' );
186 }
187
188 /**
189 * Setup the default hooks and actions.
190 *
191 * @since EditFlow 0.7.4
192 * @access private
193 * @uses add_action() To add various actions.
194 */
195 private function setup_actions() {
196 add_action( 'init', array( $this, 'action_init' ) );
197 add_action( 'init', array( $this, 'action_init_after' ), 1000 );
198
199 add_action( 'admin_init', array( $this, 'action_admin_init' ) );
200
201 /**
202 * Fires after setup of all edit_flow actions.
203 *
204 * Plugin authors can hook into this action to manipulate the edit_flow class after initial actions have been registered.
205 *
206 * @param edit_flow $this The core edit flow class
207 */
208 do_action_ref_array( 'editflow_after_setup_actions', array( &$this ) );
209 }
210
211 /**
212 * Inititalizes the Edit Flows!
213 *
214 * Loads options for each registered module and then initializes it if it's active.
215 */
216 public function action_init() {
217
218 load_plugin_textdomain( 'edit-flow', false, dirname( plugin_basename( __FILE__ ) ) . '/languages/' );
219
220 $this->load_modules();
221
222 // Load all of the module options.
223 $this->load_module_options();
224
225 // Load all of the modules that are enabled. Modules won't have an options value if they aren't enabled.
226 foreach ( $this->modules as $mod_name => $mod_data ) {
227 if ( isset( $mod_data->options->enabled ) && 'on' == $mod_data->options->enabled ) {
228 $this->$mod_name->init();
229 }
230 }
231
232 /**
233 * Fires after edit_flow has loaded all modules and module options.
234 *
235 * Plugin authors can hook into this action to trigger functionaltiy after all Edit Flow module's have been loaded.
236 */
237 do_action( 'ef_init' );
238 }
239
240 /**
241 * Initialize the plugin for the admin.
242 */
243 public function action_admin_init() {
244
245 // Upgrade if need be but don't run the upgrade if the plugin has never been used.
246 $previous_version = get_option( $this->options_group . 'version' );
247 if ( $previous_version && version_compare( $previous_version, EDIT_FLOW_VERSION, '<' ) ) {
248 foreach ( $this->modules as $mod_name => $mod_data ) {
249 if ( method_exists( $this->$mod_name, 'upgrade' ) ) {
250 $this->$mod_name->upgrade( $previous_version );
251 }
252 }
253 update_option( $this->options_group . 'version', EDIT_FLOW_VERSION );
254 } elseif ( ! $previous_version ) {
255 update_option( $this->options_group . 'version', EDIT_FLOW_VERSION );
256 }
257
258 // For each module that's been loaded, auto-load data if it's never been run before.
259 foreach ( $this->modules as $mod_name => $mod_data ) {
260 // If the module has never been loaded before, run the install method if there is one.
261 if ( ! isset( $mod_data->options->loaded_once ) || ! $mod_data->options->loaded_once ) {
262 if ( method_exists( $this->$mod_name, 'install' ) ) {
263 $this->$mod_name->install();
264 }
265 $this->update_module_option( $mod_name, 'loaded_once', true );
266 }
267 }
268
269 $this->register_scripts_and_styles();
270 }
271
272 /**
273 * Register a new module with Edit Flow.
274 *
275 * @param string $name Module name.
276 * @param array $args Module arguments.
277 * @return object|false Module object on success, false on failure.
278 */
279 public function register_module( $name, $args = array() ) {
280
281 // A title and name is required for every module.
282 if ( ! isset( $args['title'], $name ) ) {
283 return false;
284 }
285
286 $defaults = array(
287 'title' => '',
288 'short_description' => '',
289 'extended_description' => '',
290 'img_url' => false,
291 'slug' => '',
292 'post_type_support' => '',
293 'default_options' => array(),
294 'options' => false,
295 'configure_page_cb' => false,
296 'configure_link_text' => __( 'Configure', 'edit-flow' ),
297 // These messages are applied to modules and can be overridden if custom messages are needed.
298 'messages' => array(
299 'settings-updated' => __( 'Settings updated.', 'edit-flow' ),
300 'form-error' => __( 'Please correct your form errors below and try again.', 'edit-flow' ),
301 'nonce-failed' => __( 'Cheatin’ uh?', 'edit-flow' ),
302 'invalid-permissions' => __( 'You do not have necessary permissions to complete this action.', 'edit-flow' ),
303 'missing-post' => __( 'Post does not exist', 'edit-flow' ),
304 ),
305 'autoload' => false, // Autoloading a module will remove the ability to enable or disable it.
306 );
307 if ( isset( $args['messages'] ) ) {
308 $args['messages'] = array_merge( (array) $args['messages'], $defaults['messages'] );
309 }
310 $args = array_merge( $defaults, $args );
311 $args['name'] = $name;
312 $args['options_group_name'] = $this->options_group . $name . '_options';
313 if ( ! isset( $args['settings_slug'] ) ) {
314 $args['settings_slug'] = 'ef-' . $args['slug'] . '-settings';
315 }
316 if ( empty( $args['post_type_support'] ) ) {
317 $args['post_type_support'] = 'ef_' . $name;
318 }
319 // If there's a Help Screen registered for the module, make sure we auto-load it.
320 if ( ! empty( $args['settings_help_tab'] ) ) {
321 add_action( 'load-edit-flow_page_' . $args['settings_slug'], array( &$this->$name, 'action_settings_help_menu' ) );
322 }
323
324 $this->modules->$name = (object) $args;
325
326 ++$this->modules_count;
327
328 /**
329 * Fires after edit_flow has registered a module.
330 *
331 * Plugin authors can hook into this action to trigger functionaltiy after a module has been loaded.
332 *
333 * @param string $name The name of the registered module
334 */
335 do_action( 'ef_module_registered', $name );
336 return $this->modules->$name;
337 }
338
339 /**
340 * Load all of the module options from the database.
341 *
342 * If a given option isn't yet set, then set it to the module's default (upgrades, etc.).
343 */
344 public function load_module_options() {
345
346 foreach ( $this->modules as $mod_name => $mod_data ) {
347 $this->modules->$mod_name->options = get_option( $this->options_group . $mod_name . '_options', new stdClass() );
348 foreach ( $mod_data->default_options as $default_key => $default_value ) {
349 if ( ! isset( $this->modules->$mod_name->options->$default_key ) ) {
350 $this->modules->$mod_name->options->$default_key = $default_value;
351 }
352 }
353
354 $this->$mod_name->module = $this->modules->$mod_name;
355 }
356
357 /**
358 * Fires after edit_flow has loaded all of the module options from the database.
359 *
360 * Plugin authors can hook into this action to read and manipulate module settings.
361 */
362 do_action( 'ef_module_options_loaded' );
363 }
364
365 /**
366 * Load the post type options again so we give add_post_type_support() a chance to work.
367 *
368 * @see http://dev.editflow.org/2011/11/17/edit-flow-v0-7-alpha2-notes/#comment-232
369 */
370 public function action_init_after() {
371 foreach ( $this->modules as $mod_name => $mod_data ) {
372 if ( isset( $this->modules->$mod_name->options->post_types ) ) {
373 $this->modules->$mod_name->options->post_types = $this->helpers->clean_post_type_options( $this->modules->$mod_name->options->post_types, $mod_data->post_type_support );
374 }
375
376 $this->$mod_name->module = $this->modules->$mod_name;
377 }
378 }
379
380 /**
381 * Get a module by one of its descriptive values.
382 *
383 * @param string $key The property to use for searching a module (ex: 'name').
384 * @param string|int|array $value The value to compare (using ==).
385 * @return object|false Module object on success, false on failure.
386 */
387 public function get_module_by( $key, $value ) {
388 $module = false;
389 foreach ( $this->modules as $mod_name => $mod_data ) {
390 if ( 'name' === $key && $value === $mod_name ) {
391 $module = $this->modules->$mod_name;
392 } else {
393 foreach ( $mod_data as $mod_data_key => $mod_data_value ) {
394 if ( $mod_data_key === $key && $mod_data_value === $value ) {
395 $module = $this->modules->$mod_name;
396 }
397 }
398 }
399 }
400 return $module;
401 }
402
403 /**
404 * Update the $edit_flow object with new value and save to the database.
405 *
406 * @param string $mod_name Module name.
407 * @param string $key Option key.
408 * @param mixed $value Option value.
409 * @return bool True on success, false on failure.
410 */
411 public function update_module_option( $mod_name, $key, $value ) {
412 $this->modules->$mod_name->options->$key = $value;
413 $this->$mod_name->module = $this->modules->$mod_name;
414 return update_option( $this->options_group . $mod_name . '_options', $this->modules->$mod_name->options );
415 }
416
417 /**
418 * Update all module options at once.
419 *
420 * @param string $mod_name Module name.
421 * @param array|object $new_options New options.
422 * @return bool True on success, false on failure.
423 */
424 public function update_all_module_options( $mod_name, $new_options ) {
425 if ( is_array( $new_options ) ) {
426 $new_options = (object) $new_options;
427 }
428 $this->modules->$mod_name->options = $new_options;
429 $this->$mod_name->module = $this->modules->$mod_name;
430 return update_option( $this->options_group . $mod_name . '_options', $this->modules->$mod_name->options );
431 }
432
433 /**
434 * Registers commonly used scripts + styles for easy enqueueing.
435 */
436 public function register_scripts_and_styles() {
437 wp_enqueue_style( 'ef-admin-css', EDIT_FLOW_URL . 'common/css/edit-flow-admin.css', false, EDIT_FLOW_VERSION, 'all' );
438
439 wp_register_script( 'jquery-listfilterizer', EDIT_FLOW_URL . 'common/js/jquery.listfilterizer.js', array( 'jquery' ), EDIT_FLOW_VERSION, true );
440 wp_register_style( 'jquery-listfilterizer', EDIT_FLOW_URL . 'common/css/jquery.listfilterizer.css', false, EDIT_FLOW_VERSION, 'all' );
441
442
443 wp_localize_script(
444 'jquery-listfilterizer',
445 '__i18n_jquery_filterizer',
446 array(
447 'all' => esc_html__( 'All', 'edit-flow' ),
448 'selected' => esc_html__( 'Selected', 'edit-flow' ),
449 )
450 );
451 }
452 }
453
454 /**
455 * Get the Edit Flow instance.
456 *
457 * @return edit_flow The Edit Flow instance.
458 */
459 function EditFlow() { // phpcs:ignore WordPress.NamingConventions.ValidFunctionName.FunctionNameInvalid -- Legacy function name.
460 return edit_flow::instance();
461 }
462 add_action( 'plugins_loaded', 'EditFlow' );
463