1
\$\begingroup\$

I'm using Bootstrap 3 to build a tab-panel component, based on information coming from the end-user. I don't like how there's a second foreach loop, but I don't know how else to print the HTML correctly.

Given an array structured like this:

[
    {
        "title": "Title 1",
        "content": "Lorem Ipsum"
    },
    {
        "title": "Title 2",
        "content": "Lorem Ipsum"
    }
]

And a "view" template structured like this:

<?php $panels = rwmb_meta("ssc_tabpanels") ?>
<?php if( !empty($panels) ): ?>
    <div id="program-details">
        <ul class="nav nav-pills nav-stacked" role="tablist">
            <?php foreach($panels as $i => $p): ?>
            <li role="presentation">
                <a href="#tab-<?php echo $i ?>" data-toggle="tab"><?php echo $p['title'] ?></a>
            </li>
            <?php endforeach; ?>
        </ul>

        <div class="tab-content">
            <?php foreach($panels as $i => $p): ?>
            <div class="tab-pane" id="tab-<?php echo $i ?>"><?php echo $p['content'] ?></div>
            <?php endforeach; ?>
        </div>
    </div>
<?php endif; ?>

What suggestions do you have for removing the second foreach loop while still maintaining the correct bootstrap code?

\$\endgroup\$
1
\$\begingroup\$

One way would be to build the value of the tab contents in a variable during the first loop, and just print it once the loop ends. I have not written PHP in a while nor tested this code, so use as reference.

<?php $panels = rwmb_meta("ssc_tabpanels") ?>
<?php $tabContentHtm = ''; ?>
<?php if( !empty($panels) ): ?>
<div id="program-details">
    <ul class="nav nav-pills nav-stacked" role="tablist">
        <?php
        //build the tabs    
        foreach($panels as $i => $p):
        ?>
        <li role="presentation">
            <a href="#tab-<?php echo $i ?>" data-toggle="tab"><?php echo $p['title'] ?></a>
        </li>
        <?php
        // build content displayed on click of each tab
        $tabContentHtm .= '<div class="tab-pane" id="tab-'. $i .'">'. $p['content'] .'</div>\r\n';
        endforeach; 
        ?>
    </ul>

    <div class="tab-content">
        <?php echo $tabContentHtm; ?>
    </div>
</div>
<?php endif; ?>

The rendered code should look something like this

<div id="program-details">
    <ul class="nav nav-pills nav-stacked" role="tablist">
        <li role="presentation">
            <a href="#tab-1" data-toggle="tab">Title 1</a>
        </li>
        <li role="presentation">
            <a href="#tab-2" data-toggle="tab">Title 2</a>
        </li>
    </ul>

    <div class="tab-content">
        <div class="tab-pane" id="tab-1">Lorem Ipsum of Title 1</div>
        <div class="tab-pane" id="tab-2">Lorem Ipsum of Title 2</div>
    </div>
</div>
\$\endgroup\$
0
\$\begingroup\$

PHP also has a short open tag that I would use for echo.

<?= $p['content'] ?>
\$\endgroup\$
  • \$\begingroup\$ I'm stuck supporting 5.3 at the moment, so I can't guarantee that that it's available. 5.4 guarantees that. Thanks for the suggestion though! \$\endgroup\$ – Goldentoa11 Aug 21 '15 at 13:59
0
\$\begingroup\$

What I ended up doing was creating a function that re-ordered the array into a structure like

{
    "list-items": [ "<li ...><a ...>Title</a></li>", ... ],
    "pane-items": [ "<div ...>Content</div>", ... ]
}

And then in the theme I used implode("\n", $items['list-items']) and implode("\n", $items['pane-items']) where appropriate.

Code

/**
 * @param array $panels
 * @return array
 */
function restructure_panels( array $panels )
{

    $result = array(
        "list-items" => array(),
        "pane-items" => array()
    );

    $active = true;
    array_map(function ($k, $v) use (&$result, &$active) {

        if (!empty($v['title']) && !empty($v['content'])) {

            $classes = "";
            if ($active)
                $classes = " active";

            $result['list-items'][] = "<li role=\"presentation\" class=\"{$classes}\"><a href=\"#tab-{$k}\" data-toggle=\"tab\">{$v['title']}</a></li>";
            $result['pane-items'][] = "<div class=\"tab-pane {$classes}\" id=\"tab-{$k}\">{$v['content']}</div>";

            $active = false;
        }

    }, array_keys($panels), $panels);

    return $result;

}

// in single-program.php

<?php $panels = restructure_panels( rwmb_meta("ssc_tabpanels") ) ?>

<?php if( !empty($panels) ): ?>
    <div id="program-details" class="row">
        <div class="col-md-5">
            <ul class="nav nav-pills nav-stacked" role="tablist">
                 <?php echo implode( "\n", $panels['list-items'] ); ?>
            </ul>
        </div>

        <div class="col-md-7">
            <div class="tab-content">
                <?php echo implode( "\n", $panels['pane-items'] ); ?>
            </div>
        </div>
     </div>
<?php endif; ?>
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.