PluginProbe
Blog Floating Button / trunk
Blog Floating Button vtrunk
trunk 1.4.10 1.4.11 1.4.12 1.4.13 1.4.14 1.4.15 1.4.16 1.4.17 1.4.18 1.4.19 1.4.20 1.4.21 1.4.7 1.4.8 1.4.9
blog-floating-button / blog-floating-button.php

blog-floating-button.php in Blog Floating Button trunk, at blog-floating-button.php

1,758 lines 64.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /*
3 Plugin Name: Blog Floating Button
4 Plugin URI: https://bfb-plugin.com/
5 Description: 「Blog Floating Button(BFB)」はブログ�
6 にフロートボタンを簡単に実�
7 できるプラグインです。
8 Version: 1.4.21
9 Author: Meril Inc.
10 Author URI: https://meril.co.jp/
11 License: GPL2
12 */
13 ?>
14 <?php
15
16 if ( ! defined( 'ABSPATH' ) ) {
17 exit;
18 }
19
20 define( 'BFB_PLUGIN_VERSION', '1.4.21' );
21
22 #[AllowDynamicProperties] // PHP8.2対応
23 class BlogFloatingButton {
24
25 const PLUGIN_PATH = __FILE__;// プラグインディレクトリパス
26 public $metadate = array();
27 private $get_license_key_status_url = 'https://bfb-plugin.com/api/function/get_license_key_status.php';
28 private $get_license_key_optimize_status_url = 'https://bfb-plugin.com/api/function/get_license_key_optimize_status.php';
29 private $get_admin_ad_url = 'https://bfb-plugin.com/api/function/get_admin_ad.php';
30 private $echo_bfb_optimize_url = '/wp-json/bfb/api/echo_bfb_optimize';
31 private $js_is_pro = 0;
32 private $js_is_autohide = 0;
33
34 public $is_activation = false;
35 public $is_activation_optimize = false;
36 private $echo_bfb_num = 0;
37
38 public $abtest_message = '<p style="font-size:0.8em; margin-top:40px;">ABテスト稼働中は、こちらのプレビューは無効になります。該当のABテスト�
39 でプレビューをご確認ください。<br>こちらで設定したプレビューを表示したい場合は、ABテストを「実施しない」に変更してください。</p>';
40
41 public $devices = array( 'pc', 'sp' );
42 public $devicesName = array(
43 'pc' => 'PC',
44 'sp' => 'スマホ',
45 );
46 public $designTypes = array( 'textBtn', 'textTextBtn', 'textBtnTextBtn', 'imgBanner' );
47 public $designNames = array(
48 'textBtn' => 'ボタン単体',
49 'textTextBtn' => '説明文+ボタン',
50 'textBtnTextBtn' => 'ボタン+ボタン',
51 'imgBanner' => 'バナー画像',
52 );
53 public $btnItems = array(
54 'topText' => array( 'max50' ), // トップテキスト
55 'topTextColorPicker' => array( 'colorCode' ), // トップテキスト色ピッカー
56 'discText' => array( 'max80' ), // 説明文
57 'discTextColorPicker' => array( 'colorCode' ), // 説明文色ピッカー
58 'btnType' => array( 'w', 'max30' ), // ボタン形状
59 'btnText' => array( 'max30' ), // ボタンテキスト
60 'btnTextColorPicker' => array( 'colorCode' ), // ボタンテキスト色ピッカー
61 'btnColor' => array( 'w' ), // ボタン色
62 'btnColorPicker' => array( 'colorCode' ), // ボタンピックカラー
63 'btnColorLighten' => array( 'num' ), // グラデーション明度
64 'linkUrl' => array( 'url', 'max500' ), // リンク�
65 �URL
66 'linkTarget' => array( 'w' ), // リンクターゲット
67 'linkRel' => array( 'w' ), // rel属性
68 'btnText2' => array( 'max30' ), // ボタンテキスト2
69 'btnTextColorPicker2' => array( 'colorCode' ), // ボタンテキスト色ピッカー2
70 'btnColor2' => array( 'w' ), // ボタン色2
71 'btnColorPicker2' => array( 'colorCode' ), // ボタンピックカラー2
72 'btnColorLighten2' => array( 'num' ), // グラデーション明度2
73 'linkUrl2' => array( 'url', 'max500' ), // リンク�
74 �URL
75 'linkTarget2' => array( 'w' ), // リンクターゲット
76 'linkRel2' => array( 'w' ), // rel属性
77 'bfbBgColor' => array( 'w' ), // 背景色
78 'bfbBgColorPicker' => array( 'colorCode' ), // 背景ピックカラー
79 'bfbPos' => array( 'hw' ), // 表示位置
80 'bannerUrl' => array( 'url' ), // 画像URL
81 'trackingMemo' => array( 'max200' ), // クリック測定時に使えるメモ
82 'trackingMemo2' => array( 'max200' ), // クリック測定時に使えるメモ2
83 );
84 // �
85 �通設定(デバイス別の設定なし)
86 public $commonItems = array(
87 'bfb_exclude_toppage' => array( 'w' ), // トップページの表示方法
88 'bfb_exclude_post_ids' => array( 'hw' ), // 除外投稿ID
89 'bfb_license_key' => array( 'license_key' ), // ライセンスキー
90 'bfb_license_key_optimize' => array( 'license_key' ), // A/Bテスト専用ライセンスキー
91 'bfb_mode' => array( 'w' ), // 開発モード
92 'bfb_autohide' => array( 'w' ), // 自動非表示
93 'bfb_cookie_hide_span' => array( 'int' ), // Cookie非表示期間
94 'bfb_clickAnalyze' => array( 'w' ), // クリック計測の有効
95 'bfb_clickAnalyze_exclude_admin' => array( 'w' ), // クリック計測の管理�
96 除外
97 'bfb_hidden_pages' => array( 'w' ), // 非表示ページ
98 'bfb_retention_period' => array( 'w' ), // 解析レポートの保存期間
99 );
100 // BFBデザイン�
101 目(デバイス別に設定)
102 // bfb_designType.'_'.$device
103 public $bfbDesignItems = array(
104 'bfb_designType' => array( 'w' ),
105 'bfb_fontSize' => array( 'num' ),
106 'innerBfb_PaddingTop' => array( 'num' ), // BFB�
107 �体の上下余白
108 'innerBfb_PaddingLeft' => array( 'num' ), // BFB�
109 �体の左右余白
110 'topText_bottom' => array( 'num' ), // マイクロコピー下の余白
111 'bfbBtnPaddingTopBottom' => array( 'num' ), // BFB�
112 のボタンの上下余白
113 'bfb_optId' => array( 'w', 'max32' ), // ABテストID
114 'bfb_showing_area' => array( 'int' ), // [bfb_show]以降に表示する領域
115 );
116 // SCSSで使用する�
117 目で初期値
118 private $scssItems = array(
119 'device' => 'pc',
120 'designType' => 'textBtn',
121 'topTextColorPicker' => '#fff', // トップテキスト色ピッカー
122 'discTextColorPicker' => '#fff', // 説明文色ピッカー
123 'btnTextColorPicker' => '#fff', // ボタンテキスト色ピッカー
124 'btnTextColorPicker2' => '#fff', // ボタンテキスト色ピッカー2
125 'btnColor' => '#ea6103',
126 'btnColor2' => '#009f07',
127 'btnColorLighten' => '0.1',
128 'btnColorLighten2' => '0.1',
129 'bfbBgColor' => '#000',
130 'bfb_fontSize_pc' => '14',
131 'bfb_fontSize_sp' => '14',
132 'innerBfb_PaddingTop_pc' => '10',
133 'innerBfb_PaddingLeft_pc' => '10',
134 'topText_bottom_pc' => '5',
135 'bfbBtnPaddingTopBottom_pc' => '10',
136 'innerBfb_PaddingTop_sp' => '10',
137 'innerBfb_PaddingLeft_sp' => '10',
138 'topText_bottom_sp' => '5',
139 'bfbBtnPaddingTopBottom_sp' => '10',
140 'optimize_preview' => 'false',
141 );
142 // マイクロコピーと説明文のみ許可するHTML
143 // classなどは使えない
144 public $allowed_html = array(
145 'a' => array(),
146 'br' => array(),
147 'strong' => array(),
148 'b' => array(),
149 'div' => array(),
150 'span' => array(),
151 's' => array(),
152 'em' => array(),
153 );
154
155 public function __construct() {
156
157 global $pagenow;
158
159 // 管理�
160
161 add_action( 'admin_menu', array( $this, 'add_menu_page' ) );
162
163 require_once __DIR__ . '/function.php';
164 require_once __DIR__ . '/scssphp/scss.inc.php';
165 require_once __DIR__ . '/optimize.php'; // 最適化テスト
166 $this->opt = new Optimize();
167
168 if ( is_admin() ) {
169 $this->check_license_key();
170 $this->check_license_key_optimize();
171 } else {
172 add_action( 'wp_footer', array( &$this, 'insertFooter' ), 999 );
173 }
174
175 $this->init_var(); // クラス変数を初期化
176
177 // pro版にのみショートコードを登録する (v1.4.16)
178 add_action( 'init', array( $this, 'bfb_register_shortcode_for_pro' ) );
179 }
180 // pro版にのみショートコードを登録する。タイミングの問題でアクティベーションチェックが�
181 要。(v1.4.16)
182 public function bfb_register_shortcode_for_pro() {
183 if ( $this->check_license_key() ) {
184 add_shortcode( 'bfb_show', 'bfb_show_position' );
185 add_shortcode( 'bfb_hide', 'bfb_hide_position' );
186 }
187 }
188
189 // 追跡フッターメイン
190 public function insertFooter( $device = null ) {
191
192 // エラー処理を追加 v1.4.20
193 // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_set_error_handler -- SCSSコンパイル中の警告を抑止する目的。�
194 �ての return 前で restore_error_handler() により復�
195 �している
196 set_error_handler(
197 function ( $errno, $errstr, $errfile, $errline ) {
198 // すべてのエラーを無視する
199 return true;
200 }
201 );
202
203 global $post;
204
205 // 管理画面ではCookieは無視
206 if ( ! is_admin() ) {
207 // cookieが記録されていれば、非表示
208 $cookie_bfb_closed = filter_input( INPUT_COOKIE, 'bfb_closed' );
209 $cookie_bfb_closed = $cookie_bfb_closed !== null ? htmlspecialchars( $cookie_bfb_closed, ENT_QUOTES, 'UTF-8' ) : '';
210
211 if ( $cookie_bfb_closed == 'true' ) {
212 restore_error_handler();
213 return false;
214 }
215 }
216
217 // 条件に応じてデータ読み込み
218 $this->read_metadata_condi();
219
220 // 管理�
221 のみ表示
222 if ( $this->get_metadata( 'bfb_mode' ) != 'open' ) {
223 if ( ! current_user_can( 'manage_options' ) ) {
224 restore_error_handler();
225 return false;
226 }
227 }
228
229 // トップのみ表示で、トップ以外なら非表示
230 // 管理画面では非表示にならない
231 if ( isset( $this->bfb_exclude_toppage ) && $this->bfb_exclude_toppage === 'show_top_only' && is_singular() ) {
232 if ( ! is_home() && ! is_front_page() ) {
233 restore_error_handler();
234 return '';
235 }
236 }
237
238 // トップページの表示/非表示
239 if ( is_home() || is_front_page() ) {
240 if ( isset( $this->bfb_exclude_toppage ) && $this->bfb_exclude_toppage === 'hide' ) {
241 restore_error_handler();
242 return '';
243 }
244 } else {
245
246 // トップページ以外の表示非表示
247 // 指定投稿IDは非表示
248 if ( isset( $this->bfb_exclude_post_ids ) ) {
249 $bfb_exclude_post_ids = explode( ',', $this->bfb_exclude_post_ids );
250 if ( count( $bfb_exclude_post_ids ) > 0 && isset( $post->ID ) ) {
251 if ( in_array( strval( $post->ID ), $bfb_exclude_post_ids, true ) ) {
252 restore_error_handler();
253 return '';
254 }
255 }
256 }
257 }
258
259 if ( ! $this->is_mobile() && $device != 'sp' ) {
260 $device = 'pc';
261 } else {
262 $device = 'sp';
263 }
264
265 // 管理画面以外では一回でPC、SPを両方出力
266 if ( ! is_admin() ) {
267
268 // 最適化テストでは直接出力しない
269 // キャッシュ対策のためajaxで出力
270 $this->init_optimize( 'pc' ); // 最適化データ読み込み
271 if ( empty( $this->{'bfb_optId_pc'} ) ) {
272 // PC出力
273 if ( isset( $this->optDatas['status'] ) && $this->optDatas['status'] != 1 ) {
274 // 最適化を停止していたら通常出力
275 $this->init_bfb( 'pc' ); // ボタン設定読み込み
276 $this->generate_btn_html( 'pc' ); // フロートボタンHTML生成
277 } elseif ( empty( $this->optDatas ) ) {
278 // A/Bテストをしていなければ通常表示
279 $this->init_bfb( 'pc' ); // ボタン設定読み込み
280 $this->generate_btn_html( 'pc' ); // フロートボタンHTML生成
281 }
282 } else {
283 $this->init_bfb( 'pc' ); // ボタン設定読み込み
284 $this->generate_btn_html( 'pc' ); // フロートボタンHTML生成
285 }
286
287 // 初期化
288 $this->optDatas = null;
289 $this->init_optimize( 'sp' ); // 最適化データ読み込み
290 if ( empty( $this->{'bfb_optId_sp'} ) ) {
291 // スマホ出力
292 // 最適化を停止していたら通常出力
293 if ( isset( $this->optDatas['status'] ) && $this->optDatas['status'] != 1 ) {
294 // 最適化を停止していたら通常出力
295 $this->init_bfb( 'sp' ); // ボタン設定読み込み
296 $this->generate_btn_html( 'sp' ); // フロートボタンHTML生成
297 } elseif ( empty( $this->optDatas ) ) {
298 // A/Bテストをしていなければ通常表示
299 $this->init_bfb( 'sp' ); // ボタン設定読み込み
300 $this->generate_btn_html( 'sp' ); // フロートボタンHTML生成
301 }
302 } else {
303 $this->init_bfb( 'sp' ); // ボタン設定読み込み
304 $this->generate_btn_html( 'sp' ); // フロートボタンHTML生成
305 }
306 } else {
307 // 管理画面のプレビュー
308 // ボタン設定を読み込み
309 $this->init_bfb( $device ); // ボタン設定読み込み
310 $this->generate_btn_html( $device ); // フロートボタンHTML生成
311 }
312
313 // 管理画面はスクリプトは表示しない
314 if ( is_admin() ) {
315 restore_error_handler();
316 return '';
317 }
318
319 if ( empty( $this->bfb_cookie_hide_span ) ) {
320 $bfb_cookie_hide_span = 7;
321 } else {
322 $bfb_cookie_hide_span = $this->bfb_cookie_hide_span;
323 }
324
325 // pro版の時出現ポイントの領域を取得する.無料版は値は使わないがダミーとして0を�
326 �れておく (v1.4.16)
327 if ( $this->check_license_key() ) {
328 if ( ! empty( $this->{'bfb_showing_area_' . $device} ) ) {
329 $bfb_showing_area = $this->{'bfb_showing_area_' . $device};
330 } else {
331 $bfb_showing_area = 300;
332 }
333 } else {
334 $bfb_showing_area = 0;
335 }
336
337 // jsからpro版かどうかの判定できるように変数を用意 (v1.4.16)
338 if ( $this->check_license_key() ) {
339 $js_is_pro = 1;
340 } else {
341 $js_is_pro = 0;
342 }
343
344 // jsから常に表示か下にスクロール時は非表示かを判定できるように変数を用意 (v1.4.16)
345 if ( isset( $this->bfb_autohide ) && $this->bfb_autohide != 'off' ) {
346 $js_is_autohide = 1;
347 } else {
348 $js_is_autohide = 0;
349 }
350
351 // jsの�
352 容を大�
353 変更 (v1.4.17)
354 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- スクリプト本体は固定で、動的な数値は wp_json_encode() 済み
355 echo $this->delete_br(
356 '
357 <script type="text/javascript">
358 jQuery(function($){
359 $(window).on("load", function() {
360 var windowHeight = $(window).height();
361 var scrollCnt = 0;
362 var startPos = 0;
363 var scrollTop = 0;
364 var bfb_show_pos = 0;
365 var bfb_hide_pos = 99999999;
366 var bfb_showing_area = ' . wp_json_encode( (int) $bfb_showing_area ) . ';
367 var is_autohide = ' . wp_json_encode( (int) $js_is_autohide ) . ';
368 var is_pro = ' . wp_json_encode( (int) $js_is_pro ) . ';
369 var has_show_pos = 0;
370 var has_hide_pos = 0;
371
372 /* bfb_showがある場合、 表示領域が有効になる*/
373 if ($("#bfb_show_position").length) {
374 bfb_show_pos = $("#bfb_show_position").offset().top;
375 has_show_pos = 1;
376 }
377
378 /* bfb_showがある場合、 非表示にするタイミングを決める。bfb_hideを優�
379 �。*/
380 if (has_show_pos == 1){
381 if ($("#bfb_hide_position").length) {
382 bfb_hide_pos = $("#bfb_hide_position").offset().top;
383 }else{
384 bfb_hide_pos = bfb_show_pos + bfb_showing_area;
385 }
386 }
387
388 /* 表示/非表示を管理する関数 */
389 function toggleDisplay() {
390 scrollTop = $(window).scrollTop();
391 scrollCnt++;
392 var $contentElements = $("[id^=\'bfb_content_\']");
393
394 if (is_autohide == 0) {
395 /* 常に表示の場合 */
396 if (is_pro == 0) {
397 /* proでない場合は常に表示 */
398 $contentElements.css({"cssText": "display: block;"}).removeClass("bfb_hide");
399 } else {
400 /* proの場合 */
401 if (has_show_pos) {
402 if (bfb_show_pos < (scrollTop + windowHeight) && bfb_hide_pos > (scrollTop + windowHeight)) {
403 $contentElements.css({"cssText": "display: block;"}).removeClass("bfb_hide");
404 } else {
405 $contentElements.addClass("bfb_hide");
406 }
407 } else {
408 /* has_show_posがない場合は常に表示 */
409 $contentElements.css({"cssText": "display: block;"}).removeClass("bfb_hide");
410 }
411 }
412 } else {
413 /* 下にスクロール時は非表示の場合 */
414 if (is_pro == 0) {
415 /* pro版でない場合 */
416 if (scrollTop < startPos) {
417 $contentElements.css({"cssText": "display: block;"}).removeClass("bfb_hide");
418 } else if (10 < scrollCnt) {
419 $contentElements.addClass("bfb_hide");
420 scrollCnt = 0;
421 }
422 } else {
423 /* pro版の場合 */
424 if (has_show_pos) {
425 if (bfb_show_pos < (scrollTop + windowHeight) && bfb_hide_pos > (scrollTop + windowHeight)) {
426 $contentElements.css({"cssText": "display: block;"}).removeClass("bfb_hide");
427 } else {
428 $contentElements.addClass("bfb_hide");
429 }
430 }else{
431 if (scrollTop < startPos) {
432 $contentElements.css({"cssText": "display: block;"}).removeClass("bfb_hide");
433 } else if (10 < scrollCnt) {
434 $contentElements.addClass("bfb_hide");
435 scrollCnt = 0;
436 }
437 }
438 }
439 }
440
441 startPos = scrollTop;
442 }
443
444 /* 読み込み時にもチェック */
445 toggleDisplay();
446
447 /* スクロールイベントでもチェック */
448 $(window).on("scroll", toggleDisplay);
449 });
450 });
451 </script>
452
453 '
454 );
455
456 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- スクリプト本体は固定で、動的な数値は wp_json_encode() 済み
457 echo $this->delete_br(
458 '
459
460 <script type="text/javascript">
461 jQuery(function($){
462
463 $(document).on(\'click touchend\',\'[id^="bfb_content_"] .bfb_closed\',function(){
464 $(\'[id^="bfb_content_"]\').html("");
465 $.cookie("bfb_closed", "true", { expires: ' . wp_json_encode( (int) $bfb_cookie_hide_span ) . ' });
466 });
467
468 });
469 </script>
470
471 '
472 );
473
474 // 最適化テスト中
475 if ( ! empty( $this->{'bfb_optId_pc'} ) || ! empty( $this->{'bfb_optId_sp'} ) ) {
476
477 foreach ( $this->devices as $device ) {
478
479 // 初期化
480 $this->init_optimize( $device );
481
482 if ( ! empty( $this->{'bfb_optId_' . $device} ) ) {
483 // 最適化テストではキャッシュ対策のためajaxで出力
484
485 // [bfb_show]があれば初期表示しない
486 $bfb_display_ajax = ! $this->is_bfb_show();
487
488 $this->{'optimize_type_' . $device} = $this->optDatas['optimizeBtn']; // tracking_js.phpで使用
489
490 $ajax_data = array(
491 'device' => $device,
492 'post_id' => isset( $post->ID ) ? (int) $post->ID : 0,
493 'optimize_id' => $this->{'bfb_optId_' . $device},
494 'optimizeBtn' => $this->{'optimize_type_' . $device},
495 );
496 if ( is_singular() ) {
497 // 個別記事、固定ページ
498 $ajax_data['page_type'] = 'single';
499 }
500
501 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- スクリプト本体は固定で、動的な値は wp_json_encode() 済み
502 echo $this->delete_br(
503 '<script type="text/javascript">
504 jQuery(function($){
505 var bfbDevice = ' . wp_json_encode( $device, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT ) . ';
506 var bfbDisplayAjax = ' . wp_json_encode( $bfb_display_ajax ) . ';
507 try{
508 jQuery.ajax({
509 url: ' . wp_json_encode( site_url( $this->echo_bfb_optimize_url ), JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT ) . ',
510 type: "post",
511 data: ' . wp_json_encode( $ajax_data, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT ) . ',
512 }).done(function(res){
513 if( bfbDevice === "sp" ){
514 /*SPはPCを�
515 機して表示*/
516 var is_bfb_sp_show = setInterval(function(){
517 if( jQuery(\'[id^="bfb_content_pc"]\').length ){
518 jQuery("body").append(res);
519 if ( bfbDisplayAjax ) {
520 $(\'[id^="bfb_content_"]\').css({"cssText": "display: block;"});
521 }
522 clearInterval(is_bfb_sp_show);
523 }
524 }, 1000);
525 }else{
526 jQuery("body").append(res);
527 if ( bfbDisplayAjax ) {
528 $(\'[id^="bfb_content_"]\').css({"cssText": "display: block;"});
529 }
530 }
531 }).fail(function(res){
532 }).always(function(res){
533 });
534 }catch(e) {
535 }
536 });
537 </script>'
538 );
539 }
540 }
541 }
542
543 if ( isset( $this->bfb_clickAnalyze ) && $this->bfb_clickAnalyze != 'off' ) {
544 if ( $this->bfb_clickAnalyze_exclude_admin != 'on' && current_user_can( 'manage_options' ) ) {
545 require_once __DIR__ . '/inc/tracking_js.php';
546 } elseif ( ! current_user_can( 'manage_options' ) ) {
547 require_once __DIR__ . '/inc/tracking_js.php';
548 }
549 }
550 // エラー処理を追加 v1.4.20
551 restore_error_handler();
552 }
553
554 // 変数の初期化
555 protected function init_var() {
556
557 foreach ( $this->devices as $device ) {
558 foreach ( $this->designTypes as $designType ) {
559 foreach ( $this->btnItems as $btnItem => $validates ) {
560 $this->{'bfb' . '_' . $designType . '_' . $btnItem . '_' . $device} = '';
561 }
562 }
563 foreach ( $this->bfbDesignItems as $bfbDesignItem => $validates ) {
564 $this->{$bfbDesignItem . '_' . $device} = '';
565 }
566 }
567 }
568
569 // 条件に応じてデータ読み込み
570 public function read_metadata_condi( $post_id = null, $post_type = null ) {
571
572 global $post, $pagenow, $category;
573 $is_read = false; // データ読み込みフラグ
574
575 if ( isset( $post->ID ) ) {
576 $post_id = $post->ID;
577 }
578
579 // 設定データの読み込み
580 if ( is_singular() || $post_type == 'single' ) {
581 if ( get_post_meta( $post_id, 'bfb_use_post', true ) == 'true' ) {
582 // 個別記事の設定を優�
583
584 $this->read_metadata( $post_id, 'single' );
585 } elseif ( get_post_meta( $post_id, 'bfb_use_post', true ) == 'none' ) {
586 // 個別記事で表示しない
587 return false;
588 } else {
589 // 個別記事の「個別設定を優�
590 �」ではない
591 $category_ids = $this->get_categoryId( $post_id );
592 $i = 0;
593 if ( isset( $category_ids ) && count( $category_ids ) > 1 ) {
594 // 複数カテゴリーに所属
595 foreach ( $category_ids as $category_id ) {
596 $categiry_meta[ $i ] = get_option( "cat_$category_id", array() );
597 $categiry_meta[ $i ]['category_id'] = $category_id;
598 ++$i;
599 }
600 } else {
601 // 単一カテゴリーに所属
602 $categiry_meta[ $i ] = isset( $category_ids ) ? get_option( "cat_$category_ids[0]" ) : null;
603
604 // PHP8.1対応。$categiry_metaがfalseの場合、�
605 �列に変換する
606 if ( ! isset( $categiry_meta[ $i ] ) || ! is_array( $categiry_meta[ $i ] ) ) {
607 $categiry_meta[ $i ] = array();
608 }
609
610 $categiry_meta[ $i ]['category_id'] = isset( $category_ids ) ? $category_ids[0] : null;
611 }
612 if ( isset( $categiry_meta ) ) {
613 if ( $categiry_meta && count( $categiry_meta ) > 1 ) {
614 $sortedCategories = $this->init_categoryPriority( $categiry_meta, 'bfb_categoryPriority' );
615 if ( is_array( $sortedCategories[0] ) ) {
616 // 複数カテゴリー選択
617 foreach ( $sortedCategories as $key => $sortedCategory ) {
618 // 個別設定が有効なカテゴリーがあれば
619 if ( isset( $sortedCategory['bfb_use_category'] ) ) {
620 if ( $sortedCategory['bfb_use_category'] === 'true' ) {
621 $this->read_metadata( $sortedCategory['category_id'], 'category' );
622 $is_read = true;
623 break;
624 } elseif ( $sortedCategory['bfb_use_category'] === 'none' ) {
625 return false;
626 }
627 }
628 }
629 }
630 } elseif ( isset( $categiry_meta[0]['bfb_use_category'] ) ) {
631 if ( $categiry_meta[0]['bfb_use_category'] === 'true' ) {
632 // 単一カテゴリー
633 $this->read_metadata( $categiry_meta[0]['category_id'], 'category' );
634 $is_read = true;
635 } elseif ( $categiry_meta[0]['bfb_use_category'] === 'none' ) {
636 return false;
637 }
638 }
639 }
640
641 // データ読み込まれてなければ、�
642 �体設定を読み込み
643 if ( ! $is_read ) {
644 $this->read_metadata();
645 }
646 }
647 } elseif ( $pagenow == 'post.php' ) {
648 // 投稿画面
649 $this->read_metadata( $post_id, 'single' );
650 } elseif ( $pagenow == 'term.php' ) {
651 // カテゴリー設定画面
652 $get_tag_ID = filter_input( INPUT_GET, 'tag_ID', FILTER_VALIDATE_INT );
653 if ( $this->is_validate( $get_tag_ID, 'int' ) ) {
654 $this->read_metadata( $get_tag_ID, 'category' );
655 }
656 } else {
657 // トップページなどその他ページ
658 $bfb_hidden_pages = $this->get_metadata( 'bfb_hidden_pages' );
659
660 if ( is_array( $bfb_hidden_pages ) ) {
661 if ( is_category() && in_array( 'category', $bfb_hidden_pages, true ) ) {
662 return false;
663 } elseif ( is_tag() && in_array( 'tag', $bfb_hidden_pages, true ) ) {
664 return false;
665 } elseif ( is_search() && in_array( 'search', $bfb_hidden_pages, true ) ) {
666 return false;
667 } elseif ( is_author() && in_array( 'author', $bfb_hidden_pages, true ) ) {
668 return false;
669 } elseif ( is_404() && in_array( '404', $bfb_hidden_pages, true ) ) {
670 return false;
671 }
672 }
673
674 $this->read_metadata();
675 }
676 }
677
678 // プラグイン設定データの読み込み
679 // $post_idはカテゴリーではカテゴリーID
680 // $page_typeはsingle(個別記事)、category(カテゴリー)
681 public function read_metadata( $post_id = null, $page_type = null ) {
682
683 global $post, $pagenow;
684
685 foreach ( $this->commonItems as $commonItem => $validates ) {
686 $this->{$commonItem} = $this->get_metadata( $commonItem );
687 }
688
689 foreach ( $this->devices as $device ) {
690
691 // BFB�
692 �通デザイン
693 foreach ( $this->bfbDesignItems as $bfbDesignItems => $validates ) {
694 $this->{$bfbDesignItems . '_' . $device} = $this->get_metadata( $bfbDesignItems . '_' . $device );
695 }
696
697 if ( $post_id && $page_type == 'single' ) {
698 // 個別記事編集画面のみ
699 $this->bfb_use_post = get_post_meta( $post_id, 'bfb_use_post', true );
700 $this->{'bfb_designType_' . $device} = get_post_meta( $post_id, 'bfb_designType_' . $device, true );
701 $this->{'bfb_optId_' . $device} = get_post_meta( $post_id, 'bfb_optId_' . $device, true );
702
703 } elseif ( $post_id && $page_type == 'category' ) {
704 // カテゴリー編集
705 $category_meta = get_option( "cat_$post_id" );
706 if ( isset( $category_meta['bfb_use_category'] ) ) {
707 $this->bfb_use_category = $category_meta['bfb_use_category'];
708 } else {
709 $this->bfb_use_category = '';
710 }
711 if ( isset( $category_meta['bfb_categoryPriority'] ) ) {
712 $this->bfb_categoryPriority = $category_meta['bfb_categoryPriority'];
713 } else {
714 $this->bfb_categoryPriority = '';
715 }
716 if ( isset( $category_meta[ 'bfb_designType_' . $device ] ) ) {
717 $this->{'bfb_designType_' . $device} = $category_meta[ 'bfb_designType_' . $device ];
718 } else {
719 $this->{'bfb_designType_' . $device} = '';
720 }
721 if ( isset( $category_meta[ 'bfb_optId_' . $device ] ) ) {
722 $this->{'bfb_optId_' . $device} = $category_meta[ 'bfb_optId_' . $device ];
723 } else {
724 $this->{'bfb_optId_' . $device} = '';
725 }
726 } else {
727 $this->{'bfb_designType_' . $device} = $this->get_metadata( 'bfb_designType_' . $device );
728 }
729
730 foreach ( $this->designTypes as $designType ) {
731 foreach ( $this->btnItems as $item => $validates ) {
732
733 if ( $post_id && $page_type == 'single' ) {
734 $this->{'bfb_' . $designType . '_' . $item . '_' . $device} = get_post_meta( $post_id, 'bfb_' . $designType . '_' . $item . '_' . $device, true );
735 } elseif ( $post_id && $page_type == 'category' ) {
736 // カテゴリー編集
737 if ( isset( $category_meta[ 'bfb_' . $designType . '_' . $item . '_' . $device ] ) ) {
738 $this->{'bfb_' . $designType . '_' . $item . '_' . $device} = $category_meta[ 'bfb_' . $designType . '_' . $item . '_' . $device ];
739 } else {
740 $this->{'bfb_' . $designType . '_' . $item . '_' . $device} = '';
741 }
742 } else {
743 $this->{'bfb_' . $designType . '_' . $item . '_' . $device} = $this->get_metadata( 'bfb_' . $designType . '_' . $item . '_' . $device );
744 }
745 }
746 }
747 }
748 }
749 // 最適化データ読み込み
750 private function init_optimize( $device ) {
751 // **optDatasを確実に初期化**
752 $this->optDatas = array();
753
754 // 最適化テスト中
755 if ( ! empty( $this->{'bfb_optId_' . $device} ) ) {
756 $this->optDatas = $this->opt->read_optimize( $this->{'bfb_optId_' . $device} )[ $this->{'bfb_optId_' . $device} ];
757
758 $distribution_rate = $this->optDatas['distribution_rate'];
759
760 // 振り分け率:70なら70%でメインボタン
761 $opt_rand = wp_rand( 0, 100 );
762 if ( $opt_rand < $distribution_rate ) {
763 $this->optDatas['optimizeBtn'] = 'mainBtnDesign';
764 $this->optDatas['suf_optimizeBtn'] = '_opt_mainBtn';
765 } else {
766 $this->optDatas['optimizeBtn'] = 'subBtnDesign';
767 $this->optDatas['suf_optimizeBtn'] = '_opt_subBtn';
768 }
769
770 // ABCテスト稼働中以外ならABテストしない
771 if ( $this->optDatas['status'] != 1 ) {
772 $this->{'bfb_optId_' . $device} = '';
773 }
774 }
775 }
776
777 // 各ボタン設定の読み込み
778 public function init_bfb( $device ) {
779
780 $this->{'bfb_fontSize_' . $device} = $this->{'bfb_fontSize_' . $device}; //フォントサイズ
781 $this->designType = $this->{'bfb_designType_' . $device}; //BFBタイプ
782 $designType = $this->designType;
783
784 // ボタン設定
785 foreach ( $this->btnItems as $item => $validates ) {
786 if ( isset( $this->{'bfb_' . $designType . '_' . $item . '_' . $device} ) ) {
787 $this->{$item} = $this->{'bfb_' . $designType . '_' . $item . '_' . $device};
788 } else {
789 $this->{$item} = '';
790 }
791 }
792 $this->topText = '<div class="bfb_topText">' . wp_kses( $this->topText, $this->allowed_html ) . '</div>';
793 }
794
795 // フロートボタンHTML生成
796 public function generate_btn_html( $device, $preview_datas = null, $meta = null ) {
797
798 // $imagePath = plugins_url( 'images/', __FILE__ ); // 画像パス
799 $bfbDatas['device'] = $device;
800 $bfbDatas['optimize_id'] = ''; // A/Bテスト時のみ使用
801 $bfbDatas['optimize_type'] = ''; // A/Bテスト時のみ使用
802
803 // A/Bテスト専用ライセンスキーを無効にしても、ABテストが動いてしまうことを防ぐため、A/Bテスト専用ライセンスキーを無効であればテストIDを空にする
804 if ( is_admin() && ! $this->is_activation_optimize ) {
805 $this->{'bfb_optId_' . $device} = '';
806 }
807
808 // 管理画面でpro版の場合はライブプレビューをONにするフラグ
809 $admin_pro_flg = false;
810 if ( is_admin() && $this->is_activation ) {
811 $admin_pro_flg = true;
812 }
813
814 if ( ( ! $preview_datas && empty( $this->{'bfb_optId_' . $device} ) ) || $admin_pro_flg ) {
815 // ライブプレビュー以外かつ最適化テスト以外
816 // 本番、設定画面の初期表示
817 $bfbDatas['designType'] = $this->designType;
818
819 // フロートボタン�
820
821 foreach ( $this->btnItems as $item => $validates ) {
822 $bfbDatas[ $item ] = $this->{$item};
823 }
824 // 余白等のボタンデザイン
825 foreach ( $this->bfbDesignItems as $bfbDesignItem => $validates ) {
826 $bfbDatas[ $bfbDesignItem . '_' . $device ] = $this->{$bfbDesignItem . '_' . $device};
827 }
828
829 // 設定画面のプレビュー
830 if ( is_admin() ) {
831 $bfbDatas['optimize_preview'] = 'true'; // scssの�
832 �通部分を出力
833 }
834 } elseif ( ! empty( $this->{'bfb_optId_' . $device} ) && $this->{'bfb_optId_' . $device} != 'false' ) {
835 // 最適化テスト実施中
836 // ajaxで読み込み
837 // 管理画面でない(管理画面でABテストが行われていても、通常のボタンを表示する。ABテストボタンはABテストボタンページで確認してもらう)
838
839 $this->init_optimize( $device ); // 最適化データ読み込み
840
841 // 最適化ボタン種類は取得(アクセスログと
842 // ボタンタイプ(mainBtnDesignとsubBtnDesign)を合わせるため)
843
844 if ( ! empty( $meta['optimizeBtn'] ) && ! empty( $meta['suf_optimizeBtn'] ) ) {
845 // 本番の最適化
846 $optimizeBtn = $meta['optimizeBtn'];
847 $suf_optimizeBtn = $meta['suf_optimizeBtn'];
848 } else {
849 // 最適化が選択されているプレビュー
850 $optimizeBtn = $this->optDatas['optimizeBtn'];
851 $suf_optimizeBtn = $this->optDatas['suf_optimizeBtn'];
852 }
853
854 // フロートボタン�
855
856 foreach ( $this->btnItems as $item => $validates ) {
857 if ( isset( $this->optDatas[ 'bfb_' . $this->optDatas[ $optimizeBtn ] . '_' . $item . '_' . $device . $suf_optimizeBtn ] ) ) {
858 $bfbDatas[ $item ] = $this->optDatas[ 'bfb_' . $this->optDatas[ $optimizeBtn ] . '_' . $item . '_' . $device . $suf_optimizeBtn ];
859 } else {
860 $bfbDatas[ $item ] = '';
861 }
862 }
863
864 // 余白等のボタンデザイン
865 foreach ( $this->bfbDesignItems as $bfbDesignItem => $validates ) {
866 $bfbDatas[ $bfbDesignItem . '_' . $device ] = $this->{$bfbDesignItem . '_' . $device};
867 }
868
869 $bfbDatas['topText'] = '<div class="bfb_topText">' . wp_kses( $bfbDatas['topText'], $this->allowed_html ) . '</div>';
870 $bfbDatas['designType'] = $this->optDatas[ $optimizeBtn ];
871 $bfbDatas['optimize_id'] = $this->{'bfb_optId_' . $device};
872 $bfbDatas['optimize_type'] = $optimizeBtn;
873
874 // tracing_js.phpのクリック計測(アクセスログ)で使用
875 $this->optimize_id = $bfbDatas['optimize_id'];
876 $this->{'optimize_type_' . $device} = $bfbDatas['optimize_type'];
877
878 // キャッシュによりABテストできないためAjaxで読み込み
879 $bfbDatas['ajax_echo'] = true;
880
881 } else {
882 // 最適化テストが行われていない
883 // ライブプレビュー時
884 if ( isset( $preview_datas['designType'] ) ) {
885 $bfbDatas['designType'] = $preview_datas['designType'];
886 } else {
887 return false;
888 }
889 // ライブプレビュー判定
890 if ( isset( $preview_datas['live_preview'] ) ) {
891 $bfbDatas['live_preview'] = $preview_datas['live_preview'];
892 }
893
894 foreach ( $this->btnItems as $item => $validates ) {
895 if ( isset( $preview_datas[ $item ] ) ) {
896 $bfbDatas[ $item ] = $preview_datas[ $item ];
897 } else {
898 $bfbDatas[ $item ] = '';
899 }
900 }
901 foreach ( $this->devices as $device ) {
902 foreach ( $this->bfbDesignItems as $bfbDesignItem => $validates ) {
903 if ( isset( $preview_datas[ $bfbDesignItem . '_' . $device ] ) ) {
904 $bfbDatas[ $bfbDesignItem . '_' . $device ] = $preview_datas[ $bfbDesignItem . '_' . $device ];
905 } else {
906 $bfbDatas[ $bfbDesignItem . '_' . $device ] = '';
907 }
908 }
909 }
910
911 $bfbDatas['topText'] = '<div class="bfb_topText">' . wp_kses( $bfbDatas['topText'], $this->allowed_html ) . '</div>';
912
913 $bfbDatas['optimize_preview'] = 'true'; // scssの�
914 �通部分を出力
915
916 }
917
918 $bfbDatas['noopener'] = '';
919 $bfbDatas['noopener2'] = '';
920 if ( $bfbDatas['linkTarget'] == 'blank' ) {
921 $bfbDatas['noopener'] = 'noopener';
922 }
923 if ( $bfbDatas['linkTarget2'] == 'blank' ) {
924 $bfbDatas['noopener2'] = 'noopener';
925 }
926
927 // svgファイルを外部読み込みにすると、読み込み時間が異常に増えるのでコードを直接埋め込む
928 $svg_path = '<svg class="bfb_icon" version="1.1" aria-hidden="true" focusable="false" id="circle-arrow" class="circle-arrow" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="13px" height="13px" role="img" viewBox="0 0 496 496"><path fill="currentColor" d="M256,8C393,8,504,119,504,256S393,504,256,504,8,393,8,256,119,8,256,8ZM369.9,239,234.4,103.5a23.9,23.9,0,0,0-33.9,0l-17,17a23.9,23.9,0,0,0,0,33.9L285.1,256,183.5,357.6a23.9,23.9,0,0,0,0,33.9l17,17a23.9,23.9,0,0,0,33.9,0L369.9,273A24,24,0,0,0,369.9,239Z" /></svg>';
929
930 // ボタンHTML生成
931 if ( $bfbDatas['designType'] == 'textBtn' ) {
932 $btn_html = $bfbDatas['topText'] . '<a href="' . esc_url( $bfbDatas['linkUrl'] ) . '" class="bfb_btn bfb_' . esc_attr( $bfbDatas['btnColor'] ) . '" target="_' . esc_attr( $bfbDatas['linkTarget'] ) . '" rel="' . esc_attr( $bfbDatas['noopener'] ) . ' ' . esc_attr( $bfbDatas['linkRel'] ) . '" bfb-memo="' . esc_attr( $bfbDatas['trackingMemo'] ) . '" bfb-memo="' . esc_attr( $bfbDatas['trackingMemo'] ) . '" bfb-optimize-id="' . esc_attr( $bfbDatas['optimize_id'] ) . '" bfb-optimize-type="' . esc_attr( $bfbDatas['optimize_type'] ) . '">' . wp_kses( $bfbDatas['btnText'], $this->allowed_html ) . $svg_path . '</a>';
933 } elseif ( $bfbDatas['designType'] == 'textTextBtn' ) {
934 $btn_html = $bfbDatas['topText'] . '<div class="bfb_parts_2"><div class="bfb_discText">' . wp_kses( $bfbDatas['discText'], $this->allowed_html ) . '</div><a href="' . esc_url( $bfbDatas['linkUrl'] ) . '" class="bfb_btn bfb_' . esc_attr( $bfbDatas['btnColor'] ) . '" target="_' . esc_attr( $bfbDatas['linkTarget'] ) . '" rel="' . esc_attr( $bfbDatas['noopener'] ) . ' ' . esc_attr( $bfbDatas['linkRel'] ) . '" bfb-memo="' . esc_attr( $bfbDatas['trackingMemo'] ) . '" bfb-optimize-id="' . esc_attr( $bfbDatas['optimize_id'] ) . '" bfb-optimize-type="' . esc_attr( $bfbDatas['optimize_type'] ) . '">' . wp_kses( $bfbDatas['btnText'], $this->allowed_html ) . $svg_path . '</a></div>';
935 } elseif ( $bfbDatas['designType'] == 'textBtnTextBtn' ) {
936 $btn_html = $bfbDatas['topText'] . '<div class="bfb_parts_2"><a href="' . esc_url( $bfbDatas['linkUrl'] ) . '" class="bfb_btn bfb_' . esc_attr( $bfbDatas['btnColor'] ) . '" target="_' . esc_attr( $bfbDatas['linkTarget'] ) . '" rel="' . esc_attr( $bfbDatas['noopener'] ) . ' ' . esc_attr( $bfbDatas['linkRel'] ) . '" bfb-memo="' . esc_attr( $bfbDatas['trackingMemo'] ) . '" bfb-optimize-id="' . esc_attr( $bfbDatas['optimize_id'] ) . '" bfb-optimize-type="' . esc_attr( $bfbDatas['optimize_type'] ) . '">' . wp_kses( $bfbDatas['btnText'], $this->allowed_html ) . $svg_path . '</a><a href="' . esc_url( $bfbDatas['linkUrl2'] ) . '" class="bfb_btn2 bfb_' . esc_attr( $bfbDatas['btnColor2'] ) . '" target="_' . esc_attr( $bfbDatas['linkTarget2'] ) . '" rel="' . esc_attr( $bfbDatas['noopener2'] ) . ' ' . esc_attr( $bfbDatas['linkRel2'] ) . '" bfb-memo="' . esc_attr( $bfbDatas['trackingMemo2'] ) . '" bfb-optimize-id="' . esc_attr( $bfbDatas['optimize_id'] ) . '" bfb-optimize-type="' . esc_attr( $bfbDatas['optimize_type'] ) . '">' . wp_kses( $bfbDatas['btnText2'], $this->allowed_html ) . $svg_path . '</a></div>';
937 } elseif ( $bfbDatas['designType'] == 'imgBanner' ) {
938 $btn_html = '<a href="' . esc_url( $bfbDatas['linkUrl'] ) . '" target="_' . esc_attr( $bfbDatas['linkTarget'] ) . '" rel="' . esc_attr( $bfbDatas['noopener'] ) . ' ' . esc_attr( $bfbDatas['linkRel'] ) . '" bfb-memo="' . esc_attr( $bfbDatas['trackingMemo'] ) . '" bfb-optimize-id="' . esc_attr( $bfbDatas['optimize_id'] ) . '" bfb-optimize-type="' . esc_attr( $bfbDatas['optimize_type'] ) . '"><img src="' . esc_url( $bfbDatas['bannerUrl'] ) . '" alt=""></a>';
939 }
940
941 // PCで最適化テストしていたら
942 // SPは非表示→PCをajaxで出力
943 // PCで�
944 �通部分のCSSを出力
945 // CSS�
946 �通部分がないとSP表示が崩れる
947 $bfb_hide = '';
948 if ( ! empty( $this->{'bfb_optId_pc'} ) && $this->{'bfb_optId_pc'} != 'false' ) {
949 if ( ! is_admin() ) {
950 $bfb_hide = 'style="display: none !important;"';
951 }
952 } else {
953 $bfb_hide = '';
954 }
955
956 // 投稿、固定ページのみ動作
957 // 表示制御コード[bfb_show]があれば非表示
958 if ( $this->is_bfb_show() ) {
959 $bfb_hide = 'style="display: none !important;"';
960 }
961
962 // フロートボタン�
963 �体のHTML生成
964 $echo_html = '';
965 if ( $bfbDatas['designType'] != 'none' ) {
966 if ( $bfbDatas['designType'] == 'textBtn' ) {
967 $echo_html = '<div id="bfb_content_' . esc_attr( $bfbDatas['device'] ) . '" class="bfb_' . esc_attr( $bfbDatas['designType'] ) . ' bfb_' . esc_attr( $bfbDatas['btnType'] ) . ' bfb_view_' . esc_attr( $bfbDatas['device'] ) . '" ' . $bfb_hide . '><div class="inner_bfb"><div class="bfb_closed"><img src="' . plugin_dir_url( __FILE__ ) . 'images/closed.png" alt=""></div>' . $btn_html . '</div></div>';
968 } elseif ( $bfbDatas['designType'] == 'textTextBtn' || $bfbDatas['designType'] == 'textBtnTextBtn' ) {
969 $echo_html = '<div id="bfb_content_' . esc_attr( $bfbDatas['device'] ) . '" class="bfb_' . esc_attr( $bfbDatas['designType'] ) . ' bfb_' . esc_attr( $bfbDatas['btnType'] ) . ' bfb_view_' . esc_attr( $bfbDatas['device'] ) . '" ' . $bfb_hide . '><div class="inner_bfb"><div class="bfb_closed"><img src="' . plugin_dir_url( __FILE__ ) . 'images/closed.png" alt=""></div>' . $btn_html . '</div></div>';
970 } elseif ( $bfbDatas['designType'] == 'imgBanner' ) {
971 $echo_html = '<div id="bfb_content_' . esc_attr( $bfbDatas['device'] ) . '" class="bfb_' . esc_attr( $bfbDatas['designType'] ) . ' bfb_' . esc_attr( $bfbDatas['bfbPos'] ) . ' bfb_view_' . esc_attr( $bfbDatas['device'] ) . '" ' . $bfb_hide . '><div class="bfb_closed"><img src="' . plugin_dir_url( __FILE__ ) . 'images/closed.png" alt=""></div>' . $btn_html . '</div>';
972 }
973 }
974
975 $bfb_basic_scss = $this->init_scss( $bfbDatas, __DIR__ . '/css/bfb_basic.scss' );
976 $bfb_btn_scss = $this->init_scss( $bfbDatas, __DIR__ . '/css/bfb_btn.scss' );
977
978 $echo_html .= '<style type="text/css">';
979 $echo_html .= $this->delete_br( $this->compile_scss( $bfb_basic_scss ) );
980 $echo_html .= $this->delete_br( $this->compile_scss( $bfb_btn_scss ) );
981 $echo_html .= '</style>';
982
983 // 管理画面の場合
984 // 最適化テスト中であればプレビューを停止。それ以外は表示
985 if ( is_admin() ) {
986 $current_screen = get_current_screen();
987 // ABテスト結果画面ではABテスト実行中でもメッセージは出さずプレビューを出力する
988 if ( $current_screen && $current_screen->id === 'blog-floating-button_page_blog-floating-button-optimize-report' ) {
989 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- $echo_html は各値をコンテキスト別にエスケープ済みで、許可対象外の style/SVG/カスタム属性を含む生成済みマークアップ
990 echo $echo_html;
991 } elseif ( $admin_pro_flg && empty( $this->{'bfb_optId_' . $device} ) ) {
992 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- $echo_html は各値をコンテキスト別にエスケープ済みで、許可対象外の style/SVG/カスタム属性を含む生成済みマークアップ
993 echo $echo_html;
994 } else {
995 echo wp_kses_post( $this->abtest_message );
996 }
997 } elseif ( ( isset( $bfbDatas['live_preview'] ) && $bfbDatas['live_preview'] ) || ( isset( $bfbDatas['ajax_echo'] ) && $bfbDatas['ajax_echo'] ) ) {
998 return $echo_html;
999 } elseif ( empty( $this->{'bfb_optId_' . $bfbDatas['device']} ) ) {
1000 // ABテストでは出力しない
1001 // キャッシュによりABできないため
1002 // Ajaxで取得→出力
1003 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- $echo_html は各値をコンテキスト別にエスケープ済みで、許可対象外の style/SVG/カスタム属性を含む生成済みマークアップ
1004 echo $echo_html;
1005 }
1006 }
1007
1008 private function is_bfb_show() {
1009 if ( is_singular() ) {
1010 // 表示制御コード[bfb_show]があれば非表示
1011 $post_content = get_the_content();
1012 if ( strpos( $post_content, '[bfb_show]' ) > -1 ) {
1013 return true;
1014 }
1015 }
1016 return false;
1017 }
1018
1019 public function getUserMeta( $attr ) {
1020 return wp_get_current_user()->$attr;
1021 }
1022
1023 public function add_menu_page() {
1024
1025 $opt = new Optimize();
1026
1027 add_menu_page( 'Blog Floating Button', 'Blog Floating Button', 'manage_options', 'blog-floating-button', array( $this, 'option_page' ), '' );
1028 add_submenu_page( 'blog-floating-button', '設定', '設定', 'manage_options', 'blog-floating-button', array( $this, 'option_page' ) );
1029 add_submenu_page( 'blog-floating-button', '解析レポート', '解析レポート', 'manage_options', 'blog-floating-button-report', array( $this, 'report_page' ) );
1030
1031 if ( $this->is_activation_optimize ) {
1032 add_submenu_page( 'blog-floating-button', 'A/Bテスト', 'A/Bテスト', 'manage_options', 'blog-floating-button-optimize', array( $opt, 'optimize_page' ) );
1033 add_submenu_page( 'blog-floating-button', 'A/Bテスト結果', 'A/Bテスト結果', 'manage_options', 'blog-floating-button-optimize-report', array( $opt, 'optimize_report' ) );
1034 }
1035 }
1036
1037 public function option_page( $post_id = null ) {
1038
1039 global $pagenow, $hook_suffix;
1040
1041 // メディアップローダー
1042 wp_register_script(
1043 'MediaUpLoader',
1044 plugins_url( 'js/bfb_admin.js', __FILE__ ),
1045 array( 'jquery' ),
1046 BFB_PLUGIN_VERSION,
1047 true
1048 );
1049 wp_enqueue_media();
1050 wp_enqueue_script( 'MediaUpLoader' );
1051
1052 // BFB設定画面のみ保存
1053 // 個別投稿、カテゴリー画面は別関数で保存
1054 // bfb_save_fields(),bfb_save_category_fileds()
1055 if ( strpos( $hook_suffix, 'blog-floating-button' ) > -1 ) {
1056 // メタデータ保存
1057 $res = $this->save_metadata();
1058
1059 if ( $res ) {
1060 add_action( 'admin_notices', array( $this, 'updated_message' ) );
1061 do_action( 'admin_notices' );
1062 }
1063 }
1064
1065 if ( $pagenow == 'term.php' ) {
1066 // カテゴリー設定画面
1067 $this->read_metadata( $post_id, 'category' );
1068 } elseif ( $pagenow == 'post.php' ) {
1069 $this->read_metadata( $post_id, 'single' );
1070 } else {
1071 $this->read_metadata();
1072 }
1073
1074 include_once 'inc/setting_main.php';
1075 }
1076
1077 // クリック計測のレポート画面
1078 public function report_page() {
1079
1080 include_once 'tracking.php';
1081 $this->report = new Tracking();
1082
1083 include_once 'inc/report/report-main.php';
1084 }
1085
1086 // 設定保存
1087 public function save_metadata() {
1088
1089 // phpcs:ignore WordPress.Security.NonceVerification.Missing -- 直後の check_admin_referer() で検証している。nonce値自体を $_POST から取るため存在チェックが�
1090 �行するのは避けられない
1091 if ( ! $_POST ) {
1092 return false; }
1093
1094 // nonceを確認し値が正しくなければ何もしない
1095 if ( ! check_admin_referer( 'bfb_setting', '_wpnonce_bfb' ) ) {
1096 return false;
1097 }
1098
1099 // ボタン設定の保存
1100 foreach ( $this->devices as $device ) {
1101 foreach ( $this->designTypes as $designType ) {
1102 foreach ( $this->btnItems as $item => $validates ) {
1103
1104 $key = 'bfb_' . $designType . '_' . $item . '_' . $device;
1105 $postData = filter_input( INPUT_POST, $key );
1106
1107 if ( ( isset( $postData ) || $postData == '' ) && ! empty( $validates ) ) {
1108
1109 $is_validate = $this->check_validation( $postData, $validates );
1110
1111 if ( ! $is_validate ) {
1112 $this->validation_msg( $item );
1113 } else {
1114 update_option( $key, $postData );
1115 }
1116 }
1117 }
1118 }
1119 }
1120
1121 // �
1122 �通設定の保存
1123 foreach ( $this->commonItems as $item => $validates ) {
1124
1125 if ( $item == 'bfb_hidden_pages' ) {
1126 // データが�
1127 �列の場合
1128 $postData = filter_input( INPUT_POST, $item, FILTER_DEFAULT, FILTER_REQUIRE_ARRAY );
1129 } else {
1130 $postData = filter_input( INPUT_POST, $item );
1131 }
1132
1133 if ( isset( $postData ) || $postData == '' ) {
1134 if ( ! empty( $validates ) ) {
1135 $is_validate = $this->check_validation( $postData, $validates );
1136 if ( ! $is_validate ) {
1137 $this->validation_msg( $item );
1138 } else {
1139 update_option( $item, $postData );
1140 }
1141 }
1142 }
1143 }
1144
1145 // ボタン余白等の保存
1146 foreach ( $this->devices as $device ) {
1147 foreach ( $this->bfbDesignItems as $item => $validates ) {
1148
1149 $key = $item . '_' . $device;
1150 $postData = filter_input( INPUT_POST, $key );
1151
1152 if ( isset( $postData ) ) {
1153 if ( ! empty( $validates ) ) {
1154 $is_validate = $this->check_validation( $postData, $validates );
1155 if ( ! $is_validate ) {
1156 $this->validation_msg( $item );
1157 } else {
1158 update_option( $key, $postData );
1159 }
1160 }
1161 }
1162 }
1163 }
1164 return true;
1165 }
1166
1167 public function validation_msg( $item ) {
1168
1169 if ( strpos( $item, 'ColorPicker' ) > 0 ) {
1170 $item = 'ColorPicker';
1171 }
1172
1173 $text_input = 'で�
1174 �力してください。';
1175 $text_donot_save = 'を保存できませんでした。';
1176
1177 switch ( $item ) {
1178 case 'topText':
1179 $this->error_message( 'トップテキストは50文字以�
1180 ' . $text_input );
1181 break;
1182 case 'ColorPicker':
1183 $this->error_message( 'カラーピッカーは「#」+「00AABB(6文字)」' . $text_input );
1184 break;
1185 case 'discText':
1186 $this->error_message( '説明文は80文字以�
1187 ' . $text_input );
1188 break;
1189 case 'btnType':
1190 $this->error_message( 'ボタンタイプ' . $text_donot_save );
1191 break;
1192 case 'btnText':
1193 $this->error_message( 'ボタンの文言は30文字以�
1194 ' . $text_input );
1195 break;
1196 case 'btnColor':
1197 $this->error_message( 'ボタンの色' . $text_donot_save );
1198 break;
1199 case 'btnColorLighten':
1200 $this->error_message( 'グラデーションの明度は半角数字' . $text_input );
1201 break;
1202 case 'linkUrl':
1203 $this->error_message( 'リンク�
1204 �URLは500文字以�
1205 のURL' . $text_input );
1206 break;
1207 case 'linkTarget':
1208 $this->error_message( 'リンクの開き方' . $text_donot_save );
1209 break;
1210 case 'linkRel':
1211 $this->error_message( 'rel属性' . $text_donot_save );
1212 break;
1213 case 'btnText2':
1214 $this->error_message( 'ボタンの文言は30文字以�
1215 ' . $text_input );
1216 break;
1217 case 'btnColor2':
1218 $this->error_message( 'ボタンの色' . $text_donot_save );
1219 break;
1220 case 'btnColorLighten2':
1221 $this->error_message( 'グラデーションの明度は半角数字' . $text_input );
1222 break;
1223 case 'linkUrl2':
1224 $this->error_message( 'リンク�
1225 �URLは500文字以�
1226 のURL' . $text_input );
1227 break;
1228 case 'linkTarget2':
1229 $this->error_message( 'リンクの開き方' . $text_donot_save );
1230 break;
1231 case 'linkRel2':
1232 $this->error_message( 'rel属性' . $text_donot_save );
1233 break;
1234 case 'bfbBgColor':
1235 $this->error_message( '背景色' . $text_donot_save );
1236 break;
1237 case 'bfbPos':
1238 $this->error_message( '�
1239 �置' . $text_donot_save );
1240 break;
1241 case 'bannerUrl':
1242 $this->error_message( '画像URL' . $text_donot_save );
1243 break;
1244 case 'trackingMemo':
1245 $this->error_message( 'クリック測定時のメモは200文字以�
1246 ' . $text_input );
1247 break;
1248 case 'trackingMemo2':
1249 $this->error_message( 'クリック測定時のメモは200文字以�
1250 ' . $text_input );
1251 break;
1252 case 'bfb_exclude_toppage':
1253 $this->error_message( 'トップページの表示方法' . $text_donot_save );
1254 break;
1255 case 'bfb_exclude_post_ids':
1256 $this->error_message( '除外記事IDは半角数字と半角カンマ「,' . $text_input );
1257 break;
1258 case 'bfb_license_key':
1259 $this->error_message( 'ライセンスキー' . $text_donot_save );
1260 break;
1261 case 'bfb_license_key_optimize':
1262 $this->error_message( 'A/Bテスト専用ライセンスキー' . $text_donot_save );
1263 break;
1264 case 'bfb_mode':
1265 $this->error_message( '開発モード' . $text_donot_save );
1266 break;
1267 case 'bfb_autohide':
1268 $this->error_message( '自動非表示' . $text_donot_save );
1269 break;
1270 case 'bfb_cookie_hide_span':
1271 $this->error_message( '非表示の期間は半角数字' . $text_input );
1272 break;
1273 case 'bfb_clickAnalyze':
1274 $this->error_message( 'クリック計測の有効化' . $text_donot_save );
1275 break;
1276 case 'bfb_clickAnalyze_exclude_admin':
1277 $this->error_message( 'クリック計測の管理�
1278 除外' . $text_donot_save );
1279 break;
1280 case 'bfb_hidden_pages':
1281 $this->error_message( '非表示ページ' . $text_donot_save );
1282 break;
1283 case 'bfb_retention_period':
1284 $this->error_message( '解析レポートの保存期間' . $text_donot_save );
1285 break;
1286 case 'bfb_designType':
1287 $this->error_message( 'ボタンデザイン' . $text_donot_save );
1288 break;
1289 case 'bfb_fontSize':
1290 $this->error_message( 'フォントサイズは半角数字' . $text_input );
1291 break;
1292 case 'bfbBtnPaddingTopBottom':
1293 $this->error_message( 'BFB�
1294 �体の上下余白は半角数字' . $text_input );
1295 break;
1296 case 'innerBfb_PaddingTop':
1297 $this->error_message( 'ボタンの上下余白は半角数字' . $text_input );
1298 break;
1299 case 'innerBfb_PaddingLeft':
1300 $this->error_message( 'ボタンの左右余白は半角数字' . $text_input );
1301 break;
1302 case 'topText_bottom':
1303 $this->error_message( 'マイクロコピー下の余白は半角数字' . $text_input );
1304 break;
1305 case 'bfb_optId':
1306 $this->error_message( 'A/Bテストの設定' . $text_input );
1307 break;
1308 case 'bfb_categoryPriority':
1309 $this->error_message( 'カテゴリー同士の優�
1310 �度は半角数字' . $text_input );
1311 break;
1312 case 'bfb_showing_area':
1313 $this->error_message( '出現ポイントの領域は半角数字' . $text_input );
1314 break;
1315 }
1316
1317 return false;
1318 }
1319
1320 public function get_metadata( $key ) {
1321 return get_option( $key );
1322 }
1323
1324 private function is_mobile() {
1325 $useragents = array(
1326 'iPhone',
1327 'iPod',
1328 'Android.*Mobile',
1329 'Windows.*Phone',
1330 'dream',
1331 'CUPCAKE',
1332 'blackberry*',
1333 'webOS',
1334 'incognito',
1335 'webmate',
1336 );
1337 $pattern = '/' . implode( '|', $useragents ) . '/i';
1338 $user_agent = isset( $_SERVER['HTTP_USER_AGENT'] ) ? sanitize_text_field( wp_unslash( $_SERVER['HTTP_USER_AGENT'] ) ) : '';
1339 return preg_match( $pattern, $user_agent );
1340 }
1341
1342 // 更新メッセージ
1343 public function updated_message() {
1344 echo '<div id="setting-error-settings_updated" class="notice bfb_notice notice-success settings-error is-dismissible"> <p><strong>設定を保存しました。</strong></p><button type="button" class="notice-dismiss"><span class="screen-reader-text">この通知を非表示にする</span></button></div>';
1345 }
1346 // エラーメッセージ
1347 public function error_message( $msg ) {
1348 echo '<div id="setting-error-settings_updated" class="error settings-error notice bfb_notice is-dismissible"><p><strong>' . esc_html( $msg ) . '</strong></p><button type="button" class="notice-dismiss"><span class="screen-reader-text">この通知を非表示にする</span></button></div>';
1349 }
1350 // PRO版ライセンスキーのチェック
1351 public function check_license_key() {
1352
1353 $license_key = get_option( 'bfb_license_key' );
1354
1355 // キャッシュされた�
1356 報を取得
1357 $cache = get_transient( 'bfb_license_key_check_cache' );
1358
1359 // 現在の時間を取得
1360 $current_time = time();
1361 $thirty_days = 30 * 24 * 60 * 60; // 30日(秒単位)
1362
1363 // キャッシュがあり、ライセンスキーがキャッシュと同じで、キャッシュ期間が有効な場合
1364 if ( $cache && $cache['license_key'] === $license_key && ( $current_time - $cache['time_checked'] ) < $thirty_days ) {
1365 // キャッシュされた結果を返す
1366 $this->is_activation = $cache['is_activation'];
1367 return $cache['is_activation'];
1368 }
1369
1370 // キャッシュがないもしくは期限切れもしくはキーが変更されていた場合、キャッシュを削除する
1371 delete_transient( 'bfb_license_key_check_cache' );
1372
1373 // ライセンスキーを無効をはじく
1374 if ( isset( $license_key ) && ! $this->is_validate( $license_key, 'license_key' ) ) {
1375 $this->is_activation = false;
1376 return false;
1377 }
1378
1379 // 新しいライセンスキーをサーバーに問い合わせ
1380 $data = array( 'body' => array( 'license_key' => $license_key ) );
1381 $res = wp_remote_post( $this->get_license_key_status_url, $data );
1382 $body = wp_remote_retrieve_body( $res );
1383
1384 $is_activation = ( $body == 'true' );
1385 if ( $is_activation ) {
1386 $this->is_activation = true;
1387 }
1388
1389 // 新しい�
1390 報でキャッシュを更新(1週間有効)
1391 set_transient(
1392 'bfb_license_key_check_cache',
1393 array(
1394 'license_key' => $license_key,
1395 'is_activation' => $is_activation,
1396 'time_checked' => $current_time,
1397 ),
1398 $thirty_days
1399 );
1400
1401 return $is_activation;
1402 }
1403
1404 // A/Bテスト専用ライセンスキーのチェック
1405 public function check_license_key_optimize() {
1406
1407 $license_key = get_option( 'bfb_license_key_optimize' );
1408
1409 // キャッシュされた�
1410 報を取得
1411 $cache = get_transient( 'bfb_license_key_optimize_cache' );
1412
1413 // 現在の時間を取得
1414 $current_time = time();
1415 $thirty_days = 30 * 24 * 60 * 60; // 30日(秒単位)
1416
1417 // キャッシュがあり、ライセンスキーがキャッシュと同じで、キャッシュ期間が有効な場合
1418 if ( $cache && $cache['license_key'] === $license_key && ( $current_time - $cache['time_checked'] ) < $thirty_days ) {
1419 // キャッシュされた結果を返す
1420 $this->is_activation_optimize = $cache['is_activation'];
1421 return $cache['is_activation'];
1422 }
1423
1424 // キャッシュがないもしくは期限切れもしくはキーが変更されていた場合、キャッシュを削除する
1425 delete_transient( 'bfb_license_key_optimize_cache' );
1426
1427 if ( isset( $license_key ) && ! $this->is_validate( $license_key, 'license_key' ) ) {
1428 $this->is_activation_optimize = false;
1429 return false;
1430 }
1431
1432 // 現在のURL
1433 $http_host = isset( $_SERVER['HTTP_HOST'] ) ? sanitize_text_field( wp_unslash( $_SERVER['HTTP_HOST'] ) ) : '';
1434 $request_uri = isset( $_SERVER['REQUEST_URI'] ) ? esc_url_raw( wp_unslash( $_SERVER['REQUEST_URI'] ) ) : '';
1435 $url = empty( $_SERVER['HTTPS'] ) ? 'http://' : esc_url_raw( 'https://' . $http_host . $request_uri );
1436
1437 $data = array(
1438 'body' => array(
1439 'license_key' => $license_key,
1440 'url' => $url,
1441 ),
1442 );
1443 $res = wp_remote_post( $this->get_license_key_optimize_status_url, $data );
1444 $body = wp_remote_retrieve_body( $res );
1445
1446 $is_activation = ( $body == 'true' );
1447 if ( $is_activation ) {
1448 $this->is_activation_optimize = true;
1449 }
1450
1451 // 新しい�
1452 報でキャッシュを更新(1週間有効)
1453 set_transient(
1454 'bfb_license_key_optimize_cache',
1455 array(
1456 'license_key' => $license_key,
1457 'is_activation' => $is_activation,
1458 'time_checked' => $current_time,
1459 ),
1460 $thirty_days
1461 );
1462
1463 return $is_activation;
1464 }
1465
1466 public function get_ad_html() {
1467
1468 $data = array();
1469 $res = wp_remote_post( $this->get_admin_ad_url, $data );
1470 $body = wp_remote_retrieve_body( $res );
1471
1472 return $body;
1473 }
1474
1475 public function genelate_color_picker( $name, $value ) {
1476
1477 ?>
1478
1479 <input type="text" name="<?php echo esc_attr( $name ); ?>" value="<?php echo esc_attr( $value ); ?>" >
1480 <?php
1481 wp_enqueue_script( 'wp-color-picker' );
1482 $data = '(function($){
1483 var options = {
1484 defaultColor: false,
1485 change: function(event,ui){ bfb_preview(); },
1486 clear: function() {},
1487 hide: true,
1488 palettes: true
1489 };
1490 $("input:text[name=' . esc_attr( $name ) . ']").wpColorPicker(options);
1491 })( jQuery );';
1492 wp_add_inline_script( 'wp-color-picker', $data, 'after' );
1493 }
1494 private function hex2rgb( $hex ) {
1495
1496 if ( substr( $hex, 0, 1 ) == '#' ) {
1497 $hex = substr( $hex, 1 );
1498 }
1499 if ( strlen( $hex ) == 3 ) {
1500 $hex = substr( $hex, 0, 1 ) . substr( $hex, 0, 1 ) . substr( $hex, 1, 1 ) . substr( $hex, 1, 1 ) . substr( $hex, 2, 1 ) . substr( $hex, 2, 1 );
1501 }
1502
1503 return array_map( 'hexdec', array( substr( $hex, 0, 2 ), substr( $hex, 2, 2 ), substr( $hex, 4, 2 ) ) );
1504 }
1505 private function rgba_css( $rgb, $alpha = 0.85 ) {
1506 return 'rgba(' . $rgb[0] . ',' . $rgb[1] . ',' . $rgb[2] . ',' . $alpha . ')';
1507 }
1508
1509 // SCSS
1510 private function init_scss( $bfbDatas, $src ) {
1511
1512 switch ( $bfbDatas['btnColor'] ) {
1513 case 'red':
1514 $bfbDatas['btnColor'] = '#d00a0a';
1515 break;
1516 case 'orange':
1517 $bfbDatas['btnColor'] = '#ea6103';
1518 break;
1519 case 'blue':
1520 $bfbDatas['btnColor'] = '#0061a7';
1521 break;
1522 case 'green':
1523 $bfbDatas['btnColor'] = '#009f07';
1524 break;
1525 case 'yellow':
1526 $bfbDatas['btnColor'] = '#d6c200';
1527 break;
1528 default:
1529 $bfbDatas['btnColor'] = '#000';
1530 break;
1531 }
1532 if ( $bfbDatas['btnColorPicker'] ) {
1533 $bfbDatas['btnColor'] = $bfbDatas['btnColorPicker']; }
1534
1535 switch ( $bfbDatas['btnColor2'] ) {
1536 case 'red':
1537 $bfbDatas['btnColor2'] = '#d00a0a';
1538 break;
1539 case 'orange':
1540 $bfbDatas['btnColor2'] = '#ea6103';
1541 break;
1542 case 'blue':
1543 $bfbDatas['btnColor2'] = '#0061a7';
1544 break;
1545 case 'green':
1546 $bfbDatas['btnColor2'] = '#009f07';
1547 break;
1548 case 'yellow':
1549 $bfbDatas['btnColor2'] = '#d6c200';
1550 break;
1551 default:
1552 $bfbDatas['btnColor2'] = '#000';
1553 break;
1554 }
1555 if ( $bfbDatas['btnColorPicker2'] ) {
1556 $bfbDatas['btnColor2'] = $bfbDatas['btnColorPicker2']; }
1557
1558 switch ( $bfbDatas['bfbBgColor'] ) {
1559 case 'red':
1560 $bfbDatas['bfbBgColor'] = '#BF0000';
1561 break;
1562 case 'orange':
1563 $bfbDatas['bfbBgColor'] = '#EAA500';
1564 break;
1565 case 'blue':
1566 $bfbDatas['bfbBgColor'] = '#0061a7';
1567 break;
1568 case 'green':
1569 $bfbDatas['bfbBgColor'] = '#009f07';
1570 break;
1571 case 'yellow':
1572 $bfbDatas['bfbBgColor'] = '#BFB600';
1573 break;
1574 default:
1575 $bfbDatas['bfbBgColor'] = '#000';
1576 break;
1577 }
1578 if ( $bfbDatas['bfbBgColorPicker'] ) {
1579 $bfbDatas['bfbBgColor'] = $bfbDatas['bfbBgColorPicker']; }
1580
1581 $scss = $this->get_scss( $src );
1582
1583 foreach ( $this->scssItems as $item => $defaultVal ) {
1584
1585 if ( ! empty( $bfbDatas[ $item ] ) && $this->is_validate( $bfbDatas[ $item ], 'css' ) ) {
1586 $scss = str_replace( '{{' . $item . '}}', '$' . $item . ':' . $bfbDatas[ $item ] . ';', $scss );
1587 } else {
1588 $scss = str_replace( '{{' . $item . '}}', '$' . $item . ':' . $defaultVal . ';', $scss );
1589 }
1590 }
1591 return $this->compile_scss( $scss );
1592 }
1593 private function get_scss( $url ) {
1594 ob_start();
1595 require $url;
1596 return ob_get_clean();
1597 }
1598
1599
1600 private function compile_scss( $data ) {
1601 $scss = new scssc();
1602 return $scss->compile( $data );
1603 }
1604 private function delete_br( $text ) {
1605 $text = str_replace( array( "\r\n", "\r", "\n", "\t" ), ' ', $text );
1606 return preg_replace( '/\s(?=\s)/', '', $text );
1607 }
1608 // カテゴリー
1609 private function get_categoryId( $post_ID ) {
1610 foreach ( ( get_the_category( $post_ID ) ) as $obj ) {
1611 $cat_id = $obj->term_id;
1612 if ( isset( $cat_id ) && $cat_id != 0 ) {
1613 $cat_ids[] = $cat_id;
1614 }
1615 }
1616 if ( isset( $cat_ids ) ) {
1617 return $cat_ids; }
1618 }
1619 // カテゴリー優�
1620 �順位で降順に並び替え
1621 private function init_categoryPriority( $categories, $targetKey ) {
1622
1623 foreach ( $categories as $key => $value ) {
1624 if ( array_key_exists( $targetKey, $value ) ) {
1625 if ( isset( $value[ $targetKey ] ) ) {
1626 $sort_keys[] = $value[ $targetKey ];
1627 }
1628 } elseif ( isset( $value[ $targetKey ] ) ) {
1629 $sort_keys[] = $value[ $targetKey ];
1630 }
1631 }
1632 if ( isset( $sort_keys ) ) {
1633 if ( $sort_keys && count( $sort_keys ) > 1 ) {
1634 array_multisort( $sort_keys, SORT_DESC, $categories );
1635 }
1636 }
1637 return $categories;
1638 }
1639 // バリデーション
1640 public function is_validate( $data, $validation = false ) {
1641
1642 if ( ! $validation ) {
1643 return true; }
1644 if ( $validation != 'require' && $data == '' ) {
1645 return true; }
1646
1647 switch ( $validation ) {
1648 case 'css':
1649 $pattern = '/^[a-zA-Z0-9#\.]*$/';
1650 break;
1651 case 'colorCode':
1652 $pattern = '/^#([A-Fa-f0-9]{3}){1,2}$/';
1653 break;
1654 case 'int':
1655 $pattern = '/^[0-9]*$/';
1656 break;
1657 case 'num':
1658 $pattern = '/^[0-9\-\.]*$/';
1659 break;
1660 case 'w':
1661 $pattern = '/^\w*$/';
1662 break;
1663 case 'hw':
1664 $pattern = '/^[\w\-\.,]*$/';
1665 break;
1666 case 'require':
1667 $pattern = '/^.+$/';
1668 break;
1669 case 'date':
1670 $pattern = '/^[0-9]{4}-[0-9]{2}-[0-9]{2}$/';
1671 break;
1672 case 'datetime':
1673 $pattern = '/^[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}$/';
1674 break;
1675 case 'url':
1676 $pattern = '/^[\w\/:%#\$&%\?\(\)~\.=\+\-]+$/';
1677 break;
1678 case 'domain':
1679 $pattern = '/^(?!\-)[\-0-9A-Za-z]{1,63}(?<!\-)(?:\.(?!\-)[\-0-9A-Za-z]{1,63}(?<!\-))*$/';
1680 break;
1681 case 'license_key':
1682 $pattern = '/^[0-9a-zA-Z]{12}-[0-9a-zA-Z]{12}$/';
1683 break;
1684 case 'opt_id':
1685 $pattern = '/^[0-9a-zA-Z]{32}$/';
1686 break;
1687 default:
1688 $pattern = '/^.*$/';
1689 break;
1690 }
1691
1692 if ( strpos( $validation, 'max' ) !== false ) {
1693 if ( mb_strlen( $data ) > intval( ltrim( $validation, 'max' ) ) ) {
1694 return false;
1695 }
1696 }
1697
1698 // チェックボックス
1699 if ( is_array( $data ) ) {
1700 foreach ( $data as $val ) {
1701 if ( ! preg_match( $pattern, $val ) ) {
1702 return false;
1703 }
1704 }
1705 } elseif ( ! preg_match( $pattern, $data ) ) {
1706 return false;
1707 }
1708
1709 return true;
1710 }
1711 public function check_validation( $data, $validates ) {
1712
1713 $errors = array();
1714
1715 foreach ( $validates as $validate ) {
1716 $is_validate = $this->is_validate( $data, $validate );
1717 if ( ! $is_validate ) {
1718 return false;
1719 }
1720 }
1721
1722 return true;
1723 }
1724
1725 public function bfb_get_data( $key, $method = 'get' ) {
1726
1727 if ( $method == 'get' ) {
1728 $postData = filter_input( INPUT_GET, $key );
1729 if ( ! empty( $postData ) ) {
1730 return $postData;
1731 }
1732 } else {
1733 $postData = filter_input( INPUT_POST, $key );
1734 if ( ! empty( $postData ) ) {
1735 return $postData;
1736 }
1737 }
1738
1739 return '';
1740 }
1741 public function date_picker_script() {
1742 echo "<script type=\"text/javascript\">
1743 jQuery(document).ready(function ($) {
1744 $('.date-input').datepicker ({
1745 dateFormat: 'yy-mm-dd',
1746 changeMonth: true,
1747 changeYear: true,
1748 yearRange: '-2:+0'
1749 });
1750 $('.date-input').attr('placeholder', '日付を選択してください');
1751
1752 });
1753 </script>";
1754 }
1755 }
1756
1757 $bfb_content = new BlogFloatingButton();
1758