PluginProbe
Simple Client Dashboard / trunk
Simple Client Dashboard vtrunk
2.1.7.27 trunk 2.1.7.10 2.1.7.11 2.1.7.16 2.1.7.17 2.1.7.18 2.1.7.20 2.1.7.21 2.1.7.22 2.1.7.23 2.1.7.24 2.1.7.25 2.1.7.26 2.1.7.7 2.1.7.8
webmaster-user-role / webmaster-user-role.php

webmaster-user-role.php in Simple Client Dashboard trunk, at webmaster-user-role.php

739 lines 20.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /*
3 Plugin Name: Simple Client Dashboard - WP Limited Admin User Role
4 Plugin URI: https://nsquared.io/webmaster-user-role/
5 Description: Adds an "Admin" user role between Administrator and Editor. By default this user is the same as Administrator, without the capability to manage plugins or change themes
6 Version: 2.1.7.27
7 Author: N Squared
8 Author URI: https://nsquared.io
9 Author Email: team@nsquared.io
10 License:
11
12 Copyright 2012 N Squared
13
14 This program is free software; you can redistribute it and/or modify
15 it under the terms of the GNU General Public License, version 2, as
16 published by the Free Software Foundation.
17
18 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software
25 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
26
27 */
28
29
30 /**
31 * Autoloads files with classes when needed.
32 *
33 * @since 1.7.2
34 * @param string $class_name Name of the class being requested.
35 */
36 if ( ! function_exists( 'scd_autoload_classes' ) ) {
37 function scd_autoload_classes( $class_name ) {
38
39 // If our class doesn't have our prefix, don't load it.
40 if ( 0 !== strpos( $class_name, 'SCD_' ) ) {
41 return;
42 }
43
44 // Set up our filename.
45 $filename = strtolower( str_replace( '_', '-', substr( $class_name, strlen( 'SCD_' ) ) ) );
46
47 // Include our file.
48 Simple_Client_Dashboard::include_file( 'includes/class-' . $filename );
49 }
50 }
51
52 /**
53 * Autoloads files with classes when needed.
54 *
55 * @since 1.7.2
56 * @param string $class_name Name of the class being requested.
57 */
58 if ( ! function_exists( 'scd_autoload_modules' ) ) {
59 function scd_autoload_modules( $class_name ) {
60
61 // If our class doesn't have our prefix, don't load it.
62 if ( 0 !== strpos( $class_name, 'SCD_' ) ) {
63 return;
64 }
65
66 // Set up our filename.
67 $filename = strtolower( str_replace( '_', '-', substr( $class_name, strlen( 'SCD_' ) ) ) );
68
69 // Include our file.
70 Simple_Client_Dashboard::include_file( 'includes/module-' . $filename );
71 }
72 }
73
74 spl_autoload_register( 'scd_autoload_classes' );
75 spl_autoload_register( 'scd_autoload_modules' );
76
77
78 if ( ! class_exists( 'Simple_Client_Dashboard' ) ) {
79 final class Simple_Client_Dashboard {
80
81
82
83 /**
84 * Singleton instance of plugin.
85 *
86 * @var Simple_Client_Dashboard
87 * @since 1.7.2
88 */
89 protected static $single_instance = null;
90
91 /*
92 --------------------------------------------*
93 * Constants
94 *--------------------------------------------*/
95
96 const name = 'Simple Client Dashboard';
97
98 const slug = 'simple-client-dashboard';
99
100 const version = '1.7.27';
101
102 const file = __FILE__;
103
104 private $default_options = array(
105 'role_display_name' => 'Admin',
106 'cap_gravityforms_view_entries' => 1,
107 'cap_gravityforms_edit_forms' => 0,
108 );
109
110 protected $missing;
111 protected $validation;
112 protected $pro;
113 protected $updater;
114 protected $upgrade;
115 protected $settings;
116 protected $settings_installed;
117 protected $plugins_settings;
118 protected $themes_settings;
119 protected $unsupported_themes_settings;
120 protected $users_settings;
121 protected $admin_menu_tools_settings;
122 protected $wp_admin;
123 protected $bootstrap;
124 protected $encryption;
125 protected $settings_api;
126
127 /**
128 * Creates or returns an instance of this class.
129 *
130 * @since 0.0.0
131 * @return Simple_Client_Dashboard A single instance of this class.
132 */
133 public static function get_instance() {
134 if ( null === self::$single_instance ) {
135 self::$single_instance = new self();
136 }
137
138 return self::$single_instance;
139 }
140
141 // private $pro;
142
143 /*
144 --------------------------------------------*
145 * Constructor
146 *--------------------------------------------*/
147
148 /**
149 * Initializes the plugin by setting localization, filters, and administration functions.
150 * Private constructor to prevent instantiation from outside the class.
151 */
152 function __construct() {
153 }
154
155 /**
156 * Add hooks and filters.
157 *
158 * @since 0.0.0
159 */
160 public function hooks() {
161
162 $this->plugins_loaded();
163 $this->check_scd_version_update();
164 // Load JavaScript and stylesheets
165 add_action( 'admin_enqueue_scripts', array( $this, 'register_scripts_and_styles' ), 10 );
166 add_action( 'wpmu_new_blog', array( $this, 'add_role_to_blog' ) );
167 add_action( 'updated_' . self::slug . '_option', array( $this, 'updated_option' ), 10, 3 );
168 add_action( 'deleted_' . self::slug . '_option', array( $this, 'deleted_option' ) );
169 add_action( 'admin_menu', array( $this, 'admin_menu' ), 999 );
170 add_action( 'admin_init', array( $this, 'create_role_if_missing' ), 10 );
171 add_action( 'admin_init', array( $this, 'prevent_network_admin_access' ), 10 );
172 add_action( 'admin_init', array( $this, 'cleanup_dashboard_widgets' ), 20 );
173
174 add_action( 'rest_api_init', array( $this, 'rest_api_init' ), 0 );
175 }
176
177 /**
178 * Check for updates
179 *
180 * @since 1.7.2
181 */
182 public function check_scd_version_update() {
183 $site_version = get_site_option( 'td-webmaster-user-role-version' );
184 if ( $site_version != self::version ) {
185 update_site_option( 'td-webmaster-user-role-version', self::version );
186 $this->update_webmaster_caps();
187 }
188 }
189
190 /**
191 * Attach other plugin classes to the base plugin class.
192 *
193 * @since 1.7.2
194 */
195 public function plugin_classes() {
196 $classes = array(
197 'missing' => 'SCD_Missing',
198 'validation' => 'SCD_Validation',
199
200 'pro' => 'SCD_Pro',
201
202 'updater' => 'SCD_Updater',
203
204 'upgrade' => 'SCD_Upgrade',
205
206 'settings' => 'SCD_Settings',
207 'settings_installed' => 'SCD_Settings_Installed',
208
209 'plugins_settings' => 'SCD_Plugins_Settings',
210 'themes_settings' => 'SCD_Themes_Settings',
211 'unsupported_themes_settings' => 'SCD_Unsupported_Themes_Settings',
212 'users_settings' => 'SCD_Users_Settings',
213 'admin_menu_tools_settings' => 'SCD_Admin_Menu_Tools_Settings',
214
215 'wp_admin' => 'SCD_Wp_Admin',
216 'bootstrap' => 'SCD_Bootstrap',
217
218 'encryption' => 'SCD_Encryption',
219
220 // NO API CLASSES SHOULD BE HERE (should be defined in rest_api_init hook)
221 );
222
223 foreach ( $classes as $variable_name => $class_name ) {
224 if ( class_exists( $class_name ) ) {
225 $this->$variable_name = new $class_name( $this );
226 }
227 }
228 } // END OF PLUGIN CLASSES FUNCTION
229
230 /**
231 * Attach other plugin modules to the base plugin class.
232 *
233 * @since 1.7.2
234 */
235 public function plugin_modules() {
236 $classes = array(
237 /* Load Core Modules */
238 'plugins' => 'SCD_Plugins',
239 'themes' => 'SCD_Themes',
240 'users' => 'SCD_Users',
241 'tools' => 'SCD_Tools',
242
243 /* Load 3rd Party Modules */
244 'acf' => 'SCD_ACF',
245 'cf7' => 'SCD_Cf7',
246 'events_calendar' => 'SCD_Events_Calendar',
247 'gravity_forms' => 'SCD_Gravity_Forms',
248 'itsec' => 'SCD_Itsec',
249 'jetpack' => 'SCD_Jetpack',
250 'learndash' => 'SCD_LearnDash',
251 'redirection' => 'SCD_Redirection',
252 'sgcachepress' => 'SCD_SGCachePress',
253 'woocommerce' => 'SCD_WooCommerce',
254 'wpai' => 'SCD_WPAI',
255 'yoast' => 'SCD_Yoast',
256 'wordfence' => 'SCD_Wordfence',
257 'ninja_forms' => 'SCD_Ninja_Forms',
258 'simple_css' => 'SCD_SIMPLE_CSS',
259 'table_press' => 'SCD_TABLE_PRESS',
260 'businss_profile' => 'SCD_BUSINESS_PROFILE',
261 'draw_attention' => 'SCD_DRAW_ATTENTION',
262
263 );
264
265 foreach ( $classes as $variable_name => $class_name ) {
266 if ( class_exists( $class_name ) ) {
267 // $this->$variable_name = new $class_name( $this );
268 new $class_name( $this );
269 }
270 }
271 } // END OF PLUGIN CLASSES FUNCTION
272
273 /**
274 * Attach other plugin classes to the base plugin class.
275 *
276 * @since 0.0.2
277 */
278 public function rest_api_init() {
279 $classes = array(
280 'settings_api' => 'SCD_Settings_Api',
281 );
282
283 foreach ( $classes as $variable_name => $class_name ) {
284 if ( class_exists( $class_name ) ) {
285 $this->$variable_name = new $class_name( $this );
286 }
287 }
288 }
289
290 /**
291 * Magic getter for our object.
292 *
293 * @since 1.7.2
294 *
295 * @param string $field Field to get.
296 * @throws Exception Throws an exception if the field is invalid.
297 * @return mixed Value of the field.
298 */
299 public function __get( $field ) {
300 switch ( $field ) {
301 case 'version':
302 return self::version;
303 case 'name':
304 case 'file':
305 case 'slug':
306 case 'url':
307 case 'path':
308 case 'pro':
309 case 'settings':
310 case 'settings_api':
311 case 'settings_installed':
312 case 'plugins_settings':
313 case 'themes_settings':
314 case 'unsupported_themes_settings':
315 case 'users_settings':
316 case 'admin_menu_tools_settings':
317 case 'encryption':
318 case 'validation':
319 case 'wp_admin':
320 case 'bootstrap':
321 case 'missing':
322 if ( property_exists( $this, $field ) && ! is_null( $this->$field ) ) {
323 return $this->$field;
324 } else {
325 return $this->missing;
326 }
327 default:
328 return $this->missing;
329 }
330 }
331
332 /**
333 * Include a file from the includes directory.
334 *
335 * @since 1.7.2
336 *
337 * @param string $filename Name of the file to be included.
338 * @return boolean Result of include call.
339 */
340 public static function include_file( $filename ) {
341 $file = self::dir( $filename . '.php' );
342 if ( file_exists( $file ) ) {
343 return include_once $file;
344 }
345 return false;
346 }
347
348 /**
349 * This plugin's directory.
350 *
351 * @since 1.7.2
352 *
353 * @param string $path (optional) appended path.
354 * @return string Directory and path.
355 */
356 public static function dir( $path = '' ) {
357 static $dir;
358 $dir = $dir ? $dir : trailingslashit( __DIR__ );
359 return $dir . $path;
360 }
361
362 /**
363 * This plugin's url.
364 *
365 * @since 1.7.2
366 *
367 * @param string $path (optional) appended path.
368 * @return string URL and path.
369 */
370 public static function url( $path = '' ) {
371 static $url;
372 $url = $url ? $url : trailingslashit( plugin_dir_url( __FILE__ ) );
373 return $url . $path;
374 }
375
376 public function plugins_loaded() {
377
378 include __DIR__ . '/includes/class-exception.php';
379 include __DIR__ . '/includes/class-base-module.php';
380
381 // Initialize plugin classes.
382 $this->plugin_classes();
383
384 // Initialize plugin modules.
385 $this->plugin_modules();
386
387 load_plugin_textdomain( 'webmaster-user-role', false, dirname( plugin_basename( __FILE__ ) ) . '/lang/' );
388
389 do_action( 'scd_loaded' );
390 }
391
392 public function activate() {
393 }
394
395
396 public function deactivate() {
397 $this->remove_webmaster_role( is_multisite() );
398 }
399
400 public function remove_webmaster_role( $network_wide ) {
401 if ( $network_wide ) {
402 $blogs = $this->_blogs();
403 foreach ( $blogs as $blog_id ) {
404 switch_to_blog( $blog_id );
405 remove_role( 'webmaster' );
406 restore_current_blog();
407 }
408 } else {
409 remove_role( 'webmaster' );
410 }
411 }
412
413 public function add_webmaster_role( $network_wide ) {
414 if ( $network_wide ) {
415 $blogs = $this->_blogs();
416 foreach ( $blogs as $blog_id ) {
417 switch_to_blog( $blog_id );
418 $capabilities = $this->capabilities();
419 add_role( 'webmaster', $this->get_option( 'role_display_name' ), $capabilities );
420 restore_current_blog();
421 }
422 } else {
423 $capabilities = $this->capabilities();
424 add_role( 'webmaster', $this->get_option( 'role_display_name' ), $capabilities );
425 }
426 }
427
428 public function update_webmaster_caps() {
429 $is_multisite = is_multisite();
430 $this->remove_webmaster_role( $is_multisite );
431 $this->add_webmaster_role( $is_multisite );
432 }
433
434
435 /*
436 --------------------------------------------*
437 * Core Functions
438 *---------------------------------------------*/
439
440 public static function get_edition() {
441 if ( class_exists( 'SCD_Updater' ) ) {
442 return 'pro';
443 }
444 return 'basic';
445 }
446
447
448 public static function current_user_is_webmaster() {
449 if ( is_multisite() && is_super_admin() ) {
450 return false;
451 }
452 return current_user_can( 'webmaster' );
453 }
454
455 public static function get_config() {
456 global $webmaster_user_role_config;
457 if ( is_array( $webmaster_user_role_config ) ) {
458 return $webmaster_user_role_config;
459 }
460
461 $webmaster_user_role_config = scd()->settings->get();
462
463 return $webmaster_user_role_config;
464 }
465
466 function capabilities() {
467 $admin_role = get_role( 'administrator' );
468 $capabilities = $admin_role->capabilities;
469 unset( $capabilities['level_10'] );
470 unset( $capabilities['update_core'] );
471 unset( $capabilities['install_plugins'] );
472 unset( $capabilities['activate_plugins'] );
473 unset( $capabilities['update_plugins'] );
474 unset( $capabilities['edit_plugins'] );
475 unset( $capabilities['delete_plugins'] );
476 unset( $capabilities['install_themes'] );
477 unset( $capabilities['update_themes'] );
478 unset( $capabilities['switch_themes'] );
479 unset( $capabilities['edit_themes'] );
480 unset( $capabilities['delete_themes'] );
481 unset( $capabilities['list_users'] );
482 unset( $capabilities['create_users'] );
483 unset( $capabilities['add_users'] );
484 unset( $capabilities['edit_users'] );
485 unset( $capabilities['delete_users'] );
486 unset( $capabilities['remove_users'] );
487 unset( $capabilities['promote_users'] );
488
489 $capabilities['editor'] = 1; // Needed for 3rd party plugins that check explicitly for the "editor" role (looking at you NextGen Gallery)
490
491 if ( is_multisite() ) {
492 $capabilities['administrator'] = 1;
493 $capabilities['level_10'] = 1;
494 }
495
496 $webmaster_user_role_config = self::get_config();
497 if ( ! empty( $webmaster_user_role_config ) ) {
498 foreach ( $webmaster_user_role_config as $config_key => $config_value ) {
499 if ( strpos( $config_key, 'webmaster_cap' ) !== false && is_array( $config_value ) ) {
500 $capabilities = wp_parse_args( $config_value, $capabilities );
501 }
502 }
503 }
504
505 $capabilities = apply_filters( 'td_webmaster_capabilities', $capabilities );
506 return $capabilities;
507 }
508
509 function create_role_if_missing() {
510 $wp_roles = new WP_Roles();
511 if ( $wp_roles->is_role( 'webmaster' ) ) {
512 return;
513 }
514
515 $this->update_webmaster_caps();
516 }
517
518 function prevent_network_admin_access() {
519 if ( is_network_admin() && ! is_super_admin( get_current_user_id() ) ) {
520 wp_redirect( admin_url() );
521 exit();
522 }
523 }
524
525 function cleanup_dashboard_widgets() {
526 if ( $this->current_user_is_webmaster() ) {
527 // remove_meta_box( 'dashboard_recent_comments', 'dashboard', 'normal' );
528 remove_meta_box( 'dashboard_incoming_links', 'dashboard', 'normal' );
529 remove_meta_box( 'dashboard_quick_press', 'dashboard', 'side' );
530 remove_meta_box( 'dashboard_primary', 'dashboard', 'side' );
531 remove_meta_box( 'dashboard_secondary', 'dashboard', 'side' );
532 remove_meta_box( 'dashboard_recent_drafts', 'dashboard', 'side' );
533 }
534 }
535
536 function admin_menu() {
537 if ( $this->current_user_is_webmaster() ) {
538 $webmaster_user_role_config = self::get_config();
539 remove_menu_page( 'branding' );
540 if ( is_object( $webmaster_user_role_config ) && empty( $webmaster_user_role_config->sections ) ) {
541 return;
542 }
543
544 if ( empty( $webmaster_user_role_config['webmaster_admin_menu_tools_settings']['options-general.php'] ) ) {
545 remove_menu_page( 'options-general.php' );
546 }
547 if ( empty( $webmaster_user_role_config['webmaster_admin_menu_sucuri']['sucuriscan'] ) ) {
548 remove_menu_page( 'sucuriscan' );
549 }
550 if ( empty( $webmaster_user_role_config['webmaster_admin_menu_tools_settings']['tools.php'] ) ) {
551 remove_menu_page( 'tools.php' );
552 }
553 }
554 }
555
556 function add_role_to_blog( $blog_id ) {
557 switch_to_blog( $blog_id );
558 $capabilities = $this->capabilities();
559 add_role( 'webmaster', 'Admin', $capabilities );
560 restore_current_blog();
561 }
562
563 function updated_option( $option, $oldvalue, $newValue ) {
564 if ( $option == 'role_display_name' || strpos( 'cap_', $option ) !== false ) {
565 $this->update_webmaster_caps();
566 }
567 }
568
569 function deleted_option( $option ) {
570 if ( $option == 'role_display_name' || strpos( 'cap_', $option ) !== false ) {
571 $this->update_webmaster_caps();
572 }
573 }
574
575 function get_option( $option ) {
576 // Allow plugins to short-circuit options.
577 $pre = apply_filters( 'pre_' . self::slug . '_option_' . $option, false );
578 if ( false !== $pre ) {
579 return $pre;
580 }
581
582 $option = trim( $option );
583 if ( empty( $option ) ) {
584 return false;
585 }
586
587 $saved_options = get_option( self::slug . '_options' );
588
589 if ( isset( $saved_options[ $option ] ) ) {
590 $value = $saved_options[ $option ];
591 } else {
592 $saved_options = ( empty( $saved_options ) ) ? array() : $saved_options;
593 $saved_options = array_merge( $this->default_options, $saved_options );
594 $value = $saved_options[ $option ];
595 }
596
597 return apply_filters( self::slug . 'option_' . $option, $value );
598 }
599
600 function update_option( $option, $newValue ) {
601 $option = trim( $option );
602 if ( empty( $option ) ) {
603 return false;
604 }
605
606 if ( is_object( $newvalue ) ) {
607 $newvalue = clone $newvalue;
608 }
609
610 $oldvalue = $this->get_option( $option );
611 $newvalue = apply_filters( 'pre_update_' . self::slug . '_option_' . $option, $newvalue, $oldvalue );
612
613 // If the new and old values are the same, no need to update.
614 if ( $newvalue === $oldvalue ) {
615 return false;
616 }
617
618 $_newvalue = $newvalue;
619 $newvalue = maybe_serialize( $newvalue );
620
621 do_action( 'update_' . self::slug . '_option', $option, $oldvalue, $_newvalue );
622
623 $options = get_option( self::slug . '_options' );
624 if ( empty( $options ) ) {
625 $options = array( $option => $newValue );
626 } else {
627 $options[ $option ] = $newValue;
628 }
629 update_option( self::slug . '_options', $options );
630
631 do_action( 'update_' . self::slug . "_option_{$option}", $oldvalue, $_newvalue );
632 do_action( 'updated_' . self::slug . '_option', $option, $oldvalue, $_newvalue );
633
634 return true;
635 }
636
637 function delete_option( $option ) {
638 do_action( 'delete_' . self::slug . '_option', $option );
639 $options = get_option( self::slug . '_options' );
640 if ( ! isset( $options[ $option ] ) ) {
641 return false;
642 }
643 unset( $options[ $option ] );
644
645 $result = update_option( self::slug . '_options', $options );
646
647 if ( $result ) {
648 do_action( 'delete_' . self::slug . "_option_$option", $option );
649 do_action( 'deleted_' . self::slug . '_option', $option );
650 return true;
651 }
652 return false;
653 }
654
655
656
657 /*
658 --------------------------------------------*
659 * Private Functions
660 *---------------------------------------------*/
661
662 function _blogs() {
663 global $wpdb;
664 $blogs = $wpdb->get_col(
665 $wpdb->prepare(
666 "
667 SELECT blog_id
668 FROM {$wpdb->blogs}
669 WHERE site_id = %d
670 AND spam = '0'
671 AND deleted = '0'
672 AND archived = '0'
673 ORDER BY registered DESC
674 ",
675 $wpdb->siteid
676 )
677 );
678
679 return $blogs;
680 }
681
682 /**
683 * Registers and enqueues stylesheets for the administration panel and the
684 * public facing site.
685 */
686 public function register_scripts_and_styles() {
687 if ( is_admin() ) {
688 // $this->load_file( self::slug . '-admin-script', '/js/admin.js', true );
689 $this->load_file( self::slug . '-admin-style', '/css/admin.css' );
690 } else {
691 // $this->load_file( self::slug . '-script', '/js/widget.js', true );
692 // $this->load_file( self::slug . '-style', '/css/widget.css' );
693 } // end if/else
694 } // end register_scripts_and_styles
695
696 /**
697 * Helper function for registering and enqueueing scripts and styles.
698 *
699 * @name The ID to register with WordPress
700 * @file_path The path to the actual file
701 * @is_script Optional argument for if the incoming file_path is a JavaScript source file.
702 */
703 private function load_file( $name, $file_path, $is_script = false ) {
704
705 $url = plugins_url( $file_path, __FILE__ );
706 $file = plugin_dir_path( __FILE__ ) . $file_path;
707
708 if ( file_exists( $file ) ) {
709 if ( $is_script ) {
710 wp_register_script( $name, $url, array( 'jquery' ) );
711 wp_enqueue_script( $name );
712 } else {
713 wp_register_style( $name, $url );
714 wp_enqueue_style( $name );
715 } // end if
716 } // end if
717 } // end load_file
718 } // end class
719 } // end class_exists()
720
721
722 /**
723 * Grab the Simple_Client_Dashboard object and return it.
724 * Wrapper for Simple_Client_Dashboard::get_instance().
725 *
726 * @since 1.7.2
727 * @return Simple_Client_Dashboard Singleton instance of plugin class.
728 */
729 function scd() {
730 return Simple_Client_Dashboard::get_instance();
731 }
732
733 // Kick it off.
734 add_action( 'plugins_loaded', array( scd(), 'hooks' ), 0 );
735
736 // Activation and deactivation.
737 register_activation_hook( __FILE__, array( scd(), 'activate' ) );
738 register_deactivation_hook( __FILE__, array( scd(), 'deactivate' ) );
739