Admin Action Logs Archive

Published: May 17, 2017


The Admin Actions Log a useful feature of both Magento 1 and 2 Enterprise Edition. For those who haven’t seen it before, it offers an audit history of all actions taken by users in the admin panel.

A screenshot showing the admin actions log

As with sales, invoices, credit memos and shipments, Magento Enterprise occasionally archives data recorded to the admin actions log. However, for some reason, the mechanics used for archiving admin actions are completely different from how sales data is handled.

Here I’ll show you how that process works…

One Day With A MacBook Pro 15-Inch 2016

Published: May 8, 2017


My office laptop was brought to the Apple store for repair last Friday. Today, I spent a full day using a spare.

The laptop I’m used to using is a 2014 model (pre touch bar). The spare is a 2016 model (including the touch bar).

Here are my initial thoughts on the latest iteration from Apple.

Using Custom HTML Elements In A Reveal.js Deck

Published: April 22, 2017


I’m currently in the process of preparing slides for an upcoming talk. One technique I’m using to help structure the talk is an “agenda” slide. It’s basically a bulleted list of topics that will be covered in the presentation.

A screenshot demonstrating the agenda slide

As I’m presenting, to facilitate a smooth transition, I pull up the “agenda” slide each time I’m about to dive into a new topic. There, the next topic is visually distinguished from the other topics.

A screenshot demonstrating the agenda slide with a topic highlighted

I’m using reveal.js for the presentation, which allows me to write my slides in HTML (or Markdown), CSS and JavaScript. So the markup looks something like this…

<h3>What We'll Cover</h3>
    <li class="current-topic">React</li>

As I was working on the slides, I started getting frustrated with copying and pasting the agenda over and over. Doing so means that if I decide to include a new topic in the talk, I need to update multiple instances of the agenda, spread across the deck.

Here I’ll show you how I used a custom HTML element to solve this problem.

Scaling Magento's SalesRule Module to Handle 20 Million Coupons and Beyond

Published: April 18, 2017

In a recent New Relic performance audit on a client’s site, we found that the Mage_SalesRule totals collectors were causing some serious slowness. At best, totals collection would execute in around 1.2s when coupons were at play. However, in the worst cases, it would take up to 30 seconds.

A screenshot showing New Relic's production traces

Checking the database I found that the salesrule_coupon table had over 20 million records in it. In this post I’ll show you how we were able to cut that down to literally milliseconds and keep totals collection performant, even with 20 million coupons in the database.

A Trick Hack To Conditionally Customize A Magento 2 jQuery Widget

Published: April 12, 2017


Recently I’ve been working on porting Mpchadwick_SearchAutocompleteConfigmarator from Magento 1 to Magento 2. One of the module’s feature’s is a switch in the admin panel which allows you to turn off autocomplete. Rather than handling this in the controller, the module prevents the AJAX request from being dispatched entirely, which can be a big help from a scalability standpoint. In Magento 1 I used ifconfig to conditionally load a JavaScript file which mutated the Varien.searchForm prototype.


<?xml version="1.0"?>
        <reference name="head">
            <action method="addItem" ifconfig="catalog/search/disable_autocomplete">


if (typeof Varien.searchForm != 'undefined') {
    // Rather than modifying the controller, or block let's stop it here
    // so the request never even gets dispatched
        initAutocomplete : function(url, destinationElement) {
            return false;

In Magento 2, however, the frontend is very different.

Magento 2 REST API Response Formats

Published: March 28, 2017


The Magento 2 REST API can return responses in XML or JSON format. This is done based on the Accept HTTP Header. Per the developer documentation..

HTTP headers


Optional. Specifies the format of the response body. Default is JSON.

Accept: application/FORMAT

Where FORMAT is either JSON or XML.

If you omit this header, the response is returned in JSON format.

Here, I’ll dive into the code, to investigate how this works…