Creating a jCarousel component for Promo module

The final objective of this practice is that you have the Promo module functioning on the main page of your Bookstore theme integrated with jCarousel and displaying images of registered products in the administrative area of Magento. They will be integrated into different layers to show a unique result in your theme.

For this practice, you will use the responsive carousel feature provided by the jCarousel plugin (http://sorgalla.com/jcarousel/), which serves as a vertical and horizontal control for item lists in HTML. This excellent plugin was created by Jan Sorgalla and has long been used by developers in frontend projects with jQuery.

Creating a jCarousel component for Promo module

Beginning the implementation, access the download page of the jCarousel plugin and download the following JavaScript files:

  • jCarousel Core - Production Version
  • Control Plugin - Production Version
  • Pagination Plugin - Production Version

Move these files to the directory /app/code/Packt/Promo/view/frontend/web/js.

Download the file http://sorgalla.com/jcarousel/examples/responsive/jcarousel.responsive.css , rename it to jcarousel.responsive.less, and save it in the directory /app/code/Packt/Promo/view/frontend/web/css.

Once you have the jCarousel library available, it's time to create references to the functioning in the module. First, create the requirejs-config.js file in the directory /app/code/Packt/Promo/view/frontend/ and insert the following code:

var config = { 
    "map":{ 
        "*":{ 
          promo: "Packt_Promo/js/promo" 
        } 
    }, 
 
    "shim": { 
      "Packt_Promo/js/jquery.jcarousel-core.min": ["jquery"], 
      "Packt_Promo/js/jquery.jcarousel-control.min": ["jquery"], 
      "Packt_Promo/js/jquery.jcarousel-pagination.min": ["jquery"] 
    } 
}; 

In the configuration file promo: "Packt_Promo/js/promo" has been mapped, that is a custom JavaScript called promo.js, which will be created in the next sequence, as well as the referenced dependencies by the parameter "shim". These external dependencies refer to the jCarousel library that is being used in the project.

Now create the promo.js file in the directory /app/code/Packt/Promo/view/frontend/web/js with the following codification:

define([ 
  'jquery', 
  'Packt_Promo/js/jquery.jcarousel-core.min', 
  'Packt_Promo/js/jquery.jcarousel-control.min', 
  'Packt_Promo/js/jquery.jcarousel-pagination.min' 
], function($){ 
 
    var o = {}; 
 
    o.promoBlock = function(jcarousel, prev, next, pagination){ 
      var jcarousel = $(jcarousel); 
        jcarousel 
            .on('jcarousel:reload jcarousel:create', function () { 
                var carousel = $(this), 
                    width = carousel.innerWidth(); 
 
                if (width >= 600) { 
                    width = width / 3; 
                } else if (width >= 350) { 
                    width = width / 2; 
                } 
 
                carousel.jcarousel('items').css('width', Math.ceil(width) + 'px'); 
            }) 
            .jcarousel({ 
                wrap: 'circular' 
            }); 
 
        $(prev) 
            .jcarouselControl({ 
                target: '-=1' 
            }); 
 
        $(next) 
            .jcarouselControl({ 
                target: '+=1' 
            }); 
 
        $(pagination) 
            .on('jcarouselpagination:active', 'a', function() { 
                $(this).addClass('active'); 
            }) 
            .on('jcarouselpagination:inactive', 'a', function() { 
                $(this).removeClass('active'); 
            }) 
            .on('click', function(e) { 
                e.preventDefault(); 
            }) 
            .jcarouselPagination({ 
                perPage: 1, 
                item: function(page) { 
                    return '<a href="#' + page + '">' + page + '</a>'; 
                } 
            }); 
  } 
 
  return o; 
}); 

The custom JavaScript called promo.js, aims to carry the functionalities of control and pagination of the jCarousel plugin to be available for use in the template.

In the instruction definition, the external files are loaded to be used in custom JavaScript. In the second parameter of the function, define has already created the object o and has declared a method called o.promoBlock(). In the promoBlock() method that receives the template parameters to the jCarousel configuration, the jCarousel functionalities are declared that interact with the size of the images and the dynamic change of HTML and CSS files to create the effect/animation of the image carousel.

It is important at this point to note that JavaScript works with callback functions or higher-order functions; that is, basically, it is possible to pass a function as a parameter to another function. This book does not have the scope of deepening the JavaScript techniques, but it is strongly recommended that you improve your studies by researching it further.

Open the layout configuration file /app/code/Packt/Promo/view/frontend/layout/cms_index_index.xml and add the following code on line 3:

<head> 
<css src="Packt_Promo::css/jcarousel.responsive.css"/> 
</head> 

This code will be responsible for loading the jCarousel styles file in the Promo module.

At this point, you should have the following directories and file structure:

Creating a jCarousel component for Promo module

Now that you've included in the jCarousel module the already made declaration of the JavaScript file configuration and execution and have also declared the CSS file, it's time to focus on the module's objective. To begin the integration with products registered in the administrative area, open the file /app/code/Packt/Promo/Block/Promo.php and enter the following code:

<?php 
namespace PacktPromoBlock; 
 
/** 
* Promo block 
*/ 
class Promo 
    extends MagentoFrameworkViewElementTemplate{ 
 
    protected $context; 
    protected $_categoryFactory; 
    protected $storeManager; 
 
   public function __construct( 
   MagentoBackendBlockTemplateContext $context, 
   MagentoCatalogModelCategoryFactory $categoryFactory, 
   MagentoStoreModelStoreManagerInterface $storeManager, 
   array $data = [] 
   ){ 
    $this->_storeManager=$storeManager; 
    $this->_categoryFactory = $categoryFactory; 
    parent::__construct($context, $data); 
   } 
 
   public function getCategory($categoryId){ 
     $category = $this->_categoryFactory->create(); 
     $category->load($categoryId); 
     return $category; 
   } 
 
   public function getCategoryProducts($categoryId){ 
     $products = $this->getCategory($categoryId)->getProductCollection(); 
     $products->addAttributeToSelect('small_image'); 
     return $products; 
   } 
 
   public function getProductUrlImage(){ 
     return 
      $this->_storeManager->getStore()->getBaseUrl(MagentoFrameworkUrlInterface::URL_TYPE_MEDIA) . 
      "catalog/product"; 
   } 
 
    public function getTitle(){ 
      return "My Promotions Block"; 
    } 
} 

Initially, in the Promo class, there was only the getTitle() method that returns the module title. Now, besides the constructor method, three different methods were inserted that will be better detailed in the next section.

The constructor method injects three classes in the Promo class which can be highlighted CategoryFactory and StoreManagerInterface, and which provide methods for manipulating catalog information and the base URL of the store, respectively. At this point it is necessary to insert the parent::__construct referencing the $context, with the objective of being a container for other objects of a super class.

On the  getCategory() method, the category searched by ID is returned. This method will be used in the template to reference the category of images of products to be displayed on the module using the object, $_categoryFactory.

With the selected category, it is possible to return the collection of products by the getCategoryProducts() method through the instruction $this->getCategory ($categoryId)->getProductCollection(), limiting the data return scope only to small product images through the instruction, $products->addAttributeToSelect ('small_image').

The method getProductUrlImage() returns the store URL joining with the string "catalog/product" so that images can be displayed on jCarousel with your absolute URL, dynamically.

Tip

For more information, access the official documentation for backend development of Magento 2 at http://devdocs.magento.com/guides/v2.1/extension-dev-guide/bk-extension-dev-guide.html .

It only lacks the promo.phtml template to receive the implementation of jCarousel but first, enter the administrative area and access the Products | Categories menu. Create a new sub-category of products inside the Default category, called Promotions:

Creating a jCarousel component for Promo module

This category will be used to refer to the products in the Promo module. Do not forget, at the time of creation, to mark the option for the new subcategory to not be shown as a menu item:

Creating a jCarousel component for Promo module

After creation, take note of the ID number that will be generated by the system. You will need this number to configure the display Promo module template:

Creating a jCarousel component for Promo module

Add products to the Promotions category so that it has to take at least six registered products:

Creating a jCarousel component for Promo module

Be aware that the ID number can vary. Write down the number that is generated in your system for later use on the template promo.phtml.

Now open the file /app/code/Packt/Promo/view/frontend/templates/promo.phtml and insert the following code:

<?php 
/** 
 * Promo view template 
 * 
 * @var $block PacktPromoBlockPromo 
 */ 
 
$productCollection = $block->getCategoryProducts(YOUR_PROMOTIONS_ID); 
$mediaUrl = $block->getProductUrlImage(); 
 
?> 
 
<h1 style="text-align:center;"><?php echo $block->getTitle(); ?></h1> 
<div class="wrapper"> 
 
            <div class="jcarousel-wrapper"> 
                <div class="jcarousel"> 
                    <ul> 
                      <?php 
                        foreach ($productCollection as $product) { 
                          echo '<li><img src="' . 
                                $mediaUrl . 
                                $product->getData()['small_image'] . 
                                '" alt="Image 1"></li>'; 
                        } 
                      ?> 
                    </ul> 
                </div> 
 
                <a href="#" class="jcarousel-control-prev">&lsaquo;</a> 
                <a href="#" class="jcarousel-control-next">&rsaquo;</a> 
 
                <p class="jcarousel-pagination"></p> 
            </div> 
        </div> 
<script> 
requirejs(['promo'], function(promo){ 
  promo.promoBlock('.jcarousel', '.jcarousel-control-prev', '.jcarousel-control-next', '.jcarousel-pagination'); 
}); 
</script> 

This template file has PHP instructions (backend), HTML, and JS (frontend) performing a complete integration of the Promo module.

The $productCollection variable receives the registered products of the Promotions category through $block-query>getCategoryProducts() , which is passed the subcategory ID to the method declaration in the Block/Promo class. The $mediaUrl variable receives the absolute URL of the product images. The entire HTML structure and the declaration of classes in each tag are structured according to the jCarousel documentation.

The code snippet is as follows:

<?php 
foreach ($productCollection as $product) { 
echo '<li><img src="' . 
            $mediaUrl . 
               $product->getData()['small_image'] . 
               '" alt="Image 1"></li>'; 
} 
?> 

It is responsible for writing all the main images from the Promotions category, dynamically feeding the <img> tag and feeding the necessary listing for the jCarousel function according to the proposal.

Take a look at the following In the snippet:

<script> 
requirejs(['promo'], function(promo){ 
  promo.promoBlock('.jcarousel', '.jcarousel-control-prev', '.jcarousel-control-next', '.jcarousel-pagination'); 
}); 
</script> 

It creates a reference to the custom JavaScript promo.js feeding the parameters required so that the file returns to the main function of jCarousel.

Perfect! You already have your module developed and functioning. However, it is still not ready to be installed in other Magento 2 instances because it does not have its declaration of the composer.json file. Create a composer.json file in the /app/code/ Packt/Promo/ directory:

{ 
  "name": "packt/promo", 
  "description": "Module that creates a new Promotion block", 
  "type": "magento2-module", 
  "version": "1.0.0", 
  "license": [ 
    "OSL-3.0", 
    "AFL-3.0" 
  ], 
  "require": { 
    "php": "~5.5.0|~5.6.0|~7.0.0", 
    "magento/framework": "~100.0.4" 
  }, 
  "autoload": { 
    "files": [ "registration.php" ], 
    "psr-4": { 
      "Packt\Promo": "" 
    } 
  } 

Do not worry for now about the meaning of this file. In the next chapter, we will approach its use in greater depth.

To finish the changes, carry out the following procedure:

  1. Open the terminal or prompt command and access the root directory on your Magento 2 instance.
  2. Run the commands grunt exec:bookstore_en_US and grunt exec:bookstore_de_DE.
  3. Run the commands grunt less:bookstore_en_US and grunt less:bookstore_de_DE.
  4. Run the commands php bin/magento setup:static-content:deploy en_US and php bin/magento setup:static-content:deploy de_DE.
  5. Lastly, run the command php bin/magento cache:clean.

Reload the homepage of your Magento 2 instance to check the result:

Creating a jCarousel component for Promo module

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.138.110.119