Magento – Merge Detail and More Information tabs into in Magento 2

magento-2.1producttabs

Merge 'Detail' and 'More Information' tabs into And want to display data of 'More Information' above the details page data.

Solution in Magento 1.x is here: http://magento.narrativecard.com/merge-product-description-addition-information-tabs-magento/. It can help community.

Best Answer

Out the box, the two tabs in question - 'Detail' and 'More Information' are in directories:

Detail:

Block - vendor/magento/module-catalog/Block/Product/View/Attributes.php

View - vendor/magento/module-catalog/view/frontend/templates/product/view/attribute.phtml

More Information

Block - vendor/magento/module-catalog/Block/Product/View/Description.php

View - vendor/magento/module-catalog/view/frontend/templates/product/view/details.phtml


So we are going to put the contents of 'More Information' underneath the contents of the 'Details' tab:

Create a new module with the normal registration.php.

etc/module.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../lib/internal/Magento/Framework/Module/etc/module.xsd">
    <module name="<VENDOR_NAME>_<MODULE_NAME>" setup_version="0.0.1" active="true">
        <sequence>
            <module name="Magento_Catalog"/>
        </sequence>
    </module>
</config>

etc/di.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <preference for="Magento\Catalog\Block\Product\View\Description" type="<VENDOR_NAME>\<MODULE_NAME>\Block\Magento\Catalog\Block\Product\View\Description" />
</config>

Now we need to replace the 'Details' tab contents:

view/frontend/templates/product/view/details.phtml

<?php if ($detailedInfoGroup = $block->getGroupChildNames('detailed_info', 'getChildHtml')) { ?>
<div class="product info detailed">
    <?php $layout = $block->getLayout(); ?>
    <div class="product data items" data-mage-init='{"tabs":{"openedState":"active"}}'>
        <?php foreach ($detailedInfoGroup as $name) { ?>
            <?php
                $html = $layout->renderElement($name);
                if (!trim($html)) {
                    continue;
                }
                $alias = $layout->getElementAlias($name);
                $label = $block->getChildData($alias, 'title');
            ?>
            <div class="data item title"
                 aria-labeledby="tab-label-<?php /* @escapeNotVerified */ echo $alias;?>-title"
                 data-role="collapsible" id="tab-label-<?php /* @escapeNotVerified */ echo $alias;?>">
                <a class="data switch"
                   tabindex="-1"
                   data-toggle="switch"
                   href="#<?php /* @escapeNotVerified */ echo $alias; ?>"
                   id="tab-label-<?php /* @escapeNotVerified */ echo $alias;?>-title">
                    <?php /* @escapeNotVerified */ echo $label; ?>
                </a>
            </div>
            <div class="data item content" id="<?php /* @escapeNotVerified */ echo $alias; ?>" data-role="content">
                <?php /* @escapeNotVerified */ echo $html; ?>
                <?php if ($label == "Details") { ?>
                    <?php $_additional = $block->getAdditionalData(); ?>
                    <?php if (count($_additional) > 0) { ?>
                        <?php $_helper = $this->helper('Magento\Catalog\Helper\Output'); ?>
                        <?php $_product = $block->getProduct(); ?>
                        <div class="additional-attributes-wrapper table-wrapper" style="margin-top: 40px;">
                            <table class="data table additional-attributes" id="product-attribute-specs-table">
                                <caption class="table-caption"><?php /* @escapeNotVerified */ echo __('More Information') ?></caption>
                                <tbody>
                                <?php foreach ($_additional as $_data) { ?>
                                    <tr>
                                        <th class="col label" scope="row"><?php echo $block->escapeHtml(__($_data['label'])) ?></th>
                                        <td class="col data" data-th="<?php echo $block->escapeHtml(__($_data['label'])) ?>"><?php /* @escapeNotVerified */ echo $_helper->productAttribute($_product, $_data['value'], $_data['code']) ?></td>
                                    </tr>
                                <?php } ?>
                                </tbody>
                            </table>
                        </div>
                    <?php } ?>
                <?php } ?>
            </div>
        <?php } ?>
    </div>
</div>
<?php } ?>

But this makes use of the function getAdditionalData() so we need to add in that block Block/Magento/Catalog/Block/Product/View/Description.php

<?php

namespace <VENDOR_NAME>\<MODULE_NAME>\Block\Magento\Catalog\Block\Product\View;

class Description extends \Magento\Catalog\Block\Product\View\Description
{

public function getAdditionalData(array $excludeAttr = [])
{
    $data = [];
    $product = $this->getProduct();
    $attributes = $product->getAttributes();
    foreach ($attributes as $attribute) {
        if ($attribute->getIsVisibleOnFront() && !in_array($attribute->getAttributeCode(), $excludeAttr)) {
            $value = $attribute->getFrontend()->getValue($product);

            if (!$product->hasData($attribute->getAttributeCode())) {
                $value = __('N/A');
            } elseif ((string)$value == '') {
                $value = __('No');
            } elseif ($attribute->getFrontendInput() == 'price' && is_string($value)) {
                $value = $this->priceCurrency->convertAndFormat($value);
            }

            if (($value instanceof Phrase || is_string($value)) && strlen($value)) {
                $data[$attribute->getAttributeCode()] = [
                    'label' => __($attribute->getStoreLabel()),
                    'value' => $value,
                    'code' => $attribute->getAttributeCode(),
                ];
            }
        }
    }

    return $data;
}

}

We also need view/frontend/templates/product/view/attribute.phtml

<?php
$_helper = $this->helper('Magento\Catalog\Helper\Output');
$_product = $block->getProduct();
$_call = $block->getAtCall();
$_code = $block->getAtCode();
$_className = $block->getCssClass();
$_attributeLabel = $block->getAtLabel();
$_attributeType = $block->getAtType();
$_attributeAddAttribute = $block->getAddAttribute();

if ($_attributeLabel && $_attributeLabel == 'default') {
    $_attributeLabel = $_product->getResource()->getAttribute($_code)->getFrontendLabel();
}
if ($_attributeType && $_attributeType == 'text') {
    $_attributeValue = ($_helper->productAttribute($_product, $_product->$_call(), $_code)) ? $_product->getAttributeText($_code) : '';
} else {
    $_attributeValue = $_helper->productAttribute($_product, $_product->$_call(), $_code);
}
?>

<?php if ($_attributeValue): ?>
<div class="product attribute <?php /* @escapeNotVerified */ echo $_className?>">
    <?php if ($_attributeLabel != 'none'): ?><strong class="type"><?php /* @escapeNotVerified */ echo $_attributeLabel?></strong><?php endif; ?>
    <div class="value" <?php /* @escapeNotVerified */ echo $_attributeAddAttribute;?>><?php /* @escapeNotVerified */ echo $_attributeValue; ?></div>
</div>
<?php endif; ?>

and finally... view/frontend/layout/catalog_product_view.xml otherwise the existing layout file is expecting to find our view files in vendor/magento...

<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <body>
        <referenceBlock name="product.info.details" template="<VENDOR_NAME>_<MODULE_NAME>::product/view/details.phtml" />
        <referenceBlock name="product.attributes" remove="true"/>            
    </body>
</page>