web-dev-qa-db-ja.com

変数にアクセスする入れ子のショートコード関数

私はタブ付きギャラリーのためにいくつかのhtmlを出力するショートコード関数を作成しようとしていました、そして何日も経っても私は遠くに来ていません。これがショートコードの例です。

[thumbTab id="test1" nav="top" shadow="off"]
    [imgTab id="1" src="source1" width="1280" height="720" ]
    [vidTab id="2" src="source2" width="1280" height="720" ]
    [htmlTab id="4" preview_src="source3"] Other HTML stuff in here [/html]
[/thumbTab]

返されたHTMLを次のようにします(たとえば簡略化します)。

<div>
    <nav>
        <img .../>    /* 1st nested shortcode */
        <img.../>     /* 2st nested shortcode */
        <img.../>     /* 3st nested shortcode */
    </nav>
    <div>
        <img.../>         /* 1st nested shortcode */
        <video.../>       /* 2st nested shortcode */
        <section.../>     /* 3st nested shortcode */
    </div>
</div>

そのため、データをnavタグに出力するには、ネストされたショートコードが必要です。 そして div要素にこれに関する問題は、メインとネストされたショートコード関数にアクセス可能な変数を必要とすることです(私は思う)。

私のショートコードプラグインでの試みは以下の通りです(インストールを試みると致命的なエラー)。私は私の既存のコードを修正するか、あるいは問題へのより良いアプローチに関するアドバイスをいただければ幸いです。

add_shortcode('thumbTab', 'thumbTab_func');

function thumbTab_func( $atts, $content = null ) {  
    $a = shortcode_atts( array(
        'id' => 'theID',
        'nav' => 'top',
        'shadow' => 'off'
    ), $atts );

    class thumbTab_class
    {
        //Array to hold tabbed content
        $tabCon = array();

        //Array to hold navigation tabs
        $navCon = array();

        //run nested shortcodes
        do_shortcode( $content, $ignore_html = false); 

        //combine $navCon array elements into the navigation tab html
        function navCreate(){
            $navReturn = '<div><nav><ul>';
            for ($i = 0; $i < count($this->navCon) ; ++$i) {
                $navReturn .= $this->navCon["$i"];
            }
            $navReturn .= '</ul></nav></div>';
            return $navReturn;
        }
        //combine $tabCon array elements into tabbed content html
        function tabCreate(){
            $tabReturn = '';
            for ($i = 0; $i < count($this->tabCon) ; ++$i) {
                $tabReturn .= $this->tabCon["$i"];
            }
            $tabReturn .= '</ul></nav></div>';
            return $tabReturn;
        }

        // Assigning processed html code to variable
        $thumbReturn = '<div id="'.$a["id"].'" class="thumbTAB">';
        $thumbReturn .= navCreate();
        $thumbReturn .= tabCreate();
        $thumbReturn .= '</div>';

    }

    $thumbTab_class = new thumbTab_class();

    // output processed html
    return $thumbTab_class->thumbReturn; 

}

//One nested shortcode function for testing
add_shortcode('imgTab', 'imgTab_func');

function imgTab_func( $atts ) { 
    $a = shortcode_atts( array(
        'id' => 'no_order',
        'src' => 'no_source',
        'width' => '100%',
        'height' => 'auto'
    ), $atts );

    //create baseline structure
    $img = '<img src="'.$a["src"].'" width="'.$a["width"].'" height="'.$a["height"].'">';

    //assign tabbed html string to tabCon array using the id number to place in order
    $this->tabCon["a['id']"] = '<section class="tabPage tabPage_'.$a["id"].'>'.$img.'</section>';

    //same for nav html string
    $this->navCon["a['id']"] = '<li class="sDS tabHeader_'.$a["id"].'">'.$img.'</li>';
}
2
Kayboy Bebop

ちょっとした横の思考とたくさんのテストの後、私はスコープをまたぐ変数の必要性を否定する解決策を思いつくことができました。

コードは次のようになります。

  1. $contentを使用して、ネストされたpreg_match_all(ネストされたショートコード)を単一のショートコードに分割する
  2. Forループを使用して、各ショートコードにdo_shortcodeを適用します。
  3. ネストされた各ショートコード関数は、別のpreg_match関数によって2つのストリングに分割されるストリングを返します。1番目はメインコンテンツデータ、2番目はnavデータです。
  4. すべてのメインコンテンツデータを1つの配列に割り当て、navデータを別の配列に割り当てます
  5. それから、2つの配列を処理して文字列を返すだけです。

私は以下のコードのスリムダウンバージョンを提供しました。これらすべてがうまくいくためのトリックは、ショートコードを分離するための堅牢なpreg_match式を持つことです。

<?php
add_shortcode('tabs', 'tabs_func');
//Main shortcode function
function tabs_func( $atts, $content = null ) {  
    $a = shortcode_atts( array(
        'id' => '',
    ), $atts );

    //array to store nav data
    $navCon = array();

    //array to store main content data
    $tabCon = array();

    /* 
    Preg_match_all splits $content into predefined individual shortcodes [imgTab], [vidTab] and [htmlTab][/htmlTab]

    A basic explanation of the expression I used. If you want a more detailed breakdown, plug the expression below into "https://regexr.com/"

        (?<!\[)    <= checks if there's a square bracket behind the proceeding match, to avoid matching escaped shortcode
        \[    <= matches the opening bracket
        (?:(?:imgTab|vidTab).*(?<!\])\](?!\])|htmlTab[\S\s]*?\[\/htmlTab\](?!\]))    <= can't break this into parts easily, but in essence this part tries to match a string which next part goes 'imgTab', 'vidTab', or 'htmlTab' (although the 'htmlTab' is put in it's own non-capture group as it has to deal with possible linebreaks). It then matches the remaining characters until it gets to a closing square bracket (or in the case of htmlTab, '[/htmlTab]. It then checks that there aren't two closing brackets next to each other before finishing the match. 
    */
    preg_match_all( '@(?<!\[)\[(?:(?:imgTab|vidTab).*(?<!\])\](?!\])|htmlTab[\S\s]*?\[\/htmlTab\](?!\]))@', $content, $matches );   

    $matchLI = 1;
    //loops through each of the shortcode matches
    foreach ($matches[0] as $match) {

        //runs current shortcode and assigns to variable
        $match_processed = do_shortcode($match);

        /*
        This expression is much more simple than the last one :D

            ([\S\s]+)    <= this capture group basically takes all the characters that aren't matched by the next part of the expression. This capture group contains the main content
            (<[\S\s]+>)    <= this capture group matches a 'less-than' character, a string of any characters and finally a 'greater-than' character. Since this expression is greedy it won't false match any 'greater-than' symbols in the first capture group, as it will look for the last 'greater-than' in the string
        */
        preg_match( '@([\S\s]+)(<[\S\s]{4,}>)@', $match_processed, $navMatch );

        //assigns nav data of current shortcode to the $navCon array, using the $matchLI value to index it
        $navCon[$matchLI] .= "<li class='nav_NUM_" . $matchLI . "'>" . $navMatch[2] . "</li>";

        //assigns main content data of current shortcode to the $tabCon array, using the $matchLI value to index it
        $tabCon[$matchLI] = "<section class='content_NUM_" . $matchLI . "'>" . $navMatch[1] . "</section>";
        }

        //increments the value for the next loop
        $matchLI++;

    }

    //constructing html in $tabReturn variable
    $tabReturn = "<div id='" . $a['id'] . "'>";
    $tabReturn .= "<nav><ul>";
    //loops through and assigns content of $navCon array to $tabReturn
    foreach ($navCon as $navElement) {
        $tabReturn .= $navElement;
    }
    $tabReturn .= "</ul></nav>";
    //loops through and assigns content of $tabCon array to $tabReturn
    foreach ($tabCon as $tabElement) {
        $tabReturn .= $tabElement;
    }
    $tabReturn .= "</div>";

    //finished html string is returned. Mission complete!
    return $tabReturn;

}

add_shortcode('imgTab', 'imgTab_func');
function imgTab_func( $atts ) { 
    $a = shortcode_atts( array(
        'src' => '',
        'width' => '100%',
        'height' => 'auto'
    ), $atts );

    //First img element is the main content, and the second is the nav preview 
    return "<img src='" . $a['src'] . "' width='" . $a['width'] . "' height='" . $a['height'] . "'>
    <img src='". $a['src'] . "' width='" . $a['width'] . "' height='" . $a['height'] . "'>";


}

add_shortcode('vidTab', 'vidTab_func');
function vidTab_func( $atts ) { 
    $a = shortcode_atts( array(
        'poster' => '',
        'src' => '',
        'width' => '100%',
        'height' => 'auto'
    ), $atts );

    //vid element is the main content, and the img is the nav preview 
    return "<video width='" . $a['width'] . "' height='" . $a['height'] . "' poster='" . $a['poster'] . "' controls>
        <source src='" . $a['src'] . "' type='video/mp4'>
    </video>
    <img src='". $a['poster'] . "' width='" . $a['width'] . "' height='" . $a['height'] . "'>";

}

add_shortcode('htmlTab', 'htmlTab_func');
function htmlTab_func( $atts, $content = null ) {   
    $a = shortcode_atts( array(
        'poster' => '',
        'width' => '100%',
        'height' => 'auto'
    ), $atts );

    //$content is the main content, and the img is the nav preview.
    return $content . "<img src='". $a['poster'] . "' width='" . $a['width'] . "' height='" . $a['height'] . "'>";
}

そしてユーザーがテキストエディタにタイプするショートコード:

[tabs id="test1"]

//any number and combination of these elements

[imgTab src="imgTab.jpg" width="100" height="100"]

[vidTab poster="vidTab.jpg" src="vidTab.mp4" width="128" height="72"]

[htmlTab poster="htmlTab.jpg" width="100" height="100"] 
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam scelerisque maximus neque gravida gravida.</p>
[/htmlTab]

[/tabs]

そして出力は次のようになります。

<div id='test1'>
    <nav><ul>
        <li class='nav_NUM_1'> 
            <img src='imgTab.jpg' width='100' height='100'>
        </li>
        <li class='nav_NUM_2'> 
            <img src='vidTab.jpg' width='128' height='72'>
        </li>
        <li class='nav_NUM_3'> 
            <img src='htmlTab.jpg' width='100' height='100'>
        </li>
    </ul></nav>
    <section class='content_NUM_1'>
        <img src='imgTab.jpg' width='100' height='100'>
    </section>
    <section class='content_NUM_2'>
        <video width='128' height='72' poster='vidTab.jpg' controls>
            <source src='vidTab.mp4' type='video/mp4'>
        </video>
    </section>
    <section class='content_NUM_3'>
        <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam scelerisque maximus neque gravida gravida.</p>
    </section>
</div>

JavaScriptのタブ機能で処理する準備ができました!

1
Kayboy Bebop