Sticky Mini-Cart: How To Add Sticky Add to Cart Extension in Magento 2

In this article, I will explain to you how to add the sticky mini-cart on the current page. This step will help you to make users add to the cart always visible for easier checkout.

When a Magento 2 user scrolls down the current category page, home page, or product details page then this sticky cart extension will allow you to make "Add to cart" always visible for the customer so the customer can easily add more items or subtract items from the cart.

Magento 2 Sticky Mini-Cart

The Customers will also have the option to view a brief of product detail such as images, prices.

If the customer is looking for any change while scrolling the category page or product list page then they no need to scroll back to the top because the cart bar is always visible.

Therefore, this Magento 2 sticky cart extension will add value for your website customers by adding the above extremely convenient shopping experience to the users. Thus this functionality helps store owners to increase sales.

And where customers sometimes used to leave in the middle without completing the checkout, they will now be able to place their order easily.

 

Sticky Mini-Cart for The Magento Customer

The Sticky cart for the customer adds value to the customer experiance, it fixes the customer mini cart details at the bottom of the page when the page is scrolled down which leads to improves user experience.

This extension was implemented by the Wishusucess Magento development team that increase the conversion rate by encouraging customers to add products to the cart or buy now button.

 

Features of Magento Sticky Mini-Cart

The website admin panel has been implemented in such a way that anyone can manage the panel of Wishusucess_Stickycart without any coding knowledge.

We have added Enabled/Disable the features of the Wishusucess_Stickycart quickly from the admin.

Customers can view a brief of the details while scrolling the store page and also can manage their mini-cart details by just clicking on the icons.

Admin users can customize the size requirement from the admin panel of the product images.

The module is completely implemented as a responsive design so you don't have to worry about the different devices like mobiles, tablets, laptops. The module will readjust itself based on the original layout.

 

Helper Class of Sticky Cart in Magento 2

Hereby using this helper class of sticky cart you can implement the custom module for the Magento websites.

<?php
/*
* @category: Wishusucess_Stickycart
* @Wishusucess: (http://www.wishusucess.com/)
* @licence: http://www.wishusucess.com/
*/
namespace Wishusucess\Stickycart\Helper;

class Data extends \Magento\Framework\App\Helper\AbstractHelper
{
/**
* @var array
*/
protected $configModule;

/**
* @var \Magento\Framework\Json\Helper\Data
*/
protected $jsonHelper;

public function __construct(
\Magento\Framework\App\Helper\Context $context,
\Magento\Framework\Json\Helper\Data $jsonHelper
)
{
parent::__construct($context);
$this->configModule = $this->getConfig(strtolower($this->_getModuleName()));
$this->jsonHelper = $jsonHelper;
}

public function getConfig($cfg='')
{
if($cfg) return $this->scopeConfig->getValue( $cfg, \Magento\Store\Model\ScopeInterface::SCOPE_STORE );
return $this->scopeConfig;
}

public function getConfigModule($cfg='', $value=null)
{
$values = $this->configModule;
if( !$cfg ) return $values;
$config = explode('/', $cfg);
$end = count($config) - 1;
foreach ($config as $key => $vl) {
if( isset($values[$vl]) ){
if( $key == $end ) {
$value = $values[$vl];
}else {
$values = $values[$vl];
}
}

}
return $value;
}

public function isEnabled()
{
return $this->getConfigModule('general/enabled');
}
public function getWidthImage()
{
return $this->getConfigModule('general/width_image');
}
public function getHeightImage()
{
return $this->getConfigModule('general/height_image');
}
public function getHeightScroll()
{
return $this->getConfigModule('general/height_scroll');
}

public function getExcludeProducts()
{
return $this->getConfigModule('general/exclude_products');
}

public function getStickyCartConfigJson($product)
{ 
$data = [
"typeProduct" => $product->getTypeId(),
"scrollHeight" => $this->getConfigModule('general/height_scroll'),
"hiddenBottom" => $this->getConfigModule('general/hidden_bottom')
];
foreach ($data as $key => $value) {
if(is_numeric($value)){
$data[$key] = (float) $value;
continue;
}
$value = filter_var($value, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
if(!is_null($value)){
$data[$key] = $value; 
}
}
return $this->jsonHelper->jsonEncode($data);
}

}

 

How to Install Magento 2 Wishusucess Sticky Mini-Cart

Download the module and paste it into the below directory:

root_directory_of store/app/code/Wishusucess/Stickycart/

Now run the below command step by step:-

php bin/magento setup:upgrade

php bin/magento setup:di:compile

php bin/magento setup:static-content:deploy -f

php bin/magento cache:clean

 

Help And Support by Magento Team

In case of any problem, you can talk to our Magento 2 development team. Basic installation is absolutely free.

If you want to add any new features to it, then our team is available 24 hours for this, you can tell your requirement to our development team and within 24 hours your features will be implemented.

 

Similar Module

Speed Up Your Magento 2 Website By Lazy Loading Extension Free

Login With Number: Magento 2 Customer Login With Mobile Number

 

Speed Up Your Magento 2 Website By Lazy Loading Extension Free

This is the biggest problem for most of the Magento 2 website owners, how to provide a better experience to their customers, it is necessary to eliminate its lazy loading problem, because if the website loading time is higher then that would be worse for your customer to experience the website.

Our Magento team understands this problem and has developed Magento 2 Lazy Load extension which provides a better experience for your customer.

It minimizes the loading problem of your website, due to which your website loads very quickly on your customer's computer and it also helps you to be at the top of the search.

The biggest contributor to its success in any online eCommerce business is its better application and it is very important for that application to load on the customer's device quickly and efficiently.

 

Magento 2 Lazy Loading Module

By using this Magento 2 Lazy Loading extension of the Wishusucess developer team you can boost your website performance up to 70% of your current speed.

Therefore, it will increase the chances that your customers will stay on your website for a long time. Then customers will want to browse most of your pages that also increases the sales of your products.

It will also help your website to rank in google because of the faster speed of your website because a faster website also adds the improvement of SEO ranking.

Especially, the Wishusucess LazyLoading module works effectively with all Magento 2 pages such as Content Management pages, the home pages, category pages, product pages, etc.

Lazy Loading Module in Magento 2

 

Lazy Loading Adds Business Values:

It reduces the page load so faster websites Improve the user experience greatly by consuming less load time.

A faster website adds value in the search engine rank like google so it will improve the SEO ranking of your website with faster loading speed.

This module will help you to reduce the bandwidth of the server to it will save you money.

 

Lazy Loading Product Image in Magento 2

With Wishusucess Lazy Load Extension in Magento 2 website helps websites owners to speed up their websites. It will help you to decrease the load time of the product images.

 

Optimize SEO for Magento 2 Stores

Faster websites improve the SEO ranking in google so it will help your website to rank in Google Search. Wishusucess Lazy Load Magento 2 extension results improve the SEO ranking in faster website speed.

Reduce server bandwidth
By loading images and videos on-demand, you can reduce server requests and page size. This will certainly save a huge amount of bandwidth for your website.

Apply Lazy Loading on All Pages

We have designed it in such a way that this extension works for all kinds of pages including CMS pages, home pages, category pages, product pages, etc.

Download LazyLoading Extension

 

Magento Helps and Supports

If you want to improve your e-commerce website or want to make it completely new then you can contact our team. Our team is committed to providing you with the best experience at the lowest cost.

Improve SEO Ranking of your Website

 

Other Post:

PayPal Account: How to Create New PayPal Account, Transfer

 

Login With Number: Magento 2 Customer Login With Mobile Number

In this article, I am going to explain how to implement Magento 2 login customer via phone number functionality in Magento 2 and onwards version.

As we want to add the customer log-in functionality for the customer login with numbers like phone numbers or mobile numbers with the same fields.

So, in order to achieve this functionality, we have to implement the module.

Customer Login With Number in Magento 2

 

Why Customer Login With Phone Number?

When a customer wants to log in with the email then the customer will be able to log in or if the customer wants to login via their phone number then also that can be login.

Today everyone has a lack of time in this digital era, in such a situation, if we do not provide various facilities to our customers, then our customers will leave us.

That's why keeping in mind our customers, we cannot harass them by filling the registration form again and again.

They should have so much facility that they can log in as they want.

The Magento development company named Wishusucess.com has developed a module that can help your customer to log in via their mobile number or phone number or email id and password.

This module has important features that include Magento store customers can save their number while registration of their account, and they will also have the facilities to log in to their account and update their mobile number or phone number from their My Account section.

 

Features of Customer Log Via Number:

Customers can log in via their email or phone number or mobile number or both.

This customer login via the Mobile number module can be enabled or disabled from the admin panel.

Customers also can save their number while registering or after the registration from the My Account sections dashboard.

Allows customers to change their registered mobile number from their "My Account" section

Admin will have the option in the backend to view and update any customer number or phone number.

While checkout the product order customer also can log in via their mobile number or phone number.

Customer Login Via Mobile Number

Download the Module  From GitHub

Current Product Version - 2.4.x

Supported Framework Version - Magento 2.0.x, 2.1.x, 2.2.x,2.3.x, 2.4.x

Admin > Customers > All Customer > Account Information Magento 2 Customer Login With Number

 

Sorting Products: Magento 2 REST API For Sort By Product on List Page

 

Customer Account Information

However, Navigating into the admin panel

Customers > All Customers and view the list of customers.

You can also directly edit the customer numbers from this dashboard section.Customer Login With Number

Customer Image: Upload Customer Profile Pic Image Module in Magento 2

Customer Attribute: How to Add Custom Customer Attribute in Magento 2

 

Customer Attribute: How to Add Custom Customer Attribute in Magento 2

This article is all about creating custom customer attribute so here, I am going to explain this. Magento 2 custom attributes provide you the options to add additional required fields for the customer. So by adding this custom field in customer you can collect information that is required to support the order, fulfillment, and customer management processes.

Add Customer Attribute in Magento 2

Do you want to provide the best service for your customers in your business? so, you might need some additional fields to collect information.

By installing this custom customers attributes module of Wishusucess you can add custom attributes to the Account Registration of the customer, Address Book, and Billing Information.

 

How to Add Custom Attribute in Customer Account

If you want to add extra fields in the customer registration page, then for that you have to create a file named setup install data and in that, you have to set the field type keeping in mind the requirements of your attribute.

Wishusucess/CustomerAttribute/registration.php

Wishusucess/CustomerAttribute/etc/module.xml

Wishusucess/CustomerAttribute/Setup/InstallData.php

As soon as you create these three files your model will be ready and after that, you have to run the command to install the Magento model.

For example, you want to add a mobile number or phone number or some other required field to the customer account page. So you just have to follow the following code to create a field for custom attributes.

Let’s follow the below steps to Create a Custom Attribute in Magento 2 :

You may also like this :

How to Override Block, Controller, and Model in Magento 2

 

Step 1: Create Customer Attribute Registration File

app/code/Wishusucess/CustomerAttribute/registration.php

<?php
/**
* Category: Wishusucess_CustomerAttribute',
* Developer: Hemant Singh Magento 2x Developer
* Website: http://wwww.wishusucess.com
*/
\Magento\Framework\Component\ComponentRegistrar::register(
\Magento\Framework\Component\ComponentRegistrar::MODULE,
'Wishusucess_CustomerAttribute',
__DIR__
);

 

Step 2: Create Module XML File

app/code/Wishusucess/CustomerAttribute/etc/module.xml

<?xml version="1.0"?>
<!--
/**
* Category: Wishusucess_CustomerAttribute',
* Developer: Hemant Singh Magento 2x Developer
* Website: http://wwww.wishusucess.com
*/
-->
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
<module name="Wishusucess_CustomerAttribute" setup_version="1.0.7" />
</config>

 

Step 3: InstallData.php File For Customer Custom Attribute

Here, you can decide your custom customer attribute identifier name, label, and others properties types.

So you have to enter an attribute code to identify the Magento 2 attribute within the system.

There is some default rule that needs to follow while creating your InstallData PHP file.

While adding custom attributes your attribute code must begin with a letter and can include any combination of lowercase letters (a-z) and numbers (0-9).

The custom attribute code can not be greater than thirty characters in length, and also you have to keep in mind that you cannot include any special characters or spaces.

The underscore character (_) we can use while defining the name.

app/code/Wishusucess/CustomerAttribute/Setup/InstallData.php

<?php
/**
* Category: Wishusucess_CustomerAttribute
* Developer: Hemant Singh Magento 2x Developer
* Website: http://wwww.wishusucess.com
*/ 
namespace Wishusucess\CustomerAttribute\Setup;

use Magento\Customer\Setup\CustomerSetupFactory;
use Magento\Customer\Model\Customer;
use Magento\Eav\Model\Entity\Attribute\Set as AttributeSet;
use Magento\Eav\Model\Entity\Attribute\SetFactory as AttributeSetFactory;
use Magento\Framework\Setup\InstallDataInterface;
use Magento\Framework\Setup\ModuleContextInterface;
use Magento\Framework\Setup\ModuleDataSetupInterface;

/**
* Install data
* @codeCoverageIgnore
*/
class InstallData implements InstallDataInterface
{

/**
* CustomerSetupFactory
* @var CustomerSetupFactory
*/
protected $customerSetupFactory;

/**
* $attributeSetFactory
* @var AttributeSetFactory
*/
private $attributeSetFactory;

/**
* initiate object
* @param CustomerSetupFactory $customerSetupFactory
* @param AttributeSetFactory $attributeSetFactory
*/
public function __construct(
CustomerSetupFactory $customerSetupFactory,
AttributeSetFactory $attributeSetFactory
)
{
$this->customerSetupFactory = $customerSetupFactory;
$this->attributeSetFactory = $attributeSetFactory;
}

/**
* install data method
* @param ModuleDataSetupInterface $setup
* @param ModuleContextInterface $context
*/
public function install(ModuleDataSetupInterface $setup, ModuleContextInterface $context)
{

/** @var CustomerSetup $customerSetup */
$customerSetup = $this->customerSetupFactory->create(['setup' => $setup]);

$customerEntity = $customerSetup->getEavConfig()->getEntityType('customer');
$attributeSetId = $customerEntity->getDefaultAttributeSetId();

/** @var $attributeSet AttributeSet */
$attributeSet = $this->attributeSetFactory->create();
$attributeGroupId = $attributeSet->getDefaultGroupId($attributeSetId);
/**
* customer registration form default field mobile number
*/
$customerSetup->addAttribute(Customer::ENTITY, 'wishusucess_customerattribute', [
'type' => 'varchar',
'label' => 'Wishusucess Customer Attribute',
'input' => 'text',
'required' => false,
'visible' => true,
'user_defined' => true,
'sort_order' => 1000,
'position' => 1000,
'system' => 0,
]);
//add attribute to attribute set
$attribute = $customerSetup->getEavConfig()->getAttribute(Customer::ENTITY, 'wishusucess_customerattribute')
->addData([
'attribute_set_id' => $attributeSetId,
'attribute_group_id' => $attributeGroupId,
'used_in_forms' => ['adminhtml_customer', 'customer_account_create'],
]);

$attribute->save();


}
}

 

Now, you need to run the below Magento 2 command to get install your custom attribute module.

php bin/magento s:up

php bin/magento s:s:d -f

php bin/magento c:c

 

Now you can see the result in

Admin > All Customer > Customer Name 

Magento 2 Custom Attribute

Download This Module

 

Suggested Post:

Cart Images: Get Product Image in Customer Cart Magento 2 REST API

How to Send Push Notifications on Android Application

Product Alert API: Get Magento 2 Product Alert Using API

Top Magento 2 Free Extension For Banner Image Slider

In this article, I am going to explain how we can add banner image sliders on the home page, category page, cms page, or block page in Magento 2 websites.

Wishusucess Magento 2 Banner Slider Free Extension

This extension helps you t add a banner image in your store which makes your store beautiful and appealing to the customer through installing a Wishusucess free banner slider extension.

By adding these slideshows extension websites look wonderful with magnificent slide effects with Magento 2 Wishusucess free module.

 

Wishusucess Banner Image Sliders

Allows you to create a banner for your stores and you can call that banner anywhere to promote your website. By adding these banner images usually, we can show the target information to the customer.

Moreover, the Wishusucess slider extension makes your store beautiful and attractive.

  • No needs to add extra code in your store.
  • very little time takes to add your banner slider Images on your desire pages.
  • Sliders banner Improve customer experience.
  • By adding this banner you can target specific information for the customer.
  • Banner to introduce business
  • Increase Click-Through-Rate(CTR) by installing this banner module. so its increases promotions and sales.T
  • No other dependencies are required.
  • Wishusucess banner Images extension is compatible with all Magento 2 versions, from Magento 2.0, Magento 2.1, Magento 2.2, Magento 2.3, Magento 2.4, etc.

 

Banner Images Sliders Compatibility

There is no other coding is required so, you can use the Banner Slider extension on any page like you can use it for Home Page Banner Slider, category page banner slider, cms page banner slider, block images slider.

 

Advantages of Wishusucess Banner Image Sliders

You can make your store too attractive just by installing this module. So when you add this slider you will have the option to make it appealing and informative for the customer.

  • Attractive slideshows

When the banner is informative and attractive then customers can easily get engaged with the product and that will increase sales Because it attracts customers' attention through the informative image.

  • Customers always pay attention to moving images.

With a gorgeous banner image slideshow, your store will have the extra capabilities to grab the attention of your customers.

It provides an images slider flexibly so you can add any page on your store like homepage, category page, product page, CMS page.

- It has the extra customization functionality in admin so you can increase the slider speed or decrease the slider speed.

 

How to Install Magento 2 Banner Slider Extension

Just visit our official Github directory and download the  Wishusucess Slider Extension and paste it into your Magento root app/code directory.

Download Wishusucess Images Slider

 

Run The Following Command in Magento 2 Root Folder:

php bin/magento setup:upgrade

php bin/magento setup:di:compile

php bin/magento setup:static-content:deploy -f

php bin/magento cache:clean

 

Hire Magento 2 Developers for your Stores

Banner image Sliders in Magento 2

You can add image video, image as a banner slider

Also, you can change the configuration of sliders.

Magento 2 Banner Image Sliders

 

Related Post:

Shipping Address API: Customer Shipping Details Using API in Magento 2

File Permissions: Magento 2 Ownership And File Permission At Installation

 

Recommended Post:

Magento 2.4 Installation Guide: How to Install Magento 2.4.2

Categories API Key: Get All Category List Through API Key in Magento 2

This article will help you to get all category list through the API key on the frontend. When we develop a mobile application using Magento for online shopping websites then we need this kind of module to load all the categories data. Using these Categories API key extensions of Magento 2 you will be easily able to get the data.

Categories API Key in Magento 2

 

Custom Categories API key Module To Get Data

In this Magento 2 module, we will show you how you can create Magento 2 extension to get the categories data from a Magento online shopping store through REST API.

Therefore, we have to use a tool to get access to the Magento 2 store data.

So first get the category list we have to create a token that will allow you to get access the Magento 2 website data.

Endpoint:

“http://www.wishusucess.com/rest/V1/integration/admin/token”
app/code/Wishuscess/CategoriesList/registration.php

app/code/Wishuscess/CategoriesList/etc/module.xml

app/code/Wishuscess/CategoriesList/etc/di.xml

app/code/Wishuscess/CategoriesList/etc/webapi.xml

app/code/Wishuscess/CategoriesList/Model/CategoryManagement.php

app/code/Wishuscess/CategoriesList/Model/Category/Tree.php

app/code/Wishuscess/CategoriesList/Api/CategoryManagementInterface.php

app/code/Wishuscess/CategoriesList/Data/CategoryTreeInterface.php

 

Step 1 : Register Categories API Key Module

app/code/Wishuscess/CategoriesList/registration.php

<?php
/**
* Developer:Wishuscess Magento 2x Developer Team
* Module: Wishuscess_CategoriesList
* Author: Hemant Singh Magento 2X Developer
* Website: http://www.wishusucess.com/
*
*/
\Magento\Framework\Component\ComponentRegistrar::register(
\Magento\Framework\Component\ComponentRegistrar::MODULE,
'Wishuscess_CategoriesList',
__DIR__
);

 

Step: 2

app/code/Wishuscess/CategoriesList/etc/module.xml

<?xml version="1.0"?>
/**
* Developer:Wishuscess Magento 2x Developer Team
* Module: Wishuscess_CategoriesList
* Author: Hemant Singh Magento 2X Developer
* Website: http://www.wishusucess.com/
*
*/
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
<module name="Wishusucess_CategoriesList" setup_version="1.0.0">
<sequence>
<module name="Magento_Catalog"/>
</sequence>
</module>
</config>

 

Step 3: Define Dependency of Categories API Key

app/code/Wishuscess/CategoriesList/etc/di.xml

<?xml version="1.0" ?>
/**
* Developer:Wishuscess Magento 2x Developer Team
* Module: Wishuscess_CategoriesList
* Author: Hemant Singh Magento 2X Developer
* Website: http://www.wishusucess.com/
*
*/
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<preference for="Wishusucess\CategoriesList\Api\CategoryManagementInterface" type="Wishusucess\CategoriesList\Model\CategoryManagement"></preference>
</config>

 

Step 4: Create Categories List Web API

Wishuscess_CategoriesList Magento Web API will help you define your route id that can communicate with your Magento shopping website. So here we will get all category data using these APIs.

app/code/Wishuscess/CategoriesList/etc/webapi.xml

<?xml version="1.0"?>
/**
* Developer:Wishuscess Magento 2x Developer Team
* Module: Wishuscess_CategoriesList
* Author: Hemant Singh Magento 2X Developer
* Website: http://www.wishusucess.com/
*
*/
<routes xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Webapi:etc/webapi.xsd">
<route url="/V1/wishusucess/categories" method="GET">
<service class="Wishusucess\CategoriesList\Api\CategoryManagementInterface" method="getTree" />
<resources>
<resource ref="Magento_Catalog::categories" />
</resources>
</route>
</routes>

 

Step 5: Create API Category Management

app/code/Wishuscess/CategoriesList/Model/CategoryManagement.php

<?php
/**
* Developer:Wishuscess Magento 2x Developer Team
* Module: Wishuscess_CategoriesList
* Author: Hemant Singh Magento 2X Developer
* Website: http://www.wishusucess.com/
*
*/
namespace Wishusucess\CategoriesList\Model;
use Wishusucess\CategoriesList\Api\CategoryManagementInterface;
use Wishusucess\CategoriesList\Model\Category\Tree;

class CategoryManagement extends \Magento\Catalog\Model\CategoryManagement
implements CategoryManagementInterface
{
/**
* @var CategoryRepository
*/
protected $categoryRepository;

/**
* @var Tree
*/
protected $categoryTree;

/**
* @var \Magento\Catalog\Model\ResourceModel\Category\CollectionFactory
*/
private $categoriesFactory;

/**
* @param \Magento\Catalog\Api\CategoryRepositoryInterface $categoryRepository
* @param Tree $categoryTree
* @param \Magento\Catalog\Model\ResourceModel\Category\CollectionFactory $categoriesFactory
*/
public function __construct(
\Magento\Catalog\Api\CategoryRepositoryInterface $categoryRepository,
Tree $categoryTree,
\Magento\Catalog\Model\ResourceModel\Category\CollectionFactory $categoriesFactory
) {
$this->categoryRepository = $categoryRepository;
$this->categoryTree = $categoryTree;
$this->categoriesFactory = $categoriesFactory;
}


}

 

Retrieve Category Data in Tree Structure Magento 2

app/code/Wishuscess/CategoriesList/Model/Category/Tree.php

<?php
/**
* Developer:Wishuscess Magento 2x Developer Team
* Module: Wishuscess_CategoriesList
* Author: Hemant Singh Magento 2X Developer
* Website: http://www.wishusucess.com/
*
*/
namespace Wishusucess\CategoriesList\Model\Category;

/**
* Retrieve category data represented in tree structure
*/
class Tree
{
/**
* @var \Magento\Catalog\Model\ResourceModel\Category\Tree
*/
protected $categoryTree;

/**
* @var \Magento\Store\Model\StoreManagerInterface
*/
protected $storeManager;

/**
* @var \Magento\Catalog\Model\ResourceModel\Category\Collection
*/
protected $categoryCollection;

/**
* @var \Magento\Catalog\Api\Data\CategoryTreeInterfaceFactory
*/
protected $treeFactory;

/**
* @var \Magento\Catalog\Model\Indexer\Category\Flat\State
*/
protected $flatState;

/**
* @param \Magento\Catalog\Model\ResourceModel\Category\Tree $categoryTree
* @param \Magento\Store\Model\StoreManagerInterface $storeManager
* @param \Magento\Catalog\Model\ResourceModel\Category\Collection $categoryCollection
* @param \Magento\Catalog\Api\Data\CategoryTreeInterfaceFactory $treeFactory
*/
public function __construct(
\Magento\Catalog\Model\ResourceModel\Category\Tree $categoryTree,
\Magento\Store\Model\StoreManagerInterface $storeManager,
\Magento\Catalog\Model\ResourceModel\Category\Collection $categoryCollection,
\Magento\Catalog\Model\Indexer\Category\Flat\State $flatState,
\Magento\Catalog\Api\Data\CategoryTreeInterfaceFactory $treeFactory
) {
$this->categoryTree = $categoryTree;
$this->storeManager = $storeManager;
$this->categoryCollection = $categoryCollection;
$this->treeFactory = $treeFactory;
$this->flatState = $flatState;
}

/**
* @param \Magento\Catalog\Model\Category|null $category
* @return Node|null
*/
public function getRootNode($category = null)
{
if ($category !== null && $category->getId()) {
return $this->getNode($category);
}

$store = $this->storeManager->getStore();
$rootId = $store->getRootCategoryId();

$tree = $this->categoryTree->load(null);
$this->prepareCollection();
$tree->addCollectionData($this->categoryCollection);
$root = $tree->getNodeById($rootId);
return $root;
}

/**
* @param \Magento\Catalog\Model\Category $category
* @return Node
*/
protected function getNode(\Magento\Catalog\Model\Category $category)
{
$nodeId = $category->getId();
$node = $this->categoryTree->loadNode($nodeId);
$node->loadChildren();
$this->prepareCollection();
$this->categoryTree->addCollectionData($this->categoryCollection);
return $node;
}

/**
* @return void
*/
protected function prepareCollection()
{
$storeId = $this->storeManager->getStore()->getId();
$this->categoryCollection->addAttributeToSelect(
'name'
)->addAttributeToSelect(
'is_active'
)->setProductStoreId(
$storeId
)->setLoadProductCount(
true
)->setStoreId(
$storeId
);

if ($this->flatState->isAvailable()) {
$this->categoryCollection->addAttributeToSelect('image');
} else {
$this->categoryCollection->addAttributeToSelect('image', true);
}
}

/**
* @param \Magento\Framework\Data\Tree\Node $node
* @param int $depth
* @param int $currentLevel
* @return \Magento\Catalog\Api\Data\CategoryTreeInterface
*/
public function getTree($node, $depth = null, $currentLevel = 0)
{
/** @var \Magento\Catalog\Api\Data\CategoryTreeInterface[] $children */
$children = $this->getChildren($node, $depth, $currentLevel);
/** @var \Magento\Catalog\Api\Data\CategoryTreeInterface $tree */
$tree = $this->treeFactory->create();
$tree->setId($node->getId())
->setParentId($node->getParentId())
->setName($node->getName())
->setPosition($node->getPosition())
->setLevel($node->getLevel())
->setIsActive($node->getIsActive())
->setProductCount($node->getProductCount())
->setImage($node->getImage())
->setChildrenData($children);
return $tree;
}

/**
* @param \Magento\Framework\Data\Tree\Node $node
* @param int $depth
* @param int $currentLevel
* @return \Magento\Catalog\Api\Data\CategoryTreeInterface[]|[]
*/
protected function getChildren($node, $depth, $currentLevel)
{
if ($node->hasChildren()) {
$children = [];
foreach ($node->getChildren() as $child) {
if ($depth !== null && $depth <= $currentLevel) {
break;
}
$children[] = $this->getTree($child, $depth, $currentLevel + 1);
}
return $children;
}
return [];
}
}

 

Step 7: Retrieve List of Categories

app/code/Wishuscess/CategoriesList/Api/CategoryManagementInterface.php

<?php
/**
* Developer:Wishuscess Magento 2x Developer Team
* Module: Wishuscess_CategoriesList
* Author: Hemant Singh Magento 2X Developer
* Website: http://www.wishusucess.com/
*
*/
namespace Wishusucess\CategoriesList\Api;

/**
* @api
*/
interface CategoryManagementInterface
{
/**
* Retrieve list of categories
*
* @param int $rootCategoryId
* @param int $depth
* @throws \Magento\Framework\Exception\NoSuchEntityException If ID is not found
* @return \Wishusucess\CategoriesList\Api\Data\CategoryTreeInterface containing Tree objects
*/
public function getTree($rootCategoryId = null, $depth = null);

/**
* Move category
*
* @param int $categoryId
* @param int $parentId
* @param int $afterId
* @return bool
* @throws \Magento\Framework\Exception\LocalizedException
* @throws \Magento\Framework\Exception\NoSuchEntityException
*/
public function move($categoryId, $parentId, $afterId = null);

/**
* Provide the number of category count
*
* @return int
*/
public function getCount();
}

 

Step 8: Category Tree Interface - Categories API Key

app/code/Wishuscess/CategoriesList/Data/CategoryTreeInterface.php

<?php
/**
* Developer:Wishuscess Magento 2x Developer Team
* Module: Wishuscess_CategoriesList
* Author: Hemant Singh Magento 2X Developer
* Website: http://www.wishusucess.com/
*
*/
namespace Wishusucess\CategoriesList\Api\Data;

/**
* @api
*/
interface CategoryTreeInterface
{
/**
* @return int|null
* 
*/
public function getId();

/**
* @param int $id
* @return $this
*/
public function setId($id);

/**
* Get parent category ID
*
* @return int
*/
public function getParentId();

/**
* Set parent category ID
*
* @param int $parentId
* @return $this
*/
public function setParentId($parentId);

/**
* Get category name
*
* @return string
*/
public function getName();

/**
* Set category name
*
* @param string $name
* @return $this
*/
public function setName($name);

/**
* Get category image
*
* @return string
*/
public function getImage();

/**
* Set category image
*
* @param string $name
* @return $this
*/
public function setImage($image);

/**
* Check whether category is active
*
* @return bool
* @SuppressWarnings(PHPMD.BooleanGetMethodName)
*/
public function getIsActive();

/**
* Set whether category is active
*
* @param bool $isActive
* @return $this
*/
public function setIsActive($isActive);

/**
* Get category position
*
* @return int
*/
public function getPosition();

/**
* Set category position
*
* @param int $position
* @return $this
*/
public function setPosition($position);

/**
* Get category level
*
* @return int
*/
public function getLevel();

/**
* Set category level
*
* @param int $level
* @return $this
*/
public function setLevel($level);

/**
* Get product count
*
* @return int
*/
public function getProductCount();

/**
* Set product count
*
* @param int $productCount
* @return $this
*/
public function setProductCount($productCount);

/**
* @return \Wishusucess\CategoriesList\Api\Data\CategoryTreeInterface[]
*/
public function getChildrenData();

/**
* @param \Wishusucess\CategoriesList\Api\Data\CategoryTreeInterface[] $childrenData
* @return $this
*/
public function setChildrenData(array $childrenData = null);
}

 

Now, Run Following Command:

php bin/magento setup:upgrade

php bin/magento setup:static-content:deploy -f

php bin/magento cache:clean

php bin/magento cache:flush

 

Now you have the complete module so using this category API key module you can retrieve the category data from other frontend stores in  ReactJS or NodeJS. All you have to do is just call this API key your Reactjs or Nodejs store and you will get the data.

Hire Magento 2 Expert Developer to Develop Your Store

 

Related Post:

Custom Shipping Text Filed: Show Custom Text Magento 2

 

Recommended Post:

Magento 2.4 Installation Guide: How to Install Magento 2.4.2

 

SEO Packages: How Much Do SEO Packages Cost in India, SEO Pricing

Custom Customer Ajax Login Extension in Magento 2

In this article, we are going to develop a Magento 2 custom customer ajax login extension which will be something like adding a customer ajax popup in login and registration through the module in Magento 2.

 

Add Ajax PopUp Login And Registration

Now through this module, we will add an ajax popup in login and registration in Magento 2 so for that we need to create a module so in order to create that module we have to create the following files.

app/code/Wishusucess/CustomerAccount/registration.php

app/code/Wishusucess/CustomerAccount/etc/module.xml

app/code/Wishusucess/CustomerAccount/etc/frontend/sections.xml

app/code/Wishusucess/CustomerAccount/etc/frontend/routes.xml

app/code/Wishusucess/CustomerAccount/Controller/Customer/Ajax/Register.php

app/code/Wishusucess/CustomerAccount/Block/Form/Login.php

app/code/Wishusucess/CustomerAccount/Block/Form/Register.php

app/code/Wishusucess/CustomerAccount/view/frontend/layout/default.xml

app/code/Wishusucess/CustomerAccount/view/frontend/templates/login.phtml

app/code/Wishusucess/CustomerAccount/view/frontend/templates/register.phtml

app/code/Wishusucess/CustomerAccount/view/frontend/web/js/action/customer-authentication-popup.js

 

Magento 2 Add-in PopUp Customer Register

Create Customer Login PopUp

Magento 2 Customer PopUp Login

Custom Customer Ajax Login

Registration Customer Account PopUp Login

app/code/Wishusucess/CustomerAccount/registration.php

<?php
/**
* Source Wishusucess
* package Wishusucess_CustomerAccount
* Author Wishusucess Magento Development Team
* website https://www.wishusucess.com/
*/
\Magento\Framework\Component\ComponentRegistrar::register(
\Magento\Framework\Component\ComponentRegistrar::MODULE,
'Wishusucess_CustomerAccount',
__DIR__
);

 

Declare Module information of Customer Account

app/code/Wishusucess/CustomerAccount/etc/module.xml

<?xml version="1.0"?>
<!--
/**
* Source Wishusucess
* package Wishusucess_CustomerAccount
* Author Wishusucess Magento Development Team
* website https://www.wishusucess.com/
*/
-->
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
<module name="Wishusucess_CustomerAccount" setup_version="2.1.0" />
</config>

 

Create Section XML File For Custom Customer Ajax Login

This section XML file is a kind of customer data that is grouped together. So here that each section of customer data will have a key or that will be represented by a key that helps to access the content of customer data.

app/code/Wishusucess/CustomerAccount/etc/frontend/sections.xml

<?xml version="1.0"?>
<!--
/**
* Source Wishusucess
* package Wishusucess_CustomerAccount
* Author Wishusucess Magento Development Team
* website https://www.wishusucess.com/
*/
-->
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Customer:etc/sections.xsd">
<action name="wishusucess/customer_ajax/register">
<section name="checkout-data"/>
<section name="cart"/>
<section name="customer"/>
</action>
<action name="customer/ajax/login">
<section name="checkout-data"/>
<section name="cart"/>
<section name="customer"/>
</action>
</config>

 

Routes XML File For Customer Account in Magento 2

app/code/Wishusucess/CustomerAccount/etc/frontend/routes.xml

<?xml version="1.0"?>
<!--
/**
* Source Wishusucess
* package Wishusucess_CustomerAccount
* Author Wishusucess Magento Development Team
* website https://www.wishusucess.com/
*/
-->
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:App/etc/routes.xsd">
<router id="standard">
<route id="wishusucess" frontName="wishusucess">
<module name="Wishusucess_CustomerAccount"/>
</route>
</router>
</config>

 

Custom Customer Ajax Login Register

This code will add Magento 2 PopUp Registration in your customer registration section.

app/code/Wishusucess/CustomerAccount/Controller/Customer/Ajax/Register.php

<?php
/**
* Source Wishusucess
* package Wishusucess_CustomerAccount
* Author Wishusucess Magento Development Team
* website https://www.wishusucess.com/
*/
namespace Wishusucess\CustomerAccount\Controller\Customer\Ajax;

use Magento\Framework\Exception\StateException;
use Magento\Framework\Exception\InputException;
use Magento\Framework\Exception\LocalizedException;
use Magento\Customer\Helper\Address;
use Magento\Customer\Model\Account\Redirect;
use Magento\Framework\App\ObjectManager;
use Magento\Customer\Api\AccountManagementInterface;

class Register extends \Magento\Framework\App\Action\Action
{
/**
* @var \Magento\Framework\Controller\Result\JsonFactory
*/
protected $resultJsonFactory;

/**
* @var \Magento\Framework\Controller\Result\RawFactory
*/
protected $resultRawFactory;

/**
* @var \Magento\Customer\Model\Session
*/
protected $session;

/**
* @var \Magento\Customer\Model\Registration
*/
protected $registration;

/**
* @var \Magento\Framework\Data\Form\FormKey\Validator
*/
protected $formKeyValidator;

/**
* @var \Magento\Customer\Model\CustomerExtractor
*/
protected $customerExtractor;

/**
* @var \Magento\Customer\Api\AccountManagementInterface
*/
protected $accountManagement;

/**
* @var \Magento\Newsletter\Model\SubscriberFactory
*/
protected $subscriberFactory;

/**
* @var \Magento\Customer\Model\Url
*/
protected $customerUrl;

/**
* @var \Magento\Customer\Helper\Address
*/
protected $addressHelper;

/**
* @var \Magento\Store\Model\StoreManagerInterface
*/
protected $storeManager;

/**
* @var \Magento\Customer\Model\Account\Redirect
*/
protected $accountRedirect;

/**
* @var \Magento\Framework\App\Config\ScopeConfigInterface
*/
protected $scopeConfig;

/**
* @var \Magento\Framework\Stdlib\Cookie\CookieMetadataFactory
*/
protected $cookieMetadataFactory;

/**
* @var \Magento\Framework\Stdlib\Cookie\PhpCookieManager
*/
protected $cookieMetadataManager;

/**
* @var \Magento\Framework\Escaper
*/
protected $escaper;

/**
* @param \Magento\Framework\App\Action\Context $context
* @param \Magento\Framework\Controller\Result\JsonFactory $resultJsonFactory
* @param \Magento\Framework\Controller\Result\RawFactory $resultRawFactory
* @param \Magento\Customer\Model\Session $customerSession
* @param \Magento\Customer\Model\Registration $customerRegistration
* @param \Magento\Framework\Data\Form\FormKey\Validator $formKeyValidator
* @param \Magento\Customer\Api\AccountManagementInterface $accountManagement
* @param \Magento\Customer\Model\CustomerExtractor $customerExtractor
* @param \Magento\Newsletter\Model\SubscriberFactory $subscriberFactory
* @param \Magento\Customer\Model\Url $customerUrl
* @param \Magento\Framework\UrlInterface $urlModel
* @param \Magento\Customer\Helper\Address $addressHelper
* @param \Magento\Store\Model\StoreManagerInterface $storeManager
* @param \Magento\Customer\Model\Account\Redirect $accountRedirect
* @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
* @param \Magento\Framework\Escaper $escaper
* @param \Magento\Framework\Stdlib\Cookie\CookieMetadataFactory $cookieMetadataFactory
* @param \Magento\Framework\Stdlib\Cookie\PhpCookieManager $cookieMetadataManager
*/
public function __construct(
\Magento\Framework\App\Action\Context $context,
\Magento\Framework\Controller\Result\JsonFactory $resultJsonFactory,
\Magento\Framework\Controller\Result\RawFactory $resultRawFactory,
\Magento\Customer\Model\Session $customerSession,
\Magento\Customer\Model\Registration $customerRegistration,
\Magento\Framework\Data\Form\FormKey\Validator $formKeyValidator,
\Magento\Customer\Api\AccountManagementInterface $accountManagement,
\Magento\Customer\Model\CustomerExtractor $customerExtractor,
\Magento\Newsletter\Model\SubscriberFactory $subscriberFactory,
\Magento\Customer\Model\Url $customerUrl,
\Magento\Framework\UrlInterface $urlModel,
\Magento\Customer\Helper\Address $addressHelper,
\Magento\Store\Model\StoreManagerInterface $storeManager,
\Magento\Customer\Model\Account\Redirect $accountRedirect,
\Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig,
\Magento\Framework\Escaper $escaper,
\Magento\Framework\Stdlib\Cookie\CookieMetadataFactory $cookieMetadataFactory,
\Magento\Framework\Stdlib\Cookie\PhpCookieManager $cookieMetadataManager
) {
parent::__construct($context);
$this->resultJsonFactory = $resultJsonFactory;
$this->resultRawFactory = $resultRawFactory;
$this->session = $customerSession;
$this->registration = $customerRegistration;
$this->formKeyValidator = $formKeyValidator;
$this->accountManagement = $accountManagement;
$this->customerExtractor = $customerExtractor;
$this->subscriberFactory = $subscriberFactory;
$this->customerUrl = $customerUrl;
$this->urlModel = $urlModel;
$this->addressHelper = $addressHelper;
$this->storeManager = $storeManager;
$this->accountRedirect = $accountRedirect;
$this->scopeConfig = $scopeConfig;
$this->escaper = $escaper;
}

/**
* Retrieve cookie manager
*
* @deprecated 100.1.0
* @return \Magento\Framework\Stdlib\Cookie\PhpCookieManager
*/
private function getCookieManager()
{
if (!$this->cookieMetadataManager) {
$this->cookieMetadataManager = ObjectManager::getInstance()->get(
\Magento\Framework\Stdlib\Cookie\PhpCookieManager::class
);
}
return $this->cookieMetadataManager;
}

/**
* Retrieve cookie metadata factory
*
* @deprecated 100.1.0
* @return \Magento\Framework\Stdlib\Cookie\CookieMetadataFactory
*/
private function getCookieMetadataFactory()
{
if (!$this->cookieMetadataFactory) {
$this->cookieMetadataFactory = ObjectManager::getInstance()->get(
\Magento\Framework\Stdlib\Cookie\CookieMetadataFactory::class
);
}
return $this->cookieMetadataFactory;
}

/**
* @return \Magento\Framework\Controller\ResultInterface
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
*/
public function execute()
{
$credentials = null;
$httpBadRequestCode = 400;

/** @var \Magento\Framework\Controller\Result\Raw $resultRaw */
$resultRaw = $this->resultRawFactory->create();
if ($this->getRequest()->getMethod() !== 'POST' || !$this->getRequest()->isXmlHttpRequest()) {
return $resultRaw->setHttpResponseCode($httpBadRequestCode);
}

$formKeyValidation = $this->formKeyValidator->validate($this->getRequest());

$response = [
'errors' => false,
'message' => __('Login successful.')
];

if ($this->session->isLoggedIn()) {
$response = [
'errors' => false,
'message' => __('You are already logged in.')
];
} elseif (!$this->registration->isAllowed()) {
$response = [
'errors' => true,
'message' => __('Customer registration is already disabled.')
];
} elseif (!$formKeyValidation) {
$response = [
'errors' => true,
'message' => $this->getRequest()->getParam('password')
];
} else {
$this->session->regenerateId();
try {
$customer = $this->customerExtractor->extract('customer_account_create', $this->_request);

$password = $this->getRequest()->getParam('password');
$confirmation = $this->getRequest()->getParam('password_confirmation');

$this->checkPasswordConfirmation($password, $confirmation);

$customer = $this->accountManagement
->createAccount($customer, $password);

if ($this->getRequest()->getParam('is_subscribed', false)) {
$this->subscriberFactory->create()->subscribeCustomerById($customer->getId());
}

$this->_eventManager->dispatch(
'customer_register_success',
['account_controller' => $this, 'customer' => $customer]
);

$confirmationStatus = $this->accountManagement->getConfirmationStatus($customer->getId());
if ($confirmationStatus === AccountManagementInterface::ACCOUNT_CONFIRMATION_REQUIRED) {
$email = $this->customerUrl->getEmailConfirmationUrl($customer->getEmail());
$response = [
'errors' => true,
'message' => __(
'You must confirm your account. Please check your email for the confirmation link or <a href="%1">click here</a> for a new link.',
$email
)
];
} else {
$this->session->setCustomerDataAsLoggedIn($customer);
$response = [
'errors' => false,
'message' => $this->getSuccessMessage()
];
$requestedRedirect = $this->accountRedirect->getRedirectCookie();
if (!$this->scopeConfig->getValue('customer/startup/redirect_dashboard') && $requestedRedirect) {
$response['redirectUrl'] = $this->_redirect->success($requestedRedirect);
$this->accountRedirect->clearRedirectCookie();
}
}
if ($this->getCookieManager()->getCookie('mage-cache-sessid')) {
$metadata = $this->getCookieMetadataFactory()->createCookieMetadata();
$metadata->setPath('/');
$this->getCookieManager()->deleteCookie('mage-cache-sessid', $metadata);
}
} catch (StateException $e) {
$url = $this->_url->getUrl('customer/account/forgotpassword');
$response = [
'errors' => true,
'message' => __(
'There is already an account with this email address. If you are sure that it is your email address, <a href="%1">click here</a> to get your password and access your account.',
$url
)
];
} catch (InputException $e) {
$response = [
'errors' => true,
'message' => $this->escaper->escapeHtml($e->getMessage())
];
} catch (LocalizedException $e) {
$response = [
'errors' => true,
'message' => $this->escaper->escapeHtml($e->getMessage())
];
} catch (\Exception $e) {
$response = [
'errors' => true,
'message' => __('We can\'t save the customer.')
];
}

$this->session->setCustomerFormData($this->getRequest()->getPostValue());
}

/** @var \Magento\Framework\Controller\Result\Json $resultJson */
$resultJson = $this->resultJsonFactory->create();
return $resultJson->setData($response);
}

/**
* Make sure that password and password confirmation matched
*
* @param string $password
* @param string $confirmation
* @return void
* @throws InputException
*/
protected function checkPasswordConfirmation($password, $confirmation)
{
if ($password != $confirmation) {
throw new InputException(__('Please make sure your passwords match.'));
}
}

/**
* Retrieve success message
*
* @return string
*/
protected function getSuccessMessage()
{
if ($this->addressHelper->isVatValidationEnabled()) {
if ($this->addressHelper->getTaxCalculationAddressType() == Address::TYPE_SHIPPING) {
// @codingStandardsIgnoreStart
$message = __(
'If you are a registered VAT customer, please <a href="%1">click here</a> to enter your shipping address for proper VAT calculation.',
$this->_url->getUrl('customer/address/edit')
);
// @codingStandardsIgnoreEnd
} else {
// @codingStandardsIgnoreStart
$message = __(
'If you are a registered VAT customer, please <a href="%1">click here</a> to enter your billing address for proper VAT calculation.',
$this->_url->getUrl('customer/address/edit')
);
// @codingStandardsIgnoreEnd
}
} else {
$message = __('Thank you for registering with %1.', $this->storeManager->getStore()->getFrontendName());
}
return $message;
}
}

 

Magento 2 Ajax Login PopUp

So here we can add Magento 2 ajax login through this code. When we will click on the customer login then there will be one popup open for the customer login.

app/code/Wishusucess/CustomerAccount/Block/Form/Login.php

<?php
/**
* Source Wishusucess
* package Wishusucess_CustomerAccount
* Author Wishusucess Magento Development Team
* website https://www.wishusucess.com/
*/
namespace Wishusucess\CustomerAccount\Block\Form;

class Login extends \Magento\Framework\View\Element\Template
{
/**
* @var \Magento\Customer\Model\Session
*/
protected $customerSession;

/**
* @var \Magento\Framework\App\Http\Context
*/
protected $httpContext;

/**
* Registration
*
* @var \Magento\Customer\Model\Registration
*/
protected $registration;

/**
* @param \Magento\Framework\View\Element\Template\Context $context
* @param \Magento\Customer\Model\Session $customerSession
* @param \Magento\Framework\App\Http\Context $httpContext
* @param \Magento\Customer\Model\Registration $registration
* @param array $data
*/
public function __construct(
\Magento\Framework\View\Element\Template\Context $context,
\Magento\Customer\Model\Session $customerSession,
\Magento\Framework\App\Http\Context $httpContext,
\Magento\Customer\Model\Registration $registration,
array $data = []
) {
parent::__construct($context, $data);
$this->customerSession = $customerSession;
$this->httpContext = $httpContext;
$this->registration = $registration;
}

/**
* Return registration
*
* @return \Magento\Customer\Model\Registration
*/
public function getRegistration()
{
return $this->registration;
}

/**
* Retrieve form posting url
*
* @return string
*/
public function getPostActionUrl()
{
return $this->getUrl('customer/ajax/login');
}

/**
* Check if autocomplete is disabled on storefront
*
* @return bool
*/
public function isAutocompleteDisabled()
{
return (bool)!$this->_scopeConfig->getValue(
\Magento\Customer\Model\Form::XML_PATH_ENABLE_AUTOCOMPLETE,
\Magento\Store\Model\ScopeInterface::SCOPE_STORE
);
}

/**
* Checking customer login status
*
* @return bool
*/
public function customerIsAlreadyLoggedIn()
{
return (bool)$this->httpContext->getValue(\Magento\Customer\Model\Context::CONTEXT_AUTH);
}

/**
* Retrieve registering URL
*
* @return string
*/
public function getCustomerRegistrationUrl()
{
return $this->getUrl('customer/account/create');
}
}

 

Create Block For Ajax Register

in order to create a Magento2 custom customer ajax login we have to create a block for the customer registration.

app/code/Wishusucess/CustomerAccount/Block/Form/Register.php

<?php
/**
* Source Wishusucess
* package Wishusucess_CustomerAccount
* Author Wishusucess Magento Development Team
* website https://www.wishusucess.com/
*/
namespace Wishusucess\CustomerAccount\Block\Form;

use Magento\Customer\Model\AccountManagement;

class Register extends \Magento\Directory\Block\Data
{
/**
* @var \Magento\Customer\Model\Session
*/
protected $customerSession;

/**
* @var \Magento\Framework\Module\Manager
*/
protected $moduleManager;

/**
* @var \Magento\Framework\App\Http\Context
*/
protected $httpContext;

/**
* Registration
*
* @var \Magento\Customer\Model\Registration
*/
protected $registration;

/**
* Constructor
*
* @param \Magento\Framework\View\Element\Template\Context $context
* @param \Magento\Directory\Helper\Data $directoryHelper
* @param \Magento\Framework\Json\EncoderInterface $jsonEncoder
* @param \Magento\Framework\App\Cache\Type\Config $configCacheType
* @param \Magento\Directory\Model\ResourceModel\Region\CollectionFactory $regionCollectionFactory
* @param \Magento\Directory\Model\ResourceModel\Country\CollectionFactory $countryCollectionFactory
* @param \Magento\Framework\Module\Manager $moduleManager
* @param \Magento\Customer\Model\Session $customerSession
* @param \Magento\Framework\App\Http\Context $httpContext
* @param \Magento\Customer\Model\Registration $registration
* @param array $data
*
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
*/
public function __construct(
\Magento\Framework\View\Element\Template\Context $context,
\Magento\Directory\Helper\Data $directoryHelper,
\Magento\Framework\Json\EncoderInterface $jsonEncoder,
\Magento\Framework\App\Cache\Type\Config $configCacheType,
\Magento\Directory\Model\ResourceModel\Region\CollectionFactory $regionCollectionFactory,
\Magento\Directory\Model\ResourceModel\Country\CollectionFactory $countryCollectionFactory,
\Magento\Framework\Module\Manager $moduleManager,
\Magento\Customer\Model\Session $customerSession,
\Magento\Customer\Model\Url $customerUrl,
\Magento\Framework\App\Http\Context $httpContext,
\Magento\Customer\Model\Registration $registration,
array $data = []
) {
$this->moduleManager = $moduleManager;
$this->customerSession = $customerSession;
$this->httpContext = $httpContext;
$this->registration = $registration;
parent::__construct(
$context,
$directoryHelper,
$jsonEncoder,
$configCacheType,
$regionCollectionFactory,
$countryCollectionFactory,
$data
);
}

/**
* Return registration
*
* @return \Magento\Customer\Model\Registration
*/
public function getRegistration()
{
return $this->registration;
}

/**
* Retrieve the form posting URL
*
* @return string
*/
public function getPostActionUrl()
{
return $this->getUrl('wishusucess/customer_ajax/register');
}

/**
* Retrieve back URL
*
* @return string
*/
public function getBackUrl()
{
return $this->getUrl('customer/account/login');
}

/**
* Retrieve form data
*
* @return mixed
*/
public function getFormData()
{
$data = $this->getData('form_data');
if ($data === null) {
$formData = $this->customerSession->getCustomerFormData(true);
$data = new \Magento\Framework\DataObject();
if ($formData) {
$data->addData($formData);
$data->setCustomerData(1);
}
if (isset($data['region_id'])) {
$data['region_id'] = (int)$data['region_id'];
}
$this->setData('form_data', $data);
}
return $data;
}

/**
* Newsletter module availability
*
* @return bool
*/
public function isNewsletterEnabled()
{
return $this->moduleManager->isOutputEnabled('Magento_Newsletter');
}

/**
* Get minimum password length
*
* @return string
*/
public function getMinimumPasswordLength()
{
return $this->_scopeConfig->getValue(AccountManagement::XML_PATH_MINIMUM_PASSWORD_LENGTH);
}

/**
* Get number of password required character classes
*
* @return string
*/
public function getRequiredCharacterClassesNumber()
{
return $this->_scopeConfig->getValue(AccountManagement::XML_PATH_REQUIRED_CHARACTER_CLASSES_NUMBER);
}

/**
* Checking customer login status
*
* @return bool
*/
public function customerIsAlreadyLoggedIn()
{
return (bool)$this->httpContext->getValue(\Magento\Customer\Model\Context::CONTEXT_AUTH);
}
}

 

Now Call Template in XML File

app/code/Wishusucess/CustomerAccount/view/frontend/layout/default.xml

<?xml version="1.0"?>
<!--
/**
* Source Wishusucess
* package Wishusucess_CustomerAccount
* Author Wishusucess Magento Development Team
* website https://www.wishusucess.com/
*/
-->
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
<body>
<referenceBlock name="register-link">
<arguments>
<argument name="class" xsi:type="string">customer-register-link</argument>
</arguments>
</referenceBlock>
<referenceBlock name="authorization-link-login">
<arguments>
<argument name="class" xsi:type="string">customer-login-link</argument>
</arguments>
</referenceBlock>
<referenceContainer name="before.body.end">
<block class="Wishusucess\CustomerAccount\Block\Form\Login" name="customer-popup-login" template="Wishusucess_CustomerAccount::login.phtml" />
<block class="Wishusucess\CustomerAccount\Block\Form\Register" name="customer-popup-register" template="Wishusucess_CustomerAccount::register.phtml" />
</referenceContainer>
</body>
</page>

 

Create Custom Customer Ajax Login View

app/code/Wishusucess/CustomerAccount/view/frontend/templates/login.phtml

<?php
/**
* Source Wishusucess
* package Wishusucess_CustomerAccount
* Author Wishusucess Magento Development Team
* website https://www.wishusucess.com/
*/
/** @var \Wishusucess\CustomerAccount\Block\Form\Login $block */
?>
<?php if (!$block->customerIsAlreadyLoggedIn()): ?>
<style>
.customer-popup-login {
display: none;
}
.or-another-selection {
display: inline-block;
padding-right: 5px;
}
@media(max-width: 767px) {
.or-another-selection {
display: block;
text-align: center;
margin-bottom: 5px;
}
}
</style>
<div id="customer-popup-login" class="customer-popup-login">
<div class="block block-customer-login">
<div class="block-content" aria-labelledby="block-customer-popup-login-heading">
<form class="form form-login"
action="<?php /* @escapeNotVerified */ echo $block->getPostActionUrl() ?>"
method="post"
id="customer-popup-login-form"
data-mage-init='{"validation":{}}'>
<?php echo $block->getBlockHtml('formkey'); ?>
<input type="hidden" name="redirect_url" value="<?php echo $this->getUrl('*/*/*', ['_current' => true, '_use_rewrite' => true]); ?>" />
<fieldset class="fieldset login" data-hasrequired="<?php /* @escapeNotVerified */ echo __('* Required Fields') ?>">
<div class="field note"><?php /* @escapeNotVerified */ echo __('If you have an account, sign in with your email address.') ?></div>
<div class="messages"></div>
<div class="field email required">
<label class="label" for="email"><span><?php /* @escapeNotVerified */ echo __('Email') ?></span></label>
<div class="control">
<input name="username" value="" <?php if ($block->isAutocompleteDisabled()) :?> autocomplete="off"<?php endif; ?> id="email-login" type="email" class="input-text" title="<?php /* @escapeNotVerified */ echo __('Email') ?>" data-validate="{required:true, 'validate-email':true}">
</div>
</div>
<div class="field password required">
<label for="pass" class="label"><span><?php /* @escapeNotVerified */ echo __('Password') ?></span></label>
<div class="control">
<input name="password" type="password" <?php if ($block->isAutocompleteDisabled()) :?> autocomplete="off"<?php endif; ?> class="input-text" id="pass-login" title="<?php /* @escapeNotVerified */ echo __('Password') ?>" data-validate="{required:true}" >
</div>
</div>
<div class="actions-toolbar">
<div class="primary"><button type="submit" class="action login primary" name="send" id="send2-login"><span><?php /* @escapeNotVerified */ echo __('Sign In') ?></span></button></div>
<?php if ($block->getRegistration()->isAllowed()): ?>
<div class="or-another-selection"><?php echo __('or'); ?></div>
<div class="secondary"><a class="action remind" href="<?php /* @escapeNotVerified */ echo $block->getCustomerRegistrationUrl() ?>" id="customer-popup-registration"><span><?php /* @escapeNotVerified */ echo __('Create an Account') ?></span></a></div>
<?php endif; ?>
</div>
</fieldset>
</form>
</div>
</div>
<script type="text/x-magento-init">
{
"#customer-popup-login": {
"Wishusucess_CustomerAccount/js/action/customer-authentication-popup": {
"popupTitle": "<?php /* @escapeNotVerified */ echo __('Sign In') ?>",
"innerWidth": "400"
}
}
}
</script>
</div>
<?php endif; ?>

 

Create Custom Customer Ajax Register View

app/code/Wishusucess/CustomerAccount/view/frontend/templates/register.phtml

<?php
/**
* Source Wishusucess
* package Wishusucess_CustomerAccount
* Author Wishusucess Magento Development Team
* website https://www.wishusucess.com/
*/
/** @var \Wishusucess\CustomerAccount\Block\Form\Register $block */
?>
<?php if (!$block->customerIsAlreadyLoggedIn() && $block->getRegistration()->isAllowed()): ?>
<style>
.customer-popup-register {
display: none;
}
</style>
<div id="customer-popup-register" class="customer-popup-register">
<form class="form-create-account" action="<?php /* @escapeNotVerified */ echo $block->getPostActionUrl() ?>" method="post" id="customer-popup-form-register" enctype="multipart/form-data" autocomplete="off" data-mage-init='{"validation":{}}'>
<?php echo $block->getBlockHtml('formkey'); ?>
<input type="hidden" name="redirect_url" value="<?php echo $this->getUrl('*/*/*', ['_current' => true, '_use_rewrite' => true]); ?>" />
<div class="messages"></div>
<p><?php /* @escapeNotVerified */ echo __('Creating an account has many benefits: check out faster, keep more than one address, track orders and more.') ?></p>
<fieldset class="fieldset create info">
<legend class="legend"><span><?php /* @escapeNotVerified */ echo __('Personal Information') ?></span></legend><br>
<?php echo $block->getLayout()->createBlock('Magento\Customer\Block\Widget\Name')->setObject($block->getFormData())->setForceUseCustomerAttributes(true)->toHtml() ?>
<?php if ($block->isNewsletterEnabled()): ?>
<div class="field choice newsletter">
<input type="checkbox" name="is_subscribed" title="<?php /* @escapeNotVerified */ echo __('Sign Up for Newsletter') ?>" value="1" id="popup-is_subscribed" class="checkbox">
<label for="is_subscribed" class="label"><span><?php /* @escapeNotVerified */ echo __('Sign Up for Newsletter') ?></span></label>
</div>
<?php endif ?>
</fieldset>
<fieldset class="fieldset create account" data-hasrequired="<?php /* @escapeNotVerified */ echo __('* Required Fields') ?>">
<legend class="legend"><span><?php /* @escapeNotVerified */ echo __('Sign-in Information') ?></span></legend><br>
<div class="field required">
<label for="popup-email_address" class="label"><span><?php /* @escapeNotVerified */ echo __('Email') ?></span></label>
<div class="control">
<input type="email" name="email" autocomplete="email" id="popup-email_address" value="" title="<?php /* @escapeNotVerified */ echo __('Email') ?>" class="input-text" data-validate="{required:true, 'validate-email':true}">
</div>
</div>
<div class="field password required" data-mage-init='{"passwordStrengthIndicator": {}}'>
<label for="password" class="label"><span><?php /* @escapeNotVerified */ echo __('Password') ?></span></label>
<div class="control">
<input type="password" name="password" id="password"
title="<?php /* @escapeNotVerified */ echo __('Password') ?>"
class="input-text"
data-password-min-length="<?php echo $block->escapeHtml($block->getMinimumPasswordLength()) ?>"
data-password-min-character-sets="<?php echo $block->escapeHtml($block->getRequiredCharacterClassesNumber()) ?>"
data-validate="{required:true, 'validate-customer-password':true}"
autocomplete="off">
<div id="password-strength-meter-container" data-role="password-strength-meter" >
<div id="password-strength-meter" class="password-strength-meter">
<?php /* @escapeNotVerified */ echo __('Password Strength'); ?>:
<span id="password-strength-meter-label" data-role="password-strength-meter-label" >
<?php /* @escapeNotVerified */ echo __('No Password'); ?>
</span>
</div>
</div>
</div>
</div>
<div class="field confirmation required">
<label for="password-confirmation" class="label"><span><?php /* @escapeNotVerified */ echo __('Confirm Password') ?></span></label>
<div class="control">
<input type="password" name="password_confirmation" title="<?php /* @escapeNotVerified */ echo __('Confirm Password') ?>" id="password-confirmation" class="input-text" data-validate="{required:true, equalTo:'#password'}" autocomplete="off">
</div>
</div>
</fieldset>
<div class="actions-toolbar">
<div class="primary">
<button type="submit" class="action submit primary" title="<?php /* @escapeNotVerified */ echo __('Create an Account') ?>"><span><?php /* @escapeNotVerified */ echo __('Create an Account') ?></span></button>
</div>
<div class="or-another-selection"><?php echo __('or'); ?></div>
<div class="secondary"><a class="action remind" href="<?php /* @escapeNotVerified */ echo $block->getBackUrl() ?>" id="customer-popup-sign-in"><span><?php /* @escapeNotVerified */ echo __('Sign In') ?></span></a></div>
</div>
</form>
<script type="text/x-magento-init">
{
"#customer-popup-register": {
"PHPCuong_CustomerAccount/js/action/customer-authentication-popup": {
"popupTitle": "<?php /* @escapeNotVerified */ echo __('Create an Account'); ?>",
"innerWidth": "600"
}
}
}
</script>
</div>
<?php endif; ?>

 

Customer Authentication Popup in Magento 2

app/code/Wishusucess/CustomerAccount/view/frontend/web/js/action/customer-authentication-popup.js

/**
* Source Wishusucess
* package Wishusucess_CustomerAccount
* Author Wishusucess Magento Development Team
* website https://www.wishusucess.com/
*/
define([
'jquery',
'Magento_Ui/js/modal/modal',
'Magento_Customer/js/customer-data',
'mage/storage',
'mage/translate',
'mage/mage',
'jquery/ui'
], function ($, modal, customerData, storage, $t) {
'use strict';

$.widget('wishusucess.customerAuthenticationPopup', {
options: {
login: '#customer-popup-login',
nextRegister: '#customer-popup-registration',
register: '#customer-popup-register',
prevLogin: '#customer-popup-sign-in'
},

/**
*
* @private
*/
_create: function () {
var self = this,
authentication_options = {
type: 'popup',
responsive: true,
innerScroll: true,
title: this.options.popupTitle,
buttons: false,
modalClass : 'customer-popup'
};

modal(authentication_options, this.element);

// Show the login form in a popup when clicking on the sign in text
$('body').on('click', '.customer-login-link, '+self.options.prevLogin, function() {
$(self.options.register).modal('closeModal');
$(self.options.login).modal('openModal');
self._setStyleCss();
return false;
});

// Show the registration form in a popup when clicking on the create an account text
$('body').on('click', '.customer-register-link, '+self.options.nextRegister, function() {
$(self.options.login).modal('closeModal');
$(self.options.register).modal('openModal');
self._setStyleCss(self.options.innerWidth);
return false;
});

this._ajaxSubmit();
this._resetStyleCss();
},

/**
* Set width of the popup
* @private
*/
_setStyleCss: function(width) {
width = width || 400;
if (window.innerWidth > 786) {
this.element.parent().parent('.modal-inner-wrap').css({'max-width': width+'px'});
}
},

/**
* Reset width of the popup
* @private
*/
_resetStyleCss: function() {
var self = this;
$( window ).resize(function() {
if (window.innerWidth <= 786) {
self.element.parent().parent('.modal-inner-wrap').css({'max-width': 'initial'});
} else {
self._setStyleCss(self.options.innerWidth);
}
});
},

/**
* Submit data by Ajax
* @private
*/
_ajaxSubmit: function() {
var self = this,
form = this.element.find('form'),
inputElement = form.find('input');

inputElement.keyup(function (e) {
self.element.find('.messages').html('');
});

form.submit(function (e) {
if (form.validation('isValid')) {
if (form.hasClass('form-create-account')) {
$.ajax({
url: $(e.target).attr('action'),
data: $(e.target).serializeArray(),
showLoader: true,
type: 'POST',
dataType: 'json',
success: function (response) {
self._showResponse(response, form.find('input[name="redirect_url"]').val());
},
error: function() {
self._showFailingMessage();
}
});
} else {
var submitData = {},
formDataArray = $(e.target).serializeArray();
formDataArray.forEach(function (entry) {
submitData[entry.name] = entry.value;
});
$('body').loader().loader('show');
storage.post(
$(e.target).attr('action'),
JSON.stringify(submitData)
).done(function (response) {
$('body').loader().loader('hide');
self._showResponse(response, form.find('input[name="redirect_url"]').val());
}).fail(function () {
$('body').loader().loader('hide');
self._showFailingMessage();
});
}
}
return false;
});
},

/**
* Display messages on the screen
* @private
*/
_displayMessages: function(className, message) {
$('<div class="message '+className+'"><div>'+message+'</div></div>').appendTo(this.element.find('.messages'));
},

/**
* Showing response results
* @private
* @param {Object} response
* @param {String} locationHref
*/
_showResponse: function(response, locationHref) {
var self = this,
timeout = 800;
this.element.find('.messages').html('');
if (response.errors) {
this._displayMessages('message-error error', response.message);
} else {
this._displayMessages('message-success success', response.message);
}
this.element.find('.messages .message').show();
setTimeout(function() {
if (!response.errors) {
self.element.modal('closeModal');
window.location.href = locationHref;
}
}, timeout);
},

/**
* Show the failing message
* @private
*/
_showFailingMessage: function() {
this.element.find('.messages').html('');
this._displayMessages('message-error error', $t('An error occurred, please try again later.'));
this.element.find('.messages .message').show();
}
});

return $.wishusucess.customerAuthenticationPopup;
});

 

 

Now, Run Following Command:

php bin/magento setup:upgrade

php bin/magento setup:di:compile

php bin/magento setup:static-content:deploy -f

php bin/magento cache:clean

php bin/magento cache:flush

 

Hire Magento 2 Expert Developer to Develop Your Store

GitHub

Related Post:

Custom Shipping Text Filed: Show Custom Text Magento 2

Search AutoComplete: Magento 2 Module Add All Category for Search

Share Product on WhatsApp: With Products Image And URL in Magento 2

 

Recommended Post:

Magento 2.4 Installation Guide: How to Install Magento 2.4.2

Magento Store: Best 36 Magento Websites Example in The World

SEO Packages: How Much Do SEO Packages Cost in India, SEO Pricing

Newsletter Subscription: Male & Female Wise Subscription in Magento 2

Here we have developed a Magento 2 Newsletter Subscription extension that helps you to add gender-wise subscription functionality to your Magento 2 store.

Wishusucess_Newsletter Magento 2 extension developed by Wishusucess expert Magento 2 Team.

So this newsletter module will add a great experience to your shopping store and when your customer visits your site then they can subscribe to your newsletter based on their gender. So you can notify your customers based on their gender and can increase more seals. you will also be able to provide them special offer about a particular product to your customer on your Magento 2 store.

Magento 2 Newsletter Subscription Male Female

 

Create Custom Magento 2 Newwsletter Suibscription

app/code/Wishusucess/Newsletter/registration.php

app/code/Wishusucess/Newsletter/etc/module.xml

app/code/Wishusucess/Newsletter/etc/di.xml

app/code/Wishusucess/Newsletter/Setup/InstallSchema.php

app/code/Wishusucess/Newsletter/Controller/Subscribe/NewAction.php

app/code/Wishusucess/Newsletter/Block/Subscribe.php

app/code/Wishusucess/Newsletter/Model/Subscriber.php

app/code/Wishusucess/Newsletter/view/adminhtml/layout/newsletter_subscriber_block.xml

app/code/Wishusucess/Newsletter/view/frontend/layout/default.xml

app/code/Wishusucess/Newsletter/view/frontend/templates/subscribe.phtml

 

Turn off Magento 2 Newsletter Subscription

So when you don't need this feature then you will also be able to turn off these custom newsletter_subscription features from your admin.

In order to turn off, these features just go to the Magento admin and click

Stores -> Configuration -> Customers -> Newsletter Tab

and then choose your setting like set to disable if you don't need it to need then turns on this feature by setting enable newsletter.

 

Register Magento 2 Newsletter Module

app/code/Wishusucess/Newsletter/registration.php

<?php
/*
* @Author Hemant Singh
* @Developer Hemant Singh
* @Module Wishusucess_Newsletter
* @copyright Copyright (c) Wishusucess (http://www.wishusucess.com/)
*/
\Magento\Framework\Component\ComponentRegistrar::register(
\Magento\Framework\Component\ComponentRegistrar::MODULE,
'Wishusucess_Newsletter',
__DIR__
);

 

Define Basic Information of Newsletter

app/code/Wishusucess/Newsletter/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="Wishusucess_Newsletter" setup_version="1.0.0"/>
<sequence>
<module name="Magento_Newsletter" />
</sequence>
</config>

 

Decide Preferences Through Dependency Injection

So here you will be able to decide your newly added class and then you have to give the preferences in the di.xml file.

app/code/Wishusucess/Newsletter/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\Newsletter\Controller\Subscriber\NewAction" type="Wishusucess\Newsletter\Controller\Subscribe\NewAction" />
<preference for="Magento\Newsletter\Model\Subscriber" type="Wishusucess\Newsletter\Model\Subscriber" />
</config>

 

Add Column Gender in Magento 2 Newsletter Table

So here you can add the custom column which is gender in Magento 2 newsletter_subscriber database table.

app/code/Wishusucess/Newsletter/Setup/InstallSchema.php

<?php
/*
* @Author Hemant Singh
* @Developer Hemant Singh
* @Module Wishusucess_Newsletter
* @copyright Copyright (c) Wishusucess (http://www.wishusucess.com/)
*/
namespace Wishusucess\Newsletter\Setup;

use Magento\Framework\Setup\InstallSchemaInterface;
use Magento\Framework\Setup\ModuleContextInterface;
use Magento\Framework\Setup\SchemaSetupInterface;
use Magento\Framework\DB\Ddl\Table;

class InstallSchema implements InstallSchemaInterface {
public function install(SchemaSetupInterface $setup, ModuleContextInterface $context) {
$setup->startSetup();
$table = $setup->getTable('newsletter_subscriber');

$setup->getConnection()->addColumn(
$table, 'gender', [
'type' => Table::TYPE_INTEGER,
'nullable' => true,
'comment' => 'Gender'
]
);

$setup->endSetup();
}
}

 

Create Controller For Magento 2 Newsletter

So here execute() method processed over the newly added column gender Magento 2 newsletter subscription. So you can decide the action which you have to perform over this column.

app/code/Wishusucess/Newsletter/Controller/Subscribe/NewAction.php

<?php
/*
* @Author Hemant Singh
* @Developer Hemant Singh
* @Module Wishusucess_Newsletter
* @copyright Copyright (c) Wishusucess (http://www.wishusucess.com/)
*/
namespace Wishusucess\Newsletter\Controller\Subscribe;

use Magento\Customer\Api\AccountManagementInterface as CustomerAccountManagement;
use Magento\Customer\Model\Session;
use Magento\Customer\Model\Url as CustomerUrl;
use Magento\Framework\App\Action\Context;
use Magento\Framework\App\Action\HttpPostActionInterface;
use Magento\Framework\App\Config\ScopeConfigInterface;
use Magento\Framework\App\ObjectManager;
use Magento\Framework\Controller\Result\Redirect;
use Magento\Framework\Controller\ResultFactory;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\Phrase;
use Magento\Framework\Validator\EmailAddress as EmailValidator;
use Magento\Newsletter\Controller\Subscriber as SubscriberController;
use Magento\Newsletter\Model\Subscriber;
use Magento\Newsletter\Model\SubscriptionManagerInterface;
use Magento\Store\Model\ScopeInterface;
use Magento\Store\Model\StoreManagerInterface;
use Magento\Newsletter\Model\SubscriberFactory;

class NewAction extends \Magento\Newsletter\Controller\Subscriber\NewAction {

/**
* @var CustomerAccountManagement
*/
protected $customerAccountManagement;

/**
* @var EmailValidator
*/
private $emailValidator;

/**
* @var SubscriptionManagerInterface
*/
private $subscriptionManager;

/**
* Initialize dependencies.
*
* @param Context $context
* @param SubscriberFactory $subscriberFactory
* @param Session $customerSession
* @param StoreManagerInterface $storeManager
* @param CustomerUrl $customerUrl
* @param CustomerAccountManagement $customerAccountManagement
* @param SubscriptionManagerInterface $subscriptionManager
* @param EmailValidator $emailValidator
*/
public function __construct(
Context $context,
SubscriberFactory $subscriberFactory,
Session $customerSession,
StoreManagerInterface $storeManager,
CustomerUrl $customerUrl,
CustomerAccountManagement $customerAccountManagement,
SubscriptionManagerInterface $subscriptionManager,
EmailValidator $emailValidator = null
) {
$this->customerAccountManagement = $customerAccountManagement;
$this->subscriptionManager = $subscriptionManager;
$this->emailValidator = $emailValidator ?: ObjectManager::getInstance()->get(EmailValidator::class);
parent::__construct(
$context,
$subscriberFactory,
$customerSession,
$storeManager,
$customerUrl,
$customerAccountManagement,
$subscriptionManager,
$emailValidator
);
}

public function execute()
{
if ($this->getRequest()->isPost() && $this->getRequest()->getPost('email')) {
$gender = $this->getRequest()->getPost('gender');

$email = (string)$this->getRequest()->getPost('email');

try {
$this->validateEmailFormat($email);
$this->validateGuestSubscription();
$this->validateEmailAvailable($email);

$websiteId = (int)$this->_storeManager->getStore()->getWebsiteId();
/** @var Subscriber $subscriber */
$subscriber = $this->_subscriberFactory->create()->loadBySubscriberEmail($email, $websiteId);
if ($subscriber->getId()
&& (int)$subscriber->getSubscriberStatus() === Subscriber::STATUS_SUBSCRIBED) {
throw new LocalizedException(
__('This email address is already subscribed.')
);
}

$storeId = (int)$this->_storeManager->getStore()->getId();
$currentCustomerId = $this->getSessionCustomerId($email);
$subscriber = $currentCustomerId
? $this->subscriptionManager->subscribeCustomer($currentCustomerId, $storeId)
: $this->subscriptionManager->subscribe($email, $storeId);
// add gender data to the model
$subscriber->setData('gender',$gender);
$subscriber->save();
$message = $this->getSuccessMessage((int)$subscriber->getSubscriberStatus());
$this->messageManager->addSuccessMessage($message);
} catch (LocalizedException $e) {
$this->messageManager->addComplexErrorMessage(
'localizedSubscriptionErrorMessage',
['message' => $e->getMessage()]
);
} catch (\Exception $e) {
$this->messageManager->addExceptionMessage($e, __('Something went wrong with the subscription.'));
}
}
/** @var Redirect $redirect */
$redirect = $this->resultFactory->create(ResultFactory::TYPE_REDIRECT);
$redirectUrl = $this->_redirect->getRedirectUrl();
return $redirect->setUrl($redirectUrl);
}

/**
* Get customer id from session if he is owner of the email
*
* @param string $email
* @return int|null
*/
private function getSessionCustomerId(string $email): ?int
{
if (!$this->_customerSession->isLoggedIn()) {
return null;
}

$customer = $this->_customerSession->getCustomerDataObject();
if ($customer->getEmail() !== $email) {
return null;
}

return (int)$this->_customerSession->getId();
}


/**
* Get success message
*
* @param int $status
* @return Phrase
*/
private function getSuccessMessage(int $status): Phrase
{
if ($status === Subscriber::STATUS_NOT_ACTIVE) {
return __('The confirmation request has been sent.');
}

return __('Thank you for your subscription.');
}
}

 

Create Block for Magento 2 Newsletter Subscription

Now you can retrieve the form action URL and set the "secure" param to avoid confirmation. and you also decide what message you want to show when action submits the form from a secure page to unsecure.

app/code/Wishusucess/Newsletter/Block/Subscribe.php

<?php
/*
* @Author Hemant Singh
* @Developer Hemant Singh
* @Module Wishusucess_Newsletter
* @copyright Copyright (c) Wishusucess (http://www.wishusucess.com/)
*/
namespace Wishusucess\Newsletter\Block;
use Magento\Framework\View\Element\Template;

class Subscribe extends \Magento\Framework\View\Element\Template
{
/**
* Retrieve form action url and set "secure" param to avoid confirm
* message when we submit form from secure page to unsecure
*
* @return string
*/
public function getFormActionUrl()
{
return $this->getUrl('newsletter/subscriber/new', ['_secure' => true]);
}
}




/*class Subscribe extends Template {
public function __construct(Template\Context $context,array $data = []) {
parent::__construct($context, $data);
}
public function beforeToHtml(\Magento\Newsletter\Block\Subscribe $originalBlock){
$originalBlock->setTemplate('BDC_Newsletter::subscribe.phtml');
}
}*/

 

Model Class in Newsletter Subscription

app/code/Wishusucess/Newsletter/Model/Subscriber.php

<?php
/*
* @Author Hemant Singh
* @Developer Hemant Singh
* @Module Wishusucess_Newsletter
* @copyright Copyright (c) Wishusucess (http://www.wishusucess.com/)
*/
namespace Wishusucess\Newsletter\Model;

class Subscriber extends \Magento\Newsletter\Model\Subscriber {

/**
* Initialize resource model
*
* @return void
*/

public function subscribe($email) {
echo "=----------->";exit;

$this->loadByEmail($email);

if (!$this->getId()) {
$this->setSubscriberConfirmCode($this->randomSequence());
}

$isConfirmNeed = $this->_scopeConfig->getValue(
self::XML_PATH_CONFIRMATION_FLAG, \Magento\Store\Model\ScopeInterface::SCOPE_STORE
) == 1 ? true : false;
$isOwnSubscribes = false;

$isSubscribeOwnEmail = $this->_customerSession->isLoggedIn() && $this->_customerSession->getCustomerDataObject()->getEmail() == $email;

if (!$this->getId() || $this->getStatus() == self::STATUS_UNSUBSCRIBED || $this->getStatus() == self::STATUS_NOT_ACTIVE
) {
if ($isConfirmNeed === true) {
// if user subscribes own login email - confirmation is not needed
$isOwnSubscribes = $isSubscribeOwnEmail;
if ($isOwnSubscribes == true) {
$this->setStatus(self::STATUS_SUBSCRIBED);
} else {
$this->setStatus(self::STATUS_NOT_ACTIVE);
}
} else {
$this->setStatus(self::STATUS_SUBSCRIBED);
}

$this->setSubscriberEmail($_POST['email']);

}

if(!empty($_POST['subscriber_name']) ){
$this->setSubscriberName($_POST['subscriber_name']); //subscriber_name
$this->setSubscriberDateofbirth($_POST['subscriber_dateofbirth']); //date of birth
$this->setSubscriberCountrycode($_POST['subscriber_countrycode']); //country code
}

if ($isSubscribeOwnEmail) {
try {
$customer = $this->customerRepository->getById($this->_customerSession->getCustomerId());
$this->setStoreId($customer->getStoreId());
$this->setCustomerId($customer->getId());
} catch (NoSuchEntityException $e) {
$this->setStoreId($this->_storeManager->getStore()->getId());
$this->setCustomerId(0);
}
} else {
$this->setStoreId($this->_storeManager->getStore()->getId());
$this->setCustomerId(0);
}

$this->setStatusChanged(true);

try {
$this->save();
if ($isConfirmNeed === true && $isOwnSubscribes === false
) {
$this->sendConfirmationRequestEmail();
} else {
$this->sendConfirmationSuccessEmail();
}
return $this->getStatus();
} catch (\Exception $e) {
throw new \Exception($e->getMessage());
}
}

}

 

Adminhtml Layout XML File

app/code/Wishusucess/Newsletter/view/adminhtml/layout/newsletter_subscriber_block.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="adminhtml.newslettrer.subscriber.grid.columnSet">
<block class="Magento\Backend\Block\Widget\Grid\Column">
<arguments>
<argument name="header" xsi:type="string" translate="true">Gender</argument>
<argument name="index" xsi:type="string">gender</argument>
<argument name="type" xsi:type="string">options</argument>
<argument name="options" xsi:type="array">
<item name="gender_male" xsi:type="array">
<item name="value" xsi:type="string">1</item>
<item name="label" xsi:type="string" translate="true">Male</item>
</item>
<item name="gender_female" xsi:type="array">
<item name="value" xsi:type="string">2</item>
<item name="label" xsi:type="string" translate="true">Female</item>
</item>
<item name="gender_not_specified" xsi:type="array">
<item name="value" xsi:type="string">3</item>
<item name="label" xsi:type="string" translate="true">Not Specified</item>
</item>
</argument>
<argument name="header_css_class" xsi:type="string">col-gender</argument>
<argument name="column_css_class" xsi:type="string">ccol-gender</argument>
</arguments>
</block>
</referenceBlock>
</body>
</page>

 

Frontend Layout Component in Newsletter

Now we to call the component.phtml file in this default.xml so this will show everywhere of Magento 2 stores.

app/code/Wishusucess/Newsletter/view/frontend/layout/default.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="head.components">
<block class="Magento\Framework\View\Element\Js\Components" name="newsletter_head_components" template="Magento_Newsletter::js/components.phtml"/>
</referenceBlock>

<!--referenceContainer name="footer">
<block class="Magento\Newsletter\Block\Subscribe" name="form.subscribe" as="subscribe" before="-" template="Magento_Newsletter::subscribe.phtml"/>
</referenceContainer-->


<!-- <referenceContainer name="footer">
<referenceBlock name="form.subscribe" remove="true"/>
<block class="BDC\Newsletter\Block\Subscribe" name="form.custom.subscribe" before="-" template="BDC_Newsletter::subscribe.phtml"/>

<block class="BDC\Newsletter\Block\Review" name="review.list" template="right-review.phtml">
<block class="Magento\Newsletter\Block\Subscribe" name="review_list_pager" as="review_list_pager"/>
</block>
</referenceContainer> -->
</body>
</page>

 

Get Data Of Newsletter Subscription in Magento 2

Here is how you want to show the data on the front end you can decide now your newsletter_subscription extension will show the data of the extra column of the newsletter_subscription table.

app/code/Wishusucess/Newsletter/view/frontend/templates/subscribe.phtml

<?php
/*
* @Author Hemant Singh
* @Developer Hemant Singh
* @Module Wishusucess_Newsletter
* @copyright Copyright (c) Wishusucess (http://www.wishusucess.com/)
*/
?>
<div class="block newsletter">
<div class="title"><strong><?php /* @escapeNotVerified */ echo __('Newsletter') ?></strong></div>
<div class="content">
<form class="form subscribe"
novalidate
action="<?php echo $block->escapeUrl($block->getFormActionUrl()) ?>"
method="post"
data-mage-init='{"validation": {"errorClass": "mage-error"}}'
id="newsletter-validate-detail">
<div class="field firstname">
<label class="label" for="firstname"><span><?php echo $block->escapeHtml(__('First Name')) ?></span></label>
<div class="control">
<input name="firstname" type="text" id="firstname" placeholder="<?php echo $block->escapeHtmlAttr(__('First Name')) ?>"
data-validate="{required:true}"/>
</div>
</div>
<div class="field lastname">
<label class="label" for="lastname"><span><?php echo $block->escapeHtml(__('Last Name')) ?></span></label>
<div class="control">
<input name="lastname" type="text" id="lastname" placeholder="<?php echo $block->escapeHtmlAttr(__('Last Name')) ?>"
data-validate="{required:true}"/>
</div>
</div>
<?php $_gender = $block->getLayout()->createBlock('Magento\Customer\Block\Widget\Gender') ?>
<?php echo $_gender->toHtml() ?>
<div class="field newsletter">
<label class="label" for="newsletter"><span><?php echo $block->escapeHtml(__('Sign Up for Our Newsletter:')) ?></span></label>
<div class="control">
<input name="email" type="email" id="newsletter"
placeholder="<?php echo $block->escapeHtmlAttr(__('Enter your email address')) ?>"
data-validate="{required:true, 'validate-email':true}"/>
</div>
</div>
<div class="actions">
<button class="action subscribe primary" title="<?php echo $block->escapeHtmlAttr(__('Subscribe')) ?>" type="submit">
<span><?php echo $block->escapeHtml(__('Subscribe')) ?></span>
</button>
</div>
</form>
</div>
</div>

 

Now, Run Following Command:

php bin/magento setup:upgrade

php bin/magento setup:di:compile

php bin/magento setup:static-content:deplpy -f

php bin/magento cache:clean

 

Extra Column in Newsletter Subsription

Download Link:

Wishusucess Newsletter_Subscription Extension in Magento 2

Hire Magento 2 Expert Developer to Develop Your Store

 

Related Post:

Custom Shipping Text Filed: Show Custom Text Magento 2

Search AutoComplete: Magento 2 Module Add All Category for Search

Share Product on WhatsApp: With Products Image And URL in Magento 2

 

Recommended Post:

Magento 2.4 Installation Guide: How to Install Magento 2.4.2

Magento Store: Best 36 Magento Websites Example in The World

SEO Packages: How Much Do SEO Packages Cost in India, SEO Pricing

Breadcrumb Image: Add Category Attribute for Upload Image in Magento 2

In this article, I am going to explaining how we can add custom image icons in the breadcrumb section on the list page and product detail page. Through this module, you can add custom category attributes for Breadcrumb Image upload and can save those images.

Category Breadcumb Image Upload

 

Create Module For Category Breadcrumb Image Upload

In order to get the brand icon on the list page and product details page breadcrumb section, you have to create a module that can create custom category attributes and upload the images or brand icon images in the breadcrumb section for the list page and detail page.

app/code/Wishusucess/CategoryBreadcrumbImage/registration.php

app/code/Wishusucess/CategoryBreadcrumbImage/etc/module.xml

app/code/Wishusucess/CategoryBreadcrumbImage/etc/di.xml

app/code/Wishusucess/CategoryBreadcrumbImage/etc/adminhtml/routes.xml

app/code/Wishusucess/CategoryBreadcrumbImage/Setup/InstallData.php

app/code/Wishusucess/CategoryBreadcrumbImage/Model/Category/DataProvider.php

app/code/Wishusucess/CategoryBreadcrumbImage/Controller/Adminhtml/Category/BreadcrumbImage/Upload.php

app/code/Wishusucess/CategoryBreadcrumbImage/view/adminhtml/ui_component/category_form.xml

 

Register Breadcrumb image Module

app/code/Wishusucess/CategoryBreadcrumbImage/registration.php

<?php
/*
* @Author Hemant Singh
* @Developer Hemant Singh
* @Module Wishusucess_CategoryBreadcrumbImage
* @copyright Copyright (c) Wishusucess (http://www.wishusucess.com/)
*/
\Magento\Framework\Component\ComponentRegistrar::register(
\Magento\Framework\Component\ComponentRegistrar::MODULE,
'Wishusucess_CategoryBreadcrumbImage',
__DIR__
);

 

Give Basic information About Module

app/code/Wishusucess/CategoryBreadcrumbImage/etc/module.xml

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

 

Create Dependency Injection File

This di.xml basically we use for ( rewrite ) preference of a particular class. So through this file, we can inform the Magento core class to replace with a new class or existing class arguments.

app/code/Wishusucess/CategoryBreadcrumbImage/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">
<type name="Wishusucess\CategoryBreadcrumbImage\Controller\Adminhtml\Category\BreadcrumbImage\Upload">
<arguments>
<argument name="imageUploader" xsi:type="object">CategoryImageUpload</argument>
</arguments>
</type>
<virtualType name="CategoryImageUpload" type="Magento\Catalog\Model\ImageUploader">
<arguments>
<argument name="baseTmpPath" xsi:type="string">catalog/category/tmp</argument>
<argument name="basePath" xsi:type="string">catalog/category</argument>
<argument name="allowedExtensions" xsi:type="array">
<item name="jpg" xsi:type="string">jpg</item>
<item name="jpeg" xsi:type="string">jpeg</item>
<item name="gif" xsi:type="string">gif</item>
<item name="png" xsi:type="string">png</item>
</argument>
</arguments>
</virtualType>
<preference for="Magento\Catalog\Model\Category\DataProvider" type="Wishusucess\CategoryBreadcrumbImage\Model\Category\DataProvider" />
</config>

 

Define Routes ID

In Magento 2 Shopping applications routing basically we use to provide the data from a URL request to the appropriate class for processing. Magento 2 has some format to define the route ID like the below syntax.

<store-url>/<store-code>/<front-name>/<controller-name>/<action-name>

app/code/Wishusucess/CategoryBreadcrumbImage/etc/adminhtml/routes.xml

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:App/etc/routes.xsd">
<router id="admin">
<route id="breadcrumbimage" frontName="breadcrumbimage">
<module name="Wishusucess_CategoryBreadcrumbImage" before="Magento_Backend" />
</route>
</router>
</config>

 

Create Custom Category Image Upload Attribute

Using this InstallSchame.php file we can create a custom category attribute to upload the brand image on the list page breadcrumb section and as well as product detail page breadcrumb section.

$setup->addAttribute(
\Magento\Catalog\Model\Category::ENTITY, 'breadcrumb_image');

In the above code, we have decided on a custom category which is "breadcrumb_image" and we will use this identifier view/adminhtml/ui_component/category_form.xml to get the data from Magento admin.

app/code/Wishusucess/CategoryBreadcrumbImage/Setup/InstallData.php

<?php
/*
* @Author Hemant Singh
* @Developer Hemant Singh
* @Module Wishusucess_CategoryBreadcrumbImage
* @copyright Copyright (c) Wishusucess (http://www.wishusucess.com/)
*/
namespace Wishusucess\CategoryBreadcrumbImage\Setup;

use Magento\Eav\Setup\EavSetup;
use Magento\Eav\Setup\EavSetupFactory;
use Magento\Framework\Setup\InstallDataInterface;
use Magento\Framework\Setup\ModuleContextInterface;
use Magento\Framework\Setup\ModuleDataSetupInterface;
use Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface;

/**
* @codeCoverageIgnore
*/
class InstallData implements InstallDataInterface
{
/**
* EAV setup factory.
*
* @var EavSetupFactory
*/
private $_eavSetupFactory;
protected $categorySetupFactory;

/**
* Init.
*
* @param EavSetupFactory $eavSetupFactory
*/
public function __construct(EavSetupFactory $eavSetupFactory, \Magento\Catalog\Setup\CategorySetupFactory $categorySetupFactory)
{
$this->_eavSetupFactory = $eavSetupFactory;
$this->categorySetupFactory = $categorySetupFactory;
}

/**
* {@inheritdoc}
*
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
*/
public function install(
ModuleDataSetupInterface $setup,
ModuleContextInterface $context
) {
/** @var EavSetup $eavSetup */
$eavSetup = $this->_eavSetupFactory->create(['setup' => $setup]);
$setup = $this->categorySetupFactory->create(['setup' => $setup]); 
$setup->addAttribute(
\Magento\Catalog\Model\Category::ENTITY, 'breadcrumb_image', [
'type' => 'varchar',
'label' => 'Breadcrumb Image',
'input' => 'image',
'backend' => 'Magento\Catalog\Model\Category\Attribute\Backend\Image',
'required' => false,
'sort_order' => 9,
'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_STORE,
'group' => 'General Information',
]
);
}
}

 

Create Model Class for Custom Upload Image Attribute in Magento 2

Here Model class we will use to process over the breadcrumb_image attribute and do data operations like create, read, update and delete, on a database.

app/code/Wishusucess/CategoryBreadcrumbImage/Model/Category/DataProvider.php

$fields = parent::getFieldsMap();
$fields['content'][] = 'breadcrumb_image'; // breadcrumb image field

In the above code we have mapped the breadcrumb_image attribute field.

<?php
/*
* @Author Hemant Singh
* @Developer Hemant Singh
* @Module Wishusucess_CategoryBreadcrumbImage
* @copyright Copyright (c) Wishusucess (http://www.wishusucess.com/)
*/
namespace Wishusucess\CategoryBreadcrumbImage\Model\Category;

class DataProvider extends \Magento\Catalog\Model\Category\DataProvider
{

protected function getFieldsMap()
{
$fields = parent::getFieldsMap();
$fields['content'][] = 'breadcrumb_image'; // breadcrumb image field

return $fields;
}
}

 

Breadcrumb Image Upload Class in Magento 2

This controller class basically follow the actual operation on breadcrumb_image. This class has execute() method which  contain action to do.

app/code/Wishusucess/CategoryBreadcrumbImage/Controller/Adminhtml/Category/BreadcrumbImage/Upload.php

<?php
/*
* @Author Hemant Singh
* @Developer Hemant Singh
* @Module Wishusucess_CategoryBreadcrumbImage
* @copyright Copyright (c) Wishusucess (http://www.wishusucess.com/)
*/
namespace Wishusucess\CategoryBreadcrumbImage\Controller\Adminhtml\Category\BreadcrumbImage;

use Magento\Framework\Controller\ResultFactory;

/**
* Class Upload
*/
class Upload extends \Magento\Backend\App\Action
{
/**
* Image uploader
*
* @var \Magento\Catalog\Model\ImageUploader
*/
protected $imageUploader;

/**
* Uploader factory
*
* @var \Magento\MediaStorage\Model\File\UploaderFactory
*/
private $uploaderFactory;

/**
* Media directory object (writable).
*
* @var \Magento\Framework\Filesystem\Directory\WriteInterface
*/
protected $mediaDirectory;

/**
* Store manager
*
* @var \Magento\Store\Model\StoreManagerInterface
*/
protected $storeManager;

/**
* Core file storage database
*
* @var \Magento\MediaStorage\Helper\File\Storage\Database
*/
protected $coreFileStorageDatabase;

/**
* @var \Psr\Log\LoggerInterface
*/
protected $logger;

/**
* Upload constructor.
*
* @param \Magento\Backend\App\Action\Context $context
* @param \Magento\Catalog\Model\ImageUploader $imageUploader
*/
public function __construct(
\Magento\Backend\App\Action\Context $context,
\Magento\Catalog\Model\ImageUploader $imageUploader,
\Magento\MediaStorage\Model\File\UploaderFactory $uploaderFactory,
\Magento\Framework\Filesystem $filesystem,
\Magento\Store\Model\StoreManagerInterface $storeManager,
\Magento\MediaStorage\Helper\File\Storage\Database $coreFileStorageDatabase,
\Psr\Log\LoggerInterface $logger
) {
parent::__construct($context);
$this->imageUploader = $imageUploader;
$this->uploaderFactory = $uploaderFactory;
$this->mediaDirectory = $filesystem->getDirectoryWrite(\Magento\Framework\App\Filesystem\DirectoryList::MEDIA);
$this->storeManager = $storeManager;
$this->coreFileStorageDatabase = $coreFileStorageDatabase;
$this->logger = $logger;
}

/**
* Check admin permissions for this controller
*
* @return boolean
*/
protected function _isAllowed()
{
return $this->_authorization->isAllowed('Wishusucess_CategoryBreadcrumbImag::category');
}

/**
* Upload file controller action
*
* @return \Magento\Framework\Controller\ResultInterface
*/
public function execute()
{
try {
$result = $this->imageUploader->saveFileToTmpDir('breadcrumb_image');
$result['cookie'] = [
'name' => $this->_getSession()->getName(),
'value' => $this->_getSession()->getSessionId(),
'lifetime' => $this->_getSession()->getCookieLifetime(),
'path' => $this->_getSession()->getCookiePath(),
'domain' => $this->_getSession()->getCookieDomain(),
];
} catch (\Exception $e) {
$result = ['error' => $e->getMessage(), 'errorcode' => $e->getCode()];
}
return $this->resultFactory->create(ResultFactory::TYPE_JSON)->setData([[$result]]);
}
}

 

Add field ID in Category Form For Breadcrumb Image

app/code/Wishusucess/CategoryBreadcrumbImage/view/adminhtml/ui_component/category_form.xml

<?xml version="1.0" encoding="UTF-8"?>
<form xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Ui:etc/ui_configuration.xsd">
<fieldset name="cat-breadcrumb-image">
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<item name="label" xsi:type="string" translate="true">Breadcrumb Image</item>
<item name="collapsible" xsi:type="boolean">true</item>
<item name="sortOrder" xsi:type="number">100</item>
</item>
</argument>
<field name="breadcrumb_image">
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<item name="dataType" xsi:type="string">string</item>
<item name="source" xsi:type="string">category</item>
<item name="label" xsi:type="string" translate="true">Breadcrumb Image</item>
<item name="visible" xsi:type="boolean">true</item>
<item name="formElement" xsi:type="string">fileUploader</item>
<item name="elementTmpl" xsi:type="string">ui/form/element/uploader/uploader</item>
<item name="previewTmpl" xsi:type="string">Magento_Catalog/image-preview</item>
<item name="required" xsi:type="boolean">false</item>
<item name="sortOrder" xsi:type="number">40</item>
<item name="uploaderConfig" xsi:type="array">
<item name="url" xsi:type="url" path="catalog/category_image/upload"/>
</item>
</item>
</argument>
</field>
</fieldset>
</form>

 

Now, Run Following Command:

php bin/magento setup:upgrade

php bin/magento setup:di:compile

php bin/magento setup:static-content:deplpy -f

php bin/magento cache:clean

 

Download Link:

Category Breadcrumb Image Extension in Magento 2

Hire Magento 2 Expert Developer to Develop Your Store

 

Related Post:

Custom Shipping Text Filed: Show Custom Text Magento 2

Search AutoComplete: Magento 2 Module Add All Category for Search

Share Product on WhatsApp: With Products Image And URL in Magento 2

 

Recommended Post:

Magento 2.4 Installation Guide: How to Install Magento 2.4.2

Magento Store: Best 36 Magento Websites Example in The World

SEO Packages: How Much Do SEO Packages Cost in India, SEO Pricing

Share Product on WhatsApp: With Products Image And URL in Magento 2

If you are also looking for adding functionality to share the Magento 2 catalog product on WhatsApp then you have to create a module. So here in this article, Wishusucess Magento Team has created a Free extension to implement these features.

This module will implement product features functionality then we have to call the template in Magento 2 Catalog product view list page.

Share Product on WhatsApp

 

Create Share Product in WhatsApp in Magento

Some basic files we need to create to get these features which follow in below.

app/code/Wishusucess/Whatsappshare/registration.php

app/code/Wishusucess/Whatsappshare/etc/module.xml

app/code/Wishusucess/Whatsappshare/etc/config.xml

app/code/Wishusucess/Whatsappshare/etc/acl.xml

app/code/Wishusucess/Whatsappshare/etc/adminhtml/system.xml

app/code/Wishusucess/Whatsappshare/Helper/Data.php

app/code/Wishusucess/Whatsappshare/Block/Whatsappshare.php

app/code/Wishusucess/Whatsappshare/Model/Source/Size.php

app/code/Wishusucess/Whatsappshare/view/frontend/layout/catalog_product_view.xml

app/code/Wishusucess/Whatsappshare/templates/catalog/product/view/whatsappshare.phtml

app/code/Wishusucess/Whatsappshare/web/css/whatsappshare/whatsappshare.css

app/code/Wishusucess/Whatsappshare/web/images/whatsapplarge.png

app/code/Wishusucess/Whatsappshare/web/images/whatsappmedium.png

app/code/Wishusucess/Whatsappshare/web/images/whatsappsmall.png

 

WhatsApp Share Module Registration

app/code/Wishusucess/Whatsappshare/registration.php

<?php
/*
* @Author Hemant Singh
* @Developer Hemant Singh
* @Module Wishusucess_Whatsappshare
* @copyright Copyright (c) Wishusucess (http://www.wishusucess.com/)
*/
\Magento\Framework\Component\ComponentRegistrar::register(
\Magento\Framework\Component\ComponentRegistrar::MODULE,
'Wishusucess_Whatsappshare',
__DIR__
);

 

Give Basic Information Of WhatsApp Share Module

app/code/Wishusucess/Whatsappshare/etc/module.xml

<?xml version="1.0" ?>
<!--
/*
* @Author Hemant Singh
* @Developer Hemant Singh
* @Module Wishusucess_Whatsappshare
* @copyright Copyright (c) Wishusucess (http://www.wishusucess.com/)
*/
-->
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
<module name="Wishusucess_Whatsappshare" setup_version="1.0.0">
<sequence>
<module name="Magento_Catalog"/>
</sequence>
</module>
</config>

 

Create Configuration File For WhatsApp Share

app/code/Wishusucess/Whatsappshare/etc/config.xml

<?xml version="1.0"?>
<!--
/*
* @Author Hemant Singh
* @Developer Hemant Singh
* @Module Wishusucess_Whatsappshare
* @copyright Copyright (c) Wishusucess (http://www.wishusucess.com/)
*/
-->
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Store:etc/config.xsd">
<default>
<whatsappshare_tab>
<whatsappshare_setting>
<whatsappshare_active>1</whatsappshare_active>
<whatsappshare_size>2</whatsappshare_size>
<whatsappshare_text><![CDATA[Hey, Check this product I liked!]]></whatsappshare_text>
</whatsappshare_setting>
</whatsappshare_tab>
</default>
</config>

 

Create Access Controle File For Share Product on WhatsApp Module

app/code/Wishusucess/Whatsappshare/etc/acl.xml

<?xml version="1.0"?>
<!--
/*
* @Author Hemant Singh
* @Developer Hemant Singh
* @Module Wishusucess_Whatsappshare
* @copyright Copyright (c) Wishusucess (http://www.wishusucess.com/)
*/
-->
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Acl/etc/acl.xsd">
<acl>
<resources>
<resource id="Magento_Backend::admin">
<resource id="Magento_Backend::stores">
<resource id="Magento_Backend::stores_settings">
<resource id="Magento_Config::config">
<resource id="Wishusucess_Whatsappshare::whatsappshare_configuration" title="WhatsApps Enquire Setting" sortOrder="80" />
</resource>
</resource>
</resource>
</resource>
</resources>
</acl>
</config>

 

Create System XML File for WhatsApp Share

app/code/Wishusucess/Whatsappshare/etc/adminhtml/system.xml

<?xml version="1.0"?>
<!--
/*
* @Author Hemant Singh
* @Developer Hemant Singh
* @Module Wishusucess_Whatsappshare
* @copyright Copyright (c) Wishusucess (http://www.wishusucess.com/)
*/
-->

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Config:etc/system_file.xsd">
<system>
<tab id="wishusucess" translate="label" sortOrder="180">
<label>Product Enquire</label>
</tab>
<section id="whatsappshare_tab" translate="label" type="text" sortOrder="10" showInDefault="1" showInWebsite="1" showInStore="1">
<label>WhatsApp Enquire</label>
<tab>wishusucess</tab>
<resource>Wishusucess_Whatsappshare::whatsappshare_configuration</resource>
<group id="whatsappshare_setting" translate="label" type="text" sortOrder="10" showInDefault="1" showInWebsite="0"
showInStore="0">
<label>WhatsApp Enquire Setting</label>
<field id="whatsappshare_active" translate="label comment" type="select" sortOrder="10" showInDefault="1" showInWebsite="0" showInStore="0">
<label>WhatsApp Enquire Enable</label>
<source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
<validate>required-entry</validate>
<comment><![CDATA[ ]]></comment>
</field>
<field id="whatsappshare_size" translate="label comment" type="select" sortOrder="20" showInDefault="1" showInWebsite="0" showInStore="0">
<label>WhatsApp Enquire Button Size</label>
<source_model>Wishusucess\Whatsappshare\Model\Source\Size</source_model>
<validate>required-entry</validate>
<comment><![CDATA[ ]]></comment>
<depends>
<field id="*/*/whatsappshare_active">1</field>
</depends>
</field>
<field id="whatsappshare_text" translate="label comment" type="text" sortOrder="30" showInDefault="1" showInWebsite="0" showInStore="0">
<label>WhatsApp Enquire Text</label>
<validate>required-entry</validate>
<comment><![CDATA[ ]]></comment>
<depends>
<field id="*/*/whatsappshare_active">1</field>
</depends>
</field>
</group>
</section>
</system>
</config>

 

Share Product on WhatsApp Module Helper Class

app/code/Wishusucess/Whatsappshare/Helper/Data.php

<?php 
/*
* @Author Hemant Singh
* @Developer Hemant Singh
* @Module Wishusucess_ProductByCategory
* @copyright Copyright (c) Wishusucess (http://www.wishusucess.com/)
*/
namespace Wishusucess\Whatsappshare\Helper;

class Data extends \Magento\Framework\App\Helper\AbstractHelper
{

const DETECTION_TYPE_MOBILE = 'mobile';
const DETECTION_TYPE_EXTENDED = 'extended';
const VER = '([\w._\+]+)';
const MOBILE_GRADE_A = 'A';
const MOBILE_GRADE_B = 'B';
const MOBILE_GRADE_C = 'C';
const VERSION = '2.8.4';
const VERSION_TYPE_STRING = 'text';
const VERSION_TYPE_FLOAT = 'float';
protected $userAgent = null;
protected $httpHeaders = array();
protected $detectionType = self::DETECTION_TYPE_MOBILE;
protected static $mobileHeaders = array(

'HTTP_ACCEPT' => array('matches' => array(
// Opera Mini; @reference: http://dev.opera.com/articles/view/opera-binary-markup-language/
'application/x-obml2d',
// BlackBerry devices.
'application/vnd.rim.html',
'text/vnd.wap.wml',
'application/vnd.wap.xhtml+xml'
)),
'HTTP_X_WAP_PROFILE' => null,
'HTTP_X_WAP_CLIENTID' => null,
'HTTP_WAP_CONNECTION' => null,
'HTTP_PROFILE' => null,
// Reported by Opera on Nokia devices (eg. C3).
'HTTP_X_OPERAMINI_PHONE_UA' => null,
'HTTP_X_NOKIA_GATEWAY_ID' => null,
'HTTP_X_ORANGE_ID' => null,
'HTTP_X_VODAFONE_3GPDPCONTEXT' => null,
'HTTP_X_HUAWEI_USERID' => null,
// Reported by Windows Smartphones.
'HTTP_UA_OS' => null,
// Reported by Verizon, Vodafone proxy system.
'HTTP_X_MOBILE_GATEWAY' => null,
// Seend this on HTC Sensation. @ref: SensationXE_Beats_Z715e.
'HTTP_X_ATT_DEVICEID' => null,
// Seen this on a HTC.
'HTTP_UA_CPU' => array('matches' => array('ARM')),
);
protected static $phoneDevices = array(
'iPhone' => '\biPhone\b|\biPod\b', // |\biTunes
'BlackBerry' => 'BlackBerry|\bBB10\b|rim[0-9]+',
'HTC' => 'HTC|HTC.*(Sensation|Evo|Vision|Explorer|6800|8100|8900|A7272|S510e|C110e|Legend|Desire|T8282)|APX515CKT|Qtek9090|APA9292KT|HD_mini|Sensation.*Z710e|PG86100|Z715e|Desire.*(A8181|HD)|ADR6200|ADR6400L|ADR6425|001HT|Inspire 4G|Android.*\bEVO\b|T-Mobile G1|Z520m',
'Nexus' => 'Nexus One|Nexus S|Galaxy.*Nexus|Android.*Nexus.*Mobile',
// @todo: Is 'Dell Streak' a tablet or a phone? ;)
'Dell' => 'Dell.*Streak|Dell.*Aero|Dell.*Venue|DELL.*Venue Pro|Dell Flash|Dell Smoke|Dell Mini 3iX|XCD28|XCD35|\b001DL\b|\b101DL\b|\bGS01\b',
'Motorola' => 'Motorola|DROIDX|DROID BIONIC|\bDroid\b.*Build|Android.*Xoom|HRI39|MOT-|A1260|A1680|A555|A853|A855|A953|A955|A956|Motorola.*ELECTRIFY|Motorola.*i1|i867|i940|MB200|MB300|MB501|MB502|MB508|MB511|MB520|MB525|MB526|MB611|MB612|MB632|MB810|MB855|MB860|MB861|MB865|MB870|ME501|ME502|ME511|ME525|ME600|ME632|ME722|ME811|ME860|ME863|ME865|MT620|MT710|MT716|MT720|MT810|MT870|MT917|Motorola.*TITANIUM|WX435|WX445|XT300|XT301|XT311|XT316|XT317|XT319|XT320|XT390|XT502|XT530|XT531|XT532|XT535|XT603|XT610|XT611|XT615|XT681|XT701|XT702|XT711|XT720|XT800|XT806|XT860|XT862|XT875|XT882|XT883|XT894|XT901|XT907|XT909|XT910|XT912|XT928|XT926|XT915|XT919|XT925',
'Samsung' => 'Samsung|SGH-I337|BGT-S5230|GT-B2100|GT-B2700|GT-B2710|GT-B3210|GT-B3310|GT-B3410|GT-B3730|GT-B3740|GT-B5510|GT-B5512|GT-B5722|GT-B6520|GT-B7300|GT-B7320|GT-B7330|GT-B7350|GT-B7510|GT-B7722|GT-B7800|GT-C3010|GT-C3011|GT-C3060|GT-C3200|GT-C3212|GT-C3212I|GT-C3262|GT-C3222|GT-C3300|GT-C3300K|GT-C3303|GT-C3303K|GT-C3310|GT-C3322|GT-C3330|GT-C3350|GT-C3500|GT-C3510|GT-C3530|GT-C3630|GT-C3780|GT-C5010|GT-C5212|GT-C6620|GT-C6625|GT-C6712|GT-E1050|GT-E1070|GT-E1075|GT-E1080|GT-E1081|GT-E1085|GT-E1087|GT-E1100|GT-E1107|GT-E1110|GT-E1120|GT-E1125|GT-E1130|GT-E1160|GT-E1170|GT-E1175|GT-E1180|GT-E1182|GT-E1200|GT-E1210|GT-E1225|GT-E1230|GT-E1390|GT-E2100|GT-E2120|GT-E2121|GT-E2152|GT-E2220|GT-E2222|GT-E2230|GT-E2232|GT-E2250|GT-E2370|GT-E2550|GT-E2652|GT-E3210|GT-E3213|GT-I5500|GT-I5503|GT-I5700|GT-I5800|GT-I5801|GT-I6410|GT-I6420|GT-I7110|GT-I7410|GT-I7500|GT-I8000|GT-I8150|GT-I8160|GT-I8190|GT-I8320|GT-I8330|GT-I8350|GT-I8530|GT-I8700|GT-I8703|GT-I8910|GT-I9000|GT-I9001|GT-I9003|GT-I9010|GT-I9020|GT-I9023|GT-I9070|GT-I9082|GT-I9100|GT-I9103|GT-I9220|GT-I9250|GT-I9300|GT-I9305|GT-I9500|GT-I9505|GT-M3510|GT-M5650|GT-M7500|GT-M7600|GT-M7603|GT-M8800|GT-M8910|GT-N7000|GT-S3110|GT-S3310|GT-S3350|GT-S3353|GT-S3370|GT-S3650|GT-S3653|GT-S3770|GT-S3850|GT-S5210|GT-S5220|GT-S5229|GT-S5230|GT-S5233|GT-S5250|GT-S5253|GT-S5260|GT-S5263|GT-S5270|GT-S5300|GT-S5330|GT-S5350|GT-S5360|GT-S5363|GT-S5369|GT-S5380|GT-S5380D|GT-S5560|GT-S5570|GT-S5600|GT-S5603|GT-S5610|GT-S5620|GT-S5660|GT-S5670|GT-S5690|GT-S5750|GT-S5780|GT-S5830|GT-S5839|GT-S6102|GT-S6500|GT-S7070|GT-S7200|GT-S7220|GT-S7230|GT-S7233|GT-S7250|GT-S7500|GT-S7530|GT-S7550|GT-S7562|GT-S7710|GT-S8000|GT-S8003|GT-S8500|GT-S8530|GT-S8600|SCH-A310|SCH-A530|SCH-A570|SCH-A610|SCH-A630|SCH-A650|SCH-A790|SCH-A795|SCH-A850|SCH-A870|SCH-A890|SCH-A930|SCH-A950|SCH-A970|SCH-A990|SCH-I100|SCH-I110|SCH-I400|SCH-I405|SCH-I500|SCH-I510|SCH-I515|SCH-I600|SCH-I730|SCH-I760|SCH-I770|SCH-I830|SCH-I910|SCH-I920|SCH-I959|SCH-LC11|SCH-N150|SCH-N300|SCH-R100|SCH-R300|SCH-R351|SCH-R400|SCH-R410|SCH-T300|SCH-U310|SCH-U320|SCH-U350|SCH-U360|SCH-U365|SCH-U370|SCH-U380|SCH-U410|SCH-U430|SCH-U450|SCH-U460|SCH-U470|SCH-U490|SCH-U540|SCH-U550|SCH-U620|SCH-U640|SCH-U650|SCH-U660|SCH-U700|SCH-U740|SCH-U750|SCH-U810|SCH-U820|SCH-U900|SCH-U940|SCH-U960|SCS-26UC|SGH-A107|SGH-A117|SGH-A127|SGH-A137|SGH-A157|SGH-A167|SGH-A177|SGH-A187|SGH-A197|SGH-A227|SGH-A237|SGH-A257|SGH-A437|SGH-A517|SGH-A597|SGH-A637|SGH-A657|SGH-A667|SGH-A687|SGH-A697|SGH-A707|SGH-A717|SGH-A727|SGH-A737|SGH-A747|SGH-A767|SGH-A777|SGH-A797|SGH-A817|SGH-A827|SGH-A837|SGH-A847|SGH-A867|SGH-A877|SGH-A887|SGH-A897|SGH-A927|SGH-B100|SGH-B130|SGH-B200|SGH-B220|SGH-C100|SGH-C110|SGH-C120|SGH-C130|SGH-C140|SGH-C160|SGH-C170|SGH-C180|SGH-C200|SGH-C207|SGH-C210|SGH-C225|SGH-C230|SGH-C417|SGH-C450|SGH-D307|SGH-D347|SGH-D357|SGH-D407|SGH-D415|SGH-D780|SGH-D807|SGH-D980|SGH-E105|SGH-E200|SGH-E315|SGH-E316|SGH-E317|SGH-E335|SGH-E590|SGH-E635|SGH-E715|SGH-E890|SGH-F300|SGH-F480|SGH-I200|SGH-I300|SGH-I320|SGH-I550|SGH-I577|SGH-I600|SGH-I607|SGH-I617|SGH-I627|SGH-I637|SGH-I677|SGH-I700|SGH-I717|SGH-I727|SGH-i747M|SGH-I777|SGH-I780|SGH-I827|SGH-I847|SGH-I857|SGH-I896|SGH-I897|SGH-I900|SGH-I907|SGH-I917|SGH-I927|SGH-I937|SGH-I997|SGH-J150|SGH-J200|SGH-L170|SGH-L700|SGH-M110|SGH-M150|SGH-M200|SGH-N105|SGH-N500|SGH-N600|SGH-N620|SGH-N625|SGH-N700|SGH-N710|SGH-P107|SGH-P207|SGH-P300|SGH-P310|SGH-P520|SGH-P735|SGH-P777|SGH-Q105|SGH-R210|SGH-R220|SGH-R225|SGH-S105|SGH-S307|SGH-T109|SGH-T119|SGH-T139|SGH-T209|SGH-T219|SGH-T229|SGH-T239|SGH-T249|SGH-T259|SGH-T309|SGH-T319|SGH-T329|SGH-T339|SGH-T349|SGH-T359|SGH-T369|SGH-T379|SGH-T409|SGH-T429|SGH-T439|SGH-T459|SGH-T469|SGH-T479|SGH-T499|SGH-T509|SGH-T519|SGH-T539|SGH-T559|SGH-T589|SGH-T609|SGH-T619|SGH-T629|SGH-T639|SGH-T659|SGH-T669|SGH-T679|SGH-T709|SGH-T719|SGH-T729|SGH-T739|SGH-T746|SGH-T749|SGH-T759|SGH-T769|SGH-T809|SGH-T819|SGH-T839|SGH-T919|SGH-T929|SGH-T939|SGH-T959|SGH-T989|SGH-U100|SGH-U200|SGH-U800|SGH-V205|SGH-V206|SGH-X100|SGH-X105|SGH-X120|SGH-X140|SGH-X426|SGH-X427|SGH-X475|SGH-X495|SGH-X497|SGH-X507|SGH-X600|SGH-X610|SGH-X620|SGH-X630|SGH-X700|SGH-X820|SGH-X890|SGH-Z130|SGH-Z150|SGH-Z170|SGH-ZX10|SGH-ZX20|SHW-M110|SPH-A120|SPH-A400|SPH-A420|SPH-A460|SPH-A500|SPH-A560|SPH-A600|SPH-A620|SPH-A660|SPH-A700|SPH-A740|SPH-A760|SPH-A790|SPH-A800|SPH-A820|SPH-A840|SPH-A880|SPH-A900|SPH-A940|SPH-A960|SPH-D600|SPH-D700|SPH-D710|SPH-D720|SPH-I300|SPH-I325|SPH-I330|SPH-I350|SPH-I500|SPH-I600|SPH-I700|SPH-L700|SPH-M100|SPH-M220|SPH-M240|SPH-M300|SPH-M305|SPH-M320|SPH-M330|SPH-M350|SPH-M360|SPH-M370|SPH-M380|SPH-M510|SPH-M540|SPH-M550|SPH-M560|SPH-M570|SPH-M580|SPH-M610|SPH-M620|SPH-M630|SPH-M800|SPH-M810|SPH-M850|SPH-M900|SPH-M910|SPH-M920|SPH-M930|SPH-N100|SPH-N200|SPH-N240|SPH-N300|SPH-N400|SPH-Z400|SWC-E100|SCH-i909|GT-N7100|GT-N7105|SCH-I535|SM-N900A|SGH-I317|SGH-T999L|GT-S5360B|GT-I8262|GT-S6802|GT-S6312|GT-S6310|GT-S5312|GT-S5310|GT-I9105|GT-I8510|GT-S6790N|SM-G7105|SM-N9005|GT-S5301|GT-I9295|GT-I9195|SM-C101|GT-S7392|GT-S7560|GT-B7610|GT-I5510|GT-S7582|GT-S7530E|GT-I8750',
'LG' => '\bLG\b;|LG[- ]?(C800|C900|E400|E610|E900|E-900|F160|F180K|F180L|F180S|730|855|L160|LS840|LS970|LU6200|MS690|MS695|MS770|MS840|MS870|MS910|P500|P700|P705|VM696|AS680|AS695|AX840|C729|E970|GS505|272|C395|E739BK|E960|L55C|L75C|LS696|LS860|P769BK|P350|P500|P509|P870|UN272|US730|VS840|VS950|LN272|LN510|LS670|LS855|LW690|MN270|MN510|P509|P769|P930|UN200|UN270|UN510|UN610|US670|US740|US760|UX265|UX840|VN271|VN530|VS660|VS700|VS740|VS750|VS910|VS920|VS930|VX9200|VX11000|AX840A|LW770|P506|P925|P999|E612|D955|D802)',
'Sony' => 'SonyST|SonyLT|SonyEricsson|SonyEricssonLT15iv|LT18i|E10i|LT28h|LT26w|SonyEricssonMT27i|C6902|C6903|C6906|C6943',
'Asus' => 'Asus.*Galaxy|PadFone.*Mobile',
// @ref: http://www.micromaxinfo.com/mobiles/smartphones
// Added because the codes might conflict with Acer Tablets.
'Micromax' => 'Micromax.*\b(A210|A92|A88|A72|A111|A110Q|A115|A116|A110|A90S|A26|A51|A35|A54|A25|A27|A89|A68|A65|A57|A90)\b',
'Palm' => 'PalmSource|Palm', // avantgo|blazer|elaine|hiptop|plucker|xiino ; @todo - complete the regex.
'Vertu' => 'Vertu|Vertu.*Ltd|Vertu.*Ascent|Vertu.*Ayxta|Vertu.*Constellation(F|Quest)?|Vertu.*Monika|Vertu.*Signature', // Just for fun ;)
// @ref: http://www.pantech.co.kr/en/prod/prodList.do?gbrand=VEGA (PANTECH)
// Most of the VEGA devices are legacy. PANTECH seem to be newer devices based on Android.
'Pantech' => 'PANTECH|IM-A850S|IM-A840S|IM-A830L|IM-A830K|IM-A830S|IM-A820L|IM-A810K|IM-A810S|IM-A800S|IM-T100K|IM-A725L|IM-A780L|IM-A775C|IM-A770K|IM-A760S|IM-A750K|IM-A740S|IM-A730S|IM-A720L|IM-A710K|IM-A690L|IM-A690S|IM-A650S|IM-A630K|IM-A600S|VEGA PTL21|PT003|P8010|ADR910L|P6030|P6020|P9070|P4100|P9060|P5000|CDM8992|TXT8045|ADR8995|IS11PT|P2030|P6010|P8000|PT002|IS06|CDM8999|P9050|PT001|TXT8040|P2020|P9020|P2000|P7040|P7000|C790',
// @ref: http://www.fly-phone.com/devices/smartphones/ ; Included only smartphones.
'Fly' => 'IQ230|IQ444|IQ450|IQ440|IQ442|IQ441|IQ245|IQ256|IQ236|IQ255|IQ235|IQ245|IQ275|IQ240|IQ285|IQ280|IQ270|IQ260|IQ250',
'iMobile' => 'i-mobile (IQ|i-STYLE|idea|ZAA|Hitz)',
// Added simvalley mobile just for fun. They have some interesting devices.
// @ref: http://www.simvalley.fr/telephonie---gps-_22_telephonie-mobile_telephones_.html
'SimValley' => '\b(SP-80|XT-930|SX-340|XT-930|SX-310|SP-360|SP60|SPT-800|SP-120|SPT-800|SP-140|SPX-5|SPX-8|SP-100|SPX-8|SPX-12)\b',
// Wolfgang - a brand that is sold by Aldi supermarkets
// http://www.wolfgangmobile.com/
'Wolfgang' => 'AT-B24D|AT-AS50HD|AT-AS40W|AT-AS55HD|AT-AS45q2|AT-B26D|AT-AS50Q',
'Alcatel' => 'Alcatel',
// @ref: http://en.wikipedia.org/wiki/Amoi
'Amoi' => 'Amoi',
// @ref: http://en.wikipedia.org/wiki/INQ
'INQ' => 'INQ',
// @Tapatalk is a mobile app; @ref: http://support.tapatalk.com/threads/smf-2-0-2-os-and-browser-detection-plugin-and-tapatalk.15565/#post-79039
'GenericPhone' => 'Tapatalk|PDA;|SAGEM|\bmmp\b|pocket|\bpsp\b|symbian|Smartphone|smartfon|treo|up.browser|up.link|vodafone|\bwap\b|nokia|Series40|Series60|S60|SonyEricsson|N900|MAUI.*WAP.*Browser',
);

/**
* List of tablet devices.
*
* @var array
*/
protected static $tabletDevices = array(
'iPad' => 'iPad|iPad.*Mobile', // @todo: check for mobile friendly emails topic.
'NexusTablet' => 'Android.*Nexus[\s]+(7|10)|^.*Android.*Nexus(?:(?!Mobile).)*$',
'SamsungTablet' => 'SAMSUNG.*Tablet|Galaxy.*Tab|SC-01C|GT-P1000|GT-P1003|GT-P1010|GT-P3105|GT-P6210|GT-P6800|GT-P6810|GT-P7100|GT-P7300|GT-P7310|GT-P7500|GT-P7510|SCH-I800|SCH-I815|SCH-I905|SGH-I957|SGH-I987|SGH-T849|SGH-T859|SGH-T869|SPH-P100|GT-P3100|GT-P3108|GT-P3110|GT-P5100|GT-P5110|GT-P6200|GT-P7320|GT-P7511|GT-N8000|GT-P8510|SGH-I497|SPH-P500|SGH-T779|SCH-I705|SCH-I915|GT-N8013|GT-P3113|GT-P5113|GT-P8110|GT-N8010|GT-N8005|GT-N8020|GT-P1013|GT-P6201|GT-P7501|GT-N5100|GT-N5105|GT-N5110|SHV-E140K|SHV-E140L|SHV-E140S|SHV-E150S|SHV-E230K|SHV-E230L|SHV-E230S|SHW-M180K|SHW-M180L|SHW-M180S|SHW-M180W|SHW-M300W|SHW-M305W|SHW-M380K|SHW-M380S|SHW-M380W|SHW-M430W|SHW-M480K|SHW-M480S|SHW-M480W|SHW-M485W|SHW-M486W|SHW-M500W|GT-I9228|SCH-P739|SCH-I925|GT-I9200|GT-I9205|GT-P5200|GT-P5210|GT-P5210X|SM-T311|SM-T310|SM-T310X|SM-T210|SM-T210R|SM-T211|SM-P600|SM-P601|SM-P605|SM-P900|SM-P901|SM-T217|SM-T217A|SM-T217S|SM-P6000|SM-T3100|SGH-I467|XE500|SM-T110|GT-P5220|GT-I9200X|GT-N5110X|GT-N5120|SM-P905|SM-T111|SM-T2105|SM-T315|SM-T320|SM-T320X|SM-T321|SM-T520|SM-T525|SM-T530NU|SM-T230NU|SM-T330NU|SM-T900|XE500T1C|SM-P605V|SM-P905V|SM-P600X|SM-P900X|SM-T210X|SM-T230|SM-T230X|SM-T325|GT-P7503|SM-T531|SM-T330|SM-T530|SM-T705C|SM-T535|SM-T331|SM-T800|SM-T700', // SCH-P709|SCH-P729|SM-T2558 - Samsung Mega - treat them like a regular phone.
// @reference: http://www.labnol.org/software/kindle-user-agent-string/20378/
'Kindle' => 'Kindle|Silk.*Accelerated|Android.*\b(KFOT|KFTT|KFJWI|KFJWA|KFOTE|KFSOWI|KFTHWI|KFTHWA|KFAPWI|KFAPWA|WFJWAE)\b',
// Only the Surface tablets with Windows RT are considered mobile.
// @ref: http://msdn.microsoft.com/en-us/library/ie/hh920767(v=vs.85).aspx
'SurfaceTablet' => 'Windows NT [0-9.]+; ARM;.*(Tablet|ARMBJS)',
// @ref: http://shopping1.hp.com/is-bin/INTERSHOP.enfinity/WFS/WW-USSMBPublicStore-Site/en_US/-/USD/ViewStandardCatalog-Browse?CatalogCategoryID=JfIQ7EN5lqMAAAEyDcJUDwMT
'HPTablet' => 'HP Slate (7|8|10)|HP ElitePad 900|hp-tablet|EliteBook.*Touch|HP 8|Slate 21|HP SlateBook 10',
// @note: watch out for PadFone, see #132
// http://www.asus.com/de/Tablets_Mobile/Memo_Pad_Products/
'AsusTablet' => '^.*PadFone((?!Mobile).)*$|Transformer|TF101|TF101G|TF300T|TF300TG|TF300TL|TF700T|TF700KL|TF701T|TF810C|ME171|ME301T|ME302C|ME371MG|ME370T|ME372MG|ME172V|ME173X|ME400C|Slider SL101|\bK00F\b|\bK00C\b|\bK00E\b|\bK00L\b|TX201LA|ME176C|ME102A|\bM80TA\b|ME372CL|ME560CG|ME372CG',
'BlackBerryTablet' => 'PlayBook|RIM Tablet',
'HTCtablet' => 'HTC Flyer|HTC Jetstream|HTC-P715a|HTC EVO View 4G|PG41200|PG09410',
'MotorolaTablet' => 'xoom|sholest|MZ615|MZ605|MZ505|MZ601|MZ602|MZ603|MZ604|MZ606|MZ607|MZ608|MZ609|MZ615|MZ616|MZ617',
'NookTablet' => 'Android.*Nook|NookColor|nook browser|BNRV200|BNRV200A|BNTV250|BNTV250A|BNTV400|BNTV600|LogicPD Zoom2',
// @ref: http://www.acer.ro/ac/ro/RO/content/drivers
// @ref: http://www.packardbell.co.uk/pb/en/GB/content/download (Packard Bell is part of Acer)
// @ref: http://us.acer.com/ac/en/US/content/group/tablets
// @note: Can conflict with Micromax and Motorola phones codes.
'AcerTablet' => 'Android.*; \b(A100|A101|A110|A200|A210|A211|A500|A501|A510|A511|A700|A701|W500|W500P|W501|W501P|W510|W511|W700|G100|G100W|B1-A71|B1-710|B1-711|A1-810|A1-811|A1-830)\b|W3-810|\bA3-A10\b',
// @ref: http://eu.computers.toshiba-europe.com/innovation/family/Tablets/1098744/banner_id/tablet_footerlink/
// @ref: http://us.toshiba.com/tablets/tablet-finder
// @ref: http://www.toshiba.co.jp/regza/tablet/
'ToshibaTablet' => 'Android.*(AT100|AT105|AT200|AT205|AT270|AT275|AT300|AT305|AT1S5|AT500|AT570|AT700|AT830)|TOSHIBA.*FOLIO',
// @ref: http://www.nttdocomo.co.jp/english/service/developer/smart_phone/technical_info/spec/index.html
// @ref: http://www.lg.com/us/tablets
'LGTablet' => '\bL-06C|LG-V900|LG-V500|LG-V909|LG-V500|LG-V510|LG-VK810\b',
'FujitsuTablet' => 'Android.*\b(F-01D|F-02F|F-05E|F-10D|M532|Q572)\b',
// Prestigio Tablets http://www.prestigio.com/support
'PrestigioTablet' => 'PMP3170B|PMP3270B|PMP3470B|PMP7170B|PMP3370B|PMP3570C|PMP5870C|PMP3670B|PMP5570C|PMP5770D|PMP3970B|PMP3870C|PMP5580C|PMP5880D|PMP5780D|PMP5588C|PMP7280C|PMP7280C3G|PMP7280|PMP7880D|PMP5597D|PMP5597|PMP7100D|PER3464|PER3274|PER3574|PER3884|PER5274|PER5474|PMP5097CPRO|PMP5097|PMP7380D|PMP5297C|PMP5297C_QUAD',
// @ref: http://support.lenovo.com/en_GB/downloads/default.page?#
'LenovoTablet' => 'Idea(Tab|Pad)( A1|A10| K1|)|ThinkPad([ ]+)?Tablet|Lenovo.*(S2109|S2110|S5000|S6000|K3011|A3000|A3500|A1000|A2107|A2109|A1107|A5500|A7600|B6000|B8000|B8080)(-|)(FL|F|HV|H|)',
// @ref: http://www.yarvik.com/en/matrix/tablets/
'YarvikTablet' => 'Android.*\b(TAB210|TAB211|TAB224|TAB250|TAB260|TAB264|TAB310|TAB360|TAB364|TAB410|TAB411|TAB420|TAB424|TAB450|TAB460|TAB461|TAB464|TAB465|TAB467|TAB468|TAB07-100|TAB07-101|TAB07-150|TAB07-151|TAB07-152|TAB07-200|TAB07-201-3G|TAB07-210|TAB07-211|TAB07-212|TAB07-214|TAB07-220|TAB07-400|TAB07-485|TAB08-150|TAB08-200|TAB08-201-3G|TAB08-201-30|TAB09-100|TAB09-211|TAB09-410|TAB10-150|TAB10-201|TAB10-211|TAB10-400|TAB10-410|TAB13-201|TAB274EUK|TAB275EUK|TAB374EUK|TAB462EUK|TAB474EUK|TAB9-200)\b',
'MedionTablet' => 'Android.*\bOYO\b|LIFE.*(P9212|P9514|P9516|S9512)|LIFETAB',
'ArnovaTablet' => 'AN10G2|AN7bG3|AN7fG3|AN8G3|AN8cG3|AN7G3|AN9G3|AN7dG3|AN7dG3ST|AN7dG3ChildPad|AN10bG3|AN10bG3DT',
// http://www.intenso.de/kategorie_en.php?kategorie=33
// @todo: http://www.nbhkdz.com/read/b8e64202f92a2df129126bff.html - investigate
'IntensoTablet' => 'INM8002KP|INM1010FP|INM805ND|Intenso Tab|TAB1004',
// IRU.ru Tablets http://www.iru.ru/catalog/soho/planetable/
'IRUTablet' => 'M702pro',
'MegafonTablet' => 'MegaFon V9|\bZTE V9\b|Android.*\bMT7A\b',
// @ref: http://www.e-boda.ro/tablete-pc.html
'EbodaTablet' => 'E-Boda (Supreme|Impresspeed|Izzycomm|Essential)',
// @ref: http://www.allview.ro/produse/droseries/lista-tablete-pc/
'AllViewTablet' => 'Allview.*(Viva|Alldro|City|Speed|All TV|Frenzy|Quasar|Shine|TX1|AX1|AX2)',
// @reference: http://wiki.archosfans.com/index.php?title=Main_Page
'ArchosTablet' => '\b(101G9|80G9|A101IT)\b|Qilive 97R|Archos5|\bARCHOS (70|79|80|90|97|101|FAMILYPAD|)(b|)(G10| Cobalt| TITANIUM(HD|)| Xenon| Neon|XSK| 2| XS 2| PLATINUM| CARBON|GAMEPAD)\b',
// @ref: http://www.ainol.com/plugin.php?identifier=ainol&module=product
'AinolTablet' => 'NOVO7|NOVO8|NOVO10|Novo7Aurora|Novo7Basic|NOVO7PALADIN|novo9-Spark',
// @todo: inspect http://esupport.sony.com/US/p/select-system.pl?DIRECTOR=DRIVER
// @ref: Readers http://www.atsuhiro-me.net/ebook/sony-reader/sony-reader-web-browser
// @ref: http://www.sony.jp/support/tablet/
'SonyTablet' => 'Sony.*Tablet|Xperia Tablet|Sony Tablet S|SO-03E|SGPT12|SGPT13|SGPT114|SGPT121|SGPT122|SGPT123|SGPT111|SGPT112|SGPT113|SGPT131|SGPT132|SGPT133|SGPT211|SGPT212|SGPT213|SGP311|SGP312|SGP321|EBRD1101|EBRD1102|EBRD1201|SGP351|SGP341|SGP511|SGP512|SGP521|SGP541|SGP551',
// http://www.support.philips.com/support/catalog/worldproducts.jsp?userLanguage=en&userCountry=cn&categoryid=3G_LTE_TABLET_SU_CN_CARE&title=3G%20tablets%20/%20LTE%20range&_dyncharset=UTF-8
'PhilipsTablet' => '\b(PI2010|PI3000|PI3100|PI3105|PI3110|PI3205|PI3210|PI3900|PI4010|PI7000|PI7100)\b',
// @ref: db + http://www.cube-tablet.com/buy-products.html
'CubeTablet' => 'Android.*(K8GT|U9GT|U10GT|U16GT|U17GT|U18GT|U19GT|U20GT|U23GT|U30GT)|CUBE U8GT',
// @ref: http://www.cobyusa.com/?p=pcat&pcat_id=3001
'CobyTablet' => 'MID1042|MID1045|MID1125|MID1126|MID7012|MID7014|MID7015|MID7034|MID7035|MID7036|MID7042|MID7048|MID7127|MID8042|MID8048|MID8127|MID9042|MID9740|MID9742|MID7022|MID7010',
// @ref: http://www.match.net.cn/products.asp
'MIDTablet' => 'M9701|M9000|M9100|M806|M1052|M806|T703|MID701|MID713|MID710|MID727|MID760|MID830|MID728|MID933|MID125|MID810|MID732|MID120|MID930|MID800|MID731|MID900|MID100|MID820|MID735|MID980|MID130|MID833|MID737|MID960|MID135|MID860|MID736|MID140|MID930|MID835|MID733',
// http://www.msi.com/support
// @todo Research the Windows Tablets.
'MSITablet' => 'MSI \b(Primo 73K|Primo 73L|Primo 81L|Primo 77|Primo 93|Primo 75|Primo 76|Primo 73|Primo 81|Primo 91|Primo 90|Enjoy 71|Enjoy 7|Enjoy 10)\b',
// @ref: http://pdadb.net/index.php?m=pdalist&list=SMiT (NoName Chinese Tablets)
// @ref: http://www.imp3.net/14/show.php?itemid=20454
'SMiTTablet' => 'Android.*(\bMID\b|MID-560|MTV-T1200|MTV-PND531|MTV-P1101|MTV-PND530)',
// @ref: http://www.rock-chips.com/index.php?do=prod&pid=2
'RockChipTablet' => 'Android.*(RK2818|RK2808A|RK2918|RK3066)|RK2738|RK2808A',
// @ref: http://www.fly-phone.com/devices/tablets/ ; http://www.fly-phone.com/service/
'FlyTablet' => 'IQ310|Fly Vision',
// @ref: http://www.bqreaders.com/gb/tablets-prices-sale.html
'bqTablet' => 'bq.*(Elcano|Curie|Edison|Maxwell|Kepler|Pascal|Tesla|Hypatia|Platon|Newton|Livingstone|Cervantes|Avant)|Maxwell.*Lite|Maxwell.*Plus',
// @ref: http://www.huaweidevice.com/worldwide/productFamily.do?method=index&directoryId=5011&treeId=3290
// @ref: http://www.huaweidevice.com/worldwide/downloadCenter.do?method=index&directoryId=3372&treeId=0&tb=1&type=software (including legacy tablets)
'HuaweiTablet' => 'MediaPad|MediaPad 7 Youth|IDEOS S7|S7-201c|S7-202u|S7-101|S7-103|S7-104|S7-105|S7-106|S7-201|S7-Slim',
// Nec or Medias Tab
'NecTablet' => '\bN-06D|\bN-08D',
// Pantech Tablets: http://www.pantechusa.com/phones/
'PantechTablet' => 'Pantech.*P4100',
// Broncho Tablets: http://www.broncho.cn/ (hard to find)
'BronchoTablet' => 'Broncho.*(N701|N708|N802|a710)',
// @ref: http://versusuk.com/support.html
'VersusTablet' => 'TOUCHPAD.*[78910]|\bTOUCHTAB\b',
// @ref: http://www.zync.in/index.php/our-products/tablet-phablets
'ZyncTablet' => 'z1000|Z99 2G|z99|z930|z999|z990|z909|Z919|z900',
// @ref: http://www.positivoinformatica.com.br/www/pessoal/tablet-ypy/
'PositivoTablet' => 'TB07STA|TB10STA|TB07FTA|TB10FTA',
// @ref: https://www.nabitablet.com/
'NabiTablet' => 'Android.*\bNabi',
'KoboTablet' => 'Kobo Touch|\bK080\b|\bVox\b Build|\bArc\b Build',
// French Danew Tablets http://www.danew.com/produits-tablette.php
'DanewTablet' => 'DSlide.*\b(700|701R|702|703R|704|802|970|971|972|973|974|1010|1012)\b',
// Texet Tablets and Readers http://www.texet.ru/tablet/
'TexetTablet' => 'NaviPad|TB-772A|TM-7045|TM-7055|TM-9750|TM-7016|TM-7024|TM-7026|TM-7041|TM-7043|TM-7047|TM-8041|TM-9741|TM-9747|TM-9748|TM-9751|TM-7022|TM-7021|TM-7020|TM-7011|TM-7010|TM-7023|TM-7025|TM-7037W|TM-7038W|TM-7027W|TM-9720|TM-9725|TM-9737W|TM-1020|TM-9738W|TM-9740|TM-9743W|TB-807A|TB-771A|TB-727A|TB-725A|TB-719A|TB-823A|TB-805A|TB-723A|TB-715A|TB-707A|TB-705A|TB-709A|TB-711A|TB-890HD|TB-880HD|TB-790HD|TB-780HD|TB-770HD|TB-721HD|TB-710HD|TB-434HD|TB-860HD|TB-840HD|TB-760HD|TB-750HD|TB-740HD|TB-730HD|TB-722HD|TB-720HD|TB-700HD|TB-500HD|TB-470HD|TB-431HD|TB-430HD|TB-506|TB-504|TB-446|TB-436|TB-416|TB-146SE|TB-126SE',
// @note: Avoid detecting 'PLAYSTATION 3' as mobile.
'PlaystationTablet' => 'Playstation.*(Portable|Vita)',
// @ref: http://www.trekstor.de/surftabs.html
'TrekstorTablet' => 'ST10416-1|VT10416-1|ST70408-1|ST702xx-1|ST702xx-2|ST80208|ST97216|ST70104-2|VT10416-2|ST10216-2A|SurfTab',
// @ref: http://www.pyleaudio.com/Products.aspx?%2fproducts%2fPersonal-Electronics%2fTablets
'PyleAudioTablet' => '\b(PTBL10CEU|PTBL10C|PTBL72BC|PTBL72BCEU|PTBL7CEU|PTBL7C|PTBL92BC|PTBL92BCEU|PTBL9CEU|PTBL9CUK|PTBL9C)\b',
// @ref: http://www.advandigital.com/index.php?link=content-product&jns=JP001
// @Note: because of the short codenames we have to include whitespaces to reduce the possible conflicts.
'AdvanTablet' => 'Android.* \b(E3A|T3X|T5C|T5B|T3E|T3C|T3B|T1J|T1F|T2A|T1H|T1i|E1C|T1-E|T5-A|T4|E1-B|T2Ci|T1-B|T1-D|O1-A|E1-A|T1-A|T3A|T4i)\b ',
// @ref: http://www.danytech.com/category/tablet-pc
'DanyTechTablet' => 'Genius Tab G3|Genius Tab S2|Genius Tab Q3|Genius Tab G4|Genius Tab Q4|Genius Tab G-II|Genius TAB GII|Genius TAB GIII|Genius Tab S1',
// @ref: http://www.galapad.net/product.html
'GalapadTablet' => 'Android.*\bG1\b',
// @ref: http://www.micromaxinfo.com/tablet/funbook
'MicromaxTablet' => 'Funbook|Micromax.*\b(P250|P560|P360|P362|P600|P300|P350|P500|P275)\b',
// http://www.karbonnmobiles.com/products_tablet.php
'KarbonnTablet' => 'Android.*\b(A39|A37|A34|ST8|ST10|ST7|Smart Tab3|Smart Tab2)\b',
// @ref: http://www.myallfine.com/Products.asp
'AllFineTablet' => 'Fine7 Genius|Fine7 Shine|Fine7 Air|Fine8 Style|Fine9 More|Fine10 Joy|Fine11 Wide',
// @ref: http://www.proscanvideo.com/products-search.asp?itemClass=TABLET&itemnmbr=
'PROSCANTablet' => '\b(PEM63|PLT1023G|PLT1041|PLT1044|PLT1044G|PLT1091|PLT4311|PLT4311PL|PLT4315|PLT7030|PLT7033|PLT7033D|PLT7035|PLT7035D|PLT7044K|PLT7045K|PLT7045KB|PLT7071KG|PLT7072|PLT7223G|PLT7225G|PLT7777G|PLT7810K|PLT7849G|PLT7851G|PLT7852G|PLT8015|PLT8031|PLT8034|PLT8036|PLT8080K|PLT8082|PLT8088|PLT8223G|PLT8234G|PLT8235G|PLT8816K|PLT9011|PLT9045K|PLT9233G|PLT9735|PLT9760G|PLT9770G)\b',
// @ref: http://www.yonesnav.com/products/products.php
'YONESTablet' => 'BQ1078|BC1003|BC1077|RK9702|BC9730|BC9001|IT9001|BC7008|BC7010|BC708|BC728|BC7012|BC7030|BC7027|BC7026',
// @ref: http://www.cjshowroom.com/eproducts.aspx?classcode=004001001
// China manufacturer makes tablets for different small brands (eg. http://www.zeepad.net/index.html)
'ChangJiaTablet' => 'TPC7102|TPC7103|TPC7105|TPC7106|TPC7107|TPC7201|TPC7203|TPC7205|TPC7210|TPC7708|TPC7709|TPC7712|TPC7110|TPC8101|TPC8103|TPC8105|TPC8106|TPC8203|TPC8205|TPC8503|TPC9106|TPC9701|TPC97101|TPC97103|TPC97105|TPC97106|TPC97111|TPC97113|TPC97203|TPC97603|TPC97809|TPC97205|TPC10101|TPC10103|TPC10106|TPC10111|TPC10203|TPC10205|TPC10503',
// @ref: http://www.gloryunion.cn/products.asp
// @ref: http://www.allwinnertech.com/en/apply/mobile.html
// @ref: http://www.ptcl.com.pk/pd_content.php?pd_id=284 (EVOTAB)
// @todo: Softwiner tablets?
// aka. Cute or Cool tablets. Not sure yet, must research to avoid collisions.
'GUTablet' => 'TX-A1301|TX-M9002|Q702|kf026', // A12R|D75A|D77|D79|R83|A95|A106C|R15|A75|A76|D71|D72|R71|R73|R77|D82|R85|D92|A97|D92|R91|A10F|A77F|W71F|A78F|W78F|W81F|A97F|W91F|W97F|R16G|C72|C73E|K72|K73|R96G
// @ref: http://www.pointofview-online.com/showroom.php?shop_mode=product_listing&category_id=118
'PointOfViewTablet' => 'TAB-P506|TAB-navi-7-3G-M|TAB-P517|TAB-P-527|TAB-P701|TAB-P703|TAB-P721|TAB-P731N|TAB-P741|TAB-P825|TAB-P905|TAB-P925|TAB-PR945|TAB-PL1015|TAB-P1025|TAB-PI1045|TAB-P1325|TAB-PROTAB[0-9]+|TAB-PROTAB25|TAB-PROTAB26|TAB-PROTAB27|TAB-PROTAB26XL|TAB-PROTAB2-IPS9|TAB-PROTAB30-IPS9|TAB-PROTAB25XXL|TAB-PROTAB26-IPS10|TAB-PROTAB30-IPS10',
// @ref: http://www.overmax.pl/pl/katalog-produktow,p8/tablety,c14/
// @todo: add more tests.
'OvermaxTablet' => 'OV-(SteelCore|NewBase|Basecore|Baseone|Exellen|Quattor|EduTab|Solution|ACTION|BasicTab|TeddyTab|MagicTab|Stream|TB-08|TB-09)',
// @ref: http://hclmetablet.com/India/index.php
'HCLTablet' => 'HCL.*Tablet|Connect-3G-2.0|Connect-2G-2.0|ME Tablet U1|ME Tablet U2|ME Tablet G1|ME Tablet X1|ME Tablet Y2|ME Tablet Sync',
// @ref: http://www.edigital.hu/Tablet_es_e-book_olvaso/Tablet-c18385.html
'DPSTablet' => 'DPS Dream 9|DPS Dual 7',
// @ref: http://www.visture.com/index.asp
'VistureTablet' => 'V97 HD|i75 3G|Visture V4( HD)?|Visture V5( HD)?|Visture V10',
// @ref: http://www.mijncresta.nl/tablet
'CrestaTablet' => 'CTP(-)?810|CTP(-)?818|CTP(-)?828|CTP(-)?838|CTP(-)?888|CTP(-)?978|CTP(-)?980|CTP(-)?987|CTP(-)?988|CTP(-)?989',
// MediaTek - http://www.mediatek.com/_en/01_products/02_proSys.php?cata_sn=1&cata1_sn=1&cata2_sn=309
'MediatekTablet' => '\bMT8125|MT8389|MT8135|MT8377\b',
// Concorde tab
'ConcordeTablet' => 'Concorde([ ]+)?Tab|ConCorde ReadMan',
// GoClever Tablets - http://www.goclever.com/uk/products,c1/tablet,c5/
'GoCleverTablet' => 'GOCLEVER TAB|A7GOCLEVER|M1042|M7841|M742|R1042BK|R1041|TAB A975|TAB A7842|TAB A741|TAB A741L|TAB M723G|TAB M721|TAB A1021|TAB I921|TAB R721|TAB I720|TAB T76|TAB R70|TAB R76.2|TAB R106|TAB R83.2|TAB M813G|TAB I721|GCTA722|TAB I70|TAB I71|TAB S73|TAB R73|TAB R74|TAB R93|TAB R75|TAB R76.1|TAB A73|TAB A93|TAB A93.2|TAB T72|TAB R83|TAB R974|TAB R973|TAB A101|TAB A103|TAB A104|TAB A104.2|R105BK|M713G|A972BK|TAB A971|TAB R974.2|TAB R104|TAB R83.3|TAB A1042',
// Modecom Tablets - http://www.modecom.eu/tablets/portal/
'ModecomTablet' => 'FreeTAB 9000|FreeTAB 7.4|FreeTAB 7004|FreeTAB 7800|FreeTAB 2096|FreeTAB 7.5|FreeTAB 1014|FreeTAB 1001 |FreeTAB 8001|FreeTAB 9706|FreeTAB 9702|FreeTAB 7003|FreeTAB 7002|FreeTAB 1002|FreeTAB 7801|FreeTAB 1331|FreeTAB 1004|FreeTAB 8002|FreeTAB 8014|FreeTAB 9704|FreeTAB 1003',
// Vonino Tablets - http://www.vonino.eu/tablets
'VoninoTablet' => '\b(Argus[ _]?S|Diamond[ _]?79HD|Emerald[ _]?78E|Luna[ _]?70C|Onyx[ _]?S|Onyx[ _]?Z|Orin[ _]?HD|Orin[ _]?S|Otis[ _]?S|SpeedStar[ _]?S|Magnet[ _]?M9|Primus[ _]?94[ _]?3G|Primus[ _]?94HD|Primus[ _]?QS|Android.*\bQ8\b|Sirius[ _]?EVO[ _]?QS|Sirius[ _]?QS|Spirit[ _]?S)\b',
// ECS Tablets - http://www.ecs.com.tw/ECSWebSite/Product/Product_Tablet_List.aspx?CategoryID=14&MenuID=107&childid=M_107&LanID=0
'ECSTablet' => 'V07OT2|TM105A|S10OT1|TR10CS1',
// Storex Tablets - http://storex.fr/espace_client/support.html
// @note: no need to add all the tablet codes since they are guided by the first regex.
'StorexTablet' => 'eZee[_\']?(Tab|Go)[0-9]+|TabLC7|Looney Tunes Tab',
// Generic Vodafone tablets.
'VodafoneTablet' => 'SmartTab([ ]+)?[0-9]+|SmartTabII10|SmartTabII7',
// French tablets - Essentiel B http://www.boulanger.fr/tablette_tactile_e-book/tablette_tactile_essentiel_b/cl_68908.htm?multiChoiceToDelete=brand&mc_brand=essentielb
// Aka: http://www.essentielb.fr/
'EssentielBTablet' => 'Smart[ \']?TAB[ ]+?[0-9]+|Family[ \']?TAB2',
// Ross & Moor - http://ross-moor.ru/
'RossMoorTablet' => 'RM-790|RM-997|RMD-878G|RMD-974R|RMT-705A|RMT-701|RME-601|RMT-501|RMT-711',
// i-mobile http://product.i-mobilephone.com/Mobile_Device
'iMobileTablet' => 'i-mobile i-note',
// @ref: http://www.tolino.de/de/vergleichen/
'TolinoTablet' => 'tolino tab [0-9.]+|tolino shine',
// AudioSonic - a Kmart brand
// http://www.kmart.com.au/webapp/wcs/stores/servlet/Search?langId=-1&storeId=10701&catalogId=10001&categoryId=193001&pageSize=72&currentPage=1&searchCategory=193001%2b4294965664&sortBy=p_MaxPrice%7c1
'AudioSonicTablet' => '\bC-22Q|T7-QC|T-17B|T-17P\b',
// AMPE Tablets - http://www.ampe.com.my/product-category/tablets/
// @todo: add them gradually to avoid conflicts.
'AMPETablet' => 'Android.* A78 ',
// Skk Mobile - http://skkmobile.com.ph/product_tablets.php
'SkkTablet' => 'Android.* (SKYPAD|PHOENIX|CYCLOPS)',
// Tecno Mobile (only tablet) - http://www.tecno-mobile.com/index.php/product?filterby=smart&list_order=all&page=1
'TecnoTablet' => 'TECNO P9',
// JXD (consoles & tablets) - http://jxd.hk/products.asp?selectclassid=009008&clsid=3
'JXDTablet' => 'Android.*\b(F3000|A3300|JXD5000|JXD3000|JXD2000|JXD300B|JXD300|S5800|S7800|S602b|S5110b|S7300|S5300|S602|S603|S5100|S5110|S601|S7100a|P3000F|P3000s|P101|P200s|P1000m|P200m|P9100|P1000s|S6600b|S908|P1000|P300|S18|S6600|S9100)\b',
// i-Joy tablets - http://www.i-joy.es/en/cat/products/tablets/
'iJoyTablet' => 'Tablet (Spirit 7|Essentia|Galatea|Fusion|Onix 7|Landa|Titan|Scooby|Deox|Stella|Themis|Argon|Unique 7|Sygnus|Hexen|Finity 7|Cream|Cream X2|Jade|Neon 7|Neron 7|Kandy|Scape|Saphyr 7|Rebel|Biox|Rebel|Rebel 8GB|Myst|Draco 7|Myst|Tab7-004|Myst|Tadeo Jones|Tablet Boing|Arrow|Draco Dual Cam|Aurix|Mint|Amity|Revolution|Finity 9|Neon 9|T9w|Amity 4GB Dual Cam|Stone 4GB|Stone 8GB|Andromeda|Silken|X2|Andromeda II|Halley|Flame|Saphyr 9,7|Touch 8|Planet|Triton|Unique 10|Hexen 10|Memphis 4GB|Memphis 8GB|Onix 10)',
// http://www.intracon.eu/tablet
'FX2Tablet' => 'FX2 PAD7|FX2 PAD10',
// http://www.xoro.de/produkte/
// @note: Might be the same brand with 'Simply tablets'
'XoroTablet' => 'KidsPAD 701|PAD[ ]?712|PAD[ ]?714|PAD[ ]?716|PAD[ ]?717|PAD[ ]?718|PAD[ ]?720|PAD[ ]?721|PAD[ ]?722|PAD[ ]?790|PAD[ ]?792|PAD[ ]?900|PAD[ ]?9715D|PAD[ ]?9716DR|PAD[ ]?9718DR|PAD[ ]?9719QR|PAD[ ]?9720QR|TelePAD1030|Telepad1032|TelePAD730|TelePAD731|TelePAD732|TelePAD735Q|TelePAD830|TelePAD9730|TelePAD795|MegaPAD 1331|MegaPAD 1851|MegaPAD 2151',
// http://www1.viewsonic.com/products/computing/tablets/
'ViewsonicTablet' => 'ViewPad 10pi|ViewPad 10e|ViewPad 10s|ViewPad E72|ViewPad7|ViewPad E100|ViewPad 7e|ViewSonic VB733|VB100a',
// http://www.odys.de/web/internet-tablet_en.html
'OdysTablet' => 'LOOX|XENO10|ODYS[ -](Space|EVO|Xpress|NOON)|\bXELIO\b|Xelio10Pro|XELIO7PHONETAB|XELIO10EXTREME|XELIOPT2|NEO_QUAD10',
// http://www.captiva-power.de/products.html#tablets-en
'CaptivaTablet' => 'CAPTIVA PAD',
// IconBIT - http://www.iconbit.com/products/tablets/
'IconbitTablet' => 'NetTAB|NT-3702|NT-3702S|NT-3702S|NT-3603P|NT-3603P|NT-0704S|NT-0704S|NT-3805C|NT-3805C|NT-0806C|NT-0806C|NT-0909T|NT-0909T|NT-0907S|NT-0907S|NT-0902S|NT-0902S',
// @ref: http://www.teclast.com/topic.php?channelID=70&topicID=140&pid=63
'TeclastTablet' => '\(Linux;\sAndroid\s[\d\.]+;\s[PXGAT]\d{2,}.*\sBuild/.*?\)',
'JaytechTablet' => 'TPC-PA762',
'BlaupunktTablet' => 'Endeavour 800NG|Endeavour 1010',
// @ref: http://www.digma.ru/support/download/
// @todo: Ebooks also (if requested)
'DigmaTablet' => '\b(iDx10|iDx9|iDx8|iDx7|iDxD7|iDxD8|iDsQ8|iDsQ7|iDsQ8|iDsD10|iDnD7|3TS804H|iDsQ11|iDj7|iDs10)\b',
// http://www.evolioshop.com/ro/tablete-pc.html
// http://www.evolio.ro/support/downloads_static.html?cat=2
// @todo: Research some more
'EvolioTablet' => 'ARIA_Mini_wifi|Aria[ _]Mini|Evolio X10|Evolio X7|Evolio X8|\bEvotab\b|\bNeura\b',
// http://www.pocketbook-int.com/ru/support
'PocketBookTablet' => 'Pocketbook',
// @ref: http://www.tesco.com/direct/hudl/
'Hudl' => 'Hudl HT7S3',
// @ref: http://www.telstra.com.au/home-phone/thub-2/
'TelstraTablet' => 'T-Hub2',
'GenericTablet' => 'Android.*\b97D\b|Tablet(?!.*PC)|BNTV250A|MID-WCDMA|LogicPD Zoom2|\bA7EB\b|CatNova8|A1_07|CT704|CT1002|\bM721\b|rk30sdk|\bEVOTAB\b|M758A|ET904|ALUMIUM10|Smartfren Tab|Endeavour 1010|Tablet-PC-4|Tagi Tab|\bM6pro\b|CT1020W'
);

/**
* List of mobile Operating Systems.
*
* @var array
*/
protected static $operatingSystems = array(
'AndroidOS' => 'Android',
'BlackBerryOS' => 'blackberry|\bBB10\b|rim tablet os',
'PalmOS' => 'PalmOS|avantgo|blazer|elaine|hiptop|palm|plucker|xiino',
'SymbianOS' => 'Symbian|SymbOS|Series60|Series40|SYB-[0-9]+|\bS60\b',
// @reference: http://en.wikipedia.org/wiki/Windows_Mobile
'WindowsMobileOS' => 'Windows CE.*(PPC|Smartphone|Mobile|[0-9]{3}x[0-9]{3})|Window Mobile|Windows Phone [0-9.]+|WCE;',
// @reference: http://en.wikipedia.org/wiki/Windows_Phone
// http://wifeng.cn/?r=blog&a=view&id=106
// http://nicksnettravels.builttoroam.com/post/2011/01/10/Bogus-Windows-Phone-7-User-Agent-String.aspx
// http://msdn.microsoft.com/library/ms537503.aspx
'WindowsPhoneOS' => 'Windows Phone 8.0|Windows Phone OS|XBLWP7|ZuneWP7|Windows NT 6.[23]; ARM;',
'iOS' => '\biPhone.*Mobile|\biPod|\biPad',
// http://en.wikipedia.org/wiki/MeeGo
// @todo: research MeeGo in UAs
'MeeGoOS' => 'MeeGo',
// http://en.wikipedia.org/wiki/Maemo
// @todo: research Maemo in UAs
'MaemoOS' => 'Maemo',
'JavaOS' => 'J2ME/|\bMIDP\b|\bCLDC\b', // '|Java/' produces bug #135
'webOS' => 'webOS|hpwOS',
'badaOS' => '\bBada\b',
'BREWOS' => 'BREW',
);

/**
* List of mobile User Agents.
*
* @var array
*/
protected static $browsers = array(
// @reference: https://developers.google.com/chrome/mobile/docs/user-agent
'Chrome' => '\bCrMo\b|CriOS|Android.*Chrome/[.0-9]* (Mobile)?',
'Dolfin' => '\bDolfin\b',
'Opera' => 'Opera.*Mini|Opera.*Mobi|Android.*Opera|Mobile.*OPR/[0-9.]+|Coast/[0-9.]+',
'Skyfire' => 'Skyfire',
'IE' => 'IEMobile|MSIEMobile', // |Trident/[.0-9]+
'Firefox' => 'fennec|firefox.*maemo|(Mobile|Tablet).*Firefox|Firefox.*Mobile',
'Bolt' => 'bolt',
'TeaShark' => 'teashark',
'Blazer' => 'Blazer',
// @reference: http://developer.apple.com/library/safari/#documentation/AppleApplications/Reference/SafariWebContent/OptimizingforSafarioniPhone/OptimizingforSafarioniPhone.html#//apple_ref/doc/uid/TP40006517-SW3
'Safari' => 'Version.*Mobile.*Safari|Safari.*Mobile|MobileSafari',
// @ref: http://en.wikipedia.org/wiki/Midori_(web_browser)
//'Midori' => 'midori',
'Tizen' => 'Tizen',
'UCBrowser' => 'UC.*Browser|UCWEB',
'baiduboxapp' => 'baiduboxapp',
'baidubrowser' => 'baidubrowser',
// @ref: https://github.com/serbanghita/Mobile-Detect/issues/7
'DiigoBrowser' => 'DiigoBrowser',
// http://www.puffinbrowser.com/index.php
'Puffin' => 'Puffin',
// @ref: http://mercury-browser.com/index.html
'Mercury' => '\bMercury\b',
// @ref: http://en.wikipedia.org/wiki/Obigo_Browser
'ObigoBrowser' => 'Obigo',
// @ref: http://en.wikipedia.org/wiki/NetFront
'NetFront' => 'NF-Browser',
// @reference: http://en.wikipedia.org/wiki/Minimo
// http://en.wikipedia.org/wiki/Vision_Mobile_Browser
'GenericBrowser' => 'NokiaBrowser|OviBrowser|OneBrowser|TwonkyBeamBrowser|SEMC.*Browser|FlyFlow|Minimo|NetFront|Novarra-Vision|MQQBrowser|MicroMessenger',
);

/**
* Utilities.
*
* @var array
*/
protected static $utilities = array(
// Experimental. When a mobile device wants to switch to 'Desktop Mode'.
// @ref: http://scottcate.com/technology/windows-phone-8-ie10-desktop-or-mobile/
// @ref: https://github.com/serbanghita/Mobile-Detect/issues/57#issuecomment-15024011
'DesktopMode' => 'WPDesktop',
'TV' => 'SonyDTV|HbbTV', // experimental
'WebKit' => '(webkit)[ /]([\w.]+)',
'Bot' => 'Googlebot|DoCoMo|YandexBot|bingbot|ia_archiver|AhrefsBot|Ezooms|GSLFbot|WBSearchBot|Twitterbot|TweetmemeBot|Twikle|PaperLiBot|Wotbox|UnwindFetchor|facebookexternalhit',
'MobileBot' => 'Googlebot-Mobile|DoCoMo|YahooSeeker/M1A1-R2D2',
// @todo: Include JXD consoles.
'Console' => '\b(Nintendo|Nintendo WiiU|PLAYSTATION|Xbox)\b',
'Watch' => 'SM-V700',
);

/**
* All possible HTTP headers that represent the
* User-Agent string.
*
* @var array
*/
protected static $uaHttpHeaders = array(
// The default User-Agent string.
'HTTP_USER_AGENT',
// Header can occur on devices using Opera Mini.
'HTTP_X_OPERAMINI_PHONE_UA',
// Vodafone specific header: http://www.seoprinciple.com/mobile-web-community-still-angry-at-vodafone/24/
'HTTP_X_DEVICE_USER_AGENT',
'HTTP_X_ORIGINAL_USER_AGENT',
'HTTP_X_SKYFIRE_PHONE',
'HTTP_X_BOLT_PHONE_UA',
'HTTP_DEVICE_STOCK_UA',
'HTTP_X_UCBROWSER_DEVICE_UA'
);

/**
* The individual segments that could exist in a User-Agent string. VER refers to the regular
* expression defined in the constant self::VER.
*
* @var array
*/
protected static $properties = array(

// Build
'Mobile' => 'Mobile/[VER]',
'Build' => 'Build/[VER]',
'Version' => 'Version/[VER]',
'VendorID' => 'VendorID/[VER]',

// Devices
'iPad' => 'iPad.*CPU[a-z ]+[VER]',
'iPhone' => 'iPhone.*CPU[a-z ]+[VER]',
'iPod' => 'iPod.*CPU[a-z ]+[VER]',
//'BlackBerry' => array('BlackBerry[VER]', 'BlackBerry [VER];'),
'Kindle' => 'Kindle/[VER]',

// Browser
'Chrome' => array('Chrome/[VER]', 'CriOS/[VER]', 'CrMo/[VER]'),
'Coast' => array('Coast/[VER]'),
'Dolfin' => 'Dolfin/[VER]',
// @reference: https://developer.mozilla.org/en-US/docs/User_Agent_Strings_Reference
'Firefox' => 'Firefox/[VER]',
'Fennec' => 'Fennec/[VER]',
// @reference: http://msdn.microsoft.com/en-us/library/ms537503(v=vs.85).aspx
'IE' => array('IEMobile/[VER];', 'IEMobile [VER]', 'MSIE [VER];'),
// http://en.wikipedia.org/wiki/NetFront
'NetFront' => 'NetFront/[VER]',
'NokiaBrowser' => 'NokiaBrowser/[VER]',
'Opera' => array( ' OPR/[VER]', 'Opera Mini/[VER]', 'Version/[VER]' ),
'Opera Mini' => 'Opera Mini/[VER]',
'Opera Mobi' => 'Version/[VER]',
'UC Browser' => 'UC Browser[VER]',
'MQQBrowser' => 'MQQBrowser/[VER]',
'MicroMessenger' => 'MicroMessenger/[VER]',
'baiduboxapp' => 'baiduboxapp/[VER]',
'baidubrowser' => 'baidubrowser/[VER]',
// @note: Safari 7534.48.3 is actually Version 5.1.
// @note: On BlackBerry the Version is overwriten by the OS.
'Safari' => array( 'Version/[VER]', 'Safari/[VER]' ),
'Skyfire' => 'Skyfire/[VER]',
'Tizen' => 'Tizen/[VER]',
'Webkit' => 'webkit[ /][VER]',

// Engine
'Gecko' => 'Gecko/[VER]',
'Trident' => 'Trident/[VER]',
'Presto' => 'Presto/[VER]',

// OS
'iOS' => ' \bOS\b [VER] ',
'Android' => 'Android [VER]',
'BlackBerry' => array('BlackBerry[\w]+/[VER]', 'BlackBerry.*Version/[VER]', 'Version/[VER]'),
'BREW' => 'BREW [VER]',
'Java' => 'Java/[VER]',
// @reference: http://windowsteamblog.com/windows_phone/b/wpdev/archive/2011/08/29/introducing-the-ie9-on-windows-phone-mango-user-agent-string.aspx
// @reference: http://en.wikipedia.org/wiki/Windows_NT#Releases
'Windows Phone OS' => array( 'Windows Phone OS [VER]', 'Windows Phone [VER]'),
'Windows Phone' => 'Windows Phone [VER]',
'Windows CE' => 'Windows CE/[VER]',
// http://social.msdn.microsoft.com/Forums/en-US/windowsdeveloperpreviewgeneral/thread/6be392da-4d2f-41b4-8354-8dcee20c85cd
'Windows NT' => 'Windows NT [VER]',
'Symbian' => array('SymbianOS/[VER]', 'Symbian/[VER]'),
'webOS' => array('webOS/[VER]', 'hpwOS/[VER];'),
);




protected $_scopeConfig;
protected $_reportCollectionFactory;

const XML_PATH_WHATSAPP_SHARE_ENABLE = 'whatsappshare_tab/whatsappshare_setting/whatsappshare_active';
const XML_PATH_WHATSAPP_SHARE_SIZE = 'whatsappshare_tab/whatsappshare_setting/whatsappshare_size';
const XML_PATH_WHATSAPP_SHARE_TEXT = 'whatsappshare_tab/whatsappshare_setting/whatsappshare_text';

public function __construct (
\Magento\Framework\App\Helper\Context $context,
\Magento\Reports\Model\ResourceModel\Product\Sold\CollectionFactory $reportCollectionFactory,
\Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig 
) {
$this->_reportCollectionFactory = $reportCollectionFactory;
parent::__construct($context);
$this->_scopeConfig = $scopeConfig;
$this->setHttpHeaders();
$this->setUserAgent();
}







public static function getScriptVersion()
{
return self::VERSION;
}

public function setHttpHeaders($httpHeaders = null)
{
//use global _SERVER if $httpHeaders aren't defined
if (!is_array($httpHeaders) || !count($httpHeaders)) {
$httpHeaders = $_SERVER;
}

//clear existing headers
$this->httpHeaders = array();

//Only save HTTP headers. In PHP land, that means only _SERVER vars that
//start with HTTP_.
foreach ($httpHeaders as $key => $value) {
if (substr($key,0,5) == 'HTTP_') {
$this->httpHeaders[$key] = $value;
}
}
}

public function getHttpHeaders()
{
return $this->httpHeaders;
}

public function getHttpHeader($header)
{
//are we using PHP-flavored headers?
if (strpos($header, '_') === false) {
$header = str_replace('-', '_', $header);
$header = strtoupper($header);
}

//test the alternate, too
$altHeader = 'HTTP_' . $header;

//Test both the regular and the HTTP_ prefix
if (isset($this->httpHeaders[$header])) {
return $this->httpHeaders[$header];
} elseif (isset($this->httpHeaders[$altHeader])) {
return $this->httpHeaders[$altHeader];
}

return null;
}

public function getMobileHeaders()
{
return self::$mobileHeaders;
}

public function getUaHttpHeaders()
{
return self::$uaHttpHeaders;
}

public function setUserAgent($userAgent = null)
{
if (!empty($userAgent)) {
return $this->userAgent = $userAgent;
} else {

$this->userAgent = null;

foreach ($this->getUaHttpHeaders() as $altHeader) {
if (!empty($this->httpHeaders[$altHeader])) { // @todo: should use getHttpHeader(), but it would be slow. (Serban)
$this->userAgent .= $this->httpHeaders[$altHeader] . " ";
}
}

return $this->userAgent = (!empty($this->userAgent) ? trim($this->userAgent) : null);

}
}

public function getUserAgent()
{
return $this->userAgent;
}

public function setDetectionType($type = null)
{
if ($type === null) {
$type = self::DETECTION_TYPE_MOBILE;
}

if ($type != self::DETECTION_TYPE_MOBILE && $type != self::DETECTION_TYPE_EXTENDED) {
return;
}

$this->detectionType = $type;
}

public static function getPhoneDevices()
{
return self::$phoneDevices;
}

public static function getTabletDevices()
{
return self::$tabletDevices;
}

public static function getUserAgents()
{
return self::getBrowsers();
}

public static function getBrowsers()
{
return self::$browsers;
}

public static function getUtilities()
{
return self::$utilities;
}

public static function getMobileDetectionRules()
{
static $rules;

if (!$rules) {
$rules = array_merge(
self::$phoneDevices,
self::$tabletDevices,
self::$operatingSystems,
self::$browsers
);
}

return $rules;

}

public function getMobileDetectionRulesExtended()
{
static $rules;

if (!$rules) {
// Merge all rules together.
$rules = array_merge(
self::$phoneDevices,
self::$tabletDevices,
self::$operatingSystems,
self::$browsers,
self::$utilities
);
}

return $rules;
}

public function getRules()
{
if ($this->detectionType == self::DETECTION_TYPE_EXTENDED) {
return self::getMobileDetectionRulesExtended();
} else {
return self::getMobileDetectionRules();
}
}

public static function getOperatingSystems()
{
return self::$operatingSystems;
}

public function checkHttpHeadersForMobile()
{

foreach ($this->getMobileHeaders() as $mobileHeader => $matchType) {
if ( isset($this->httpHeaders[$mobileHeader]) ) {
if ( is_array($matchType['matches']) ) {
foreach ($matchType['matches'] as $_match) {
if ( strpos($this->httpHeaders[$mobileHeader], $_match) !== false ) {
return true;
}
}

return false;
} else {
return true;
}
}
}

return false;

}

public function __call($name, $arguments)
{
//make sure the name starts with 'is', otherwise
if (substr($name, 0, 2) != 'is') {
throw new BadMethodCallException("No such method exists: $name");
}

$this->setDetectionType(self::DETECTION_TYPE_MOBILE);

$key = substr($name, 2);

return $this->matchUAAgainstKey($key);
}


protected function matchDetectionRulesAgainstUA($userAgent = null)
{
// Begin general search.
foreach ($this->getRules() as $_regex) {
if (empty($_regex)) {
continue;
}
if ($this->match($_regex, $userAgent)) {
return true;
}
}

return false;
}

protected function matchUAAgainstKey($key, $userAgent = null)
{
// Make the keys lowercase so we can match: isIphone(), isiPhone(), isiphone(), etc.
$key = strtolower($key);

//change the keys to lower case
$_rules = array_change_key_case($this->getRules());

if (array_key_exists($key, $_rules)) {
if (empty($_rules[$key])) {
return null;
}

return $this->match($_rules[$key], $userAgent);
}

return false;
}

public function isMobile($userAgent = null, $httpHeaders = null)
{

if ($httpHeaders) {
$this->setHttpHeaders($httpHeaders);
}

if ($userAgent) {
$this->setUserAgent($userAgent);
}

$this->setDetectionType(self::DETECTION_TYPE_MOBILE);

if ($this->checkHttpHeadersForMobile()) {
return true;
} else {
return $this->matchDetectionRulesAgainstUA();
}

}

public function isTablet($userAgent = null, $httpHeaders = null)
{
$this->setDetectionType(self::DETECTION_TYPE_MOBILE);

foreach (self::$tabletDevices as $_regex) {
if ($this->match($_regex, $userAgent)) {
return true;
}
}

return false;
}

public function is($key, $userAgent = null, $httpHeaders = null)
{
// Set the UA and HTTP headers only if needed (eg. batch mode).
if ($httpHeaders) {
$this->setHttpHeaders($httpHeaders);
}

if ($userAgent) {
$this->setUserAgent($userAgent);
}

$this->setDetectionType(self::DETECTION_TYPE_EXTENDED);

return $this->matchUAAgainstKey($key);
}

public function match($regex, $userAgent = null)
{
// Escape the special character which is the delimiter.
$regex = str_replace('/', '\/', $regex);

return (bool) preg_match('/'.$regex.'/is', (!empty($userAgent) ? $userAgent : $this->userAgent));
}

public static function getProperties()
{
return self::$properties;
}

public function prepareVersionNo($ver)
{
$ver = str_replace(array('_', ' ', '/'), '.', $ver);
$arrVer = explode('.', $ver, 2);

if (isset($arrVer[1])) {
$arrVer[1] = @str_replace('.', '', $arrVer[1]); // @todo: treat strings versions.
}

return (float) implode('.', $arrVer);
}

public function version($propertyName, $type = self::VERSION_TYPE_STRING)
{
if (empty($propertyName)) {
return false;
}

//set the $type to the default if we don't recognize the type
if ($type != self::VERSION_TYPE_STRING && $type != self::VERSION_TYPE_FLOAT) {
$type = self::VERSION_TYPE_STRING;
}

$properties = self::getProperties();

// Check if the property exists in the properties array.
if (array_key_exists($propertyName, $properties)) {

// Prepare the pattern to be matched.
// Make sure we always deal with an array (string is converted).
$properties[$propertyName] = (array) $properties[$propertyName];

foreach ($properties[$propertyName] as $propertyMatchString) {

$propertyPattern = str_replace('[VER]', self::VER, $propertyMatchString);

// Escape the special character which is the delimiter.
$propertyPattern = str_replace('/', '\/', $propertyPattern);

// Identify and extract the version.
preg_match('/'.$propertyPattern.'/is', $this->userAgent, $match);

if (!empty($match[1])) {
$version = ( $type == self::VERSION_TYPE_FLOAT ? $this->prepareVersionNo($match[1]) : $match[1] );

return $version;
}

}

}

return false;
}

public function mobileGrade()
{
$isMobile = $this->isMobile();

if (
// Apple iOS 3.2-5.1 - Tested on the original iPad (4.3 / 5.0), iPad 2 (4.3), iPad 3 (5.1), original iPhone (3.1), iPhone 3 (3.2), 3GS (4.3), 4 (4.3 / 5.0), and 4S (5.1)
$this->isIOS() && $this->version('iPad', self::VERSION_TYPE_FLOAT)>=4.3 ||
$this->isIOS() && $this->version('iPhone', self::VERSION_TYPE_FLOAT)>=3.1 ||
$this->isIOS() && $this->version('iPod', self::VERSION_TYPE_FLOAT)>=3.1 ||

// Android 2.1-2.3 - Tested on the HTC Incredible (2.2), original Droid (2.2), HTC Aria (2.1), Google Nexus S (2.3). Functional on 1.5 & 1.6 but performance may be sluggish, tested on Google G1 (1.5)
// Android 3.1 (Honeycomb) - Tested on the Samsung Galaxy Tab 10.1 and Motorola XOOM
// Android 4.0 (ICS) - Tested on a Galaxy Nexus. Note: transition performance can be poor on upgraded devices
// Android 4.1 (Jelly Bean) - Tested on a Galaxy Nexus and Galaxy 7
( $this->version('Android', self::VERSION_TYPE_FLOAT)>2.1 && $this->is('Webkit') ) ||

// Windows Phone 7-7.5 - Tested on the HTC Surround (7.0) HTC Trophy (7.5), LG-E900 (7.5), Nokia Lumia 800
$this->version('Windows Phone OS', self::VERSION_TYPE_FLOAT)>=7.0 ||

// Blackberry 7 - Tested on BlackBerry Torch 9810
// Blackberry 6.0 - Tested on the Torch 9800 and Style 9670
$this->is('BlackBerry') && $this->version('BlackBerry', self::VERSION_TYPE_FLOAT)>=6.0 ||
// Blackberry Playbook (1.0-2.0) - Tested on PlayBook
$this->match('Playbook.*Tablet') ||

// Palm WebOS (1.4-2.0) - Tested on the Palm Pixi (1.4), Pre (1.4), Pre 2 (2.0)
( $this->version('webOS', self::VERSION_TYPE_FLOAT)>=1.4 && $this->match('Palm|Pre|Pixi') ) ||
// Palm WebOS 3.0 - Tested on HP TouchPad
$this->match('hp.*TouchPad') ||

// Firefox Mobile (12 Beta) - Tested on Android 2.3 device
( $this->is('Firefox') && $this->version('Firefox', self::VERSION_TYPE_FLOAT)>=12 ) ||

// Chrome for Android - Tested on Android 4.0, 4.1 device
( $this->is('Chrome') && $this->is('AndroidOS') && $this->version('Android', self::VERSION_TYPE_FLOAT)>=4.0 ) ||

// Skyfire 4.1 - Tested on Android 2.3 device
( $this->is('Skyfire') && $this->version('Skyfire', self::VERSION_TYPE_FLOAT)>=4.1 && $this->is('AndroidOS') && $this->version('Android', self::VERSION_TYPE_FLOAT)>=2.3 ) ||

// Opera Mobile 11.5-12: Tested on Android 2.3
( $this->is('Opera') && $this->version('Opera Mobi', self::VERSION_TYPE_FLOAT)>11 && $this->is('AndroidOS') ) ||

// Meego 1.2 - Tested on Nokia 950 and N9
$this->is('MeeGoOS') ||

// Tizen (pre-release) - Tested on early hardware
$this->is('Tizen') ||

// Samsung Bada 2.0 - Tested on a Samsung Wave 3, Dolphin browser
// @todo: more tests here!
$this->is('Dolfin') && $this->version('Bada', self::VERSION_TYPE_FLOAT)>=2.0 ||

// UC Browser - Tested on Android 2.3 device
( ($this->is('UC Browser') || $this->is('Dolfin')) && $this->version('Android', self::VERSION_TYPE_FLOAT)>=2.3 ) ||

// Kindle 3 and Fire - Tested on the built-in WebKit browser for each
( $this->match('Kindle Fire') ||
$this->is('Kindle') && $this->version('Kindle', self::VERSION_TYPE_FLOAT)>=3.0 ) ||

// Nook Color 1.4.1 - Tested on original Nook Color, not Nook Tablet
$this->is('AndroidOS') && $this->is('NookTablet') ||

// Chrome Desktop 11-21 - Tested on OS X 10.7 and Windows 7
$this->version('Chrome', self::VERSION_TYPE_FLOAT)>=11 && !$isMobile ||

// Safari Desktop 4-5 - Tested on OS X 10.7 and Windows 7
$this->version('Safari', self::VERSION_TYPE_FLOAT)>=5.0 && !$isMobile ||

// Firefox Desktop 4-13 - Tested on OS X 10.7 and Windows 7
$this->version('Firefox', self::VERSION_TYPE_FLOAT)>=4.0 && !$isMobile ||

// Internet Explorer 7-9 - Tested on Windows XP, Vista and 7
$this->version('MSIE', self::VERSION_TYPE_FLOAT)>=7.0 && !$isMobile ||

// Opera Desktop 10-12 - Tested on OS X 10.7 and Windows 7
// @reference: http://my.opera.com/community/openweb/idopera/
$this->version('Opera', self::VERSION_TYPE_FLOAT)>=10 && !$isMobile

){
return self::MOBILE_GRADE_A;
}

if (
$this->isIOS() && $this->version('iPad', self::VERSION_TYPE_FLOAT)<4.3 ||
$this->isIOS() && $this->version('iPhone', self::VERSION_TYPE_FLOAT)<3.1 ||
$this->isIOS() && $this->version('iPod', self::VERSION_TYPE_FLOAT)<3.1 ||

// Blackberry 5.0: Tested on the Storm 2 9550, Bold 9770
$this->is('Blackberry') && $this->version('BlackBerry', self::VERSION_TYPE_FLOAT)>=5 && $this->version('BlackBerry', self::VERSION_TYPE_FLOAT)<6 ||

//Opera Mini (5.0-6.5) - Tested on iOS 3.2/4.3 and Android 2.3
( $this->version('Opera Mini', self::VERSION_TYPE_FLOAT)>=5.0 && $this->version('Opera Mini', self::VERSION_TYPE_FLOAT)<=6.5 &&
($this->version('Android', self::VERSION_TYPE_FLOAT)>=2.3 || $this->is('iOS')) ) ||

// Nokia Symbian^3 - Tested on Nokia N8 (Symbian^3), C7 (Symbian^3), also works on N97 (Symbian^1)
$this->match('NokiaN8|NokiaC7|N97.*Series60|Symbian/3') ||

// @todo: report this (tested on Nokia N71)
$this->version('Opera Mobi', self::VERSION_TYPE_FLOAT)>=11 && $this->is('SymbianOS')
){
return self::MOBILE_GRADE_B;
}

if (
// Blackberry 4.x - Tested on the Curve 8330
$this->version('BlackBerry', self::VERSION_TYPE_FLOAT)<5.0 ||
// Windows Mobile - Tested on the HTC Leo (WinMo 5.2)
$this->match('MSIEMobile|Windows CE.*Mobile') || $this->version('Windows Mobile', self::VERSION_TYPE_FLOAT)<=5.2

){
return self::MOBILE_GRADE_C;
}

//All older smartphone platforms and featurephones - Any device that doesn't support media queries
//will receive the basic, C grade experience.
return self::MOBILE_GRADE_C;
}






public function whatsappshare_enable() {
return $this->_scopeConfig->getValue(self::XML_PATH_WHATSAPP_SHARE_ENABLE);
}

public function whatsappshare_size() {
return $this->_scopeConfig->getValue(self::XML_PATH_WHATSAPP_SHARE_SIZE);
}

public function whatsappshare_text() {
return $this->_scopeConfig->getValue(self::XML_PATH_WHATSAPP_SHARE_TEXT);
}
}

 

Create Block For Share Product on WhatApp in Magento 2

app/code/Wishusucess/Whatsappshare/Block/Whatsappshare.php

<?php 
/*
* @Author Hemant Singh
* @Developer Hemant Singh
* @Module Wishusucess_Whatsappshare
* @copyright Copyright (c) Wishusucess (http://www.wishusucess.com/)
*/
namespace Wishusucess\Whatsappshare\Block;

use Magento\Framework\Registry;
use \Wishusucess\Whatsappshare\Helper\Data;

class Whatsappshare extends \Magento\Framework\View\Element\Template
{
public $assetRepository;

public function __construct(
\Magento\Framework\View\Element\Template\Context $context,
array $data = [],
\Magento\Framework\View\Asset\Repository $assetRepository,
Data $helperData
)
{
// Get the asset repository to get URL of our assets
$this->assetRepository = $assetRepository;
$this->_helperData = $helperData;
return parent::__construct($context, $data);
}
public function helperInit() {
return $this->_helperData;
}
}

 

Create Model Class For Share product on WhatsApp Module

app/code/Wishusucess/Whatsappshare/Model/Source/Size.php

<?php
/*
* @Author Hemant Singh
* @Developer Hemant Singh
* @Module Wishusucess_Whatsappshare
* @copyright Copyright (c) Wishusucess (http://www.wishusucess.com/)
*/
namespace Wishusucess\Whatsappshare\Model\Source;

class Size implements \Magento\Framework\Option\ArrayInterface
{
public function toOptionArray() {
return array(
array(
'value' => '1',
'label' => __('Small')
),
array(
'value' => '2',
'label' => __('Medium')
),
array(
'value' => '3',
'label' => __('Large')
)
);
}

public function toArray() {
return [
'1' => __('Small'),
'2' => __('Medium'),
'3' => __('Large')
];
}
}

 

Call Template File in Layout

app/code/Wishusucess/Whatsappshare/view/frontend/layout/catalog_product_view.xml

<?xml version="1.0"?>
<!--
/*
* @Author Hemant Singh
* @Developer Hemant Singh
* @Module Wishusucess_Whatsappshare
* @copyright Copyright (c) Wishusucess (http://www.wishusucess.com/)
*/
-->
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
<head>
<css src="Wishusucess_Whatsappshare::css/whatsappshare/whatsappshare.css" />
</head>
<body>
<referenceContainer name="product.info.addtocart">
<block class="Wishusucess\Whatsappshare\Block\Whatsappshare" name="whatsapp.share" as="whatsappshare" after="-" template="catalog/product/view/whatsappshare.phtml" />
</referenceContainer>
</body>
</page>

 

Show Share Product on WhatsApp Functionality

app/code/Wishusucess/Whatsappshare/templates/catalog/product/view/whatsappshare.phtml

<?php
/*
* @Author Hemant Singh
* @Developer Hemant Singh
* @Module Wishusucess_Whatsappshare
* @copyright Copyright (c) Wishusucess (http://www.wishusucess.com/)
*/
?>
<?php
$helper = $this->helperInit();

$objectManagerInstance = \Magento\Framework\App\ObjectManager::getInstance();
$url = $objectManagerInstance -> get('Magento\Framework\UrlInterface');
$currentUrl = $url -> getCurrentUrl();

$active = $helper->whatsappshare_enable();
$size = $helper->whatsappshare_size();
$text = $helper->whatsappshare_text();

$size_class = "whatsapp_small";
if($size == 1) {
$size_class = "whatsapp_small";
} else if($size == 2) {
$size_class = "whatsapp_medium";
} else if($size == 3) {
$size_class = "whatsapp_large";
}

if($helper->isMobile() || $helper->isTablet()) {
/* <a href="whatsapp://send?text=<?php echo $text?>%0A%0A<?php echo "",$currentUrl."%3Futm_source%3Dwhatsappshare";?>" class=""><?php echo __('Share');?></a> */
?>
<div class="whatsapp_share <?php echo $size_class; ?>" alt="Enquire" title="Enquire">
<a href="whatsapp://send?text=<?php echo $text?>%0A%0A<?php echo "",$currentUrl."";?>"><?php echo __('Enquire');?></a>
</div> 
<?php 
} else {
?>
<div class="whatsapp_share <?php echo $size_class; ?>" alt="Enquire" title="Enquire">
<a href="https://web.whatsapp.com/send?text=<?php echo $text?>%0A%0A<?php echo "",$currentUrl."";?>" target="_blank"><?php echo __('Enquire');?></a>
</div>
<?php
}
?>

 

Design Share Product on WhatsApp Button

app/code/Wishusucess/Whatsappshare/web/css/whatsappshare/whatsappshare.css

/**
* 
* @package Wishusucess_Whatsappshare
*/

.whatsapp_share a {width: 100%;display: block;height: inherit;font-size: 0px;}
.whatsapp_small {background: url("../../images/whatsappsmall.png") no-repeat scroll 0 0 !important;height:48px;width: 48px;}
.whatsapp_medium {background:url("../../images/whatsappmedium.png") no-repeat scroll 0 0 !important;width:167px;height:42px;}
.whatsapp_large {background:url("../../images/whatsapplarge.png") no-repeat scroll 0 0 !important;width:218px;height:40px;}

 

Put Button For Small, Medium, And Large Button

  • app/code/Wishusucess/Whatsappshare/web/images/whatsapplarge.png
  • app/code/Wishusucess/Whatsappshare/web/images/whatsappmedium.png
  • app/code/Wishusucess/Whatsappshare/web/images/whatsappsmall.png

 

Now Call this Below line on

<?php echo $this->getLayout()->createBlock("Wishusucess\Whatsappshare\Block\Whatsappshare")->setTemplate("Wishusucess_Whatsappshare::catalog/product/view/whatsappshare.phtml")->toHtml();?>

Your_Theme/Theme_Name/Magento_Catalog/templates/product/list.phtml file near add to cart button (line no. 94)

 

Now, Run Following Command:

php bin/magento setup:upgrade

php bin/magento setup:di:compile

php bin/magento setup:static-content:deplpy -f

php bin/magento cache:clean

 

Download Link:

Share Prodcut on WhatsApp Extension in Magento 2

Hire Magento 2 Expert Developer to Develop Your Store

 

Related Post:

Custom Shipping Text Filed: Show Custom Text Magento 2

Search AutoComplete: Magento 2 Module Add All Category for Search

Sort By Price: Add Sort By Price High to Low & Low To High in Magento 2

 

Recommended Post:

Magento 2.4 Installation Guide: How to Install Magento 2.4.2

Magento Store: Best 36 Magento Websites Example in The World

SEO Packages: How Much Do SEO Packages Cost in India, SEO Pricing