PluginProbe
Advanced Access Manager – Access Governance for WordPress / 6.9.26
Advanced Access Manager – Access Governance for WordPress v6.9.26
7.1.4 7.1.2 7.1.3 6.8.4 6.8.5 6.9.0 6.9.1 6.9.10 6.9.11 6.9.12 6.9.13 6.9.14 6.9.15 6.9.16 6.9.17 6.9.18 6.9.19 6.9.2 6.9.20 6.9.21 6.9.22 6.9.23 6.9.24 6.9.25 6.9.26 All 210 releases
advanced-access-manager / application / Service / Multisite.php
Multisite.php
299 lines 8.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * ======================================================================
5 * LICENSE: This file is subject to the terms and conditions defined in *
6 * file 'license.txt', which is part of this source code package. *
7 * ======================================================================
8 */
9
10 /**
11 * Multisite service
12 *
13 * @since 6.9.18 https://github.com/aamplugin/advanced-access-manager/issues/328
14 * @since 6.7.5 https://github.com/aamplugin/advanced-access-manager/issues/170
15 * @since 6.4.2 https://github.com/aamplugin/advanced-access-manager/issues/81
16 * @since 6.3.0 Rewrote the way options are synced across the network
17 * @since 6.2.2 Fixed the bug where reset settings was not synced across all sites
18 * @since 6.2.0 Initial implementation of the class
19 *
20 * @package AAM
21 * @version 6.9.18
22 */
23 class AAM_Service_Multisite
24 {
25 use AAM_Core_Contract_RequestTrait,
26 AAM_Core_Contract_ServiceTrait;
27
28 /**
29 * AAM configuration setting that is associated with the feature
30 *
31 * @version 6.2.0
32 */
33 const FEATURE_FLAG = 'core.service.multisite.enabled';
34
35 /**
36 * Syncing flag
37 *
38 * Preventing from any unexpected loops
39 *
40 * @var boolean
41 *
42 * @access protected
43 * @version 6.3.0
44 */
45 protected $syncing = false;
46
47 /**
48 * Constructor
49 *
50 * @return void
51 *
52 * @access protected
53 * @version 6.2.0
54 */
55 protected function __construct()
56 {
57 if (is_admin()) {
58 // Hook that returns the detailed information about the nature of the
59 // service. This is used to display information about service on the
60 // Settings->Services tab
61 add_filter('aam_service_list_filter', function ($services) {
62 $services[] = array(
63 'title' => __('Multisite Settings Sync', AAM_KEY),
64 'description' => __('Automatically synchronize changes to the list of roles and capabilities as well as all access settings (if configured accordingly).', AAM_KEY),
65 'setting' => self::FEATURE_FLAG
66 );
67
68 return $services;
69 }, 20);
70 }
71
72 if (AAM_Core_Config::get(self::FEATURE_FLAG, true) && is_multisite()) {
73 $this->initializeHooks();
74 }
75 }
76
77 /**
78 * Initialize multisite sync hooks
79 *
80 * @return void
81 *
82 * @since 6.7.5 https://github.com/aamplugin/advanced-access-manager/issues/170
83 * @since 6.4.2 Fixed https://github.com/aamplugin/advanced-access-manager/issues/81
84 * @since 6.3.0 Optimized for Multisite setup
85 * @since 6.2.2 Hooks to the setting clearing and policy table list
86 * @since 6.2.0 Initial implementation of the method
87 *
88 * @access protected
89 * @version 6.7.5
90 */
91 protected function initializeHooks()
92 {
93 $roles = AAM_Framework_Manager::roles();
94
95 if (is_main_site()) {
96 // Any changes to the user_roles option should be replicated
97 add_action('update_option_' . $roles->role_key, function($old, $value) {
98 $this->syncUpdatedOption('%suser_roles', $value);
99 }, 10, 2);
100
101 add_action('update_option', function($option, $old, $value) {
102 if ($this->syncing === false) {
103 $this->syncing = true;
104 $list = array(
105 AAM_Core_Config::DB_OPTION,
106 AAM_Core_ConfigPress::DB_OPTION,
107 AAM_Core_AccessSettings::DB_OPTION
108 );
109
110 if (in_array($option, $list, true)) {
111 $this->syncUpdatedOption($option, $value);
112 }
113 $this->syncing = false;
114 }
115 }, 10, 3);
116
117 add_action('aam_top_right_column_action', function() {
118 echo AAM_Backend_View::loadPartial('multisite-sync-notification');
119 });
120
121 add_action('add_option', function($option, $value) {
122 if ($this->syncing === false) {
123 $this->syncing = true;
124 $list = array(
125 AAM_Core_Config::DB_OPTION,
126 AAM_Core_ConfigPress::DB_OPTION,
127 AAM_Core_AccessSettings::DB_OPTION
128 );
129
130 if (in_array($option, $list, true)) {
131 $this->syncUpdatedOption($option, $value);
132 }
133 $this->syncing = false;
134 }
135 }, 10, 2);
136
137 add_action('aam_clear_settings_action', function($options) {
138 foreach($options as $option) {
139 $this->syncDeletedOption($option);
140 }
141 }, PHP_INT_MAX);
142 }
143
144 add_filter('wp_insert_post_data', function($data) {
145 if (
146 isset($data['post_type'])
147 && ($data['post_type'] === AAM_Service_AccessPolicy::POLICY_CPT)
148 ) {
149 switch_to_blog(AAM_Core_API::getMainSiteId());
150 }
151
152 return $data;
153 });
154
155 add_action('aam_pre_policy_fetch_action', function() {
156 switch_to_blog(AAM_Core_API::getMainSiteId());
157 });
158
159 add_action('aam_post_policy_fetch_action', function() {
160 restore_current_blog();
161 });
162
163 add_action('wp', function() {
164 if (apply_filters('aam_allowed_site_filter', true) === false) {
165 wp_die('Access Denied', 'aam_access_denied');
166 }
167 }, 999);
168 }
169
170 /**
171 * Sync option across all sites
172 *
173 * @param string $option
174 * @param mixed $value
175 *
176 * @return void
177 *
178 * @since 6.2.2 Refactored how the list of sites is fetched
179 * @since 6.2.0 Initial implementation of the method
180 *
181 * @global WPDB $wpdb
182 *
183 * @access protected
184 *
185 * @since 6.9.18 https://github.com/aamplugin/advanced-access-manager/issues/328
186 * @since 6.2.2 Initial implementation of the method
187 *
188 * @version 6.9.18
189 */
190 protected function syncUpdatedOption($option, $value)
191 {
192 global $wpdb;
193
194 foreach($this->getSitList() as $site) {
195 if ($this->isSyncDisabled($site->blog_id) !== true) {
196 AAM_Core_API::updateOption(
197 str_replace('%s', $wpdb->get_blog_prefix($site->blog_id), $option),
198 $value,
199 true,
200 $site->blog_id
201 );
202 }
203 }
204 }
205
206 /**
207 * Sync deleted option across all sites
208 *
209 * @param string $option
210 *
211 * @return void
212 *
213 * @access protected
214 * @global WPDB $wpdb
215 * @version 6.3.0
216 */
217 protected function syncDeletedOption($option)
218 {
219 global $wpdb;
220
221 foreach($this->getSitList() as $site) {
222 if ($this->isSyncDisabled($site->blog_id) !== true) {
223 AAM_Core_API::deleteOption(
224 str_replace('%s', $wpdb->get_blog_prefix($site->blog_id), $option),
225 $site->blog_id
226 );
227 }
228 }
229 }
230
231 /**
232 * Get list of sites
233 *
234 * @return array
235 *
236 * @access protected
237 * @version 6.2.2
238 */
239 protected function getSitList()
240 {
241 return get_sites(array(
242 'number' => PHP_INT_MAX,
243 'offset' => 0,
244 'orderby' => 'id',
245 'site__not_in' => array_merge(
246 $this->getExcludedBlogs(), array(get_current_blog_id())
247 )
248 ));
249 }
250
251 /**
252 * Get the list of excluded blogs from sync process
253 *
254 * @return array
255 *
256 * @access protected
257 * @version 6.2.0
258 */
259 protected function getExcludedBlogs()
260 {
261 $excluded = array();
262 $config = AAM::api()->getConfig('multisite.sync.exclude.blogs', array());
263
264 if (is_string($config)) {
265 $excluded = explode(',', $config);
266 } elseif (is_array($config)) {
267 $excluded = array_filter($config, function($site) {
268 return is_numeric($site);
269 });
270 }
271
272 return $excluded;
273 }
274
275 /**
276 * Check if blog has sync service disabled
277 *
278 * @param int $blog_id
279 *
280 * @return boolean
281 *
282 * @access protected
283 * @version 6.3.0
284 */
285 protected function isSyncDisabled($blog_id)
286 {
287 $config = AAM_Core_API::getOption(
288 AAM_Core_Config::DB_OPTION, array(), $blog_id
289 );
290
291 return isset($config[self::FEATURE_FLAG])
292 && ($config[self::FEATURE_FLAG] === false);
293 }
294
295 }
296
297 if (defined('AAM_KEY')) {
298 AAM_Service_Multisite::bootstrap();
299 }