How to implement Google reCaptcha V3 in PHP

Google recently introduced reCAPTCHA V3, which is a pure Javascript API that requires no user interaction at all. Official documentation can be found here.

One major difference is that reCAPTCHA’s Site Verify Response now returns more information:

"success": true|false,      // whether this request was a valid reCAPTCHA token for your site
"score": number             // the score for this request (0.0 - 1.0)
"action": string            // the action name for this request (important to verify)
"challenge_ts": timestamp,  // timestamp of the challenge load (ISO format yyyy-MM-dd'T'HH:mm:ssZZ)
"hostname": string,         // the hostname of the site where the reCAPTCHA was solved
"error-codes": [...]        // optional

So in your verification code you can check for parameters like “success”, “score”, “action”, etc. The below is a very basic one-page demo on how to use reCaptcha V3 in a form.
Continue reading “How to implement Google reCaptcha V3 in PHP”

How to make custom admin “Save and Continue Edit” button work in Magento 2

I recently created a custom module that has a “Save and Continue Edit” button on the admin edit form. The tricky part is to make the page stay on the edit screen after the button is pressed and the form is saved.

When Save and Continue button is pressed, a back/edit string is appended to the submit url by default, so in the save controller we can check for it and set redirect url accordingly.

The return statement of the save controller should look something like this:

    //check for 'back' parameter
    if ($this->getRequest()->getParam('back')) {
        //redirect to edit page
        return $resultRedirect->setPath('*/*/edit', ['id' => $model->getId(), '_current' => true]);
    //redirect to index page
    return $resultRedirect->setPath('*/*/');

Use AWS CloudFront with EC2 instance

Hi guys, I haven’t written anything for quite some time due to lack of time (and laziness). In this article I’m going to share my experience on how to put a whole website, hosted on a EC2 instance, behind CloudFront.

If you want your website to have a global presence and to be accessed quickly anywhere around the world, even in China probably, AWS CloudFront is a great tool to do just that. CloudFront supports the distribution of both static and dynamic content, so you can pretty much set it up with any type of website.
Continue reading “Use AWS CloudFront with EC2 instance”

Show address fields on Magento customer registration page

There’s no setting in Magento’s backend to switch on/off address fields display on customer registration page. The easiest way to show address fields is to add a ‘show_address_fields’ argument to the layout file customer_account_create.xml

File: app/design/frontend//Magento_Customer/layout/customer_account_create.xml

<?xml version="1.0"?>
<page xmlns:xsi="" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
        <referenceBlock name="customer_form_register">
                <argument name="show_address_fields" xsi:type="number">1</argument>

Clear cache afterwards and the address fields should appear on the customer account creation page.

How to implement Google Invisible reCaptcha in PHP

Google recently introduced the Invisible reCAPTCHA, which hides Captcha challenge from view and makes it even simpler for website’s users to fill in a form.

Official documentation can be found here. The below is an example of how to implement it on a PHP website.
Continue reading “How to implement Google Invisible reCaptcha in PHP”

Sending emails with High Importance in Magento

I recently had to customize a transactional email and send it with High Importance in Magento 1.9. After googling around found this post explaining how to do it in Zend Mail.

Since Magento’s mail object extends Zend_Mail, here’s how it’s done in Magento.

$mailTemplate = Mage::getModel('core/email_template');
//get Zend_Mail and add Importance headers
             ->addHeader('X-Priority', '1')
             ->addHeader('X-MSMail-Priority', 'High')
             ->addHeader('Importance', 'High');
$mailTemplate->setDesignConfig(array('area' => 'frontend'))         

Add default alt attribute to all product images in Magento 2

Here’s another good use of the handy Plugin feature introduced in Magento 2.

To make product name as the default value of all product image’s ‘alt’ attribute, all we need to do is to create a simple Plugin.

First, declare the Plugin in your custom module’s di.xml

File: app/code/Vendor/Module/etc/frontend/di.xml

<?xml version="1.0"?>
<config xmlns:xsi="" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <type name="Magento\Catalog\Block\Product\View\Gallery">
	<plugin name="vendor_module_block_product_view_gallery_plugin" type="Vendor\Module\Block\Product\View\Gallery\Plugin" sortOrder="10" />

Now the Plugin’s code. The function we’re targeting is getGalleryImages,

File: app/code/Vendor/Module/Block/Product/View/Gallery/Plugin.php

namespace Vendor\Module\Block\Product\View\Gallery;
class Plugin
    public function afterGetGalleryImages($block, $images)
        if ($images instanceof \Magento\Framework\Data\Collection) {
            $product = $block->getProduct();
            foreach ($images as $image) {
                //check if label is set
        return $images;

And that’s it.

Cron job setup in Magento 2

It is important to correctly setup cron job for Magento 2 as some basic functions such as reindexing rely on cron job to execute.

Below is a typical cron job setup on a cPanel server with logging enabled.

* * * * * /usr/local/bin/php /path_to_your_magento_installation/bin/magento cron:run | grep -v "Ran jobs by schedule" >> /path_to_your_magento_installation/var/log/magento.cron.log
* * * * * /usr/local/bin/php /path_to_your_magento_installation/update/cron.php >> /path_to_your_magento_installation/var/log/update.cron.log
* * * * * /usr/local/bin/php /path_to_your_magento_installation/bin/magento setup:cron:run >> /path_to_your_magento_installation/var/log/setup.cron.log

Make sure the jobs are set to run every minute if you’re using the default Magento configurations. If the interval is longer, e.g. every five minutes, the indexer scripts will be missed and a ‘One or more indexers are invalid‘ message will appear in the admin area.

How to add a custom image field to Catalog Category in Magento 2

Update: Magento 2.2 compatible version can be downloaded here. Note: tested in Magento version 2.2.2.

This article explains the steps needed to add a custom image field to categories in Magento 2. The code is tested on Magento version 2.1.2.

First, in the InstallData script of your custom module, insert a category image attribute to Catalog Category model. In this example the attribute name is ‘thumbnail’.
File: app/code/Vendor/Module/Setup/InstallData.php

    public function install(ModuleDataSetupInterface $setup, ModuleContextInterface $context)
        /** @var \Magento\Catalog\Setup\CategorySetup $categorySetup */
        $categorySetup = $this->categorySetupFactory->create(['setup' => $setup]);
                'type' => 'varchar',
                'label' => 'Thumbnail',
                'input' => 'image',
                'backend' => 'Magento\Catalog\Model\Category\Attribute\Backend\Image',
                'required' => false,
                'sort_order' => 5,
                'global' => ScopedAttributeInterface::SCOPE_STORE,
                'group' => 'Content',
                'is_used_in_grid' => false,
                'is_visible_in_grid' => false,
                'is_filterable_in_grid' => false

Continue reading “How to add a custom image field to Catalog Category in Magento 2”