To go a little deeper on the concepts seen so far, we will develop a new module called Sweet Tweet integrating with social media. This module will make an integration with the Application Programming Interface (API) of Twitter and it will be used to display tweets with hashtags #magento2, #magentodev and #magentolive in the visualization layer of your Magento 2 instance. With this practice it will be possible to memorize even more the concept of componentization and managing dependencies via composer.json
file.
In the previous development of the Promo module, you used the jCarousel library as a third-party library. In the development of the Sweet Tweet module you will use the TwitterOAuth authentication package that enables authentication on the API layer Twitter but with a crucial difference: You will use the composer.json
to manage this additional package in a more effective way.
The Twitter developers' area (https://dev.twitter.com/) provides documentation about its API so developers all over the world can create applications that have interaction directly with the Twitter database providing a series of options, parameterization and ways to exchange messages using the Representational State Transfer (REST) architecture. The REST API uses OAuth (http://oauth.net/) technology to identify Twitter applications. Users and its responses are available in JSON format.
For the development of the new module, it will be necessary for you to have an activated account on Twitter to generate the access tokens that are responsible for the authentication of your application with the REST API Twitter.
Access the address https://apps.twitter.com and click on the Create New App button. You will have access to the creation page and fill in the following fields:
After accepting the Developer Agreement from Twitter click on the Create your Twitter Application button. Access the applications configuration by clicking on your new application and click on the Keys and Access Tokens tab to take note of the following fields:
Keep these fields because they will be needed later in the solution development sequence.
To learn more about the REST API options available on Twitter access the link https://dev.twitter.com/rest/public .
The library Twitter OAuth (https://twitteroauth.com/) was created by Abraham Williams in order to provide a transparent way to authenticate applications with the REST API Twitter. Well used by the development community, this library will be used as a third-party library to develop the Sweet Tweet module.
In addition, to provide the OAuth authentication method, the library provides the methods of GET
, POST
, Proxy
, and others that complement a robust solution for those who want to use this library in their application.
To use this library on the Sweet Tweet module, the process will be a little different from the usual. You will use the Composer and the composer.json
file to install this dependency on the Sweet Tweet module in the nest section of the chapter.
For more information about the Twitter OAuth access the official documentation available at https://twitteroauth.com/ .
Initially create the following directories that will be part of the new module:
<magento_root>/app/code/Packt/SweetTweet
<magento_root>/app/code/Packt/SweetTweet/Block
<magento_root>/app/code/Packt/SweetTweet/Controller
<magento_root>/app/code/Packt/SweetTweet/Controller/Index
<magento_root>/app/code/Packt/SweetTweet/Controller/Magento2
<magento_root>/app/code/Packt/SweetTweet/Controller/MagentoDev
<magento_root>/app/code/Packt/SweetTweet/Controller/MagentoLive
<magento_root>/app/code/Packt/SweetTweet/etc
<magento_root>/app/code/Packt/SweetTweet/etc/frontend
<magento_root>/app/code/Packt/SweetTweet/Observer
<magento_root>/app/code/Packt/SweetTweet/view
<magento_root>/app/code/Packt/SweetTweet/view/frontend/layout
<magento_root>/app/code/Packt/SweetTweet/view/frontend/templates
<magento_root>/app/code/Packt/SweetTweet/view/frontend/web/css/source
You don't have to worry at the moment about each directory specification created. They will be detailed in the development sequence.
Create the composer.json
file in the root directory of your SweetTweet
module and insert the following code:
{ "name": "packt/sweet-tweet", "description": "Tweet Magento Module - Packt Publishing", "type": "magento2-module", "version": "1.0.0", "license": [ "OSL-3.0", "AFL-3.0" ], "require": { "abraham/twitteroauth": "^0.6.2" }, "autoload": { "files": [ "registration.php" ], "psr-4": { "Packt\SweetTweet": "" } } }
In the composer.json
file the names of the module, version, type, as well as the licenses that are applied are declared. Open Software License 3 (https://opensource.org/licenses/OSL-3.0) and Academic Free License (https://opensource.org/licenses/AFL-3.0).
The module dependencies are declared as versions of PHP language by the declaration "php": "5.5.0|~ 5.6.0|~7.0.0"
. The most important point however in the declaration is the dependence of the package TwitterOAuth "abraham/twitteroauth": "^ 0.6.2"
which is the minimum necessary prerequisite to run the SweetTweet
module.
In the autoload
declaration, the registration.php
file is declared to be loaded accompanied of the convention name PacktSweetTweet
linked directly to PHP Standards Recommendations (PSR) 4 - Autoloader. In the next chapter, a more detailed way to adopt PSRs on Magento 2 will be approached.
Open the terminal or the prompt command to access the root directory of your SweetTweet
module and run the following command:
composer install --no-autoloader
This command will make the Twitter OAuth installation on the Packt/SweetTweet/vendor
directory. The packages will be included on the registration.php
in the next sequence.
It is important to reiterate that the Composer installs the packages that are available on Packagist (https://packagist.org/). Once we have the TwitterOAuth available on Packagist, it is possible to automate the management of its dependence on the SweetTweet
module:
The vendor
directory will have the following provision:
Create the registration.php
file on the Packt/SweetTweet/
directory with the following codification:
<?php MagentoFrameworkComponentComponentRegistrar::register( MagentoFrameworkComponentComponentRegistrar::MODULE, 'Packt_SweetTweet', __DIR__ ); require_once __DIR__ . "/vendor/abraham/twitteroauth/autoload.php";
Besides the instructions that you already know, you will also require the instruction require_once "/vendor/abraham/twitteroauth/autoload.php"
which will be responsible for loading the package TwitterOAuth
using the Autoloader (PSR-4) concept. This instruction is important because it allows your module to be fully extensible providing for the installation of third-party libraries in a transparent way and which work in your module using the PSR-4 notation.
Now, the basic module settings will be declared in the XML files.
First, create the module.xml
file for module declaration in the directory Packt/SweetTweet/etc
on Magento 2:
<?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="Packt_SweetTweet" setup_version="1.0.0"/> </config>
Magento 2 works with the validation scheme called Uniform Resource Names (URN) as reference to the XML declarations. The tag <module>
contains the name of the Vendor
and the module, being a standard nomenclature: Vendor_Module
.
In the directory, Packt/SweetTweet/etc/
frontend create the routes.xml
file with the following code:
<?xml version="1.0"?> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework: App/etc/routes.xsd"> <router id="standard"> <route id="sweettweet" frontName="sweettweet"> <module name="Packt_SweetTweet" /> </route> </router> </config>
The routes.xml
file is responsible for defining which URL will be accessible to the user and, consequently, which Controller will process the request. In this case the module will be accessible from the URL http://localhost/Packt/SweetTweet
.
In the directory, Packt/SweetTweet/etc/frontend
create the events.xml
file with the following code:
<?xml version="1.0"?> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework: Event/etc/events.xsd"> <event name="page_block_html_topmenu_gethtml_before"> <observer name="Packt_SweetTweet_observer" instance="PacktSweetTweetObserverTopmenu" /> </event> </config>
The events.xml
is declaring one Observer
in the module that will be responsible for declaring a new menu item on the front-end Magento 2 directing the user to access the SweetTweet
module. Observer
is an event handler that listens to events triggered by the user or system. The <event>
tag is getting the basic information of the top menu block to handle later in PHP code and the <observer>
tag is declaring the Topmenu
observer class.
For more information about Observers in Magento 2 consult the official documentation available at http://devdocs.magento.com/guides/v2.0/architecture/archi_perspectives/framework.html .
In the directory Packt/SweetTweet/Controller/Index
create the Index.php
file with the following code:
<?php namespace PacktSweetTweetControllerIndex; class Index extends MagentoFrameworkAppActionAction{ protected $resultPageFactory; public function __construct( MagentoFrameworkAppActionContext $context, MagentoFrameworkViewResultPageFactory $resultPageFactory ) { $this->resultPageFactory = $resultPageFactory; parent::__construct($context); } public function execute(){ return $this->resultPageFactory->create(); } }
Now you will create controllers to manage the three distinct layers according to the hashtag. All the controllers will have the nomenclature of the file as Index.php
, but in different directories.
In the directory Packt/SweetTweet/Controller/Magento2
create the Index.php
controller with the following code:
<?php namespace PacktSweetTweetControllerMagento2; class Index extends MagentoFrameworkAppActionAction{ protected $resultPageFactory; public function __construct( MagentoFrameworkAppActionContext $context, MagentoFrameworkViewResultPageFactory $resultPageFactory ) { $this->resultPageFactory = $resultPageFactory; parent::__construct($context); } public function execute() { return $this->resultPageFactory->create(); } }
In the directory Packt/SweetTweet/Controller/MagentoDev
create the Index.php
controller:
<?php namespace PacktSweetTweetControllerMagentoDev; class Index extends MagentoFrameworkAppActionAction{ protected $resultPageFactory; public function __construct( MagentoFrameworkAppActionContext $context, MagentoFrameworkViewResultPageFactory $resultPageFactory ) { $this->resultPageFactory = $resultPageFactory; parent::__construct($context); } public function execute() { return $this->resultPageFactory->create(); } }
Finally, in the directory Packt/SweetTweet/Controller/MagentoLive
create the Index.php
controller:
<?php namespace PacktSweetTweetControllerMagentoLive; class Index extends MagentoFrameworkAppActionAction{ protected $resultPageFactory; public function __construct( MagentoFrameworkAppActionContext $context, MagentoFrameworkViewResultPageFactory $resultPageFactory ) { $this->resultPageFactory = $resultPageFactory; parent::__construct($context); } public function execute() { return $this->resultPageFactory->create(); } }
These controllers will be responsible for creating the rendering of the module home page and the three pages that will display the results of tweets. The rendering according to the access to the module index page is done by the use of PageFactory
class and its creation is done by the execute()
method, extending the functionalities of the Action
class.
The inheritance of the Action
class provides the functionality to handle actions triggered by the URL access. When the user accesses the URL: http://localhost/SweetTweet/ the routes.xml
the file will redirect to the Index/Index.php
controller to treat the user request made by the access of the URL.
The Dependency Injection
Context $context
and PageFactory $resultPageFactory
in the __construct()
method are declaring the initial construct of the Action
class and declaring the View layer to work with the template file.
For more information about the Dependency Injection access the Magento 2 official documentation at http://devdocs.magento.com/guides/v2.0/extension-dev-guide/depend-inj.html .
The blocks will be responsible for the declaration of applied logic and to the View layer of SweetTweet
module. In the directory Packt/SweetTweet/Block
create the Index.php
file with the following code:
<?php namespace PacktSweetTweetBlock; class Index extends MagentoFrameworkViewElementTemplate{ public function getMagento2(){ return $this->getData('urlMagento2'); } public function getMagentoDev(){ return $this->getData('urlMagentoDev'); } public function getMagentoLive(){ return $this->getData('urlMagentoLive'); } }
The getMagento2()
, getMagentoDev()
and getMagentoLive()
methods are responsible for collecting the URLs that will be declared in the XML files to the configuration of the View layer extending the Template
class for access to the getData()
method.
You will now encode the heart of the Sweet Tweet module. This degree of importance is because of the fact that the block loads the Business layer that effectively give life to the module. To create the Tweets.php
file in the Packt/SweetTweet/Block
directory use the following code:
<?php namespace PacktSweetTweetBlock; use AbrahamTwitterOAuthTwitterOAuth; class Tweets extends MagentoFrameworkViewElementTemplate{ private $consumerKey; private $consumerSecret; private $accessToken; private $accessTokenSecret; public function searchTweets(){ $connection = $this->twitterDevAuth(); $result = $connection->get("search/tweets", array("q" =>$this->getData('hashtag'), "result_type"=>"recent", "count" => 10)); return $result->statuses; } private function twitterDevAuth(){ $this->consumerKey = YOUR_CONSUMER_KEY; $this->consumerSecret = YOUR_CONSUMER_SECRET; $this->accessToken = YOUR_ACCESS_TOKEN; $this->accessTokenSecret = YOUR_ACCESS_TOKEN_SECRET; return new TwitterOAuth($this->consumerKey, $this->consumerSecret, $this->accessToken, $this->accessTokenSecret); } }
This block effectively uses the TwitterOAuth
package that is being declared by the PSR notation AbrahamTwitterOAuthTwitterOAuth
. Only here there are two PSR standards used: PSR-0 and PSR-4.
The searchTweets()
method is responsible for performing the research of the top ten most recent tweets according to #hashtags that will be declared following the sequence on the project layout configuration files.
The twitterDevAuth()
method authenticates the REST API Twitter.
Previously you declared the XML file responsible for the initial indication of the Observer
that will be responsible for the module inclusion on the top menu. Now, in the directory Packt/SweetTweet/Observer
, create the Topmenu.php
observer with the following code:
<?php namespace PacktSweetTweetObserver; use MagentoFrameworkEventObserver as EventObserver; use MagentoFrameworkDataTreeNode; use MagentoFrameworkEventObserverInterface; class Topmenu implements ObserverInterface{ /** * @param EventObserver $observer * @return $this */ public function execute(EventObserver $observer) { $urlInterface = MagentoFrameworkApp ObjectManager::getInstance()-> get('MagentoFrameworkUrlInterface'); $active = strpos($urlInterface->getCurrentUrl(), "sweettweet"); $menu = $observer->getMenu(); $tree = $menu->getTree(); $data = [ 'name' => __("SweetTweet"), 'id' => 'tweetsmenu', 'url' => $urlInterface->getBaseUrl() . 'sweettweet', 'is_active' => $active ]; $node = new Node($data, 'id', $tree, $menu); $menu->addChild($node); return $this; } }
The Topmenu.php
dynamically creates a new item for the Sweet Tweet module by adding a node in the top menu link schema. The ObjectManager::getInstance()->get('MagentoFrameworkUrlInterface')
gets the base URL and the current URL to create the specific link to Sweet Tweet module. The observer
works dynamically with the Document Object Model (DOM) concept of node and trees.
You have already prepared all the logical functioning scheme of the Sweet Tweet module, and it is now necessary to create rules of View templates and effectively provide access to the user.
Now, working with the Packt/SweetTweet/view/frontend/layout
directory declare the sweettweet_index_index.xml
file as follows:
<?xml version="1.0"?> <page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="1column" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd"> <head> <title> SweetTweet PacktModule </title> </head> <body> <referenceContainer name="content"> <block class="PacktSweetTweetBlockIndex" template="Packt_SweetTweet::index.phtml"> <arguments> <argument name="urlMagento2" xsi:type="url" path="sweettweet/magento2" /> <argument name="urlMagentoLive" xsi:type="url" path="sweettweet/magentolive" /> <argument name="urlMagentoDev" xsi:type="url" path="sweettweet/magentodev" /> </arguments> </block> </referenceContainer> </body> </page>
The <block>
tag is binding the block Index.php
to the index.phtml
template. The <arguments>
tag is transporting three URL parameters to the block. These parameters will be used in index.phtml
file.
In the same directory, you will declare three more configuration files that will be responsible for taking care of the templates that display the tweets according to the hashtag.
Declare the sweettweet_magento2_index.xml
file:
<?xml version="1.0"?> <page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="1column" xsi:noNamespaceSchemaLocation="urn:magento:framework: View/Layout/etc/page_configuration.xsd"> <head> <title> SweetTweet #Magento2 </title> <css src="Packt_SweetTweet::css/source/module.css"/> </head> <body> <referenceContainer name="content"> <block class="PacktSweetTweetBlockTweets" template="Packt_SweetTweet::tweets.phtml"> <arguments> <argument name="hashtag"xsi:type="string"> #magento2 </argument> </arguments> </block> </referenceContainer> </body> </page>
Declare the file sweettweet_magentodev_index.xml
:
<?xml version="1.0"?> <page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="1column" xsi:noNamespaceSchemaLocation="urn:magento:framework: View/Layout/etc/page_configuration.xsd"> <head> <title> SweetTweet #MagentoDev </title> <css src="Packt_SweetTweet::css/source/module.css"/> </head> <body> <referenceContainer name="content"> <block class="PacktSweetTweetBlockTweets" template="Packt_SweetTweet::tweets.phtml"> <arguments> <argument name="hashtag" xsi:type="string"> #magentodev </argument> </arguments> </block> </referenceContainer> </body> </page>
Declare the file sweettweet_magentolive_index.xml
:
<?xml version="1.0"?> <page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="1column" xsi:noNamespaceSchemaLocation="urn:magento:framework: View/Layout/etc/page_configuration.xsd"> <head> <title> SweetTweet #MagentoLive </title> <css src="Packt_SweetTweet::css/source/module.css"/> </head> <body> <referenceContainer name="content"> <block class="PacktSweetTweetBlockTweets" template="Packt_SweetTweet::tweets.phtml"> <arguments> <argument name="hashtag" xsi:type="string"> #magentolive </argument> </arguments> </block> </referenceContainer> </body> </page>
The <css>
element is responsible for loading the module css
. The <block>
tag is binding the block Tweets.php
to the tweets.phtml
template. The <argument name="hashtag">
is transporting the hashtag parameter to the Tweets.php
block to search the last mentions of the specific hashtag in the Twitter database.
Once the settings of the templates are ready, it is time to code the template files. In the directory Packt/SweetTweet/view/frontend/templates
you will encode two distinct templates. The first will be the module index page and the second will have the purpose of displaying the tweet results according to the #hashtag selected.
Create the index.phtml
file with the following code:
<h2><?php echo __('Recent Tweets:')?></h2> <ul> <li> <a href="<?php echo $block->escapeHtml($block->getMagento2()) ?>"> <span><?php echo __('Magento2')?></span> </a> </li> <li> <a href="<?php echo $block->escapeHtml($block->getMagentoDev()) ?>"> <span><?php echo __('MagentoDev')?></span> </a> </li> <li> <a href="<?php echo $block->escapeHtml($block->getMagentoLive()) ?>"> <span><?php echo __('MagentoLive')?></span> </a> </li> </ul>
The $block
object has access to the methods of Block/Index.php
and the URL of the pages are building dynamically.
Now create the file tweets.phtml
:
<?php $tweets = $block->searchTweets(); ?> <div id="wrapper"> <div id="columns"> <?php foreach ($tweets as $tweet){ ?> <div class="tweet"> <p> <a href="https://twitter.com/intent/user?user_id= <?php echo $tweet->user->id; ?>" target="_blank"> <img src="<?php echo $tweet->user->profile_image_url; ?>" alt="profile"> <?php echo $tweet->user->name; ?> </a> <br /> <?php echo __('Created:')?> <?php echo $tweet->created_at; ?> <br /><br /> <a href="<?php echo isset($tweet->entities->urls[0]->url) ? $tweet->entities->urls[0]->url : "#"; ?>" target="_blank"><?php echo $tweet->text;?></a> <?php echo $tweet->text;?> </a> </p> </div> <?php } ?> </div> </div>
The searchTweets()
method is iterating over the results obtained by accessing the JSON response sent by the REST API Twitter and writing the URL to access the tweet by $tweet->statement->entities->urls[0]->url
, as well as displaying user information, creation date, and tweet.
To finish the View layer, declare the file module.less
in the directory Packt/SweetTweet/view/frontend/web/css/source
, which will be the CSS / LESS stylesheet:
@media (min-width: 960px){ #wrapper { width: 90%; max-width: 1100px; min-width: 800px; margin: 50px auto; } #columns { -webkit-column-count: 3; -webkit-column-gap: 10px; -webkit-column-fill: auto; -moz-column-count: 3; -moz-column-gap: 10px; -moz-column-fill: auto; column-count: 3; column-gap: 15px; column-fill: auto; } } .tweet { display: inline-block; background: #FEFEFE; border: 2px solid #FAFAFA; box-shadow: 0 1px 2px rgba(34, 25, 25, 0.4); margin: 0 2px 15px; -webkit-column-break-inside: avoid; -moz-column-break-inside: avoid; column-break-inside: avoid; padding: 15px; padding-bottom: 5px; background: -webkit-linear-gradient(45deg, #FFF, #F9F9F9); opacity: 1; -webkit-transition: all .2s ease; -moz-transition: all .2s ease; -o-transition: all .2s ease; transition: all .2s ease; } .tweet img { width: 15%; display:block; float:left; margin: 0px 5px 0px 0px; } .tweet p { font: 12px/18px Arial, sans-serif; color: #333; margin: 0; } #columns:hover .img:not(:hover) { opacity: 0.4; }
Done! After too much work it is time to activate the module in Magento 2.
At the end you basically have the following SweetTweet
module directory structure:
Notice that you worked on all layers of the Magento 2 system components to create a unique solution for your instance. Too much work here, isn't it? But it was definitely worth it.
Now it's time to have your efforts rewarded by activating the module. Follow the step by step instructions to active the module in your Magento 2 instance:
php bin/magento module:enable --clear-static-content Packt_SweetTweet
*
Run the command php bin/magento setup:upgrade
Take a look at the following screenshot:
With the activated module, it is necessary to run the Grunt scripts and make a new deployment of static files in your Magento 2 instance:
grunt clean:bookstore_en_US
and grunt clean:bookstore_de_DE
grunt exec:bookstore_en_US
and grunt exec:bookstore_de_DE
grunt less:bookstore_en_US
and grunt less:bookstore_de_DE
php bin/magento setup:static-content:deploy en_US de_DE
php bin/magento cache:clean
Access your Magento 2 local instance and check that you now have an item of a new menu called SweetTweet
with the following content:
This home page contains links that will direct you to the Tweets pages. Click on any of the links to view how the Tweets will be displayed:
3.138.174.174