PluginProbe
PublishPress Planner – Editorial Calendar, Marketing Content, Kanban Board / 4.8.0
PublishPress Planner – Editorial Calendar, Marketing Content, Kanban Board v4.8.0
trunk 1.0.0 1.0.1 1.0.2 1.0.3 1.0.4 1.0.5 1.1.0 1.10.0 1.11.2 1.11.3 1.11.4 1.12.0 1.12.1 1.13.0 1.14.0 1.14.1 1.15.0 1.16.0 1.16.1 1.16.2 1.16.3 1.17.0 1.18.0 1.18.1 All 140 releases
publishpress / publishpress.php

publishpress.php in PublishPress Planner – Editorial Calendar, Marketing Content, Kanban Board 4.8.0, at publishpress.php

1,543 lines 60.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Plugin Name: PublishPress Planner Free
4 * Plugin URI: https://publishpress.com/
5 * Description: PublishPress Planner helps you plan and publish content inside WordPress. Features include a content calendar, kanban board, and notifications.
6 * Version: 4.8.0
7 * Author: PublishPress
8 * Author URI: https://publishpress.com
9 * Text Domain: publishpress
10 * Domain Path: /languages
11 * Requires at least: 5.5
12 * Requires PHP: 7.2.5
13 *
14 * Copyright (c) 2025 PublishPress
15 *
16 * ------------------------------------------------------------------------------
17 * Based on Edit Flow
18 * Author: Daniel Bachhuber, Scott Bressler, Mohammad Jangda, Automattic, and
19 * others
20 * Copyright (c) 2009-2016 Mohammad Jangda, Daniel Bachhuber, et al.
21 * ------------------------------------------------------------------------------
22 *
23 * GNU General Public License, Free Software Foundation <http://creativecommons.org/licenses/GPL/2.0/>
24 *
25 * This program is free software: you can redistribute it and/or modify
26 * it under the terms of the GNU General Public License as published by
27 * the Free Software Foundation, either version 3 of the License, or
28 * (at your option) any later version.
29 *
30 * This program is distributed in the hope that it will be useful,
31 * but WITHOUT ANY WARRANTY; without even the implied warranty of
32 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
33 * GNU General Public License for more details.
34 *
35 * You should have received a copy of the GNU General Public License
36 * along with this program. If not, see <http://www.gnu.org/licenses/>.
37 *
38 * @package PublishPress
39 * @author PublishPress
40 * @copyright Copyright (C) 2024 PublishPress. All rights reserved.
41 * @link https://publishpress.com/
42 *
43 */
44
45 use PPVersionNotices\Module\MenuLink\Module;
46 use PublishPress\Notifications\Traits\Dependency_Injector;
47 use PublishPress\Notifications\Traits\PublishPress_Module;
48
49 global $wp_version;
50
51 $min_php_version = '7.2.5';
52 $min_wp_version = '5.5';
53
54 $invalid_php_version = version_compare(phpversion(), $min_php_version, '<');
55 $invalid_wp_version = version_compare($wp_version, $min_wp_version, '<');
56
57 if ($invalid_php_version || $invalid_wp_version) {
58 return;
59 }
60
61 if (! defined('PP_LIB_VENDOR_PATH')) {
62 define('PP_LIB_VENDOR_PATH', __DIR__ . '/lib/vendor');
63 }
64
65 $instanceProtectionIncPath = PP_LIB_VENDOR_PATH . '/publishpress/instance-protection/include.php';
66 if (is_file($instanceProtectionIncPath) && is_readable($instanceProtectionIncPath)) {
67 require_once $instanceProtectionIncPath;
68 }
69
70 if (class_exists('PublishPressInstanceProtection\\Config')) {
71 $pluginCheckerConfig = new PublishPressInstanceProtection\Config();
72 $pluginCheckerConfig->pluginSlug = 'publishpress';
73 $pluginCheckerConfig->pluginName = 'PublishPress Planner';
74
75 $pluginChecker = new PublishPressInstanceProtection\InstanceChecker($pluginCheckerConfig);
76 }
77
78 $autoloadFilePath = PP_LIB_VENDOR_PATH . '/autoload.php';
79 if (! class_exists('ComposerAutoloaderInitPublishPressPlanner')
80 && is_file($autoloadFilePath)
81 && is_readable($autoloadFilePath)
82 ) {
83 require_once $autoloadFilePath;
84 }
85
86 add_action('plugins_loaded', function () {
87
88 require_once 'includes.php';
89
90 // Core class
91 if (! class_exists('publishpress')) {
92 #[\AllowDynamicProperties]
93 class publishpress
94 {
95 use Dependency_Injector, PublishPress_Module;
96
97 // Unique identified added as a prefix to all options
98 /**
99 * @var PublishPress The one true PublishPress
100 */
101 private static $instance;
102
103 public $options_group = 'publishpress_';
104
105 public $options_group_name = 'publishpress_options';
106
107 /**
108 * @var stdClass
109 */
110 public $modules;
111
112 public $custom_status; // back compat
113
114 /**
115 * @var array
116 */
117 public $class_names;
118
119 protected $added_menu_page = false;
120
121 protected $menu_slug;
122
123 protected $loadedModules = [];
124
125 /**
126 * Main PublishPress Instance
127 *
128 * Insures that only one instance of PublishPress exists in memory at any one
129 * time. Also prevents needing to define globals all over the place.
130 *
131 * @return publishpress
132 */
133 public static function instance()
134 {
135 if (! isset(self::$instance)) {
136 self::$instance = new publishpress();
137 self::$instance->setup_globals();
138 self::$instance->setup_actions();
139 // Backwards compat for when we promoted use of the $publishpress global
140 global $publishpress;
141 $publishpress = self::$instance;
142 }
143
144 return self::$instance;
145 }
146
147 private function setup_globals()
148 {
149 $this->modules = new stdClass();
150 }
151
152 /**
153 * Setup the default hooks and actions
154 *
155 * @since PublishPress 0.7.4
156 * @access private
157 * @uses add_action() To add various actions
158 */
159 private function setup_actions()
160 {
161 add_action('init', [$this, 'action_init'], PUBLISHPRESS_ACTION_PRIORITY_INIT);
162 add_action('init', [$this, 'action_init_after'], PUBLISHPRESS_ACTION_PRIORITY_INIT_LATE);
163 add_action('init', [$this, 'action_ini_for_admin'], PUBLISHPRESS_ACTION_PRIORITY_INIT_ADMIN);
164 add_action('admin_menu', [$this, 'action_admin_menu'], 9);
165
166 add_action('admin_enqueue_scripts', [$this, 'register_scripts_and_styles']);
167
168 // Fix the order of the submenus
169 add_filter('custom_menu_order', [$this, 'filter_custom_menu_order']);
170
171 do_action_ref_array('publishpress_after_setup_actions', [$this]);
172
173 add_filter('debug_information', [$this, 'filterDebugInformation']);
174
175 add_filter('cme_plugin_capabilities', [$this, 'filterCapabilities'], 11);
176 // Redirect on plugin activation
177 add_action('admin_init', [$this, 'redirect_on_activate'], 2000);
178 // Add meta keys search
179 add_action('wp_ajax_publishpress_content_search_meta_keys', [$this, 'searchMetaKeys']);
180 }
181
182 /**
183 * The capabilities need to be set before the modules are loaded,
184 * so the submenu items can be displayed correctly right after activate.
185 * Otherwise we only see the submenus after visiting the PublishPress settings
186 * menu for the first time.
187 *
188 */
189 public static function activation_hook()
190 {
191 // @todo: This should be executed only when it is an upgrade, for specific versions, otherwise it overwrites the user's customizations.
192 // Add necessary capabilities to allow management of calendar, content overview, notifications
193 $genericCaps = [
194 'pp_view_calendar',
195 'pp_view_content_overview',
196 'pp_view_content_board',
197 'edit_post_subscriptions',
198 'pp_set_notification_channel',
199 'pp_delete_editorial_comment',
200 'pp_delete_others_editorial_comment',
201 'pp_edit_editorial_comment',
202 'pp_edit_others_editorial_comment',
203 ];
204
205 $roles = [
206 'administrator' => $genericCaps,
207 'editor' => $genericCaps,
208 'author' => $genericCaps,
209 'contributor' => $genericCaps,
210 ];
211
212 foreach ($roles as $role => $caps) {
213 PublishPress\Legacy\Util::add_caps_to_role($role, $caps);
214 }
215
216 // Additional capabilities
217 $roles = [
218 'administrator' => [apply_filters('pp_manage_roles_cap', 'pp_manage_roles')],
219 ];
220
221 foreach ($roles as $role => $caps) {
222 PublishPress\Legacy\Util::add_caps_to_role($role, $caps);
223 }
224 }
225
226 /**
227 * Inititalizes the PublishPress!
228 * Loads options for each registered module and then initializes it if it's active
229 */
230 public function action_init()
231 {
232 load_plugin_textdomain('publishpress', null, plugin_basename(PUBLISHPRESS_BASE_PATH) . '/languages/');
233
234 $this->load_modules();
235
236 // Load all of the module options
237 $this->load_module_options();
238
239 $this->checkBlockEditor();
240
241 // Load all of the modules that are enabled.
242 // Modules won't have an options value if they aren't enabled
243 foreach ($this->modules as $mod_name => $mod_data) {
244 if (isset($mod_data->options->enabled) && $mod_data->options->enabled == 'on') {
245 $this->$mod_name->init();
246 }
247 }
248
249 do_action('pp_init');
250 }
251
252 /**
253 * Include the common resources to PublishPress and dynamically load the modules
254 */
255 private function load_modules()
256 {
257 // We use the WP_List_Table API for some of the table gen
258 if (! class_exists('WP_List_Table')) {
259 require_once(ABSPATH . 'wp-admin/includes/class-wp-list-table.php');
260 }
261
262 // PublishPress base module
263 if (! class_exists('PP_Module')) {
264 require_once(PUBLISHPRESS_BASE_PATH . '/common/php/class-module.php');
265 }
266
267 $module_dirs = $this->getModulesDirs();
268
269 $class_names = [];
270
271 foreach ($module_dirs as $module_dir => $base_path) {
272 if (file_exists("{$base_path}/modules/{$module_dir}/{$module_dir}.php")) {
273 include_once "{$base_path}/modules/{$module_dir}/{$module_dir}.php";
274
275 // Prepare the class name because it should be standardized
276 $tmp = explode('-', $module_dir);
277 $class_name = '';
278 $slug_name = '';
279
280 foreach ($tmp as $word) {
281 $class_name .= ucfirst($word) . '_';
282 $slug_name .= $word . '_';
283 }
284
285 $slug_name = rtrim($slug_name, '_');
286 $class_names[$slug_name] = 'PP_' . rtrim($class_name, '_');
287 }
288 }
289
290 // Instantiate PP_Module as $helpers for back compat and so we can
291 // use it in this class
292 $this->helpers = new PP_Module();
293
294 // Other utils
295 require_once(PUBLISHPRESS_BASE_PATH . '/common/php/util.php');
296
297 // Instantiate all of our classes onto the PublishPress object
298 // but make sure they exist too
299 foreach ($class_names as $slug => $class_name) {
300 if (class_exists($class_name)) {
301 $slug = PublishPress\Legacy\Util::sanitize_module_name($slug);
302 $module_instance = new $class_name();
303
304 $this->$slug = $module_instance;
305
306 // If there's a Help Screen registered for the module, make sure we auto-load it
307 $args = null;
308 if (isset($this->modules->$slug)) {
309 $args = $this->modules->$slug;
310 }
311
312 if (! is_null($args) && ! empty($args->settings_help_tab)) {
313 add_action(
314 'load-publishpress_page_' . $args->settings_slug,
315 [$module_instance, 'action_settings_help_menu']
316 );
317 }
318
319 $this->loadedModules[] = $slug;
320 }
321 }
322
323 $this->class_names = $class_names;
324
325 // back compat for any existing $publishpress->custom_status->get_custom_status_by() calls
326 if (class_exists('PublishPress_Statuses')) {
327 $this->custom_status = \PublishPress_Statuses::instance();
328 } else {
329 $this->custom_status = new \PP_Module();
330 }
331
332 // Supplementary plugins can hook into this, include their own modules
333 // and add them to the $publishpress object
334 do_action('pp_modules_loaded');
335 }
336
337 /**
338 * @return array
339 */
340 private function getModulesDirs()
341 {
342 // Scan the modules directory and include any modules that exist there
343 $defaultDirs = [
344 'calendar' => PUBLISHPRESS_BASE_PATH,
345 'content-overview' => PUBLISHPRESS_BASE_PATH,
346 'content-board' => PUBLISHPRESS_BASE_PATH,
347 'notifications' => PUBLISHPRESS_BASE_PATH,
348 'improved-notifications' => PUBLISHPRESS_BASE_PATH,
349 'async-notifications' => PUBLISHPRESS_BASE_PATH,
350 'notifications-log' => PUBLISHPRESS_BASE_PATH,
351 'editorial-metadata' => PUBLISHPRESS_BASE_PATH,
352 'editorial-comments' => PUBLISHPRESS_BASE_PATH,
353 'efmigration' => PUBLISHPRESS_BASE_PATH,
354 'debug' => PUBLISHPRESS_BASE_PATH,
355 'reviews' => PUBLISHPRESS_BASE_PATH,
356 'theeventscalendar-integration' => PUBLISHPRESS_BASE_PATH,
357 'dashboard' => PUBLISHPRESS_BASE_PATH,
358 'modules-settings' => PUBLISHPRESS_BASE_PATH,
359 'settings' => PUBLISHPRESS_BASE_PATH,
360 ];
361
362 // Add filters to extend the modules
363 return apply_filters('pp_module_dirs', $defaultDirs);
364 }
365
366 /**
367 * Load all of the module options from the database
368 * If a given option isn't yet set, then set it to the module's default (upgrades, etc.)
369 */
370 public function load_module_options()
371 {
372 foreach ($this->modules as $mod_name => $mod_data) {
373 $this->modules->$mod_name->options = get_option(
374 $this->options_group . $mod_name . '_options',
375 new stdClass()
376 );
377 foreach ($mod_data->default_options as $default_key => $default_value) {
378 if (! isset($this->modules->$mod_name->options->$default_key)) {
379 $this->modules->$mod_name->options->$default_key = $default_value;
380 }
381 }
382 $this->$mod_name->module = $this->modules->$mod_name;
383 }
384
385 do_action('pp_module_options_loaded');
386 }
387
388 /**
389 * Check if need to restrict the use of the block editor, or Gutenberg.
390 */
391 protected function checkBlockEditor()
392 {
393 // If version is > 5+, check if the classical editor is installed, if not, ask to install.
394 add_filter('use_block_editor_for_post_type', [$this, 'canUseBlockEditorForPostType'], 5, 2);
395 add_filter('gutenberg_can_edit_post_type', [$this, 'canUseBlockEditorForPostType'], 5, 2);
396
397 add_action('add_meta_boxes', [$this, 'removeEditorMetaBox']);
398 }
399
400 /**
401 * @param array $debugInfo
402 *
403 * @return array
404 */
405 public function filterDebugInformation($debugInfo)
406 {
407 $constDisableWpCron = 'undefined';
408 if (defined('DISABLE_WP_CRON')) {
409 $constDisableWpCron = DISABLE_WP_CRON;
410 }
411
412 $constWpDebug = 'undefined';
413 if (defined('WP_DEBUG')) {
414 $constWpDebug = WP_DEBUG;
415 }
416
417 $constWpDebugLog = 'undefined';
418 if (defined('WP_DEBUG_LOG')) {
419 $constWpDebugLog = WP_DEBUG_LOG;
420 }
421
422 $constWpDisplay = 'undefined';
423 if (defined('WP_DEBUG_DISPLAY')) {
424 $constWpDisplay = WP_DEBUG_DISPLAY;
425 }
426
427 $debugInfo['publishpress'] = [
428 'label' => 'PublishPress Planner',
429 'description' => '',
430 'show_count' => false,
431 'fields' => [
432 'PUBLISHPRESS_VERSION' => [
433 'label' => __('PUBLISHPRESS_VERSION'),
434 'value' => PUBLISHPRESS_VERSION,
435 ],
436 'PUBLISHPRESS_BASE_PATH' => [
437 'label' => __('PUBLISHPRESS_BASE_PATH'),
438 'value' => PUBLISHPRESS_BASE_PATH,
439 ],
440 'PUBLISHPRESS_FILE_PATH' => [
441 'label' => __('PUBLISHPRESS_FILE_PATH'),
442 'value' => PUBLISHPRESS_FILE_PATH,
443 ],
444 'PUBLISHPRESS_URL' => [
445 'label' => __('PUBLISHPRESS_URL'),
446 'value' => PUBLISHPRESS_URL,
447 ],
448 'PUBLISHPRESS_SETTINGS_PAGE' => [
449 'label' => __('PUBLISHPRESS_SETTINGS_PAGE'),
450 'value' => PUBLISHPRESS_SETTINGS_PAGE,
451 ],
452 'PUBLISHPRESS_LIBRARIES_PATH' => [
453 'label' => __('PUBLISHPRESS_LIBRARIES_PATH'),
454 'value' => PUBLISHPRESS_LIBRARIES_PATH,
455 ],
456 'WP_CONTENT_DIR' => [
457 'label' => __('WP_CONTENT_DIR'),
458 'value' => WP_CONTENT_DIR,
459 ],
460 'WP_CONTENT_URL' => [
461 'label' => __('WP_CONTENT_URL'),
462 'value' => WP_CONTENT_URL,
463 ],
464 'DISABLE_WP_CRON' => [
465 'label' => __('DISABLE_WP_CRON'),
466 'value' => $constDisableWpCron,
467 ],
468 'WP_DEBUG' => [
469 'label' => __('WP_DEBUG'),
470 'value' => $constWpDebug,
471 ],
472 'WP_DEBUG_LOG' => [
473 'label' => __('WP_DEBUG_LOG'),
474 'value' => $constWpDebugLog,
475 ],
476 'WP_DEBUG_DISPLAY' => [
477 'label' => __('WP_DEBUG_DISPLAY'),
478 'value' => $constWpDisplay,
479 ],
480 'option::date_format' => [
481 'label' => __('WP Date Format'),
482 'value' => get_option('date_format'),
483 ],
484 'option::time_format' => [
485 'label' => __('WP Time Format'),
486 'value' => get_option('time_format'),
487 ],
488 'option::timezone_string' => [
489 'label' => __('WP Timezone String'),
490 'value' => get_option('timezone_string'),
491 ],
492 'option::gmt_offset' => [
493 'label' => __('WP GMT Offset'),
494 'value' => get_option('gmt_offset'),
495 ],
496 'php::date_default_timezone_get' => [
497 'label' => __('date_default_timezone_get'),
498 'value' => date_default_timezone_get(),
499 ],
500 ],
501 ];
502
503
504 // Modules
505 $modules = [];
506 $modulesDirs = $this->getModulesDirs();
507
508 foreach ($this->loadedModules as $module) {
509 $dashCaseModule = str_replace('_', '-', $module);
510
511 $status = isset($this->{$module}) && isset($this->{$module}->module->options->enabled) ? $this->{$module}->module->options->enabled : 'on';
512
513 $modules[$module] = [
514 'label' => $module,
515 'value' => $status . ' [' . $modulesDirs[$dashCaseModule] . '/modules/' . $module . ']',
516 ];
517 }
518
519 $debugInfo['publishpress-modules'] = [
520 'label' => 'PublishPress Modules',
521 'description' => '',
522 'show_count' => true,
523 'fields' => $modules,
524 ];
525
526 return $debugInfo;
527 }
528
529 /**
530 * Initialize the plugin for the admin
531 */
532 public function action_ini_for_admin()
533 {
534 // Upgrade if need be but don't run the upgrade if the plugin has never been used
535 $previous_version = get_option($this->options_group . 'version');
536 if ($previous_version && version_compare($previous_version, PUBLISHPRESS_VERSION, '<')) {
537 foreach ($this->modules as $mod_name => $mod_data) {
538 if (method_exists($this->$mod_name, 'upgrade')) {
539 $this->$mod_name->upgrade($previous_version);
540 }
541 }
542 }
543
544 update_option($this->options_group . 'version', PUBLISHPRESS_VERSION);
545
546 // For each module that's been loaded, auto-load data if it's never been run before
547 foreach ($this->modules as $mod_name => $mod_data) {
548 // If the module has never been loaded before, run the install method if there is one
549 if (! isset($mod_data->options->loaded_once) || ! $mod_data->options->loaded_once) {
550 if (method_exists($this->$mod_name, 'install')) {
551 $this->$mod_name->install();
552 }
553 $this->update_module_option($mod_name, 'loaded_once', true);
554 }
555 }
556 }
557
558 /**
559 * Update the $publishpress object with new value and save to the database
560 */
561 public function update_module_option($mod_name, $key, $value)
562 {
563 if (false === $this->modules->$mod_name->options) {
564 $this->modules->$mod_name->options = new stdClass();
565 }
566
567 $this->modules->$mod_name->options->$key = $value;
568 $this->$mod_name->module = $this->modules->$mod_name;
569
570 return update_option($this->options_group . $mod_name . '_options', $this->modules->$mod_name->options);
571 }
572
573 /**
574 * @param $page_title
575 * @param $menu_title
576 * @param $capability
577 * @param $menu_slug
578 * @param string $function
579 * @param string $icon_url
580 * @param null $position
581 */
582 public function add_menu_page($page_title, $capability, $menu_slug, $function = '')
583 {
584 if ($this->added_menu_page) {
585 return;
586 }
587
588 add_menu_page(
589 $page_title,
590 esc_html__('Planner', 'publishpress'),
591 $capability,
592 $menu_slug,
593 $function,
594 'dashicons-calendar-alt',
595 26
596 );
597
598 $this->added_menu_page = true;
599 $this->menu_slug = $menu_slug;
600 }
601
602 /**
603 * Returns true if the menu page was already created. Returns false if not.
604 *
605 * @return bool
606 */
607 public function is_menu_page_created()
608 {
609 return (bool)$this->added_menu_page;
610 }
611
612 /**
613 * Returns the menu slug for the menu page.
614 *
615 * @return string
616 */
617 public function get_menu_slug()
618 {
619 return $this->menu_slug;
620 }
621
622 /**
623 * Add the menu page and call an action for modules add submenus
624 */
625 public function action_admin_menu()
626 {
627 /**
628 * Filters the menu slug. By default, each filter should only set a menu slug if it is empty.
629 * To determine the precedence of menus, use different priorities among the filters.
630 *
631 * @param string $menu_slug
632 */
633 $this->menu_slug = apply_filters('publishpress_admin_menu_slug', $this->menu_slug);
634
635 /**
636 * Action for adding menu pages.
637 */
638 do_action('publishpress_admin_menu_page');
639
640 /**
641 * @deprecated
642 */
643 do_action('publishpress_admin_menu');
644
645 /**
646 * Action for adding submenus.
647 */
648 do_action('publishpress_admin_submenu');
649 }
650
651 /**
652 * Register a new module with PublishPress
653 */
654 public function register_module($name, $args = [])
655 {
656 // A title and name is required for every module
657 if (! isset($args['title'], $name)) {
658 return false;
659 }
660
661 $defaults = [
662 'title' => '',
663 'short_description' => '',
664 'extended_description' => '',
665 'icon_class' => 'dashicons dashicons-calendar-alt',
666 'slug' => '',
667 'post_type_support' => '',
668 'default_options' => [],
669 'options' => false,
670 'configure_page_cb' => false,
671 'configure_link_text' => __('Configure', 'publishpress'),
672 // These messages are applied to modules and can be overridden if custom messages are needed
673 'messages' => [
674 'form-error' => __('Please correct your form errors below and try again.', 'publishpress'),
675 'nonce-failed' => __('Cheatin&#8217; uh?', 'publishpress'),
676 'invalid-permissions' => __(
677 'You do not have necessary permissions to complete this action.',
678 'publishpress'
679 ),
680 'missing-post' => __('Post does not exist', 'publishpress'),
681 ],
682 'autoload' => false, // autoloading a module will remove the ability to enable or disable it
683 ];
684 if (isset($args['messages'])) {
685 $args['messages'] = array_merge((array)$args['messages'], $defaults['messages']);
686 }
687 $args = array_merge($defaults, $args);
688 $args['name'] = $name;
689 $args['options_group_name'] = $this->options_group . $name . '_options';
690
691 if (! isset($args['settings_slug'])) {
692 $args['settings_slug'] = 'pp-' . $args['slug'] . '-settings';
693 }
694
695 if (empty($args['post_type_support'])) {
696 $args['post_type_support'] = 'pp_' . $name;
697 }
698
699 // If there's a Help Screen registered for the module, make sure we
700 // auto-load it
701 if (! empty($args['settings_help_tab'])) {
702 add_action(
703 'load-publishpress_page_' . $args['settings_slug'],
704 [&$this->$name, 'action_settings_help_menu']
705 );
706 }
707
708 $this->modules->$name = (object)$args;
709 do_action('pp_module_registered', $name);
710
711 return $this->modules->$name;
712 }
713
714 /**
715 * Load the post type options again so we give add_post_type_support() a chance to work
716 *
717 * @see https://publishpress.com/2011/11/17/publishpress-v0-7-alpha2-notes/#comment-232
718 */
719 public function action_init_after()
720 {
721 foreach ($this->modules as $mod_name => $mod_data) {
722 if (isset($this->modules->$mod_name->options->post_types)) {
723 $this->modules->$mod_name->options->post_types = $this->helpers->clean_post_type_options(
724 $this->modules->$mod_name->options->post_types,
725 $mod_data->post_type_support
726 );
727 }
728
729 $this->$mod_name->module = $this->modules->$mod_name;
730 }
731 }
732
733 /**
734 * Get a module by one of its descriptive values
735 */
736 public function get_module_by($key, $value)
737 {
738 $module = false;
739 foreach ($this->modules as $mod_name => $mod_data) {
740 if ($key == 'name' && $value == $mod_name) {
741 $module = $this->modules->$mod_name;
742 } else {
743 foreach ($mod_data as $mod_data_key => $mod_data_value) {
744 if ($mod_data_key == $key && $mod_data_value == $value) {
745 $module = $this->modules->$mod_name;
746 }
747 }
748 }
749 }
750
751 return $module;
752 }
753
754 public function update_all_module_options($mod_name, $new_options)
755 {
756 if (is_array($new_options)) {
757 $new_options = (object)$new_options;
758 }
759
760 $this->modules->$mod_name->options = $new_options;
761 $this->$mod_name->module = $this->modules->$mod_name;
762
763 return update_option($this->options_group . $mod_name . '_options', $this->modules->$mod_name->options);
764 }
765
766 /**
767 * Registers commonly used scripts + styles for easy enqueueing
768 *
769 * @var string $hook
770 */
771 public function register_scripts_and_styles()
772 {
773 global $pagenow, $typenow;
774 $publishpress_pages = [
775 'pp-calendar',
776 'pp-content-overview',
777 'pp-content-board',
778 'pp-notif-log',
779 'pp-manage-roles',
780 'pp-modules-settings',
781 ];
782
783 $is_pp_page_param = isset($_GET['page']) && in_array(sanitize_key($_GET['page']), $publishpress_pages);
784 $is_pp_post_type_param = isset($_GET['post_type']) && sanitize_key($_GET['post_type']) === 'psppnotif_workflow';
785 $is_pp_edit_page_param = isset($_GET['post']) && (isset($pagenow) && $pagenow === 'post.php') && (isset($typenow) && $typenow === 'psppnotif_workflow');
786 $is_publishpress_page = $is_pp_page_param || $is_pp_post_type_param || $is_pp_edit_page_param;
787
788 wp_register_style(
789 'jquery-listfilterizer',
790 PUBLISHPRESS_URL . 'common/css/jquery.listfilterizer.css',
791 false,
792 PUBLISHPRESS_VERSION,
793 'all'
794 );
795
796 if ($is_publishpress_page) {
797 wp_enqueue_style(
798 'pressshack-admin-css',
799 PUBLISHPRESS_URL . 'common/css/pressshack-admin.css',
800 [],
801 PUBLISHPRESS_VERSION,
802 'all'
803 );
804
805 wp_enqueue_style(
806 'pp-admin-css',
807 PUBLISHPRESS_URL . 'common/css/publishpress-admin.css',
808 ['pressshack-admin-css'],
809 PUBLISHPRESS_VERSION,
810 'all'
811 );
812 }
813
814 wp_register_script(
815 'jquery-listfilterizer',
816 PUBLISHPRESS_URL . 'common/js/jquery.listfilterizer.js',
817 ['jquery'],
818 PUBLISHPRESS_VERSION,
819 true
820 );
821
822 wp_register_script(
823 'jquery-quicksearch',
824 PUBLISHPRESS_URL . 'common/js/jquery.quicksearch.js',
825 ['jquery'],
826 PUBLISHPRESS_VERSION,
827 true
828 );
829
830 // @compat 3.3
831 // Register jQuery datepicker plugin if it doesn't already exist. Datepicker plugin was added in WordPress 3.3
832 global $wp_scripts;
833 if (! isset($wp_scripts->registered['jquery-ui-datepicker'])) {
834 wp_register_script(
835 'jquery-ui-datepicker',
836 PUBLISHPRESS_URL . 'common/js/jquery.ui.datepicker.min.js',
837 ['jquery', 'jquery-ui-core'],
838 '1.8.16',
839 true
840 );
841 }
842
843
844 // Load on all admin pages to fix the menu, except the customize
845 global $pagenow;
846 }
847
848 public function filter_custom_menu_order($menu_ord)
849 {
850 global $submenu, $publishpress;
851
852 $parentMenuSlug = $publishpress->get_menu_slug();
853
854 if (isset($submenu[$parentMenuSlug])) {
855 $currentSubmenu = $submenu[$parentMenuSlug];
856 $newSubmenu = [];
857 $upgradeMenuSlugs = [];
858
859 $menuItemCalendar = 'pp-calendar';
860 $menuItemContentOverview = 'pp-content-overview';
861 $menuItemContentBoard = 'pp-content-board';
862 $menuItemNotifications = 'edit.php?post_type=psppnotif_workflow';
863 $menuItemNotificationsLog = 'pp-notif-log';
864 $menuItemRoles = 'pp-manage-roles';
865 $menuItemSettings = 'pp-modules-settings';
866
867 // Get the index for the menus.
868 $itemsToSort = [
869 $menuItemCalendar => null,
870 $menuItemContentOverview => null,
871 $menuItemContentBoard => null,
872 $menuItemNotifications => null,
873 $menuItemNotificationsLog => null,
874 $menuItemRoles => null,
875 $menuItemSettings => null,
876 ];
877
878 if (! defined('PUBLISHPRESS_SKIP_VERSION_NOTICES')) {
879 $suffix = Module::MENU_SLUG_SUFFIX;
880 $upgradeMenuSlugs = [
881 $menuItemCalendar . $suffix => null,
882 $menuItemContentOverview . $suffix => null,
883 $menuItemContentBoard . $suffix => null,
884 $menuItemNotifications . $suffix => null,
885 $menuItemNotificationsLog . $suffix => null,
886 $menuItemRoles . $suffix => null,
887 $menuItemSettings . $suffix => null,
888 ];
889
890 $itemsToSort = array_merge($itemsToSort, $upgradeMenuSlugs);
891 }
892
893 foreach ($currentSubmenu as $index => $item) {
894 if (array_key_exists($item[2], $itemsToSort)) {
895 $itemsToSort[$item[2]] = $index;
896 }
897 }
898
899 // Calendar
900 if (isset($itemsToSort[$menuItemCalendar]) && ! is_null($itemsToSort[$menuItemCalendar])) {
901 $newSubmenu[] = $currentSubmenu[$itemsToSort[$menuItemCalendar]];
902
903 unset($currentSubmenu[$itemsToSort[$menuItemCalendar]]);
904 }
905
906 // Content Overview
907 if (isset($itemsToSort[$menuItemContentOverview]) && ! is_null(
908 $itemsToSort[$menuItemContentOverview]
909 )) {
910 $newSubmenu[] = $currentSubmenu[$itemsToSort[$menuItemContentOverview]];
911
912 unset($currentSubmenu[$itemsToSort[$menuItemContentOverview]]);
913 }
914
915 // Content Board
916 if (isset($itemsToSort[$menuItemContentBoard]) && ! is_null(
917 $itemsToSort[$menuItemContentBoard]
918 )) {
919 $newSubmenu[] = $currentSubmenu[$itemsToSort[$menuItemContentBoard]];
920
921 unset($currentSubmenu[$itemsToSort[$menuItemContentBoard]]);
922 }
923
924 // Notifications
925 // Check if we have the menu as a main menu
926 if (isset($submenu[$menuItemNotifications])) {
927 $firstKey = array_keys($submenu[$menuItemNotifications])[0];
928 $newSubmenu[] = $submenu[$menuItemNotifications][$firstKey];
929
930 unset($submenu[$menuItemNotifications]);
931 remove_menu_page($menuItemNotifications);
932 } else {
933 if (isset($itemsToSort[$menuItemNotifications]) && ! is_null(
934 $itemsToSort[$menuItemNotifications]
935 )) {
936 $newSubmenu[] = $currentSubmenu[$itemsToSort[$menuItemNotifications]];
937
938 unset($currentSubmenu[$itemsToSort[$menuItemNotifications]]);
939 }
940 }
941
942 // Notification logs
943 if (isset($itemsToSort[$menuItemNotificationsLog]) && ! is_null(
944 $itemsToSort[$menuItemNotificationsLog]
945 )) {
946 $newSubmenu[] = $currentSubmenu[$itemsToSort[$menuItemNotificationsLog]];
947
948 unset($currentSubmenu[$itemsToSort[$menuItemNotificationsLog]]);
949 }
950
951 // Roles
952 if (isset($itemsToSort[$menuItemRoles]) && ! is_null($itemsToSort[$menuItemRoles])) {
953 $newSubmenu[] = $currentSubmenu[$itemsToSort[$menuItemRoles]];
954
955 unset($currentSubmenu[$itemsToSort[$menuItemRoles]]);
956 }
957
958 // Permissions - Role Capabilities
959 if (isset($itemsToSort['pp-manage-capabilities']) && ! is_null(
960 $itemsToSort['pp-manage-capabilities']
961 )) {
962 $newSubmenu[] = $currentSubmenu[$itemsToSort['pp-manage-capabilities']];
963
964 unset($itemsToSort[$itemsToSort['pp-manage-capabilities']]);
965 }
966
967 // Add the additional items
968 foreach ($currentSubmenu as $index => $item) {
969 if (! in_array($index, $itemsToSort)) {
970 $newSubmenu[] = $item;
971 unset($currentSubmenu[$index]);
972 }
973 }
974
975 // Settings
976 if (isset($itemsToSort[$menuItemSettings]) && ! is_null($itemsToSort[$menuItemSettings])) {
977 $newSubmenu[] = $currentSubmenu[$itemsToSort[$menuItemSettings]];
978
979 unset($currentSubmenu[$itemsToSort[$menuItemSettings]]);
980 }
981
982 // Upgrade to Pro
983 if (! defined('PUBLISHPRESS_SKIP_VERSION_NOTICES')) {
984 foreach ($upgradeMenuSlugs as $index => $item) {
985 if (! is_null($itemsToSort[$index])) {
986 $newSubmenu[] = $currentSubmenu[$itemsToSort[$index]];
987 }
988 }
989 }
990
991 $submenu[$parentMenuSlug] = $newSubmenu;
992 }
993
994 return $menu_ord;
995 }
996
997 /**
998 * @return bool
999 */
1000 public function hasMissedRequirements()
1001 {
1002 return $this->isBlockEditorActive() && ! $this->isClassicEditorInstalled();
1003 }
1004
1005 /**
1006 * Based on Edit Flow's \Block_Editor_Compatible::should_apply_compat method.
1007 *
1008 * @return bool
1009 */
1010 public function isBlockEditorActive()
1011 {
1012 // Check if Revisionary lower than v1.3 is installed. It disables Gutenberg.
1013 if (is_plugin_active('revisionary/revisionary.php')
1014 && defined('RVY_VERSION')
1015 && version_compare(RVY_VERSION, '1.3', '<')) {
1016 return false;
1017 }
1018
1019 $pluginsState = [
1020 'classic-editor' => is_plugin_active('classic-editor/classic-editor.php'),
1021 'gutenberg' => is_plugin_active('gutenberg/gutenberg.php'),
1022 'gutenberg-ramp' => is_plugin_active('gutenberg-ramp/gutenberg-ramp.php'),
1023 ];
1024
1025
1026 if (function_exists('get_post_type')) {
1027 $postType = get_post_type();
1028 }
1029
1030 if (! isset($postType) || empty($postType)) {
1031 $postType = 'post';
1032 }
1033
1034 /**
1035 * If show_in_rest is not true for the post type, the block editor is not available.
1036 */
1037 if (
1038 ($postTypeObject = get_post_type_object($postType))
1039 && empty($postTypeObject->show_in_rest)
1040 ) {
1041 return false;
1042 }
1043
1044 $conditions = [];
1045
1046 /**
1047 * 5.0:
1048 *
1049 * Classic editor either disabled or enabled (either via an option or with GET argument).
1050 * It's a hairy conditional :(
1051 */
1052 // phpcs:ignore WordPress.VIP.SuperGlobalInputUsage.AccessDetected, WordPress.Security.NonceVerification.NoNonceVerification
1053 $conditions[] = $this->isWp5()
1054 && ! $pluginsState['classic-editor']
1055 && ! $pluginsState['gutenberg-ramp']
1056 && apply_filters('use_block_editor_for_post_type', true, $postType, PHP_INT_MAX);
1057
1058 $conditions[] = $this->isWp5()
1059 && $pluginsState['classic-editor']
1060 && (get_option('classic-editor-replace') === 'block'
1061 && ! isset($_GET['classic-editor__forget']));
1062
1063 $conditions[] = $this->isWp5()
1064 && $pluginsState['classic-editor']
1065 && (get_option('classic-editor-replace') === 'classic'
1066 && isset($_GET['classic-editor__forget']));
1067
1068 /**
1069 * < 5.0 but Gutenberg plugin is active.
1070 */
1071 $conditions[] = ! $this->isWp5() && ($pluginsState['gutenberg'] || $pluginsState['gutenberg-ramp']);
1072
1073 // Returns true if at least one condition is true.
1074 return count(
1075 array_filter(
1076 $conditions,
1077 function ($c) {
1078 return (bool)$c;
1079 }
1080 )
1081 ) > 0;
1082 }
1083
1084 /**
1085 * Returns true if is a beta or stable version of WP 5.
1086 *
1087 * @return bool
1088 */
1089 public function isWp5()
1090 {
1091 global $wp_version;
1092
1093 return version_compare($wp_version, '5.0', '>=') || substr($wp_version, 0, 2) === '5.';
1094 }
1095
1096 /**
1097 * @return mixed
1098 */
1099 public function isClassicEditorInstalled()
1100 {
1101 return is_plugin_active('classic-editor/classic-editor.php');
1102 }
1103
1104 /**
1105 *
1106 */
1107 public function removeEditorMetaBox()
1108 {
1109 $isClassicEditor = isset($_GET['classic-editor']);
1110 $postType = $this->getCurrentPostType();
1111
1112 if ($this->isWp5() && $isClassicEditor && $this->postTypeRequiresClassicEditor($postType)) {
1113 remove_meta_box('classic-editor-switch-editor', null, 'side');
1114 }
1115 }
1116
1117 /**
1118 * @return string|null
1119 */
1120 public function getCurrentPostType()
1121 {
1122 global $post, $typenow, $current_screen, $pagenow;
1123
1124 if ($post && $post->post_type) {
1125 // We have a post so we can just get the post type from that.
1126 return $post->post_type;
1127 } elseif ($typenow) {
1128 // Check the global $typenow - set in admin.php.
1129 return $typenow;
1130 } elseif ($current_screen && $current_screen->post_type) {
1131 // Check the global $current_screen object - set in screen.php.
1132 return $current_screen->post_type;
1133 } elseif (isset($_REQUEST['post_type'])) {
1134 // Check the post_type querystring.
1135 return sanitize_key($_REQUEST['post_type']);
1136 } elseif (isset($_REQUEST['post'])) {
1137 // Lastly check if post ID is in query string.
1138 return get_post_type((int)$_REQUEST['post']);
1139 } elseif ($pagenow === 'edit.php') {
1140 // The edit page without post_type param is always "post".
1141 return 'post';
1142 }
1143
1144 // We do not know the post type!
1145 return null;
1146 }
1147
1148 /**
1149 * @param $postType
1150 *
1151 * @return bool
1152 */
1153 protected function postTypeRequiresClassicEditor($postType)
1154 {
1155 $specialPostTypes = $this->getPostTypesWhichRequiresClassicEditor();
1156
1157 return in_array($postType, $specialPostTypes);
1158 }
1159
1160 /**
1161 * @return array
1162 */
1163 protected function getPostTypesWhichRequiresClassicEditor()
1164 {
1165 global $publishpress;
1166
1167 $postTypes = [];
1168 $modules = [];
1169
1170 /**
1171 * @param array $modules
1172 */
1173 $modules = apply_filters('publishpress_modules_require_classic_editor', $modules);
1174
1175 if (! empty($modules)) {
1176 // Get the post types activated for each module.
1177 foreach ($modules as $module) {
1178 // Check if the plugin is active.
1179 if (! isset($publishpress->{$module}) || $publishpress->{$module}->module->options->enabled != 'on') {
1180 continue;
1181 }
1182
1183 $modulePostTypes = PublishPress\Legacy\Util::get_post_types_for_module(
1184 $publishpress->modules->{$module}
1185 );
1186
1187 $postTypes = array_merge($postTypes, $modulePostTypes);
1188 }
1189 }
1190
1191 return $postTypes;
1192 }
1193
1194 /**
1195 * Disable Gutenberg/Block Editor for post types.
1196 *
1197 * @param bool $useBlockEditor
1198 * @param string $postType
1199 *
1200 * @return bool
1201 */
1202 public function canUseBlockEditorForPostType($useBlockEditor, $postType)
1203 {
1204 // Short-circuit in case any other plugin disabled the block editor.
1205 if (! $useBlockEditor) {
1206 return false;
1207 }
1208
1209 return $this->postTypeRequiresClassicEditor($postType) ? false : $useBlockEditor;
1210 }
1211
1212 /**
1213 * @param array $capabilities
1214 *
1215 * @return array
1216 */
1217 public function filterCapabilities($pluginCaps)
1218 {
1219 $caps = [
1220 'pp_view_content_board',
1221 'pp_view_calendar',
1222 'pp_view_content_overview',
1223 'pp_set_notification_channel',
1224 'edit_post_subscriptions',
1225 'pp_edit_editorial_metadata',
1226 'pp_view_editorial_metadata',
1227 'pp_delete_editorial_comment',
1228 'pp_delete_others_editorial_comment',
1229 'pp_edit_editorial_comment',
1230 'pp_edit_others_editorial_comment',
1231 'delete_pp_notif_workflow',
1232 'edit_pp_notif_workflow',
1233 'read_pp_notif_workflow',
1234 ];
1235
1236 $pluginCaps['PublishPress Planner'] = $caps;
1237
1238 return $pluginCaps;
1239 }
1240
1241 /**
1242 * Returns the a single status object based on ID, title, or slug
1243 *
1244 * @param string|int $string_or_int The status to search for, either by slug, name or ID
1245 *
1246 * @return object|WP_Error|false $status The object for the matching status
1247 */
1248 public function getPostStatusBy($field, $value) {
1249 if (class_exists('PublishPress_Statuses')) {
1250 return \PublishPress_Statuses::getStatusBy($field, $value);
1251 }
1252
1253 if (! in_array($field, ['id', 'slug', 'name', 'label'])) {
1254 return false;
1255 }
1256
1257 if (in_array($field, ['id', 'slug'])) {
1258 $field = 'name';
1259 }
1260
1261 // New and auto-draft do not exists as status. So we map them to draft for now.
1262 if ('name' === $field && in_array($value, ['new', 'auto-draft'])) {
1263 $value = 'draft';
1264 }
1265
1266 $status = wp_filter_object_list($this->getCorePostStatuses(), [$field => $value]);
1267
1268 if (!empty($status)) {
1269 return array_shift($status);
1270 } else {
1271 if ($status = get_post_status_object($value)) {
1272 return $status;
1273 }
1274 }
1275
1276 return false;
1277 }
1278
1279 public function getPostStatuses()
1280 {
1281 if (class_exists('PublishPress_Statuses')) {
1282 return \PublishPress_Statuses::instance()->getPostStatuses([], 'object'); // note: static method is getPostStati()
1283 } else {
1284 return $this->getCorePostStatuses();
1285 }
1286 }
1287
1288 public function getCustomStatuses() {
1289 if (class_exists('PublishPress_Statuses')) {
1290 $customStatuses = \PublishPress_Statuses::getCustomStatuses(['for_revision' => false], 'object');
1291
1292 if (defined('PUBLISHPRESS_REVISIONS_VERSION') || defined('PUBLISHPRESS_REVISIONS_PRO_VERSION')) {
1293 $customStatuses = array_merge(
1294 $customStatuses,
1295 \PublishPress_Statuses::getCustomStatuses(['for_revision' => true], 'object')
1296 );
1297 }
1298
1299 return $customStatuses;
1300 } else {
1301 return [];
1302 }
1303 }
1304
1305 public function getCorePostStatuses() {
1306 return [
1307 (object)[
1308 'label' => __('Draft'),
1309 'description' => '',
1310 'name' => 'draft',
1311 'slug' => 'draft', // include slug property as a back compat fallback
1312 'position' => 1,
1313 ],
1314 (object)[
1315 'label' => __('Pending Review'),
1316 'description' => '',
1317 'name' => 'pending',
1318 'slug' => 'pending',
1319 'position' => 2,
1320 ],
1321 (object)[
1322 'label' => __('Published'),
1323 'description' => '',
1324 'name' => 'publish',
1325 'slug' => 'publish',
1326 'position' => 3,
1327 ],
1328 (object)[
1329 'label' => __('Scheduled'),
1330 'description' => '',
1331 'name' => 'future',
1332 'slug' => 'future',
1333 'position' => 4,
1334 ],
1335 ];
1336 }
1337
1338 /**
1339 * Redirect user on plugin activation
1340 *
1341 * @return void
1342 */
1343 public function redirect_on_activate()
1344 {
1345 if (get_option('pp_planner_activated')) {
1346 delete_option('pp_planner_activated');
1347 wp_safe_redirect(admin_url("admin.php?page=pp-calendar"));
1348 exit;
1349 }
1350 }
1351
1352 /**
1353 * Meta keys search ajax callback
1354 *
1355 * @return void
1356 */
1357 public function searchMetaKeys()
1358 {
1359 global $wpdb;
1360
1361 header('Content-type: application/json;');
1362
1363 if (empty($_GET['nonce']) || ! wp_verify_nonce(sanitize_text_field($_GET['nonce']), 'publishpress-content-get-data')) {
1364 wp_send_json([]);
1365 }
1366
1367 $queryText = isset($_GET['q']) ? sanitize_text_field($_GET['q']) : '';
1368
1369 // If queryText is not empty, add a WHERE clause to filter meta_key
1370 $whereClause = '';
1371 if (!empty($queryText)) {
1372 $like = '%' . $wpdb->esc_like($queryText) . '%';
1373 $whereClause = $wpdb->prepare("AND meta_key LIKE %s", $like);
1374 }
1375
1376 // Updated query with conditional search
1377 $queryResults = $wpdb->get_col("SELECT DISTINCT meta_key FROM $wpdb->postmeta WHERE 1=1 $whereClause ORDER BY meta_key ASC LIMIT 20");
1378
1379 $results = [];
1380 if (!empty($queryResults)) {
1381 foreach ($queryResults as $queryResult) {
1382 $results[] = [
1383 'id' => $queryResult,
1384 'text' => $queryResult,
1385 ];
1386 }
1387 }
1388
1389 wp_send_json($results);
1390 }
1391
1392
1393 }
1394 }
1395
1396 /**
1397 * Registered here so the Notifications submenu is displayed right after the
1398 * plugin is activate.
1399 *
1400 * @since 1.9.8
1401 */
1402 if (! function_exists('publishPressRegisterImprovedNotificationsPostTypes')) {
1403 function publishPressRegisterImprovedNotificationsPostTypes()
1404 {
1405 global $publishpress;
1406
1407 // Check if the notification module is enabled, before register the post type.
1408 $options = get_option('publishpress_improved_notifications_options', null);
1409
1410 if (! is_object($options)) {
1411 return;
1412 }
1413
1414 if (! isset($options->enabled) || $options->enabled !== 'on') {
1415 return;
1416 }
1417
1418 // Create the post type if not exists
1419 if (! post_type_exists(PUBLISHPRESS_NOTIF_POST_TYPE_WORKFLOW)) {
1420 // Notification Workflows
1421 register_post_type(
1422 PUBLISHPRESS_NOTIF_POST_TYPE_WORKFLOW,
1423 [
1424 'labels' => [
1425 'name' => __('Notifications', 'publishpress'),
1426 'singular_name' => __('Notification', 'publishpress'),
1427 'add_new_item' => __('Add New Notification', 'publishpress'),
1428 'edit_item' => __('Edit Notification', 'publishpress'),
1429 'search_items' => __('Search Notifications', 'publishpress'),
1430 'menu_name' => __('Notifications', 'publishpress'),
1431 'name_admin_bar' => __('Notification', 'publishpress'),
1432 'not_found' => __('No notification found', 'publishpress'),
1433 'not_found_in_trash' => __('No notification found', 'publishpress'),
1434 ],
1435 'public' => false,
1436 'publicly_queryable' => false,
1437 'has_archive' => false,
1438 'rewrite' => false,
1439 'show_ui' => true,
1440 'query_var' => true,
1441 'capability_type' => 'pp_notif_workflow',
1442 'hierarchical' => false,
1443 'can_export' => true,
1444 'show_in_admin_bar' => true,
1445 'exclude_from_search' => true,
1446 'show_in_menu' => $publishpress->get_menu_slug(),
1447 'menu_position' => '30',
1448 'supports' => [
1449 'title',
1450 ],
1451 ]
1452 );
1453 }
1454 }
1455 }
1456
1457
1458
1459 if (! function_exists('PublishPress')) {
1460 function PublishPress()
1461 {
1462 return publishpress::instance();
1463 }
1464 }
1465
1466 if (! defined('PUBLISHPRESS_HOOKS_REGISTERED')) {
1467 PublishPress();
1468 add_action('init', 'publishPressRegisterImprovedNotificationsPostTypes');
1469 // currently not working inside plugins_loaded
1470 // register_activation_hook(__FILE__, ['publishpress', 'activation_hook']);
1471 define('PUBLISHPRESS_HOOKS_REGISTERED', 1);
1472 } else {
1473 $message = __('PublishPress Planner tried to load multiple times. Please, deactivate and remove other instances of PublishPress, specially if you are using PublishPress Pro.', 'publishpress');
1474
1475 if (is_admin()) {
1476 add_action(
1477 'admin_notices',
1478 function () use ($message) {
1479 $msg = sprintf(
1480 '<strong>%s:</strong> %s',
1481 esc_html__('Warning', 'publishpress'),
1482 esc_html($message)
1483 );
1484
1485 echo "<div class='notice notice-error is-dismissible' style='color:black'><p>" . $msg . '</p></div>';
1486 },
1487 5
1488 );
1489 }
1490 }
1491 do_action('publishpress_planner_loaded');
1492 }, -10);
1493
1494 register_activation_hook(
1495 __FILE__,
1496 function () {
1497 global $wp_roles;
1498
1499 $genericCaps = [
1500 'pp_view_calendar',
1501 'pp_view_content_overview',
1502 'pp_view_content_board',
1503 'edit_post_subscriptions',
1504 'pp_set_notification_channel',
1505 'pp_delete_editorial_comment',
1506 'pp_delete_others_editorial_comment',
1507 'pp_edit_editorial_comment',
1508 'pp_edit_others_editorial_comment',
1509 ];
1510
1511 $roles = [
1512 'administrator' => $genericCaps,
1513 'editor' => $genericCaps,
1514 'author' => $genericCaps,
1515 'contributor' => $genericCaps,
1516 ];
1517
1518 foreach ($roles as $role => $caps) {
1519 if ($wp_roles->is_role($role)) {
1520 $role = get_role($role);
1521 foreach ($caps as $cap) {
1522 $role->add_cap($cap);
1523 }
1524 }
1525 }
1526
1527 // Additional capabilities
1528 $roles = [
1529 'administrator' => [apply_filters('pp_manage_roles_cap', 'pp_manage_roles')],
1530 ];
1531
1532 foreach ($roles as $role => $caps) {
1533 if ($wp_roles->is_role($role)) {
1534 $role = get_role($role);
1535 foreach ($caps as $cap) {
1536 $role->add_cap($cap);
1537 }
1538 }
1539 }
1540
1541 update_option('pp_planner_activated', true);
1542 }
1543 );