How to create custom tabs in product page magento 2?

Let’s create a product tab in Magento 2 product page using the simple module. We want to display short content for a product using product tabs.

Example, We want to display short description info in product tabs.
Start with the Simple module in Magento 2, create registration.php file to register our module.

Path, app/code/Rbj/ProductTabs/registration.php

<?php

\Magento\Framework\Component\ComponentRegistrar::register(
    \Magento\Framework\Component\ComponentRegistrar::MODULE,
    'Rbj_ProductTabs',
    __DIR__
);

File path, app/code/Rbj/ProductTabs/etc/module.xml

<?xml version="1.0"?>

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
    <module name="Rbj_ProductTabs" setup_version="2.0.0">
        <sequence>
            <module name="Magento_Catalog"/>
        </sequence>
    </module>
</config>

We have passed dependency of Catalog module in sequence tag of our module.
Now We want to create catalog_product_view.xml file for display our custom tabs of the short description.
Create a layout file,
Path, app/code/Rbj/ProductTabs/view/frontend/layout/catalog_product_view.xml

<?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">
        	<!-- For short description tab -->
            <block class="Rbj\ProductTabs\Block\ExtraInfo" name="product.short.description" template="Rbj_ProductTabs::short-descripiton.phtml" group="detailed_info">
                <arguments>
                    <argument name="title" translate="true" xsi:type="string">Extra Info</argument>
                </arguments>
            </block>
   		</referenceBlock>
   	</body>
</page>

We have keep our tab name is Extra Info if you want to change tabs title you can replace Extra info with your title in argument tag.  In the above layout file, We must need to pass group=”detailed_info”  in the block class.

Create template file for call short description content in tabs using template, Path, app/code/Rbj/ProductTabs/view/frontend/templates/short-descripiton.phtml

<?php $extraInfo = $block->getTabsContent(); ?>

<div class="short">
    <?php echo $extraInfo; ?>
</div>

We need to create ExtraInfo.php file to check if a product has short description we need to display tabs otherwise we don’t need to display empty tabs for the short description.

Path, app/code/Rbj/ProductTabs/Block/ExtraInfo.php

<?php

namespace Rbj\ProductTabs\Block;

class ExtraInfo extends \Magento\Framework\View\Element\Template
{
    public function __construct(
        \Magento\Catalog\Block\Product\Context $context,
         array $data = []
    ) {
        $this->_coreRegistry = $context->getRegistry();
        parent::__construct($context, $data);
    }

    /**
     * Retrieve current product object
     *
     * @return \Magento\Catalog\Model\Product
     */
    public function getProduct()
    {
        if (!$this->hasData('product')) {
            $this->setData('product', $this->_coreRegistry->registry('product'));
        }
        return $this->getData('product');
    }

    /**
     * @return string
     */
    public function getTabsContent()
    {
        return $this->getProduct()->getShortDescription();
    }

    /**
     * @return return HTML
     */
    protected function _toHtml()
    {
        if(!empty($this->getTabsContent())) {
            return parent::_toHtml();
        }

        return false;
    }
}

Now run command to activate our module,

php bin/magento setup:upgrade
php bin/magento setup:static-content:deploy -f
php bin/magento cache:flush

You can see new tabs on the product page in the tabs section below the image section. Your new tab will be displayed if your product has the short description otherwise tabs will not display in product page.
You can add new attribute details using the above way.

 

How to create popup modal in magento 2?

How to create Popup Modal using Javascript in Magento 2?

Create a .phtml template file with the given content to make POPUP using Magento 2,

<div class="main-block">
    <div class="content">
    	<a href="javascript:void(0)" id="chart"><?php echo __('Chart Link');?></a>
    </div>
    <!-- Your Popup content with main div display none -->
	<div id="popup-chart" style="display:none;">
	    YOUR POPUP CONTENT GOES HERE
	</div>
</div>
<script>
    require(
        [
            'jquery',
            'Magento_Ui/js/modal/modal',
            'domReady!'
        ],
        function($, modal) {
            $(function() {
            	$("body").on("click", "#chart", function(e) {
                    var options = {
                        type: 'popup',
                        responsive: true,
                        innerScroll: true,
                        buttons: false
                    };
                    var popup = modal(options, $('#popup-chart'));
                    $("#popup-chart").modal("openModal");
                }
            });
        }
    );
</script>

In the above template file, we can show popup based on click on chart link. When click on the chart link defined in our DOM element popup modal will be displayed.

Call Magento_Ui/js/modal/modal object in your require dependency.

There are many default options are available for modal.js file.
Different types of optios you can pass as per your requirement in above options object.

List of default options for a modal popup, if you want to override default value set options value in your custom template in the options object.

    type: 'popup',
    title: '',
    subTitle: '',
    modalClass: '',
    focus: '[data-role="closeBtn"]',
    autoOpen: false,
    clickableOverlay: true,
    popupTpl: popupTpl,
    slideTpl: slideTpl,
    customTpl: customTpl,
    modalVisibleClass: '_show',
    parentModalClass: '_has-modal',
    innerScrollClass: '_inner-scroll',
    responsive: false,
    innerScroll: false,
    modalTitle: '[data-role="title"]',
    modalSubTitle: '[data-role="subTitle"]',
    modalBlock: '[data-role="modal"]',
    modalCloseBtn: '[data-role="closeBtn"]',
    modalContent: '[data-role="content"]',
    modalAction: '[data-role="action"]',
    focusableScope: '[data-role="focusable-scope"]',
    focusableStart: '[data-role="focusable-start"]',
    focusableEnd: '[data-role="focusable-end"]',
    appendTo: 'body',
    wrapperClass: 'modals-wrapper',
    overlayClass: 'modals-overlay',
    responsiveClass: 'modal-slide',
    trigger: '',
    modalLeftMargin: 45,
    closeText: $.mage.__('Close'),
    buttons: [{
        text: $.mage.__('Ok'),
        class: '',
        attr: {},

        /**
         * Default action on button click
         */
        click: function (event) {
            this.closeModal(event);
        }
    }],

How to Create a CSV and Download Programmatically by Magento 2?

Create Export and Download CSV, Excel or Text File Programmatically in Magento 2 by FileFactory Class.

\Magento\Framework\App\Response\Http\FileFactory used to create CSV and download CSV by Magento way. create() function in FileFactory.php is used for create CSV file.

There are many other ways to download CSV files using Core PHP script but its not the best way to use within the Magento Coding standard.
You can write CSV and download a CSV file using just simple below code snippet in your controller file,

<?php
namespace Rbj\CSV\Controller\Adminhtml\Index;

use Magento\Framework\App\Filesystem\DirectoryList;

class Export extends \Magento\Backend\App\Action
{
    public function __construct(
        \Magento\Backend\App\Action\Context $context,
        \Magento\Framework\App\Response\Http\FileFactory $fileFactory,
        \Magento\Framework\Filesystem $filesystem
    ) {
        $this->_fileFactory = $fileFactory;
        $this->directory = $filesystem->getDirectoryWrite(DirectoryList::VAR_DIR);
        parent::__construct($context);
    }

    public function execute()
    {
        $name = date('m_d_Y_H_i_s');
        $filepath = 'export/custom' . $name . '.csv';
        $this->directory->create('export');
        /* Open file */
        $stream = $this->directory->openFile($filepath, 'w+');
        $stream->lock();
        $columns = $this->getColumnHeader();
        foreach ($columns as $column) {
            $header[] = $column;
        }
        /* Write Header */
        $stream->writeCsv($header);

        $products[] = array(1,'Test 1','test 1',100);
        $products[] = array(2,'Test 2','test 2',299);

        foreach ($products as $item) {
            $itemData = [];
            $itemData[] = $item[0];
            $itemData[] = $item[1];
            $itemData[] = $item[2];
            $itemData[] = $item[3];
            $stream->writeCsv($itemData);
        }

        $content = [];
        $content['type'] = 'filename'; // must keep filename
        $content['value'] = $filepath;
        $content['rm'] = '1'; //remove csv from var folder

        $csvfilename = 'Product.csv';
        return $this->_fileFactory->create($csvfilename, $content, DirectoryList::VAR_DIR);
        
    }

    /* Header Columns */
    public function getColumnHeader() {
        $headers = ['Id','Product name','SKU','Price'];
        return $headers;
    }
}

When you run controller action you can download CSV file using just Magento straight forward way.
Using the above way you can download CSV file using Magento 2 Way.