Plugin Directory

Changeset 3724996


Ignore:
Timestamp:
10/02/2026 02:44:32 PM (3 weeks ago)
Author:
kaoruyakabi
Message:

Release 1.1.1

Location:
hatatate
Files:
8 edited
1 copied

Legend:

Unmodified
Added
Removed
  • hatatate/tags/1.1.1/admin/js/hatatate-placements.js

    r3721496 r3724996  
    316316
    317317    // ハイライト要素を作成して iframe 内の適切な位置に挿入する
    318     function _insertHighlight(iframeDoc, rule, contentArea) {
     318    // tails: 位置ごとに最後に描いた枠。同じ位置の 2 つ目以降はその直後に入れて、並べ替えの順(上から順)に並べる(記事の側と同じ)
     319    function _insertHighlight(iframeDoc, rule, contentArea, tails) {
    319320        var hl     = _createHighlight(iframeDoc, [{ name: rule.name, id: rule.id }], rule.preset, rule.alignment);
    320321        var preset = rule.preset;
    … …  
    323324            hl.style.textAlign = rule.alignment || 'center';
    324325        }
     326
     327        var tail = (tails && preset !== 'modal' && preset !== 'fixed_button') ? tails[preset] : null;
     328        if (tail && tail.parentNode) {
     329            tail.parentNode.insertBefore(hl, tail.nextSibling);
     330            tails[preset] = hl;
     331            return;
     332        }
     333        // モーダル・固定ボタンは重なり順が同じなので、後ろに置いたものが手前に見える。
     334        // 記事の側と同じく並びで上のものを手前に見せるため、同じ隅の 2 つ目以降は前の枠より前に置く
     335        var corner = null;
     336        if (preset === 'modal') {
     337            var anim = rule.modal_animation || 'slide_right';
     338            corner = 'modal:' + (anim === 'slide_right' || anim === 'slide_left' ? anim : 'center');
     339        } else if (preset === 'fixed_button') {
     340            corner = 'fixed_button';
     341        }
     342        var front = (tails && corner) ? tails[corner] : null;
    325343
    326344        if (preset === 'before_content') {
    … …  
    344362                hl.style.cssText += ';position:fixed;bottom:' + modalBottom + ';right:16px;max-width:280px;margin:0;z-index:9999;';
    345363            }
    346             iframeDoc.body.appendChild(hl);
     364            if (front && front.parentNode) front.parentNode.insertBefore(hl, front); else iframeDoc.body.appendChild(hl);
    347365        } else if (preset === 'fixed_button') {
    348366            hl.style.cssText += ';position:fixed;bottom:0;left:0;right:0;margin:0;border-radius:0;border-left:none;border-right:none;border-bottom:none;z-index:9999;';
    349             iframeDoc.body.appendChild(hl);
     367            if (front && front.parentNode) front.parentNode.insertBefore(hl, front); else iframeDoc.body.appendChild(hl);
    350368        } else {
    351369            // カスタム配置位置
    … …  
    361379                }
    362380            }
     381        }
     382        if (tails && hl.parentNode) {
     383            tails[corner || preset] = hl;
    363384        }
    364385    }
    … …  
    619640            ? window.hatatateDeviceMatches
    620641            : function () { return true; };
     642        var tails = {};
    621643        _buildRules().forEach(function (rule) {
    622644            // 「PC のみ」「スマホのみ」の配置は、いま見ている側に出るものだけ描く
    623645            if (!matches(rule.device, previewDevice)) { return; }
    624             _insertHighlight(iframeDoc, rule, contentArea);
     646            _insertHighlight(iframeDoc, rule, contentArea, tails);
    625647        });
    626648    }
  • hatatate/tags/1.1.1/hatatate.php

    r3724488 r3724996  
    44 * Plugin URI:        https://border-haze.co.jp/tools/hatatate/
    55 * Description:       Place a call-to-action (banner or text) on every post, run an A/B test, and read the report. No per-post editing.
    6  * Version:           1.1.0
     6 * Version:           1.1.1
    77 * Requires at least: 6.0
    88 * Requires PHP:      7.4
    … …  
    1919}
    2020
    21 define( 'HATATATE_VERSION', '1.1.0' );
     21define( 'HATATATE_VERSION', '1.1.1' );
    2222define( 'HATATATE_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
    2323define( 'HATATATE_PLUGIN_URL', plugin_dir_url( __FILE__ ) );
  • hatatate/tags/1.1.1/includes/class-hatatate-engine.php

    r3721496 r3724996  
    551551
    552552        /**
     553         * 同じ位置に先に入れたバナーがあれば、その直後に入れる(並べ替えの順を記事でも保つ)
     554         *
     555         * 「本文の前」「要素の後」「要素の中の先頭」は、毎回同じ場所に入れると後から入れたものが上に来てしまう。
     556         * 2 つ目以降を前のバナーの末尾の直後に入れれば、どの挿入方法でも上から順に並ぶ。
     557         *
     558         * @param array                $tails    位置ごとに最後に入れたバナーの末尾の要素
     559         * @param string               $key      位置
     560         * @param DOMDocumentFragment  $fragment 入れるバナー
     561         * @return bool 入れたら true(先に入れたものが無ければ何もしないで false)
     562         */
     563        private static function insert_after_tail( $tails, $key, $fragment ) {
     564                if ( empty( $tails[ $key ] ) || ! $tails[ $key ]->parentNode ) {
     565                        return false;
     566                }
     567                $tail = $tails[ $key ];
     568                if ( $tail->nextSibling ) {
     569                        $tail->parentNode->insertBefore( $fragment, $tail->nextSibling );
     570                } else {
     571                        $tail->parentNode->appendChild( $fragment );
     572                }
     573                return true;
     574        }
     575
     576        /**
    553577         * HTML の中で目印に一致する要素の数(「他の記事でも見つかるか」の判定に使う)
    554578         *
    … …  
    951975
    952976                // モーダルウィンドウ・固定ボタン挿入
     977                // HTML は並べ替えの順のまま出し、同じ隅で重なるものは並びで上のものを手前に見せる(2 つ目以降の重なり順を 1 つずつ下げる)
     978                $stack = array();
    953979                foreach ( $this->overlay_rules_for_preset( 'modal' ) as $rule_item ) {
    954                         self::print_cta_html( $this->render_modal_html( $rule_item ) );
    955                 }
     980                        $corner           = self::modal_corner( $rule_item );
     981                        $stack[ $corner ] = isset( $stack[ $corner ] ) ? $stack[ $corner ] + 1 : 0;
     982                        self::print_cta_html( $this->render_modal_html( $rule_item, $stack[ $corner ] ) );
     983                }
     984                $below = 0;
    956985                foreach ( $this->overlay_rules_for_preset( 'fixed_button' ) as $rule_item ) {
    957                         self::print_cta_html( $this->render_fixed_button_html( $rule_item ) );
     986                        self::print_cta_html( $this->render_fixed_button_html( $rule_item, $below++ ) );
    958987                }
    959988        }
    … …  
    10351064                $modified = false;
    10361065
     1066                // 同じ位置に 2 つ以上あるときは、配置パターンの並び(上から順)のとおりに出す。
     1067                // $nth: 同じ位置の何番目か(二重防止の目印を 1 つずつ分ける)
     1068                // $loc_targets: 位置ごとの目印の要素(2 つ目以降も最初に見つけた要素を使う。先に入れたバナーの中の要素に当たらないように)
     1069                // $loc_tails: 位置ごとに最後に入れたバナーの末尾(2 つ目以降はその直後に入れる)
     1070                $nth         = array();
     1071                $loc_targets = array();
     1072                $loc_tails   = array();
     1073
    10371074                foreach ( $all_rules as $rule_item ) {
    10381075                        // cta_id が空でも、ABテストとしてフラグが立っていればスキップしない
    … …  
    10411078                        }
    10421079
    1043                         $p_id   = isset( $rule_item['pattern_id'] ) ? $rule_item['pattern_id'] : 'tmp';
    1044                         $preset = isset( $rule_item['placement_preset'] ) ? $rule_item['placement_preset'] : 'custom';
    1045                         $mark   = $p_id . '_' . $preset;
     1080                        $p_id    = isset( $rule_item['pattern_id'] ) ? $rule_item['pattern_id'] : 'tmp';
     1081                        $preset  = isset( $rule_item['placement_preset'] ) ? $rule_item['placement_preset'] : 'custom';
     1082                        $loc_key = ( $preset === 'custom' ) ? self::get_placement_key( $rule_item ) : $preset;
     1083                        $mark    = $p_id . '_' . $loc_key;
     1084                        $nth[ $mark ] = isset( $nth[ $mark ] ) ? $nth[ $mark ] + 1 : 1;
     1085                        $mark   .= '_' . $nth[ $mark ];
    10461086
    10471087                        // サイドバー・フッター・オーバーレイは別フックで処理するためスキップ
    … …  
    10511091                        }
    10521092
    1053                         // すでにこのリクエストで挿入済みのパターン(位置)であればスキップ(重複表示対策)
     1093                        // すでにこのリクエストで挿入済みの配置(パターン・位置・同じ位置の何番目か)であればスキップ(重複表示対策)
    10541094                        if ( isset( self::$injected_marks[ $mark ] ) ) {
    10551095                                continue;
    … …  
    10611101                        }
    10621102
     1103                        $tail = $fragment->lastChild;
     1104
    10631105                        if ( $preset === 'before_content' ) {
    1064                                 // 本文前: 最初の要素の前に挿入
     1106                                // 本文前: 最初の要素の前に挿入(同じ位置の 2 つ目以降は、前のバナーの直後)
    10651107                                if ( $body ) {
    1066                                         // $body->firstChild が null でも insertBefore(..., null) は appendChild と同様に機能し、結果的に先頭になる
    1067                                         $body->insertBefore( $fragment, $body->firstChild );
     1108                                        if ( ! self::insert_after_tail( $loc_tails, $loc_key, $fragment ) ) {
     1109                                                // $body->firstChild が null でも insertBefore(..., null) は appendChild と同様に機能し、結果的に先頭になる
     1110                                                $body->insertBefore( $fragment, $body->firstChild );
     1111                                        }
     1112                                        $loc_tails[ $loc_key ] = $tail;
    10681113                                        $modified = true;
    10691114                                        self::$injected_marks[ $mark ] = true;
    … …  
    11041149                                }
    11051150
    1106                                 $target_node = self::find_location_target( $xpath, $loc_def );
     1151                                if ( ! isset( $loc_targets[ $loc_key ] ) ) {
     1152                                        $loc_targets[ $loc_key ] = self::find_location_target( $xpath, $loc_def );
     1153                                }
     1154                                $target_node = $loc_targets[ $loc_key ];
    11071155                                if ( $target_node ) {
    11081156                                        $position = ( ! empty( $loc_def['position'] ) ) ? $loc_def['position'] : 'before';
    1109                                         self::insert_fragment( $target_node, $fragment, $position );
     1157                                        if ( ! self::insert_after_tail( $loc_tails, $loc_key, $fragment ) ) {
     1158                                                self::insert_fragment( $target_node, $fragment, $position );
     1159                                        }
     1160                                        $loc_tails[ $loc_key ] = $tail;
    11101161                                        $modified = true;
    11111162                                        self::$injected_marks[ $mark ] = true;
    … …  
    15461597        }
    15471598
     1599        /** モーダルの重なり順の基準(1.1.0 から同じ値。同じ隅の 1 つ目はこの値のまま) */
     1600        const MODAL_Z_INDEX = 99999;
     1601
     1602        /** 固定ボタンの重なり順の基準(public/css/hatatate-front.css の .hatatate-fixed-bar と同じ値) */
     1603        const FIXED_Z_INDEX = 9990;
     1604
     1605        /**
     1606         * モーダルが出る隅(重なり順を数える単位): 'right'(右下)/ 'left'(左下)/ 'center'(画面の中央)
     1607         *
     1608         * render_modal_html() と同じ分け方。知らない値は中央のフェードインで描くので 'center'。
     1609         */
     1610        public static function modal_corner( $rule_item ) {
     1611                $animation = isset( $rule_item['modal_animation'] ) ? $rule_item['modal_animation'] : 'slide_right';
     1612                if ( $animation === 'slide_right' ) {
     1613                        return 'right';
     1614                }
     1615                return ( $animation === 'slide_left' ) ? 'left' : 'center';
     1616        }
     1617
    15481618        /**
    15491619         * モーダルウィンドウ用の HTML を生成する(動きは public/js/hatatate-front.js。ここは data 属性だけ)
    1550          */
    1551         private function render_modal_html( $rule_item ) {
     1620         *
     1621         * @param array $rule_item 配置 1 件
     1622         * @param int   $below     同じ隅で、並びでこれより上にあるモーダルの数(その数だけ重なり順を下げ、上のものを手前に見せる)
     1623         */
     1624        private function render_modal_html( $rule_item, $below = 0 ) {
    15521625                $cta_html = $this->render_cta_html( $rule_item );
    15531626                if ( empty( $cta_html ) ) {
    … …  
    15911664                // 角丸や地は CTA 側が持つ。上に空けた帯は閉じるボタンの置き場所で、見た目には出ない。
    15921665                $width_css = self::modal_width_css( $rule_item );
     1666                $z_index   = self::MODAL_Z_INDEX - max( 0, (int) $below );
    15931667                // box-sizing は CSS ファイル(.hatatate-modal-box)に置く。
    15941668                // WordPress の wp_kses は style 属性に書ける CSS を許可リストで絞っていて、box-sizing は入っていない
    15951669                $box_base  = 'position:relative;padding-top:' . self::MODAL_CLOSE_LANE . 'px;' . $width_css;
    15961670                if ( $animation === 'slide_right' ) {
    1597                         $overlay_style = 'display:none;position:fixed;bottom:' . $modal_bottom . 'px;right:20px;z-index:99999;';
     1671                        $overlay_style = 'display:none;position:fixed;bottom:' . $modal_bottom . 'px;right:20px;z-index:' . $z_index . ';';
    15981672                        $box_style     = $box_base;
    15991673                        $display_val   = 'block';
    16001674                        $click_overlay = false;
    16011675                } elseif ( $animation === 'slide_left' ) {
    1602                         $overlay_style = 'display:none;position:fixed;bottom:' . $modal_bottom . 'px;left:20px;z-index:99999;';
     1676                        $overlay_style = 'display:none;position:fixed;bottom:' . $modal_bottom . 'px;left:20px;z-index:' . $z_index . ';';
    16031677                        $box_style     = $box_base;
    16041678                        $display_val   = 'block';
    … …  
    16071681                        // fade_in: 全画面中央(後ろのページを伏せる暗い層は残す。これは CTA の外枠ではない)
    16081682                        // inset も許可リストに入っていないので、上下左右を 1 つずつ書く
    1609                         $overlay_style = 'display:none;position:fixed;top:0;right:0;bottom:0;left:0;background:rgba(0,0,0,.55);z-index:99999;align-items:center;justify-content:center;';
     1683                        $overlay_style = 'display:none;position:fixed;top:0;right:0;bottom:0;left:0;background:rgba(0,0,0,.55);z-index:' . $z_index . ';align-items:center;justify-content:center;';
    16101684                        $box_style     = $box_base;
    16111685                        $display_val   = 'flex';
    … …  
    16311705        /**
    16321706         * 固定ボタン(画面下部バー)用の HTML を生成する(動きは public/js/hatatate-front.js)
    1633          */
    1634         private function render_fixed_button_html( $rule_item ) {
     1707         *
     1708         * @param array $rule_item 配置 1 件
     1709         * @param int   $below     並びでこれより上にある固定ボタンの数。1 以上なら重なり順を CSS の値からその数だけ下げる
     1710         *                         (固定ボタンはどれも画面の下端に出るので、同じ高さなら並びで上のものだけが見える)
     1711         */
     1712        private function render_fixed_button_html( $rule_item, $below = 0 ) {
    16351713                $cta_html = $this->render_cta_html( $rule_item );
    16361714                if ( empty( $cta_html ) ) {
    … …  
    16581736                $close_btn = '<button type="button" class="hatatate-fixed-close-btn" aria-label="閉じる">&#x2715;</button>';
    16591737
    1660                 $html = '<div id="' . $uid . '" class="' . esc_attr( 'hatatate-fixed-bar' . self::device_class_suffix( $rule_item ) ) . '" style="background:' . $bg_rgba . '; display:block;"' . $hide_attr . '>'
     1738                $html = '<div id="' . $uid . '" class="' . esc_attr( 'hatatate-fixed-bar' . self::device_class_suffix( $rule_item ) ) . '" style="background:' . $bg_rgba . '; display:block;' . ( $below > 0 ? ' z-index:' . (int) ( self::FIXED_Z_INDEX - $below ) . ';' : '' ) . '"' . $hide_attr . '>'
    16611739                        . '<div class="hatatate-fixed-bar-inner">'
    16621740                        . $close_btn
  • hatatate/tags/1.1.1/readme.txt

    r3724488 r3724996  
    44Requires at least: 6.0
    55Tested up to: 7.1
    6 Stable tag: 1.1.0
     6Stable tag: 1.1.1
    77Requires PHP: 7.4
    88License: GPLv2 or later
    … …  
    117117== Changelog ==
    118118
     119= 1.1.1 =
     120* Fix: when two or more CTAs were placed at the same position inside the post (before the content, after the content, or a custom position), only the first one was shown. All of them are now shown, in the order you arrange them in the placement pattern. The preview on the placement screen shows the same order.
     121* When two or more modals appear in the same corner, or two or more fixed buttons appear at the bottom of the screen, the one placed higher in the placement pattern is now shown in front.
     122
    119123= 1.1.0 =
    120124* The Home tab has a short news box at the bottom with tips and news. Its text ships with the plugin; nothing is loaded from outside.
  • hatatate/trunk/admin/js/hatatate-placements.js

    r3721496 r3724996  
    316316
    317317    // ハイライト要素を作成して iframe 内の適切な位置に挿入する
    318     function _insertHighlight(iframeDoc, rule, contentArea) {
     318    // tails: 位置ごとに最後に描いた枠。同じ位置の 2 つ目以降はその直後に入れて、並べ替えの順(上から順)に並べる(記事の側と同じ)
     319    function _insertHighlight(iframeDoc, rule, contentArea, tails) {
    319320        var hl     = _createHighlight(iframeDoc, [{ name: rule.name, id: rule.id }], rule.preset, rule.alignment);
    320321        var preset = rule.preset;
    … …  
    323324            hl.style.textAlign = rule.alignment || 'center';
    324325        }
     326
     327        var tail = (tails && preset !== 'modal' && preset !== 'fixed_button') ? tails[preset] : null;
     328        if (tail && tail.parentNode) {
     329            tail.parentNode.insertBefore(hl, tail.nextSibling);
     330            tails[preset] = hl;
     331            return;
     332        }
     333        // モーダル・固定ボタンは重なり順が同じなので、後ろに置いたものが手前に見える。
     334        // 記事の側と同じく並びで上のものを手前に見せるため、同じ隅の 2 つ目以降は前の枠より前に置く
     335        var corner = null;
     336        if (preset === 'modal') {
     337            var anim = rule.modal_animation || 'slide_right';
     338            corner = 'modal:' + (anim === 'slide_right' || anim === 'slide_left' ? anim : 'center');
     339        } else if (preset === 'fixed_button') {
     340            corner = 'fixed_button';
     341        }
     342        var front = (tails && corner) ? tails[corner] : null;
    325343
    326344        if (preset === 'before_content') {
    … …  
    344362                hl.style.cssText += ';position:fixed;bottom:' + modalBottom + ';right:16px;max-width:280px;margin:0;z-index:9999;';
    345363            }
    346             iframeDoc.body.appendChild(hl);
     364            if (front && front.parentNode) front.parentNode.insertBefore(hl, front); else iframeDoc.body.appendChild(hl);
    347365        } else if (preset === 'fixed_button') {
    348366            hl.style.cssText += ';position:fixed;bottom:0;left:0;right:0;margin:0;border-radius:0;border-left:none;border-right:none;border-bottom:none;z-index:9999;';
    349             iframeDoc.body.appendChild(hl);
     367            if (front && front.parentNode) front.parentNode.insertBefore(hl, front); else iframeDoc.body.appendChild(hl);
    350368        } else {
    351369            // カスタム配置位置
    … …  
    361379                }
    362380            }
     381        }
     382        if (tails && hl.parentNode) {
     383            tails[corner || preset] = hl;
    363384        }
    364385    }
    … …  
    619640            ? window.hatatateDeviceMatches
    620641            : function () { return true; };
     642        var tails = {};
    621643        _buildRules().forEach(function (rule) {
    622644            // 「PC のみ」「スマホのみ」の配置は、いま見ている側に出るものだけ描く
    623645            if (!matches(rule.device, previewDevice)) { return; }
    624             _insertHighlight(iframeDoc, rule, contentArea);
     646            _insertHighlight(iframeDoc, rule, contentArea, tails);
    625647        });
    626648    }
  • hatatate/trunk/hatatate.php

    r3724488 r3724996  
    44 * Plugin URI:        https://border-haze.co.jp/tools/hatatate/
    55 * Description:       Place a call-to-action (banner or text) on every post, run an A/B test, and read the report. No per-post editing.
    6  * Version:           1.1.0
     6 * Version:           1.1.1
    77 * Requires at least: 6.0
    88 * Requires PHP:      7.4
    … …  
    1919}
    2020
    21 define( 'HATATATE_VERSION', '1.1.0' );
     21define( 'HATATATE_VERSION', '1.1.1' );
    2222define( 'HATATATE_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
    2323define( 'HATATATE_PLUGIN_URL', plugin_dir_url( __FILE__ ) );
  • hatatate/trunk/includes/class-hatatate-engine.php

    r3721496 r3724996  
    551551
    552552        /**
     553         * 同じ位置に先に入れたバナーがあれば、その直後に入れる(並べ替えの順を記事でも保つ)
     554         *
     555         * 「本文の前」「要素の後」「要素の中の先頭」は、毎回同じ場所に入れると後から入れたものが上に来てしまう。
     556         * 2 つ目以降を前のバナーの末尾の直後に入れれば、どの挿入方法でも上から順に並ぶ。
     557         *
     558         * @param array                $tails    位置ごとに最後に入れたバナーの末尾の要素
     559         * @param string               $key      位置
     560         * @param DOMDocumentFragment  $fragment 入れるバナー
     561         * @return bool 入れたら true(先に入れたものが無ければ何もしないで false)
     562         */
     563        private static function insert_after_tail( $tails, $key, $fragment ) {
     564                if ( empty( $tails[ $key ] ) || ! $tails[ $key ]->parentNode ) {
     565                        return false;
     566                }
     567                $tail = $tails[ $key ];
     568                if ( $tail->nextSibling ) {
     569                        $tail->parentNode->insertBefore( $fragment, $tail->nextSibling );
     570                } else {
     571                        $tail->parentNode->appendChild( $fragment );
     572                }
     573                return true;
     574        }
     575
     576        /**
    553577         * HTML の中で目印に一致する要素の数(「他の記事でも見つかるか」の判定に使う)
    554578         *
    … …  
    951975
    952976                // モーダルウィンドウ・固定ボタン挿入
     977                // HTML は並べ替えの順のまま出し、同じ隅で重なるものは並びで上のものを手前に見せる(2 つ目以降の重なり順を 1 つずつ下げる)
     978                $stack = array();
    953979                foreach ( $this->overlay_rules_for_preset( 'modal' ) as $rule_item ) {
    954                         self::print_cta_html( $this->render_modal_html( $rule_item ) );
    955                 }
     980                        $corner           = self::modal_corner( $rule_item );
     981                        $stack[ $corner ] = isset( $stack[ $corner ] ) ? $stack[ $corner ] + 1 : 0;
     982                        self::print_cta_html( $this->render_modal_html( $rule_item, $stack[ $corner ] ) );
     983                }
     984                $below = 0;
    956985                foreach ( $this->overlay_rules_for_preset( 'fixed_button' ) as $rule_item ) {
    957                         self::print_cta_html( $this->render_fixed_button_html( $rule_item ) );
     986                        self::print_cta_html( $this->render_fixed_button_html( $rule_item, $below++ ) );
    958987                }
    959988        }
    … …  
    10351064                $modified = false;
    10361065
     1066                // 同じ位置に 2 つ以上あるときは、配置パターンの並び(上から順)のとおりに出す。
     1067                // $nth: 同じ位置の何番目か(二重防止の目印を 1 つずつ分ける)
     1068                // $loc_targets: 位置ごとの目印の要素(2 つ目以降も最初に見つけた要素を使う。先に入れたバナーの中の要素に当たらないように)
     1069                // $loc_tails: 位置ごとに最後に入れたバナーの末尾(2 つ目以降はその直後に入れる)
     1070                $nth         = array();
     1071                $loc_targets = array();
     1072                $loc_tails   = array();
     1073
    10371074                foreach ( $all_rules as $rule_item ) {
    10381075                        // cta_id が空でも、ABテストとしてフラグが立っていればスキップしない
    … …  
    10411078                        }
    10421079
    1043                         $p_id   = isset( $rule_item['pattern_id'] ) ? $rule_item['pattern_id'] : 'tmp';
    1044                         $preset = isset( $rule_item['placement_preset'] ) ? $rule_item['placement_preset'] : 'custom';
    1045                         $mark   = $p_id . '_' . $preset;
     1080                        $p_id    = isset( $rule_item['pattern_id'] ) ? $rule_item['pattern_id'] : 'tmp';
     1081                        $preset  = isset( $rule_item['placement_preset'] ) ? $rule_item['placement_preset'] : 'custom';
     1082                        $loc_key = ( $preset === 'custom' ) ? self::get_placement_key( $rule_item ) : $preset;
     1083                        $mark    = $p_id . '_' . $loc_key;
     1084                        $nth[ $mark ] = isset( $nth[ $mark ] ) ? $nth[ $mark ] + 1 : 1;
     1085                        $mark   .= '_' . $nth[ $mark ];
    10461086
    10471087                        // サイドバー・フッター・オーバーレイは別フックで処理するためスキップ
    … …  
    10511091                        }
    10521092
    1053                         // すでにこのリクエストで挿入済みのパターン(位置)であればスキップ(重複表示対策)
     1093                        // すでにこのリクエストで挿入済みの配置(パターン・位置・同じ位置の何番目か)であればスキップ(重複表示対策)
    10541094                        if ( isset( self::$injected_marks[ $mark ] ) ) {
    10551095                                continue;
    … …  
    10611101                        }
    10621102
     1103                        $tail = $fragment->lastChild;
     1104
    10631105                        if ( $preset === 'before_content' ) {
    1064                                 // 本文前: 最初の要素の前に挿入
     1106                                // 本文前: 最初の要素の前に挿入(同じ位置の 2 つ目以降は、前のバナーの直後)
    10651107                                if ( $body ) {
    1066                                         // $body->firstChild が null でも insertBefore(..., null) は appendChild と同様に機能し、結果的に先頭になる
    1067                                         $body->insertBefore( $fragment, $body->firstChild );
     1108                                        if ( ! self::insert_after_tail( $loc_tails, $loc_key, $fragment ) ) {
     1109                                                // $body->firstChild が null でも insertBefore(..., null) は appendChild と同様に機能し、結果的に先頭になる
     1110                                                $body->insertBefore( $fragment, $body->firstChild );
     1111                                        }
     1112                                        $loc_tails[ $loc_key ] = $tail;
    10681113                                        $modified = true;
    10691114                                        self::$injected_marks[ $mark ] = true;
    … …  
    11041149                                }
    11051150
    1106                                 $target_node = self::find_location_target( $xpath, $loc_def );
     1151                                if ( ! isset( $loc_targets[ $loc_key ] ) ) {
     1152                                        $loc_targets[ $loc_key ] = self::find_location_target( $xpath, $loc_def );
     1153                                }
     1154                                $target_node = $loc_targets[ $loc_key ];
    11071155                                if ( $target_node ) {
    11081156                                        $position = ( ! empty( $loc_def['position'] ) ) ? $loc_def['position'] : 'before';
    1109                                         self::insert_fragment( $target_node, $fragment, $position );
     1157                                        if ( ! self::insert_after_tail( $loc_tails, $loc_key, $fragment ) ) {
     1158                                                self::insert_fragment( $target_node, $fragment, $position );
     1159                                        }
     1160                                        $loc_tails[ $loc_key ] = $tail;
    11101161                                        $modified = true;
    11111162                                        self::$injected_marks[ $mark ] = true;
    … …  
    15461597        }
    15471598
     1599        /** モーダルの重なり順の基準(1.1.0 から同じ値。同じ隅の 1 つ目はこの値のまま) */
     1600        const MODAL_Z_INDEX = 99999;
     1601
     1602        /** 固定ボタンの重なり順の基準(public/css/hatatate-front.css の .hatatate-fixed-bar と同じ値) */
     1603        const FIXED_Z_INDEX = 9990;
     1604
     1605        /**
     1606         * モーダルが出る隅(重なり順を数える単位): 'right'(右下)/ 'left'(左下)/ 'center'(画面の中央)
     1607         *
     1608         * render_modal_html() と同じ分け方。知らない値は中央のフェードインで描くので 'center'。
     1609         */
     1610        public static function modal_corner( $rule_item ) {
     1611                $animation = isset( $rule_item['modal_animation'] ) ? $rule_item['modal_animation'] : 'slide_right';
     1612                if ( $animation === 'slide_right' ) {
     1613                        return 'right';
     1614                }
     1615                return ( $animation === 'slide_left' ) ? 'left' : 'center';
     1616        }
     1617
    15481618        /**
    15491619         * モーダルウィンドウ用の HTML を生成する(動きは public/js/hatatate-front.js。ここは data 属性だけ)
    1550          */
    1551         private function render_modal_html( $rule_item ) {
     1620         *
     1621         * @param array $rule_item 配置 1 件
     1622         * @param int   $below     同じ隅で、並びでこれより上にあるモーダルの数(その数だけ重なり順を下げ、上のものを手前に見せる)
     1623         */
     1624        private function render_modal_html( $rule_item, $below = 0 ) {
    15521625                $cta_html = $this->render_cta_html( $rule_item );
    15531626                if ( empty( $cta_html ) ) {
    … …  
    15911664                // 角丸や地は CTA 側が持つ。上に空けた帯は閉じるボタンの置き場所で、見た目には出ない。
    15921665                $width_css = self::modal_width_css( $rule_item );
     1666                $z_index   = self::MODAL_Z_INDEX - max( 0, (int) $below );
    15931667                // box-sizing は CSS ファイル(.hatatate-modal-box)に置く。
    15941668                // WordPress の wp_kses は style 属性に書ける CSS を許可リストで絞っていて、box-sizing は入っていない
    15951669                $box_base  = 'position:relative;padding-top:' . self::MODAL_CLOSE_LANE . 'px;' . $width_css;
    15961670                if ( $animation === 'slide_right' ) {
    1597                         $overlay_style = 'display:none;position:fixed;bottom:' . $modal_bottom . 'px;right:20px;z-index:99999;';
     1671                        $overlay_style = 'display:none;position:fixed;bottom:' . $modal_bottom . 'px;right:20px;z-index:' . $z_index . ';';
    15981672                        $box_style     = $box_base;
    15991673                        $display_val   = 'block';
    16001674                        $click_overlay = false;
    16011675                } elseif ( $animation === 'slide_left' ) {
    1602                         $overlay_style = 'display:none;position:fixed;bottom:' . $modal_bottom . 'px;left:20px;z-index:99999;';
     1676                        $overlay_style = 'display:none;position:fixed;bottom:' . $modal_bottom . 'px;left:20px;z-index:' . $z_index . ';';
    16031677                        $box_style     = $box_base;
    16041678                        $display_val   = 'block';
    … …  
    16071681                        // fade_in: 全画面中央(後ろのページを伏せる暗い層は残す。これは CTA の外枠ではない)
    16081682                        // inset も許可リストに入っていないので、上下左右を 1 つずつ書く
    1609                         $overlay_style = 'display:none;position:fixed;top:0;right:0;bottom:0;left:0;background:rgba(0,0,0,.55);z-index:99999;align-items:center;justify-content:center;';
     1683                        $overlay_style = 'display:none;position:fixed;top:0;right:0;bottom:0;left:0;background:rgba(0,0,0,.55);z-index:' . $z_index . ';align-items:center;justify-content:center;';
    16101684                        $box_style     = $box_base;
    16111685                        $display_val   = 'flex';
    … …  
    16311705        /**
    16321706         * 固定ボタン(画面下部バー)用の HTML を生成する(動きは public/js/hatatate-front.js)
    1633          */
    1634         private function render_fixed_button_html( $rule_item ) {
     1707         *
     1708         * @param array $rule_item 配置 1 件
     1709         * @param int   $below     並びでこれより上にある固定ボタンの数。1 以上なら重なり順を CSS の値からその数だけ下げる
     1710         *                         (固定ボタンはどれも画面の下端に出るので、同じ高さなら並びで上のものだけが見える)
     1711         */
     1712        private function render_fixed_button_html( $rule_item, $below = 0 ) {
    16351713                $cta_html = $this->render_cta_html( $rule_item );
    16361714                if ( empty( $cta_html ) ) {
    … …  
    16581736                $close_btn = '<button type="button" class="hatatate-fixed-close-btn" aria-label="閉じる">&#x2715;</button>';
    16591737
    1660                 $html = '<div id="' . $uid . '" class="' . esc_attr( 'hatatate-fixed-bar' . self::device_class_suffix( $rule_item ) ) . '" style="background:' . $bg_rgba . '; display:block;"' . $hide_attr . '>'
     1738                $html = '<div id="' . $uid . '" class="' . esc_attr( 'hatatate-fixed-bar' . self::device_class_suffix( $rule_item ) ) . '" style="background:' . $bg_rgba . '; display:block;' . ( $below > 0 ? ' z-index:' . (int) ( self::FIXED_Z_INDEX - $below ) . ';' : '' ) . '"' . $hide_attr . '>'
    16611739                        . '<div class="hatatate-fixed-bar-inner">'
    16621740                        . $close_btn
  • hatatate/trunk/readme.txt

    r3724488 r3724996  
    44Requires at least: 6.0
    55Tested up to: 7.1
    6 Stable tag: 1.1.0
     6Stable tag: 1.1.1
    77Requires PHP: 7.4
    88License: GPLv2 or later
    … …  
    117117== Changelog ==
    118118
     119= 1.1.1 =
     120* Fix: when two or more CTAs were placed at the same position inside the post (before the content, after the content, or a custom position), only the first one was shown. All of them are now shown, in the order you arrange them in the placement pattern. The preview on the placement screen shows the same order.
     121* When two or more modals appear in the same corner, or two or more fixed buttons appear at the bottom of the screen, the one placed higher in the placement pattern is now shown in front.
     122
    119123= 1.1.0 =
    120124* The Home tab has a short news box at the bottom with tips and news. Its text ships with the plugin; nothing is loaded from outside.
Note: See TracChangeset for help on using the changeset viewer.