PluginProbe
Plugin Load Filter / 2.3.1
Plugin Load Filter v2.3.1
trunk 2.0.0 2.0.1 2.1.0 2.2.0 2.2.1 2.3.0 2.3.1 2.4.0 2.4.1 2.5.1 3.3.0 4.0.6 4.1.1 4.2.0 4.3.0 4.3.1 4.4.0
← All changes | mu-plugins/plf-filter.php +215 -1176 4.1.1 → 2.3.1 View file →
@@ -1,42 +1,19 @@
1 1 <?php
2 2 /*
3 3 Plugin Name: plugin load filter [plf-filter]
4 4 Description: Dynamically activated only plugins that you have selected in each page. [Note] plf-filter has been automatically installed / deleted by Activate / Deactivate of "load filter plugin".
5 - Version: 4.1.1
6 - Plugin URI: http://celtislab.net/en/wp-plugin-load-filter
5 + Version: 2.3.1
6 + Plugin URI: http://celtislab.net/wp_plugin_load_filter
7 7 Author: enomoto@celtislab
8 8 Author URI: http://celtislab.net/
9 9 License: GPLv2
10 10 */
11 -defined( 'ABSPATH' ) || exit;
12 11
13 12 /***************************************************************************
14 13 * pluggable.php defined function overwrite
15 14 * pluggable.php read before the query_posts () is processed by the current user undetermined
16 15 **************************************************************************/
17 -/**
18 - * Gets hash of given string.
19 - *
20 - * @param string $data Plain text to hash.
21 - * @return string Hash of $data.
22 - */
23 - //wp_salt( $scheme ) を簡略化して logged_in cookie 限定
24 -function plf_logged_in_hash( $data ) {
25 - $values = array(
26 - 'key' => '',
27 - 'salt' => '',
28 - );
29 - foreach ( array( 'key', 'salt' ) as $type ) {
30 - $const = strtoupper( "logged_in_{$type}" );
31 - if ( defined( $const ) && constant( $const ) ) {
32 - $values[ $type ] = constant( $const );
33 - }
34 - }
35 - $salt = $values['key'] . $values['salt'];
36 - return hash_hmac( 'md5', $data, $salt );
37 -}
38 -
39 16 if ( !function_exists('wp_get_current_user') ) :
40 17 /**
41 18 * Retrieve the current user object.
42 19 * @return WP_User Current user WP_User object
@@ -41,40 +18,17 @@
41 18 * Retrieve the current user object.
42 19 * @return WP_User Current user WP_User object
43 20 */
44 21 function wp_get_current_user() {
45 - if ( ! function_exists( 'wp_set_current_user' ) ){
46 - if ( defined( 'LOGGED_IN_COOKIE' ) && !empty( $_COOKIE[ LOGGED_IN_COOKIE ] ) ) {
47 - $cookie_elements = explode( '|', $_COOKIE[ LOGGED_IN_COOKIE ] );
48 - if ( count( $cookie_elements ) === 4 ) {
49 - list( $username, $expiration, $token, $hmac ) = $cookie_elements;
50 - if ( $expiration > time() ) {
51 - $user = get_user_by( 'login', $username );
52 - if ( $user ) {
53 - $pass_frag = substr( $user->user_pass, 8, 4 );
54 -
55 - $key = plf_logged_in_hash( $username . '|' . $pass_frag . '|' . $expiration . '|' . $token );
56 -
57 - // If ext/hash is not present, compat.php's hash_hmac() does not support sha256.
58 - $algo = function_exists( 'hash' ) ? 'sha256' : 'sha1';
59 - $hash = hash_hmac( $algo, $username . '|' . $expiration . '|' . $token, $key );
60 -
61 - if ( hash_equals( $hash, $hmac ) ) {
62 - $manager = WP_Session_Tokens::get_instance( $user->ID );
63 - if ( $manager->verify( $token ) ) {
64 - return $user;
65 - }
66 - }
67 - }
68 - }
69 - }
70 - }
71 - //ver4.0.17 fixed https://wordpress.org/support/topic/wp_get_current_user-is-overridden/
72 - //return 0;
73 - $user = new WP_User( 0 );
74 - return $user;
75 -
76 - } else {
22 + if ( ! function_exists( 'wp_set_current_user' ) )
23 + return 0;
24 + //get_currentuserinfo is deprecated since version 4.5
25 + if ( version_compare( $GLOBALS['wp_version'], '4.5', '<' ) ){
26 + global $current_user;
27 + get_currentuserinfo();
28 + return $current_user;
29 + }
30 + else {
77 31 return _wp_get_current_user();
78 32 }
79 33 }
80 34 endif;
@@ -128,453 +82,113 @@
128 82 }
129 83 endif;
130 84
131 85 /***************************************************************************
132 - * Plugin Load Filter
86 + * Plugin Load Filter( Admin, Desktop, Mobile, Page 4types filter)
133 87 **************************************************************************/
134 88
135 -if(in_array( 'plugin-load-filter/plugin-load-filter.php', (array) get_option( 'active_plugins', array() ) )){
136 - $plugin_load_filter = new Plf_filter();
137 -} elseif ( is_multisite() ) {
138 - $plugins = get_site_option( 'active_sitewide_plugins');
139 - if ( isset($plugins['plugin-load-filter/plugin-load-filter.php']) ){
140 - $plugin_load_filter = new Plf_filter();
141 - }
142 -}
89 +$plugin_load_filter = new Plf_filter();
143 90
144 -class Plf_filter {
145 - static private $filter; //Plugin Load Filter Setting option data
146 - static private $rlocale;
147 - static private $url_filter;
148 - static private $s_url_filter;
149 - static private $is_filterkey;
150 - static private $iniget_active_plugins;
151 - static private $iniget_active_sitewide_plugins;
152 - static private $base_plugins;
153 - static private $filtered_plugins;
154 - static private $cache;
155 - static private $url2id;
156 - static private $pre_post_id;
157 - static private $base_public_query_vars;
91 +class Plf_filter {
92 +
93 + private $filter = array(); //Plugin Load Filter Setting option data
94 + private $cache;
158 95
159 96 function __construct() {
160 - self::$rlocale = null;
161 - self::$cache = array();
162 - self::$url2id = array();
163 - self::$pre_post_id = 0;
164 - self::$base_public_query_vars = array();
165 - self::$url_filter = array();
166 - self::$s_url_filter = array();
167 - self::$is_filterkey = false;
168 - self::$iniget_active_plugins = array();
169 - self::$iniget_active_sitewide_plugins = array();
170 - self::$base_plugins = array();
171 - self::$filtered_plugins = array();
172 - self::$filter = get_option('plf_option', array());
173 - if(!empty(self::$filter)){
174 - //Addon option get
175 - self::$iniget_active_plugins = $plugins = get_option( 'active_plugins', array() );
176 - if ( is_multisite() ) {
177 - self::$iniget_active_sitewide_plugins = (array) get_site_option( 'active_sitewide_plugins', array() );
178 - $plugins = array_merge( $plugins, array_keys( self::$iniget_active_sitewide_plugins ) );
179 - }
180 - if(!empty($plugins) && in_array( 'plugin-load-filter-addon/plugin-load-filter-addon.php', $plugins)){
181 - self::$url_filter = get_option('plf_addon_options', array());
182 - }
183 -
184 - //active_plugins filter
185 - if ( is_multisite() ) {
186 - add_filter('pre_site_option_active_sitewide_plugins', array('Plf_filter', 'active_sitewide_plugins'));
187 - add_action('update_site_option_active_sitewide_plugins', array($this, 'update_active_sitewide_plugins'), 99999, 4);
188 - }
189 - add_filter('pre_option_active_plugins', array('Plf_filter', 'active_plugins'));
190 - add_filter('pre_option_jetpack_active_modules', array('Plf_filter', 'active_jetmodules'));
191 - add_filter('pre_option_celtispack_active_modules', array('Plf_filter', 'active_celtismodules'));
192 -
193 - add_action('update_option_active_plugins', array($this, 'update_active_plugins'), 99999, 3);
194 - add_action('update_option_jetpack_active_modules', array($this, 'update_active_jetmodules'), 99999, 3);
195 - add_action('update_option_celtispack_active_modules', array($this, 'update_active_celtismodules'), 99999, 3);
196 - add_action('switch_theme', array($this, 'switch_theme'));
197 -
198 - add_action('plugins_loaded', array($this, 'plugins_loaded'));
199 - add_action('admin_init', array($this, 'cache_post_type'));
200 - //admin-bar filtered status
201 - if(!empty(self::$filter['admin_bar'])){
202 - add_action('admin_bar_menu', array($this,'custom_bar_menus'), 201);
203 - }
204 - //language locale filter
205 - if(!empty(self::$filter['language'])){
206 - add_filter( 'locale', array('Plf_filter', 'post_locale') );
207 - add_filter( 'determine_locale', array('Plf_filter', 'post_determine_locale') );
208 - }
209 - }
210 - }
211 -
212 - //Notice: scriptを使うと AMP でエラーとなるので target でオープン/クローズを行う
213 - static function plf_filtered_result_dialog( $text ) {
214 - ?>
215 - <style>
216 - #wpadminbar #wp-admin-bar-plf-statlink .ab-icon:before { content: '\f106'; top: 2px;}
217 - #plf-status { display:none;}
218 - #plf-status:target { display:block;}
219 - #plf-status .dialog-overlay{ position:fixed; left:0px; top:0px; width:100%; height:100%; background-color:rgba(0,0,0,.5); z-index:999999999;}
220 - #plf-status div.dialog { position:fixed; top:50%; left:50%; transform:translate(-50%, -50%); width:66%; max-width:420px; height:auto; padding:1.5em; color:#222; background:#fff; z-index:999999999;}
221 - #plf-status .dialog-title { margin: 0 0 1em; font-size: 16px;}
222 - #plf-status textarea { font-size: 13px;}
223 - #plf-status .button-group { display:block; margin-top:2em; text-align:right; font-size:1em;}
224 - #plf-status a.button { display:inline-block; text-decoration:none; margin: 0 0 0 1em; padding: .5em 1em; color: #0071a1; background: #f5f5f5; border:solid 1px #0071a1; border-radius:3px; cursor:pointer;}
225 - #plf-status a.button:hover { background: #e8ffff; border-color: #016087; color: #016087;}
226 - </style>
227 - <div id="plf-status">
228 - <div class="dialog-overlay"></div>
229 - <div class="dialog">
230 - <p class="dialog-title"><strong><?php echo 'Plugin Load Filter status'; ?></strong></p>
231 - <div><textarea id="plf-filtered-result" style="width:100%; height:320px; margin:5px 0;"><?php echo $text; ?></textarea></div>
232 - <div class="button-group">
233 - <a href="#" id="plf-status-close" class="button" aria-label="Close modal">Close</a>
234 - </div>
235 - </div>
236 - </div>
237 - <?php
238 - }
239 -
240 - //filtered plugins list print
241 - static function result_plugin_print( $e_plugins, $d_plugins ) {
242 - $text = PHP_EOL . "[Activate Plugins]" . PHP_EOL;
243 - $idx = 1;
244 - foreach ($e_plugins as $key) {
245 - if(!empty($key)){
246 - $key = preg_replace('|/.+?\.php|', '', $key);
247 - $text .= "$idx. $key" . PHP_EOL;
248 - $idx++;
249 - }
250 - }
251 - $text .= PHP_EOL . "[Deactivate Plugins]" . PHP_EOL;
252 - $idx = 1;
253 - foreach ($d_plugins as $key) {
254 - if(!empty($key)){
255 - $key = preg_replace('|/.+?\.php|', '', $key);
256 - $text .= "$idx. $key" . PHP_EOL;
257 - $idx++;
258 - }
259 - }
260 - return $text;
261 - }
262 -
263 - public function custom_bar_menus($wp_admin_bar) {
264 - if (current_user_can( 'activate_plugins' )) {
265 - $base_plugins = self::get_base_plugins();
266 - if(!empty($base_plugins)){
267 - $text = '==== Plugin Load Filter status ====' . PHP_EOL;
268 - $is_filterkey = self::is_filterkey();
269 - if($is_filterkey !== false){
270 - $text .= '[Filter] ' . $is_filterkey . PHP_EOL;
271 - $e_plugins = self::get_filtered_plugins();
272 - $d_plugins = array_diff( $base_plugins, $e_plugins );
273 - } else {
274 - $text .= '[Filter] Not Used' . PHP_EOL;
275 - $e_plugins = $base_plugins;
276 - $d_plugins = array();
97 + $this->filter = get_option('plf_option');
98 + //v2.3.0 option change
99 + if(empty($this->filter['optver']) || $this->filter['optver'] < '2'){
100 + //For ver2.2.0 compatibility, set '_pagefilter' data to 'desktop' and 'mobile'
101 + if(empty($this->filter['group']['desktop']) && empty($this->filter['group']['mobile'])){
102 + if(!empty($this->filter['_pagefilter'])){
103 + $this->filter['group']['desktop'] = $this->filter['_pagefilter'];
104 + $this->filter['group']['mobile'] = $this->filter['_pagefilter'];
277 105 }
278 - ksort($e_plugins, SORT_STRING);
279 - ksort($d_plugins, SORT_STRING);
280 -
281 - $text .= self::result_plugin_print( $e_plugins, $d_plugins );
282 - self::plf_filtered_result_dialog( $text );
283 - $wp_admin_bar->add_menu( array(
284 - 'id' => 'plf-statlink',
285 - 'title' => '<span class="ab-icon"></span>PLF',
286 - 'href' => '#plf-status',
287 - ));
288 106 }
289 107 }
290 - }
291 108
292 - //active_sitewide plugins Filter add ver2.4.0
293 - static function active_sitewide_plugins( $default = false) {
294 - return self::plf_filter( 'active_sitewide_plugins', $default);
109 + $this->cache = null;
110 + if(!empty($this->filter)){
111 + add_filter('pre_option_active_plugins', array(&$this, 'active_plugins'));
112 + add_filter('pre_option_jetpack_active_modules', array(&$this, 'active_jetmodules'));
113 + add_filter('pre_option_celtispack_active_modules', array(&$this, 'active_celtismodules'));
114 + add_action('wp_loaded', array(&$this, 'cache_post_type'), 1);
115 + }
295 116 }
296 -
297 - //active plugins Filter
298 - static function active_plugins( $default = false) {
299 - return self::plf_filter( 'active_plugins', $default);
117 +
118 + //Active plugins Filter
119 + function active_plugins( $default = false) {
120 + return $this->plf_filter( 'active_plugins', $default);
300 121 }
301 122
302 123 //Jetpack module Filter
303 - static function active_jetmodules( $default = false) {
304 - return self::plf_filter( 'jetpack_active_modules', $default);
124 + function active_jetmodules( $default = false) {
125 + return $this->plf_filter( 'jetpack_active_modules', $default);
305 126 }
306 127
307 128 //Celtispack module Filter
308 - static function active_celtismodules( $default = false) {
309 - return self::plf_filter( 'celtispack_active_modules', $default);
129 + function active_celtismodules( $default = false) {
130 + return $this->plf_filter( 'celtispack_active_modules', $default);
310 131 }
311 132
312 - function updated_plf_stat() {
313 - $default = array(
314 - 'post_type_query_vars' => array(),
315 - 'queryable_post_types' => array(),
316 - //'wp_post_statuses' => array(),
317 - //'wp_post_types' => array(),
318 - //'wp_taxonomies' => array(),
319 - 'stat_change' => false,
320 - );
321 - $data = get_option('plf_queryvars', array());
322 - $data = wp_parse_args( (array) $data, $default);
323 - //plugin bulk action repeated call
324 - if(empty($data['stat_change'])){
325 - $data['stat_change'] = true;
326 - update_option('plf_queryvars', $data);
327 - }
328 - }
329 -
330 - //Plugin/Module activate or deactivate stat change
331 - function update_active_sitewide_plugins( $option, $value, $old_value, $network_id ) {
332 - $this->updated_plf_stat();
333 - }
334 - function update_active_plugins( $old_value, $value, $option ) {
335 - $this->updated_plf_stat();
336 - }
337 - function update_active_jetmodules( $old_value, $value, $option ) {
338 - $this->updated_plf_stat();
339 - }
340 - function update_active_celtismodules( $old_value, $value, $option ) {
341 - $this->updated_plf_stat();
342 - }
343 - function switch_theme() {
344 - $this->updated_plf_stat();
345 - }
346 -
347 - //Make taxonomies and posts available to 'plugin load filter'.
348 - //force register_taxonomy (category, post_tag, post_format)
349 - static function force_initial_taxonomies(){
350 - global $wp_actions;
351 - $wp_actions[ 'init' ] = 1;
352 - create_initial_taxonomies();
353 - create_initial_post_types();
354 - unset($wp_actions[ 'init' ]);
355 - }
356 -
357 - //all plugins loaded
358 - function plugins_loaded() {
359 - //ver4.0.5 カスタムポストタイプのキャッシュデータを $wp_post_types グローバル変数には反映しないよう変更したのでこの処理は不要となるが、なんらかの影響があると嫌なのでとりあえず残しておく
360 - // woocommerce が init 後に register_post_type, register_taxonomy が実行されたか判定しているので該当データを一旦クリアして init で再登録させる
361 - if(post_type_exists( 'product' )){
362 - if(method_exists('WC_Post_Types', 'register_post_types')){
363 - unregister_post_type( 'product' );
364 - //ver4.0.2 wc_register_order_type で登録されるタイプも一旦クリアする
365 - if(post_type_exists( 'shop_order' )){
366 - unregister_post_type( 'shop_order' );
367 - }
368 - if(post_type_exists( 'shop_order_refund' )){
369 - unregister_post_type( 'shop_order_refund' );
370 - }
371 - }
372 - }
373 - if ( taxonomy_exists( 'product_type' ) ) {
374 - if(method_exists('WC_Post_Types', 'register_taxonomies')){
375 - unregister_taxonomy( 'product_type' );
376 - }
377 - }
378 - }
379 -
380 133 //Post Format Type, Custom Post Type Data Cache for parse request
381 134 function cache_post_type() {
382 - if (!is_admin() || self::$is_filterkey !== false || ( defined('DOING_AJAX') && DOING_AJAX ))
383 - return;
384 -
385 - $default = array(
386 - 'post_type_query_vars' => array(),
387 - 'queryable_post_types' => array(),
388 - //'wp_post_statuses' => array(),
389 - //'wp_post_types' => array(),
390 - //'wp_taxonomies' => array(),
391 - 'stat_change' => false,
392 - );
393 - $data = get_option('plf_queryvars', array());
394 - $data = wp_parse_args( (array) $data, $default);
135 + if (!is_admin() || ( defined('DOING_AJAX') && DOING_AJAX ) || (defined('DOING_CRON') && DOING_CRON))
136 + return;
395 137
396 - global $plugin_page;
397 - if(isset($plugin_page) && $plugin_page === 'plugin_load_filter_admin_manage_page'){
398 - $data['stat_change'] = true;
138 + global $wp;
139 + $public_query_vars = (!empty($wp->public_query_vars))? $wp->public_query_vars : array();;
140 + $post_type_query_vars = array();
141 + foreach ( get_post_types( array(), 'objects' ) as $post_type => $t ){
142 + if ( $t->query_var )
143 + $post_type_query_vars[$t->query_var] = $post_type;
399 144 }
145 + $queryable_post_types = get_post_types( array('publicly_queryable' => true) );
400 146
401 - //init or plugin activate or deactivate stat change
402 - if(!empty($data['stat_change'])){
403 - global $wp;
404 - $public_query_vars = (!empty($wp->public_query_vars))? $wp->public_query_vars : array();;
405 - $post_type_query_vars = array();
406 - foreach ( get_post_types( array(), 'objects' ) as $post_type => $t ){
407 - if (!empty($t) && $t->query_var )
408 - $post_type_query_vars[$t->query_var] = $post_type;
409 - }
410 - $queryable_post_types = get_post_types( array('publicly_queryable' => true) );
411 -
412 - //global $wp_post_types;
413 - //global $wp_post_statuses;
414 - //global $wp_taxonomies;
415 - //$data['wp_post_types'] = $wp_post_types;
416 - //$data['wp_post_statuses'] = $wp_post_statuses;
417 - //$data['wp_taxonomies'] = $wp_taxonomies;
418 - //$data['public_query_vars'] = $public_query_vars;
419 - //ver4.0.11 使わないデータを取り除きオプションデータを縮小化
420 - if(!empty($data['rewrite_rules'])){
421 - unset($data['rewrite_rules']); //データの残骸があれば使わないので取り除く
422 - }
423 - if(!empty($data['wp_post_types'])){
424 - unset($data['wp_post_types']);
425 - }
426 - if(!empty($data['wp_post_statuses'])){
427 - unset($data['wp_post_statuses']);
428 - }
429 - if(!empty($data['wp_taxonomies'])){
430 - unset($data['wp_taxonomies']);
431 - }
432 - if(!empty($data['public_query_vars'])){
433 - unset($data['public_query_vars']);
434 - }
435 - $add_query_vars = array_diff( $public_query_vars, self::$base_public_query_vars );
436 - $data['add_public_query_vars']= $add_query_vars;
147 + $data = get_option('plf_queryvars');
148 + if(!empty($post_type_query_vars) && !empty($queryable_post_types)){
149 + $data['public_query_vars'] = $public_query_vars;
437 150 $data['post_type_query_vars'] = $post_type_query_vars;
438 151 $data['queryable_post_types'] = $queryable_post_types;
439 - $data['stat_change'] = false;
440 152 update_option('plf_queryvars', $data);
441 153 }
442 - }
443 -
444 - /**
445 - * Filters the locale for the current request.
446 - *
447 - * @param string $locale The locale.
448 - */
449 - static function post_locale( $locale ) {
450 - if(empty(self::$rlocale)) {
451 - $pid = 0;
452 - if(isset($_SERVER['REQUEST_URI'])){
453 - if ( strpos( $_SERVER['REQUEST_URI'], 'wp-json' ) !== false || preg_match( '/(admin|wc)-ajax/', $_SERVER['REQUEST_URI'])) {
454 - $refurl = wp_get_raw_referer();
455 - if(!empty( $refurl )){
456 - if(preg_match( '/post=([0-9]+)?/', $refurl, $match )){
457 - $pid = (int)$match[1];
458 - } elseif(preg_match( '/post_ID=([0-9]+)?/', $refurl, $match )){
459 - $pid = (int)$match[1];
460 - } else {
461 - $pid = (isset(self::$url2id[$refurl]))? self::$url2id[$refurl] : url_to_postid( $refurl );
462 - self::$url2id[$refurl] = (int)$pid;
463 - }
464 - }
465 - } elseif ( strpos( $_SERVER['REQUEST_URI'], 'wp-admin' ) !== false) {
466 - if ( isset( $_GET['post'] ) ) {
467 - $pid = (int) $_GET['post'];
468 - } elseif ( isset( $_POST['post_ID'] ) ) {
469 - $pid = (int) $_POST['post_ID'];
470 - }
471 - } else {
472 - global $wp_query;
473 - if(!empty(self::$pre_post_id)){
474 - $pid = self::$pre_post_id;
475 - } elseif(!empty($wp_query)){
476 - if(!empty($wp_query->post) && !empty($wp_query->post->ID)){
477 - $pid = $wp_query->post->ID;
478 - } else {
479 - $refurl = wp_get_raw_referer();
480 - if (!empty( $refurl )) {
481 - $pid = (isset(self::$url2id[$refurl]))? self::$url2id[$refurl] : url_to_postid( $refurl );
482 - self::$url2id[$refurl] = (int)$pid;
483 - }
484 - }
485 - }
486 - }
487 - }
488 - if(!empty($pid)){
489 - $c_locale = get_post_meta( $pid, '_locale', true );
490 - if(!empty($c_locale)){
491 - self::$rlocale = $c_locale;
492 - }
493 - }
154 + else if(!empty($data['post_type_query_vars']) || !empty($data['queryable_post_types'])){
155 + delete_option('plf_queryvars');
494 156 }
495 - if(!empty(self::$rlocale)) {
496 - $locale = self::$rlocale;
497 - }
498 - return $locale;
499 157 }
500 -
501 - static function post_determine_locale( $locale ) {
502 - if(!empty(self::$rlocale)) {
503 - $locale = self::$rlocale;
504 - }
505 - return $locale;
506 - }
507 158
508 - //プラグインロード前は bbPress等 カスタムポストタイプのデバッグモードでのエラー表示抑制
509 - static function exclude_trigger_error( $trigger, $function, $message, $version) {
510 - if (did_action( 'plugins_loaded' ) === 0) {
511 - if($function === 'map_meta_cap'){
512 - $trigger = false;
513 - }
514 - }
515 - return $trigger;
516 - }
517 - //プラグインロード前は closed 等のカスタムステータスがまだ登録されてない状態でも取得 posts 情報がクリアされないよう抑制
518 - static function exclude_map_meta_cap( $caps, $cap, $user_id, $args) {
519 - if (did_action( 'plugins_loaded' ) === 0) {
520 - if(!empty($caps) && $caps[0] === 'edit_others_posts'){
521 - $caps = array();
522 - }
523 - }
524 - return $caps;
525 - }
526 -
527 - //parse_request Action Hook for Custom Post Type query add
528 - static function parse_request( &$args ) {
529 - if (did_action( 'plugins_loaded' ) === 0) {
530 - $data = get_option('plf_queryvars', array());
531 - if(!empty($data['post_type_query_vars']) && !empty($data['queryable_post_types']) && empty($data['stat_change'])){
532 - //ver4.0.5 グローバルのカスタムポストタイプに事前設定するとプラグイン内での登録済みチェック処理とコンフリクトするので止める
533 - //global $wp_post_statuses;
534 - //global $wp_post_types;
535 - //global $wp_taxonomies;
536 - //$wp_post_statuses = $data['wp_post_statuses'];
537 - //$wp_post_types = $data['wp_post_types'];
538 - //$wp_taxonomies = $data['wp_taxonomies'];
539 -
159 + //parse_request Action Hook for Custom Post Type query add
160 + function parse_request( &$args ) {
161 + if (did_action( 'plugins_loaded' ) === 0 ) {
162 + $data = get_option('plf_queryvars');
163 + if(!empty($data['post_type_query_vars']) && !empty($data['queryable_post_types'])){
540 164 $post_type_query_vars = $data['post_type_query_vars'];
541 165 $queryable_post_types = $data['queryable_post_types'];
542 166
543 - //query_vars に query_posts() で実行するSQL用のポストタイプデータをセット
544 - if(isset($data['add_public_query_vars'])){
545 - //ver4.0.11 差分データにしたのでここでマージするが更新時にエラーとならないよう旧処理も残しておく
546 - $args->public_query_vars = array_merge(self::$base_public_query_vars, $data['add_public_query_vars']);
547 - } else {
548 - $args->public_query_vars = $data['public_query_vars'];
549 - }
167 + $args->public_query_vars = $data['public_query_vars'];
550 168 if ( isset( $args->matched_query ) ) {
551 169 parse_str($args->matched_query, $perma_query_vars);
552 170 }
553 -
554 171 foreach ( $args->public_query_vars as $wpvar ) {
555 - if ( isset( $args->extra_query_vars[$wpvar] ) ){
172 + if ( isset( $args->extra_query_vars[$wpvar] ) )
556 173 $args->query_vars[$wpvar] = $args->extra_query_vars[$wpvar];
557 - } elseif ( isset( $_GET[ $wpvar ] ) && isset( $_POST[ $wpvar ] ) && $_GET[ $wpvar ] !== $_POST[ $wpvar ] ) {
558 - wp_die( 'A variable mismatch has been detected.', 'Sorry, you are not allowed to view this item.', 400 );
559 - } elseif ( isset( $_POST[$wpvar] ) ){
174 + elseif ( isset( $_POST[$wpvar] ) )
560 175 $args->query_vars[$wpvar] = $_POST[$wpvar];
561 - } elseif ( isset( $_GET[$wpvar] ) ){
176 + elseif ( isset( $_GET[$wpvar] ) )
562 177 $args->query_vars[$wpvar] = $_GET[$wpvar];
563 - } elseif ( isset( $perma_query_vars[$wpvar] ) ){
178 + elseif ( isset( $perma_query_vars[$wpvar] ) )
564 179 $args->query_vars[$wpvar] = $perma_query_vars[$wpvar];
565 - }
180 +
566 181 if ( !empty( $args->query_vars[$wpvar] ) ) {
567 182 if ( ! is_array( $args->query_vars[$wpvar] ) ) {
568 183 $args->query_vars[$wpvar] = (string) $args->query_vars[$wpvar];
569 184 } else {
570 185 foreach ( $args->query_vars[$wpvar] as $vkey => $v ) {
571 - if ( is_scalar( $v ) ) {
186 + if ( !is_object( $v ) ) {
572 187 $args->query_vars[$wpvar][$vkey] = (string) $v;
573 188 }
574 189 }
575 190 }
576 -
577 191 if ( isset($post_type_query_vars[$wpvar] ) ) {
578 192 $args->query_vars['post_type'] = $post_type_query_vars[$wpvar];
579 193 $args->query_vars['name'] = $args->query_vars[$wpvar];
580 194 }
@@ -580,768 +194,208 @@
580 194 }
581 195 }
582 196 }
583 197
584 - // Limit publicly queried post_types to those that are 'publicly_queryable'.
198 + // Limit publicly queried post_types to those that are publicly_queryable
585 199 if ( isset( $args->query_vars['post_type']) ) {
586 200 if ( ! is_array( $args->query_vars['post_type'] ) ) {
587 - if ( ! in_array( $args->query_vars['post_type'], $queryable_post_types, true ) ) {
201 + if ( ! in_array( $args->query_vars['post_type'], $queryable_post_types ) )
588 202 unset( $args->query_vars['post_type'] );
589 - }
590 203 } else {
591 204 $args->query_vars['post_type'] = array_intersect( $args->query_vars['post_type'], $queryable_post_types );
592 205 }
593 - }
594 - }
595 - }
596 - }
597 -
598 - //get filter name
599 - static function is_filterkey() {
600 - return self::$is_filterkey;
601 - }
602 - //base plugins (initial activated plugins & module)
603 - static function get_base_plugins() {
604 - return self::$base_plugins;
605 - }
606 - //filtered plugins (plugins & module)
607 - static function get_filtered_plugins() {
608 - return self::$filtered_plugins;
609 - }
610 -
611 - /**
612 - * Get URL Filter (for addon optional)
613 - * @param $stat : 'active' / 'deactive' / '' = all
614 - * @param $urltype : 'front' / 'admin' / '' = all
615 - * @param $device : 'desktop' / 'mobile' / '' = all
616 - * @return url filter data array.
617 - */
618 - static function get_url_filter( $stat='', $urltype='', $device='' ) {
619 - $frontlist = array();
620 - $adminlist = array();
621 - if(!empty(self::$url_filter)){
622 - foreach (self::$url_filter['filter'] as $slug => $v) {
623 - if(empty($stat) || (!empty($v['stat']) && $stat === 'active') || (empty($v['stat']) && $stat === 'deactive')){
624 - if(empty($device) || (!empty($v['desktop']) && $device === 'desktop') || (!empty($v['mobile']) && $device === 'mobile')){
625 - if(!empty($v['type'])){
626 - $item = "{$v['group']}-{$v['slug']}";
627 - if($v['type'] == 'front'){
628 - $frontlist[$item] = $v;
629 - } elseif($v['type'] == 'admin'){
630 - $adminlist[$item] = $v;
631 - }
632 - }
633 - }
634 206 }
635 207 }
636 - //group 毎に slug をソート A-Za-z 順となる
637 - ksort($frontlist, SORT_STRING);
638 - ksort($adminlist, SORT_STRING);
639 208 }
640 - $list = array();
641 - if(empty($urltype) || $urltype === 'front'){
642 - foreach ($frontlist as $item => $v) {
643 - if(!empty($v)){
644 - $list[] = $v;
645 - }
646 - }
647 - }
648 - if(empty($urltype) || $urltype === 'admin'){
649 - foreach ($adminlist as $item => $v) {
650 - if(!empty($v)){
651 - $list[] = $v;
652 - }
653 - }
654 - }
655 - return $list;
656 209 }
657 - //active group list
658 - static function get_active_group() {
659 - $grouplist = array();
660 - $sluglist = self::get_url_filter( 'active' );
661 - foreach ($sluglist as $v) {
662 - if(!empty($v['group']) && !in_array($v['group'], $grouplist)){
663 - $grouplist[] = $v['group'];
664 - }
665 - }
666 - return $grouplist;
667 - }
668 - //active slug filter data in group
669 - static function get_slug_filter( $group ) {
670 - $list = array();
671 - $sluglist = self::get_url_filter( 'active' );
672 - foreach ($sluglist as $v) {
673 - if(!empty($v['group']) && $v['group'] == $group){
674 - $list[] = $v;
675 - }
676 - }
677 - return $list;
678 - }
679 210
680 - //Is there a term in taxonomies
681 - static function is_term_in_taxonomy( $post_id, $term, $taxonomies) {
682 - $ret = false;
683 - $txs = explode(',', $taxonomies);
684 - foreach ( $txs as $slug ) {
685 - if(!empty($slug)){
686 - $names = '';
687 - $terms = get_the_terms( $post_id, $slug );
688 - if (!empty($terms) ) {
689 - foreach ( $terms as $tobj ) {
690 - if(!empty($tobj)){
691 - $names .= $tobj->name . ',';
692 - }
693 - }
694 - if(strpos($names, $term ) !== false){
695 - $ret = true;
696 - break;
697 - }
698 - }
699 - }
700 - }
701 - return $ret;
702 - }
703 -
704 - // url path, query parameter match check
705 - static function is_url_match( $req_url, $parse_url, $filter ) {
706 - if(empty($req_url) || empty($parse_url['path']))
211 + //Plugin Load Filter Main (active plugins/modules filtering)
212 + function plf_filter( $option, $default = false) {
213 + if ( defined( 'WP_SETUP_CONFIG' ) )
707 214 return false;
708 - $_url['url_path'] = $parse_url['path'];
709 - $_url['url_q_and'] = $_url['url_q_not'] = (!empty($parse_url['query']))? $parse_url['query'] : '';
710 -
711 - $match = array();
712 - $keynum = array();
713 - foreach (array('url_path', 'url_q_and', 'url_q_not') as $item) {
714 - $match[$item] = 0;
715 - $keynum[$item] = 0;
716 - if($item === 'url_path'){
717 - $reg_before = "(/?)";
718 - $reg_after = "(/?$)";
719 - } else {
720 - $reg_before = "(^|&)";
721 - $reg_after = "(=|&|$)";
722 - }
723 215
724 - $keylist = (!empty($filter[$item])) ? $filter[$item] : '';
725 - $keylist = str_replace( "*", ".+?", $keylist);
726 - $ar_key = (!empty($keylist))? array_filter( array_map("trim", explode(PHP_EOL, $keylist))) : array();
727 - $keynum[$item] = count($ar_key);
728 - if(empty($ar_key)) {
729 - if($item === 'url_path')
730 - $match[$item] += 1;
731 - } else {
732 - $ar_new = array();
733 - foreach ($ar_key as $key) {
734 - //v4.0.6 home (/) のみの指定は別判定しないとトレイルスラッシュで終わる全てのURLにマッチしてしまう
735 - if($item === 'url_path' && $key === '/'){
736 - if($_url['url_path'] === '/'){
737 - $match[$item] += 1;
738 - }
739 - } elseif(preg_match("#{$reg_before}{$key}{$reg_after}#ui", $_url[$item])){
740 - $match[$item] += 1;
741 - }
742 - }
743 - }
744 - }
745 - $group = false;
746 - $hit = ($match['url_path'] > 0 && $match['url_q_and'] === $keynum['url_q_and'] && $match['url_q_not'] === 0)? true : false;
747 - if($hit){
748 - if((strpos($_url['url_path'], 'admin-ajax.php' ) !== false || strpos($_url['url_q_and'], 'wc-ajax' ) !== false) && (int)$filter['targetpage'] === 2){
749 - $action = '';
750 - if(isset($_REQUEST['action'])){
751 - $action = esc_attr($_REQUEST['action']);
752 - } elseif(!empty( $_GET['wc-ajax'] )) {
753 - $action = sanitize_text_field( wp_unslash( $_GET['wc-ajax'] ) );
754 - }
755 - if(!empty($filter['ajax_action'])){
756 - if( $action == $filter['ajax_action'] ){
757 - $group = $filter['group'];
758 - }
759 - } else {
760 - //exclude special action : plugin_load_filter, plf_urlfilter_test
761 - if (! in_array( $action, array('plugin_load_filter', 'plf_urlfilter_test')) ){
762 - $group = $filter['group'];
763 - }
764 - }
765 - } elseif(strpos($_url['url_path'], 'post-new.php' ) === false && (int)$filter['targetpage'] === 1){
766 - $post_id = 0;
767 - if ( isset( $_GET['post'] ) && isset( $_POST['post_ID'] ) && (int) $_GET['post'] !== (int) $_POST['post_ID'] ) {
768 - } elseif ( isset( $_GET['post'] ) ) {
769 - $post_id = (int) $_GET['post'];
770 - } elseif ( isset( $_POST['post_ID'] ) ) {
771 - $post_id = (int) $_POST['post_ID'];
772 - }
773 - if(empty($post_id)){
774 - //クエリーパラメータ形式だとポストIDが取得できないようなので、シュミレータ以外なら $wp_query->post->ID を使う
775 - global $wp_query;
776 - if(!empty($wp_query)){
777 - if (isset($_REQUEST['action']) && isset($_POST['test_url']) ) {
778 - $post_id = (isset(self::$url2id[$req_url]))? self::$url2id[$req_url] : url_to_postid( $req_url );
779 - self::$url2id[$req_url] = (int)$post_id;
780 - } else {
781 - if(!empty($wp_query->post) && !empty($wp_query->post->ID)){
782 - $post_id = $wp_query->post->ID;
783 - } else {
784 - $post_id = (isset(self::$url2id[$req_url]))? self::$url2id[$req_url] : url_to_postid( $req_url );
785 - self::$url2id[$req_url] = (int)$post_id;
786 - }
787 - }
788 - }
789 - }
790 - if(!empty($post_id)){
791 - $post = get_post( $post_id );
792 - if ( is_object($post) && !empty($post->post_type)) {
793 - if(!empty($filter['post_type'])){
794 - if(preg_match("#{$post->post_type}#", $filter['post_type'])){
795 - if(!empty($filter['taxonomies']) && !empty($filter['term'])){
796 - if(self::is_term_in_taxonomy( $post_id, $filter['term'], $filter['taxonomies'])){
797 - $group = $filter['group'];
798 - }
799 - } else {
800 - $group = $filter['group'];
801 - }
802 - }
803 - } else {
804 - if(!empty($filter['taxonomies']) && !empty($filter['term'])){
805 - if(self::is_term_in_taxonomy( $post_id, $filter['term'], $filter['taxonomies'])){
806 - $group = $filter['group'];
807 - }
808 - } else {
809 - $group = $filter['group'];
810 - }
811 - }
812 - }
813 - }
814 - } else {
815 - $group = $filter['group'];
816 - }
817 - }
818 - return($group);
819 - }
216 + //Admin mode exclude
217 + if(is_admin())
218 + return false;
820 219
821 - static function plugin_keygen( $fname, $option ) {
822 - $key = false;
823 - if($option === 'jetpack_active_modules'){
824 - $key = 'jetpack_module/' . $fname;
825 - } elseif($option === 'celtispack_active_modules'){
826 - $key = 'celtispack_module/' . str_replace( '.php', '', basename( $fname ) );
827 - } else {
828 - $key = $fname;
829 - }
830 - return $key;
831 - }
832 -
833 - /**
834 - * Get valid plugins list for groupkey (for addon optional)
835 - * @param $groupkey : url filter group name
836 - * @param $filter : plf filtering setting data
837 - * @param $option : option data eg. 'active_plugins', 'active_sitewide_plugins', 'jetpack_active_modules' ...
838 - * @param $plugins : active plugins values before filtering
839 - * @return data values after filtering
840 - */
841 - static function filter_to_active_plugins( $groupkey, $filter, $option, $plugins ){
842 - $new_plugins = array();
843 - foreach ( $plugins as $item ) {
844 - if(!empty($item)){
845 - $unload = false;
846 - $p_key = self::plugin_keygen( $item, $option );
847 - if(!empty($filter['plfurlkey'][$groupkey]['plugins'])){
848 - if(false !== strpos($filter['plfurlkey'][$groupkey]['plugins'], $p_key))
849 - $unload = true;
850 - }
851 - if(!$unload) {
852 - if($option === 'active_sitewide_plugins'){
853 - // v4.0.6 $new_plugins[$item] = $plugins[$item];
854 - $new_plugins[$item] = $item;
855 - } else {
856 - $new_plugins[] = $item;
857 - }
858 - }
859 - }
860 - }
861 -
862 - $new_plugins = apply_filters('plf_custom_changes_to_active_plugins', $new_plugins);
863 - return $new_plugins;
864 - }
865 -
866 - /**
867 - * Get valid plugins list for ajax acceleration filter
868 - * @param $p_slugs : ajax _ajax_plf activate plugins slug data (Separate multiple with commas)
869 - * @param $option : option data eg. 'active_plugins', 'active_sitewide_plugins', 'jetpack_active_modules' ...
870 - * @param $plugins : active plugins values before filtering
871 - * @return data values after filtering
872 - */
873 - static function ajaxfilter_to_active_plugins( $p_slugs, $option, $plugins ){
874 - //照合用にカンマ区切りをスラッシュ区切りへ変換
875 - $arslugs = array_filter( array_map("trim", explode(',', $p_slugs)));
876 - $slugs = '/' . implode('/', $arslugs) . '/';
877 -
878 - $new_plugins = array();
879 - foreach ( $plugins as $item ) {
880 - if(!empty($item)){
881 - $unload = false;
882 - $p_key = self::plugin_keygen( $item, $option );
883 - $sep = strpos($p_key, '/' );
884 - $p_slug = ($sep !== false)? substr($p_key, 0, $sep) : $p_key;
885 - if(false === strpos($slugs, "/$p_slug/")){
886 - $unload = true;
887 - }
888 - if(!$unload) {
889 - if($option === 'active_sitewide_plugins'){
890 - $new_plugins[$item] = $item;
891 - } else {
892 - $new_plugins[] = $item;
893 - }
894 - }
895 - }
896 - }
897 - return $new_plugins;
898 - }
899 -
900 - //Plugin Load Filter Main (active plugins/modules filtering)
901 - static function plf_filter( $option, $default = false) {
902 - if ( defined( 'WP_SETUP_CONFIG' ) || did_action( 'mu_plugin_loaded' ) === 0)
903 - return false;
904 -
905 - //Check if the caller is wp-settings.php wp_get_active_network_plugins() / wp_get_active_and_valid_plugins()
906 - if( in_array($option, array('active_plugins', 'active_sitewide_plugins' ))){
907 - $is_caller_target = false;
908 - $trace = debug_backtrace();
909 - foreach ($trace as $stp) {
910 - if(isset($stp['file']) && strpos($stp['file'], 'wp-settings.php') !== false){
911 - if(isset($stp['function']) && in_array($stp['function'], array('wp_get_active_network_plugins', 'wp_get_active_and_valid_plugins'))){
912 - $is_caller_target = true;
913 - break;
914 - }
915 - }
916 - }
917 - if( !$is_caller_target ) {
918 - return false;
919 - }
920 - }
921 -
922 220 if ( ! defined( 'WP_INSTALLING' ) ) {
923 - global $wpdb, $current_site;
924 - if ( is_multisite() && $option === 'active_sitewide_plugins' ) {
925 - //get_network_option() current site ID
926 - $network_id = $current_site->id;
221 + // prevent non-existent options from triggering multiple queries
222 + $notoptions = wp_cache_get( 'notoptions', 'options' );
223 + if ( isset( $notoptions[$option] ) )
224 + return apply_filters( 'default_option_' . $option, $default );
927 225
928 - // prevent non-existent options from triggering multiple queries
929 - $notoptions_key = "$network_id:notoptions";
930 - $notoptions = wp_cache_get( $notoptions_key, 'site-options' );
931 - if ( isset( $notoptions[ $option ] ) ) {
932 - return apply_filters( 'default_site_option_' . $option, $default, $option );
933 - }
226 + $alloptions = wp_load_alloptions();
227 + if ( isset( $alloptions[$option] ) ) {
228 + $value = $alloptions[$option];
229 + } else {
230 + $value = wp_cache_get( $option, 'options' );
934 231
935 - $cache_key = "$network_id:$option";
936 - $opt_value = wp_cache_get( $cache_key, 'site-options' );
232 + if ( false === $value ) {
233 + $row = $wpdb->get_row( $wpdb->prepare( "SELECT option_value FROM $wpdb->options WHERE option_name = %s LIMIT 1", $option ) );
937 234
938 - if ( ! isset( $opt_value ) || false === $opt_value ) {
939 - $row = $wpdb->get_row( $wpdb->prepare( "SELECT meta_value FROM $wpdb->sitemeta WHERE meta_key = %s AND site_id = %d", $option, $network_id ) );
940 -
941 235 // Has to be get_row instead of get_var because of funkiness with 0, false, null values
942 236 if ( is_object( $row ) ) {
943 - $opt_value = $row->meta_value;
944 - $opt_value = maybe_unserialize( $opt_value );
945 - wp_cache_set( $cache_key, $opt_value, 'site-options' );
946 - } else {
947 - if ( ! is_array( $notoptions ) ) {
948 - $notoptions = array();
949 - }
950 - $notoptions[ $option ] = true;
951 - wp_cache_set( $notoptions_key, $notoptions, 'site-options' );
237 + $value = $row->option_value;
238 + wp_cache_add( $option, $value, 'options' );
239 + } else { // option does not exist, so we must cache its non-existence
240 + $notoptions[$option] = true;
241 + wp_cache_set( 'notoptions', $notoptions, 'options' );
952 242
953 243 /** This filter is documented in wp-includes/option.php */
954 - $opt_value = apply_filters( 'default_site_option_' . $option, $default, $option );
244 + return apply_filters( 'default_option_' . $option, $default );
955 245 }
956 246 }
957 - } else {
958 - // prevent non-existent options from triggering multiple queries
959 - $notoptions = wp_cache_get( 'notoptions', 'options' );
960 - if ( isset( $notoptions[$option] ) )
961 - return apply_filters( 'default_option_' . $option, $default );
962 -
963 - $alloptions = wp_load_alloptions();
964 - if ( isset( $alloptions[$option] ) ) {
965 - $opt_value = $alloptions[$option];
966 - } else {
967 - $opt_value = wp_cache_get( $option, 'options' );
968 -
969 - if ( false === $opt_value ) {
970 - $row = $wpdb->get_row( $wpdb->prepare( "SELECT option_value FROM $wpdb->options WHERE option_name = %s LIMIT 1", $option ) );
971 -
972 - // Has to be get_row instead of get_var because of funkiness with 0, false, null values
973 - if ( is_object( $row ) ) {
974 - $opt_value = $row->option_value;
975 - wp_cache_add( $option, $opt_value, 'options' );
976 - } else { // option does not exist, so we must cache its non-existence
977 - if ( ! is_array( $notoptions ) ) {
978 - $notoptions = array();
979 - }
980 - $notoptions[$option] = true;
981 - wp_cache_set( 'notoptions', $notoptions, 'options' );
982 -
983 - /** This filter is documented in wp-includes/option.php */
984 - return apply_filters( 'default_option_' . $option, $default, $option );
985 - }
986 - }
987 - }
988 247 }
989 248 } else {
990 249 return false;
991 250 }
992 -
993 - $req_url = (isset($_SERVER['REQUEST_URI']))? $_SERVER['REQUEST_URI'] : '';
994 - $req_url = str_replace( "\\", "/", $req_url);
995 - $parse_url = parse_url($req_url);
996 - $action = (!empty($parse_url['path']) && strpos($parse_url['path'], 'admin-ajax.php' ) !== false && isset($_REQUEST['action']))? esc_attr($_REQUEST['action']) : '';
997 -
998 - $act_plugins = ($option === 'active_sitewide_plugins')? array_keys( (array)$opt_value ) : maybe_unserialize( $opt_value );
999 - if($option === 'celtispack_active_modules'){
1000 - if(empty(self::$base_plugins['celtispack-addon/celtispack-addon.php'])){
1001 - $opt = get_option( 'celtis_addon_options', array() );
1002 - if(!empty($opt['active_modules'])){
1003 - $nact_plugins = array();
1004 - foreach ($act_plugins as $pkey) {
1005 - if(!empty($pkey)){
1006 - $key = str_replace( '.php', '', basename( $pkey ));
1007 - if(!empty($opt['active_modules'][$key]))
1008 - continue;
1009 - $nact_plugins[] = $pkey;
1010 - }
1011 - }
1012 - $act_plugins = $nact_plugins;
1013 - }
1014 - }
1015 - }
1016 -
1017 - //Equal treatment for when the wp_is_mobile is not yet available(wp-include/vars.php wp_is_mobile)
1018 - if ( empty($_SERVER['HTTP_USER_AGENT']) ) {
1019 - $is_mobile = false;
1020 - } elseif ( strpos($_SERVER['HTTP_USER_AGENT'], 'Mobile') !== false // many mobile devices (all iPhone, iPad, etc.)
1021 - || strpos($_SERVER['HTTP_USER_AGENT'], 'Android') !== false
1022 - || strpos($_SERVER['HTTP_USER_AGENT'], 'Silk/') !== false
1023 - || strpos($_SERVER['HTTP_USER_AGENT'], 'Kindle') !== false
1024 - || strpos($_SERVER['HTTP_USER_AGENT'], 'BlackBerry') !== false
1025 - || strpos($_SERVER['HTTP_USER_AGENT'], 'Opera Mini') !== false
1026 - || strpos($_SERVER['HTTP_USER_AGENT'], 'Opera Mobi') !== false ) {
1027 - $is_mobile = true;
1028 - } else {
1029 - $is_mobile = false;
1030 - }
1031 - $is_mobile = apply_filters( 'custom_is_mobile' , $is_mobile );
1032 251
252 + $filter = $this->filter;
1033 253 //get_option is called many times, intermediate processing data to cache
1034 - $keyid = md5('plf_'. (string)$is_mobile . $req_url . $action);
1035 - if(!empty(self::$cache[$keyid][$option])){
1036 - return self::$cache[$keyid][$option];
254 + $keyid = md5('plf_'. (string)wp_is_mobile(). $_SERVER['REQUEST_URI']);
255 + if(!empty($this->cache[$keyid][$option])){
256 + return apply_filters( 'option_' . $option, $this->cache[$keyid][$option]);
1037 257 }
1038 258
1039 259 //Before plugins loaded, it does not use conditional branch such as is_home, to set wp_query, wp in temporary query
1040 260 if(empty($GLOBALS['wp_the_query'])){
1041 - // プラグイン無効化時等で rewrite_rule がクリアされると rewrite_rule が更新されるまでカスタムポストタイプを判定できずにカスタムポストタイプのページはホームへ飛ばされる
1042 - // 但し、permlink structure が plain(基本) の場合は除く
1043 - if(!empty(get_option( 'permalink_structure' ))){
1044 - $rewrite_rules = get_option('rewrite_rules');
1045 - // rewrite_rule を監視して変更された場合はプラグインのフィルタリングをスキップさせていたが、
1046 - // plugin activate / deactivate を監視するように変更したのでここでは空の場合のみチェック
1047 - if(empty($rewrite_rules)){
1048 - return false;
1049 - }
1050 - // Welcart usces_itemnew 新規商品追加時のエラー (A variable mismatch has been detected.) parse_request で発生してるので特別に回避
1051 - if ( isset( $_GET[ 'page' ] ) && isset( $_POST[ 'page' ] ) && $_GET[ 'page' ] !== $_POST[ 'page' ] ) {
1052 - return false;
1053 - }
1054 - }
1055 261 $GLOBALS['wp_the_query'] = new WP_Query();
1056 262 $GLOBALS['wp_query'] = $GLOBALS['wp_the_query'];
1057 263 $GLOBALS['wp_rewrite'] = new WP_Rewrite();
1058 264 $GLOBALS['wp'] = new WP();
1059 - self::$base_public_query_vars = $GLOBALS['wp']->public_query_vars;
1060 - //register_taxonomy(category, post_tag, post_format) support for is_archive
1061 - self::force_initial_taxonomies();
1062 -
1063 - if((!empty($parse_url['path']) && (strpos($parse_url['path'], 'admin-ajax.php' ) !== false || strpos($parse_url['path'], '/wp-cron' ) !== false || strpos($parse_url['path'], '/wp-json' ) !== false)) || (!empty($parse_url['query']) && strpos($parse_url['query'], 'rest_route=' ) !== false )){
1064 - //ver4.0.15 admin-ajax action:send-attachment-to-editor リクエストが query_posts() 呼び出し時にエラーとなるので ajax, rest api, cron では呼び出さず url filter 処理へ
1065 - //https://wordpress.org/support/topic/amin-ajax-php-cant-add-images-in-posts/#post-16938082
1066 - } else {
1067 - //Post Format, Custom Post Type support
1068 - add_action('parse_request', array('Plf_filter', 'parse_request'));
1069 - add_filter('doing_it_wrong_trigger_error', array('Plf_filter', 'exclude_trigger_error'), 10, 4 );
1070 - //custom parse request filter (for experimental development)
1071 - $custom = apply_filters( 'plf_experimental_custom_parse_request', false );
1072 - if ( false === $custom) {
1073 - $GLOBALS['wp']->parse_request('');
1074 - }
1075 - $GLOBALS['wp']->query_posts();
1076 - }
265 + //Post Format, Custom Post Type support
266 + add_action('parse_request', array(&$this, 'parse_request'));
267 + $GLOBALS['wp']->parse_request('');
268 + $GLOBALS['wp']->query_posts();
1077 269 }
1078 -
1079 - //active plugin data
1080 - foreach ($act_plugins as $key) {
1081 - if(!empty($key)){
1082 - $key = self::plugin_keygen( $key, $option );
1083 - self::$base_plugins[$key] = $key;
270 + //Only available display pages (login, cron, ajax request ... excluded)
271 + //downloadmanager plugin downloadlink request [home]/?wpdmact=XXXXXX exclude home GET query
272 + global $wp_query;
273 + if(!(function_exists('is_embed') && is_embed())){
274 + if((is_home() || is_front_page() || is_archive() || is_search() || is_singular()) == false
275 + || (is_home() && !empty($_GET))
276 + || (is_singular() && empty($wp_query->post))){
277 + return false;
1084 278 }
1085 - }
1086 -
1087 - $filter = self::$filter;
1088 -
1089 - //plf Addon Extract only target data
1090 - $devtype = ($is_mobile)? 'mobile' : 'desktop';
1091 - $urltype = (!empty($parse_url['path']) && strpos($parse_url['path'], '/wp-admin' ) !== false)? 'admin' : 'front';
1092 - if(!empty(self::$url_filter) && empty(self::$s_url_filter)){
1093 - self::$s_url_filter = self::get_url_filter( 'active', $urltype, $devtype );
1094 279 }
1095 280
1096 -
1097 - //======== The following are Admin backend page processes ========
1098 -
1099 - if($urltype === 'admin'){
1100 - //wp-admin/plugins.php or wp-admin/update-core.php request : Do not filter this request URL
1101 - if(strpos($parse_url['path'], '/plugins.php' ) !== false || strpos($parse_url['path'], '/update-core.php' ) !== false){
1102 - return false;
281 + $us_value = maybe_unserialize( $value );
282 + $new_value = array();
283 + foreach ( $us_value as $item ) {
284 + $unload = false;
285 + //Jetpack module slug / Celtiapack module slug / Plugin php file name
286 + if($option === 'jetpack_active_modules'){
287 + $p_key = 'jetpack_module/' . $item;
1103 288 }
1104 - //Ajax acceleration plugin filter (for plugin developers)
1105 - if(!empty($action) && !empty(self::$filter['ajax_accelfilter'])){
1106 - $slugs = (isset($_REQUEST['_ajax_plf']))? wp_kses( stripslashes($_REQUEST['_ajax_plf']), 'strip' ) : '';
1107 - if(!empty($slugs)){
1108 - $referer = (!empty( $_SERVER['HTTP_REFERER'] )) ? wp_kses( stripslashes($_SERVER['HTTP_REFERER']), 'strip' ) : '';
1109 - $parse_ref = parse_url($referer);
1110 - if(!empty($parse_ref['host']) && strpos( home_url(), $parse_ref['host'] ) !== false){
1111 - $new_plugins = self::ajaxfilter_to_active_plugins( $slugs, $option, $act_plugins );
1112 - foreach ($new_plugins as $key) {
1113 - if(!empty($key)){
1114 - $key = self::plugin_keygen( $key, $option );
1115 - self::$filtered_plugins[$key] = $key;
289 + elseif($option === 'celtispack_active_modules'){
290 + $p_key = 'celtispack_module/' . str_replace( '.php', '', basename( $item) );
291 + }
292 + else {
293 + $p_key = $item;
294 + }
295 + //admin mode filter
296 + if(!empty($filter['_admin']['plugins'])){
297 + if(in_array($p_key, array_map("trim", explode(',', $filter['_admin']['plugins']))))
298 + $unload = true;
299 + }
300 + //page filter
301 + if(!$unload){
302 + if(!empty($filter['_pagefilter']['plugins'])){
303 + if(in_array($p_key, array_map("trim", explode(',', $filter['_pagefilter']['plugins'])))){
304 + $unload = true;
305 +
306 + //desktop/mobile device disable filter
307 + $single_opt = false;
308 + $dis_dev = true;
309 + $devtype = (wp_is_mobile())? 'mobile' : 'desktop';
310 + if(is_singular() && is_object($wp_query->post)){
311 + $myfilter = get_post_meta( $wp_query->post->ID, '_plugin_load_filter', true );
312 + //For ver2.2.0 compatibility, set 'plugins' data to 'desktop' and 'mobile'
313 + if(!empty($myfilter['plugins'])){
314 + $myfilter['desktop'] = $myfilter['plugins'];
315 + $myfilter['mobile'] = $myfilter['plugins'];
316 + unset($myfilter['plugins']);
1116 317 }
1117 - }
1118 - return $new_plugins;
1119 - }
1120 - }
1121 - }
1122 - if(!empty(self::$s_url_filter)){
1123 - //plf Addon Admin Backend URL filtering
1124 - foreach (self::$s_url_filter as $key => $v) {
1125 - if(!empty($v)){
1126 - $groupkey = self::is_url_match( $req_url, $parse_url, $v );
1127 - if($groupkey !== false) {
1128 - self::$is_filterkey = 'url-group-filter : ' . $groupkey;
1129 - $new_plugins = self::filter_to_active_plugins( $groupkey, $filter, $option, $act_plugins );
1130 - self::$cache[$keyid][$option] = $new_plugins;
1131 - foreach ($new_plugins as $key) {
1132 - if(!empty($key)){
1133 - $key = self::plugin_keygen( $key, $option );
1134 - self::$filtered_plugins[$key] = $key;
1135 - }
318 + $default = array( 'filter' => 'default', 'desktop' => '', 'mobile' => '');
319 + $single_opt = (!empty($myfilter))? $myfilter : $default;
320 + $single_opt = wp_parse_args( $single_opt, $default);
321 + if($single_opt['filter'] === 'include'){
322 + if(false !== strpos($single_opt[$devtype], $p_key))
323 + $dis_dev = false;
324 + else if(strpos($p_key, 'jetpack/') !== false && strpos($single_opt[$devtype], 'jetpack_module/') !== false)
325 + $dis_dev = false;
326 + else if(strpos($p_key, 'celtispack/') !== false && strpos($single_opt[$devtype], 'celtispack_module/') !== false)
327 + $dis_dev = false;
1136 328 }
1137 - return $new_plugins;
1138 - }
1139 - }
1140 - }
1141 - }
1142 - return false;
1143 - }
1144 -
1145 -
1146 - //======== The following are frontend page processes ========
1147 -
1148 - global $wp_query;
1149 - $unknown = false;
1150 - if( ! is_embed() ){
1151 - if((is_home() || is_front_page() || is_archive() || is_search() || is_singular()) == false || (is_home() && !empty($_GET))) {
1152 - //bbPress users page requests are treated the same as is_home
1153 - //downloadmanager plugin downloadlink request [home]/?wpdmact=XXXXXX exclude home GET query
1154 - $unknown = true;
1155 -
1156 - } elseif(is_singular() && empty($wp_query->post)){
1157 - //documentroot special php file (wp-login.php, wp-cron.php, etc) これらはこの時点では singular とみなされるが post が設定されていないことで判別
1158 - //フィルタリングしたい場合は urlfilter Addon を使用すること
1159 - //但し、private (非公開)ページ時は post がこの時点ではまだ設定されていないので private でクエリー発行して再確認
1160 - if(!empty($parse_url['path']) && strpos( $parse_url['path'], '.php' ) === false && !empty($wp_query->query)) {
1161 - //get post for private
1162 - $query = $wp_query->query;
1163 - $query['post_status'] = 'private';
1164 - $r = new WP_Query( $query );
1165 - if ($r->have_posts()) {
1166 - if(!empty($r->post)){
1167 - $wp_query->posts = $r->posts;
1168 - $wp_query->post = $r->post;
1169 329 }
1170 - } else {
1171 - //カスタムステータスがまだ登録されてない状態でも取得 posts 情報がクリアされないよう抑制
1172 - add_filter( 'map_meta_cap', array('Plf_filter', 'exclude_map_meta_cap'), 10, 4 );
1173 - $query['post_status'] = 'any';
1174 - $r = new WP_Query( $query );
1175 - if ($r->have_posts()) {
1176 - if(!empty($r->post)){
1177 - $wp_query->posts = $r->posts;
1178 - $wp_query->post = $r->post;
330 + if(empty($single_opt) || $single_opt['filter'] === 'default'){
331 + if(!empty($filter['group'][$devtype]['plugins'])){
332 + if(false !== strpos($filter['group'][$devtype]['plugins'], $p_key))
333 + $dis_dev = false;
334 + else if(strpos($p_key, 'jetpack/') !== false && strpos($filter['group'][$type]['plugins'], 'jetpack_module/') !== false)
335 + $dis_dev = false;
336 + else if(strpos($p_key, 'celtispack/') !== false && strpos($filter['group'][$type]['plugins'], 'celtispack_module/') !== false)
337 + $dis_dev = false;
1179 338 }
1180 339 }
1181 - }
1182 - }
1183 - if(empty($wp_query->post)){
1184 - $unknown = true;
1185 - }
1186 - }
1187 - }
1188 -
1189 - $single_opt = array();
1190 - if(is_singular() && is_object($wp_query->post)){
1191 - self::$pre_post_id = $wp_query->post->ID; //for post_locale()
1192 - $myfilter = get_post_meta( $wp_query->post->ID, '_plugin_load_filter', true );
1193 - $default = array( 'filter' => 'default', 'desktop' => '', 'mobile' => '');
1194 - $single_opt = (!empty($myfilter))? $myfilter : $default;
1195 - $single_opt = wp_parse_args( $single_opt, $default);
1196 - }
1197 - if(!empty(self::$s_url_filter)){
1198 - //Addon frontend URL filtering
1199 - //個別フィルター有効なシングラーは URL filtering 無効(個別フィルター優先)
1200 - if(empty($single_opt) || $single_opt['filter'] === 'default'){
1201 - foreach (self::$s_url_filter as $key => $v) {
1202 - if(!empty($v)){
1203 - $groupkey = self::is_url_match( $req_url, $parse_url, $v );
1204 - if($groupkey !== false) {
1205 - self::$is_filterkey = 'url-group-filter : ' . $groupkey;
1206 - $new_plugins = self::filter_to_active_plugins( $groupkey, $filter, $option, $act_plugins );
1207 - self::$cache[$keyid][$option] = $new_plugins;
1208 - foreach ($new_plugins as $key) {
1209 - if(!empty($key)){
1210 - $key = self::plugin_keygen( $key, $option );
1211 - self::$filtered_plugins[$key] = $key;
340 + if(!$dis_dev){
341 + //oEmbed Content API
342 + if(function_exists('is_embed') && is_embed()){
343 + $type = 'content-card';
344 + if(!empty($filter['group'][$type]['plugins'])){
345 + if(false !== strpos($filter['group'][$type]['plugins'], $p_key))
346 + $unload = false;
347 + else if(strpos($p_key, 'jetpack/') !== false && strpos($filter['group'][$type]['plugins'], 'jetpack_module/') !== false)
348 + $unload = false;
349 + else if(strpos($p_key, 'celtispack/') !== false && strpos($filter['group'][$type]['plugins'], 'celtispack_module/') !== false)
350 + $unload = false;
1212 351 }
1213 352 }
1214 - return $new_plugins;
1215 - }
1216 - }
1217 - }
1218 - }
1219 - }
1220 - if($unknown || empty($parse_url['path']) || strpos($parse_url['path'], '/wp-cron' ) !== false || strpos($parse_url['path'], '/wp-json' ) !== false || (!empty($parse_url['query']) && strpos($parse_url['query'], 'rest_route=' ) !== false )){
1221 - //url filter 処理後、REST api, cron, フィルター対象外の不明なリクエストはフィルタリング処理を行わない
1222 - return false;
1223 - }
1224 -
1225 - //plf standard filtering
1226 - $type = false;
1227 - if(!empty($filter['_pagefilter']['plugins'])){
1228 - if(is_embed()){
1229 - $type = 'content-card';
1230 - } elseif(is_home() || is_front_page()){
1231 - $type = 'home';
1232 - } elseif(is_archive()) {
1233 - $type = 'archive';
1234 - } elseif(is_search()) {
1235 - $type = 'search';
1236 - } elseif(is_attachment()) {
1237 - $type = 'attachment';
1238 - } elseif(is_page()) {
1239 - $type = 'page';
1240 - } elseif(is_single()){ //Post & Custom Post
1241 - $type = get_post_type( $wp_query->post);
1242 - //bbPress private (非公開)ページ時のポストタイプ取得
1243 - if($type === false && isset($wp_query->query_vars['post_type'])){
1244 - $type = $wp_query->query_vars['post_type'];
1245 - }
1246 - if($type === 'post'){
1247 - $fmt = get_post_format( $wp_query->post);
1248 - $type = ($fmt === 'standard' || $fmt == false)? 'post' : "post-$fmt";
1249 - }
1250 - } else {
1251 - $type = 'unknown';
1252 - }
1253 - self::$is_filterkey = 'page-type-filter : ' . $type;
1254 - if(is_singular()){
1255 - if(!empty($single_opt) && $single_opt['filter'] === 'include'){
1256 - self::$is_filterkey = 'page-type-filter : Single page option';
1257 - }
1258 - }
1259 - } elseif(!empty($filter['_admin']['plugins'])){
1260 - //Page Type 未指定時は admin type 除外フィルターのみ
1261 - self::$is_filterkey = 'page-type-filter : admin filter';
1262 - }
1263 -
1264 - $new_plugins = array();
1265 - foreach ( $act_plugins as $item ) {
1266 - if(!empty($item)){
1267 - $unload = false;
1268 - $p_key = self::plugin_keygen( $item, $option );
1269 - //admin filter
1270 - if(!empty($filter['_admin']['plugins'])){
1271 - if(in_array($p_key, array_map("trim", explode(',', $filter['_admin']['plugins'])))){
1272 - $unload = true;
1273 - }
1274 - }
1275 - //page filter
1276 - if(!$unload){
1277 - if(!empty($filter['_pagefilter']['plugins'])){
1278 - if(in_array($p_key, array_map("trim", explode(',', $filter['_pagefilter']['plugins'])))){
1279 - $unload = true;
1280 -
1281 - //desktop/mobile device disable filter
1282 - $dis_dev = true;
1283 - if(is_singular() && is_object($wp_query->post)){
1284 - if(!empty($single_opt) && $single_opt['filter'] === 'include'){
1285 - if(!empty($single_opt[$devtype])){
1286 - if(false !== strpos($single_opt[$devtype], $p_key))
1287 - $dis_dev = false;
1288 - elseif(strpos($p_key, 'jetpack/') !== false && strpos($single_opt[$devtype], 'jetpack_module/') !== false)
1289 - $dis_dev = false;
1290 - elseif(strpos($p_key, 'celtispack/') !== false && strpos($single_opt[$devtype], 'celtispack_module/') !== false)
1291 - $dis_dev = false;
353 + else {
354 + $pgfopt = false;
355 + if(is_singular()){
356 + if(!empty($single_opt) && $single_opt['filter'] === 'include'){
357 + $pgfopt = true;
358 + if(false !== strpos($single_opt[$devtype], $p_key)){
359 + $unload = false;
360 + }
361 + else {
362 + //Enable plugin because plugin module is selected
363 + if(strpos($p_key, 'jetpack/') !== false && strpos($single_opt[$devtype], 'jetpack_module/') !== false)
364 + $unload = false;
365 + else if(strpos($p_key, 'celtispack/') !== false && strpos($single_opt[$devtype], 'celtispack_module/') !== false)
366 + $unload = false;
367 +
368 + }
1292 369 }
1293 370 }
1294 - }
1295 - if(empty($single_opt) || $single_opt['filter'] === 'default'){
1296 - if(!empty($filter['group'][$devtype]['plugins'])){
1297 - if(false !== strpos($filter['group'][$devtype]['plugins'], $p_key))
1298 - $dis_dev = false;
1299 - elseif(strpos($p_key, 'jetpack/') !== false && strpos($filter['group'][$devtype]['plugins'], 'jetpack_module/') !== false)
1300 - $dis_dev = false;
1301 - elseif(strpos($p_key, 'celtispack/') !== false && strpos($filter['group'][$devtype]['plugins'], 'celtispack_module/') !== false)
1302 - $dis_dev = false;
1303 - }
1304 - }
1305 - if(!$dis_dev){
1306 - //oEmbed Content API
1307 - if(is_embed()){
1308 - if(!empty($type) && !empty($filter['group'][$type]['plugins'])){
1309 - if(false !== strpos($filter['group'][$type]['plugins'], $p_key))
1310 - $unload = false;
1311 - elseif(strpos($p_key, 'jetpack/') !== false && strpos($filter['group'][$type]['plugins'], 'jetpack_module/') !== false)
1312 - $unload = false;
1313 - elseif(strpos($p_key, 'celtispack/') !== false && strpos($filter['group'][$type]['plugins'], 'celtispack_module/') !== false)
1314 - $unload = false;
1315 - }
1316 - } else {
1317 - $pgfopt = false;
1318 - if(is_singular()){
1319 - if(!empty($single_opt) && $single_opt['filter'] === 'include'){
1320 - $pgfopt = true;
1321 - if(!empty($single_opt[$devtype])){
1322 - if(false !== strpos($single_opt[$devtype], $p_key)){
1323 - $unload = false;
1324 - } else {
1325 - //Enable plugin because plugin module is selected
1326 - if(strpos($p_key, 'jetpack/') !== false && strpos($single_opt[$devtype], 'jetpack_module/') !== false)
1327 - $unload = false;
1328 - elseif(strpos($p_key, 'celtispack/') !== false && strpos($single_opt[$devtype], 'celtispack_module/') !== false)
1329 - $unload = false;
1330 - }
1331 - }
371 + if($pgfopt === false){
372 + $type = false;
373 + if(is_home() || is_front_page())
374 + $type = 'home';
375 + elseif(is_archive())
376 + $type = 'archive';
377 + elseif(is_search())
378 + $type = 'search';
379 + elseif(is_attachment())
380 + $type = 'attachment';
381 + elseif(is_page())
382 + $type = 'page';
383 + elseif(is_single()){ //Post & Custom Post
384 + $type = get_post_type( $wp_query->post);
385 + if($type === 'post'){
386 + $fmt = get_post_format( $wp_query->post);
387 + $type = ($fmt === 'standard' || $fmt == false)? 'post' : "post-$fmt";
1332 388 }
1333 389 }
1334 - if($pgfopt === false){
1335 - if(!empty($type) && !empty($filter['group'][$type]['plugins'])){
1336 - if(in_array($p_key, array_map("trim", explode(',', $filter['group'][$type]['plugins'])))){
390 + if($type !== false && !empty($filter['group'][$type]['plugins'])){
391 + if(in_array($p_key, array_map("trim", explode(',', $filter['group'][$type]['plugins']))))
392 + $unload = false;
393 + else {
394 + if(strpos($p_key, 'jetpack/') !== false && strpos($filter['group'][$type]['plugins'], 'jetpack_module/') !== false)
1337 395 $unload = false;
1338 - } else {
1339 - if(strpos($p_key, 'jetpack/') !== false && strpos($filter['group'][$type]['plugins'], 'jetpack_module/') !== false)
1340 - $unload = false;
1341 - else if(strpos($p_key, 'celtispack/') !== false && strpos($filter['group'][$type]['plugins'], 'celtispack_module/') !== false)
1342 - $unload = false;
1343 - }
396 + else if(strpos($p_key, 'celtispack/') !== false && strpos($filter['group'][$type]['plugins'], 'celtispack_module/') !== false)
397 + $unload = false;
1344 398 }
1345 399 }
1346 400 }
1347 401 }
@@ -1347,28 +401,13 @@
1347 401 }
1348 402 }
1349 403 }
1350 404 }
1351 - if(!$unload) {
1352 - if($option === 'active_sitewide_plugins') {
1353 - // v4.0.6 $new_plugins[$item] = $opt_value[$item];
1354 - $new_plugins[$item] = $item;
1355 - } else {
1356 - $new_plugins[] = $item;
1357 - }
1358 - }
1359 405 }
1360 - }
1361 -
1362 - //https://wordpress.org/support/topic/function-to-retriev-user-before-init-hook-is-fired/
1363 - $new_plugins = apply_filters('plf_custom_changes_to_active_plugins', $new_plugins);
1364 -
1365 - self::$cache[$keyid][$option] = $new_plugins;
1366 - foreach ($new_plugins as $key) {
1367 - if(!empty($key)){
1368 - $key = self::plugin_keygen( $key, $option );
1369 - self::$filtered_plugins[$key] = $key;
406 + if(!$unload) {
407 + $new_value[] = $item;
1370 408 }
1371 409 }
1372 - return $new_plugins;
410 + $this->cache[$keyid][$option] = $new_value;
411 + return apply_filters( 'option_' . $option, $new_value );
1373 412 }
1374 413 }