Speed up Woocommerce WordPress

Add following few lines into functions.php ( in your theme directory ), at the very bottom.


add_action( 'wp_enqueue_scripts', 'remove_woocommerce_when_not_needed', 99 );

function remove_woocommerce_when_not_needed() {
	remove_action( 'wp_head', array( $GLOBALS['woocommerce'], 'generator' ) );

	if ( function_exists( 'is_woocommerce' ) ) {

		if ( ! is_woocommerce() && ! is_cart() && ! is_checkout() ) {
			// dequeue styles
			wp_dequeue_style( 'woocommerce_frontend_styles' );
			wp_dequeue_style( 'woocommerce_fancybox_styles' );
			wp_dequeue_style( 'woocommerce_chosen_styles' );
			wp_dequeue_style( 'woocommerce-general' );
			wp_dequeue_style( 'woocommerce-layout' );
			wp_dequeue_style( 'woocommerce-smallscreen' );
			wp_dequeue_style( 'sv-wc-payment-gateway-payment-form' );

			// dequeue scripts
			wp_dequeue_script( 'wc_price_slider' );
			wp_dequeue_script( 'wc-single-product' );
			wp_dequeue_script( 'wc-add-to-cart' );
			wp_dequeue_script( 'wc-cart-fragments' );
			wp_dequeue_script( 'wc-checkout' );
			wp_dequeue_script( 'wc-add-to-cart-variation' );
			wp_dequeue_script( 'wc-single-product' );
			wp_dequeue_script( 'wc-cart' );
			wp_dequeue_script( 'wc-chosen' );
			wp_dequeue_script( 'woocommerce' );
			wp_dequeue_script( 'jquery-blockui' );
			wp_dequeue_script( 'jquery-placeholder' );
			wp_dequeue_script( 'fancybox' );
			wp_dequeue_script( 'jqueryui' );
			wp_dequeue_script( 'braintree-data' );
			wp_dequeue_script( 'braintree-js' );
			wp_dequeue_script( 'sv-wc-payment-gateway-payment-form');
		}
	}
}

Scripts checks if the page you are on actually needs woocommerce component ( e.g. product page, checkout page .. ) – if not, it will remove all scripts and styles related to Woocommerce and Braintree.

It’s also possible to disable woocommerce entirely on these pages through dedicated plugin – https://wordpress.org/plugins/plugin-organizer/

Also make sure you update maximum memory limit https://phpsolved.com/wordpress-adjust-maximum-memory-limit/

Youtube iframe and Analytics tracking

If you need to use iframe to display youtube video on your website, tracking starts and pauses via analytics can be easily done.
The main trick is to add enablejsapi=1 into url.

E.g.
<iframe width=”560″ id=”somevideo” height=”315″ src=”https://www.youtube.com/embed/aCpGA7OrwyI?autoplay=1&enablejsapi=1″></iframe></pre>

becomes

<iframe width=”560″ id=”somevideo” height=”315″ src=”https://www.youtube.com/embed/aCpGA7OrwyI?autoplay=1&enablejsapi=1“></iframe></pre>

Now you can easily use the API. Feel free to use following example


<iframe width="560" id="somevideo" height="315" src="https://www.youtube.com/embed/aCpGA7OrwyI?autoplay=1&enablejsapi=1"></iframe></pre>

<script>
var player;
function onYouTubeIframeAPIReady() {
    player = new YT.Player( 'somevideo', {
        events: { 'onStateChange': function(state){
            if(state.data){
                if(state.data == YT.PlayerState.PAUSED){
                    // paused
                    ga('send', 'event', 'somevideo', 'paused', creativecoffeebreak.getCurrentTime());
                } else if(state.data == YT.PlayerState.PLAYING){
                    if(!playedAlready){
                        playedAlready = true;
                        ga('send', 'event', 'somevideo', 'start', creativecoffeebreak.getCurrentTime());
                    }
                } else if(state.data == YT.PlayerState.ENDED){
                    ga('send', 'event', 'somevideo', 'finished', creativecoffeebreak.getCurrentTime());
                }
            }
        } }
    });
}

</script>
<script src="https://www.youtube.com/iframe_api"></script>

Please note that the YT.PlayerState.ENDED doesn’t work in almost any browser.
Also, the “PAUSED” event is triggered when fast forwarding as well.

You need to load iframe_api javascript, otherwise the YT object won’t exist.

Braintree Paypal – Please try a different payment method

If you got any of these errors
Oops, something went wrong. Please try a different payment method.
Error: This PayPal integration does not support this currency
Hups, něco se pokazilo. Zkuste prosím jiný způsob platby.

or any other localized version of this message, the issue is not with b>Merchand ID, as official documentation might hint.
It’s the issue with plugin itself.

Open this file wp-content/plugins/woocommerce-gateway-paypal-powered-by-braintree/includes/class-wc-gateway-braintree.php
On line 108, you need to comment out the wp_enqueue_script() and replace it with a different ( up-to-date url )

public function enqueue_gateway_assets() {

	if ( $this->is_available() ) {

		// braintree.js library
		wp_enqueue_script( 'braintree-js', 'https://js.braintreegateway.com/v2/braintree.js', array(), WC_Braintree::VERSION, true );

		parent::enqueue_gateway_assets();
	}
}

becomes

public function enqueue_gateway_assets() {

	if ( $this->is_available() ) {

		// braintree.js library
		// wp_enqueue_script( 'braintree-js', 'https://js.braintreegateway.com/v2/braintree.js', array(), WC_Braintree::VERSION, true );
		wp_enqueue_script( 'braintree-js', 'https://js.braintreegateway.com/js/braintree-2.32.1.min.js', array(), WC_Braintree::VERSION, true );
		parent::enqueue_gateway_assets();
	}
}

That’s it, works without adding additional Merchant ID. Simply but, the JS used in official plugin is outdated.

Run nodejs application in background

There are several ways to do this, you can either use nohup, or append & at the end of command – personally, I’ve found forever to do the job perfectly fine.
Assuming you already have npm installed, if not, just do

sudo apt-get install npm

Then install forever

npm install forever --global

Now you can run it like this

forever start app.js

And it will take care of everything.

/usr/bin/env: node: No such file or directory

Can be fixed by creating symlink.

cd /usr/bin
sudo ln -s nodejs node

View list of running nodejs apps in forever

root@ubuntu:/# forever list
info:    Forever processes running
data:        uid  command         script forever pid   id logfile                 uptime       
data:    [0] mqgC /usr/bin/nodejs app.js 29570   31398    /root/.forever/mqgC.log 0:1:25:6.344 

To see logs for your application, do forever logs + ID of the app ( in our list it’s [0] – 0 )

root@ubuntu:/# forever logs 0
data:    app.js:31398 - Node app is running on port 5000

DrawerJS unofficial documentation

In case you have bought https://www.drawerjs.com/ license, you might be wondering how to do couple special, yet very often needed, tricks that are not covered in documentation.

add new Text object into canvas

For example, in the documentation you’ll find how to add an image through code – https://www.drawerjs.com/try-standalone-api

drawer.api.setBackgroundImageByUrl(url)

But how to add a Text object and place it into canvas? You won’t find that in the official docs..
In order to do that, you need to create fabric.IText object, add default styling and place it into canvas. You can find complete example below.

On last 2 lines I’ve also changed the text – you can change any style, or position value like this.

// This is default Drawer initialization, 
// as can be found in documentation
var canvas = new DrawerJs.Drawer(null, {
    // I recommend to keep this at 'false', 
    // latest version of DrawerJS has a bug related to this
    exitOnOutsideClick: false,
    backgroundCss: 'transparent',
    // you can load as many plugins as you want, 
    // this for this example, we will only need 'Text'
    plugins: [ 'Text' ],
    pluginsConfig: {
        Text: {
            fonts: {
                'Arial': 'Arial, Helvetica, sans-serif',
            },
            defaultFont: 'Arial'
        }
    },
    basePath: '/',
    transparentBackground: true,
    align: 'center' // equivalent of margin: 0 auto
}, 582, 414);

$(document).ready(function () {
    $('#canvas-editor').append(canvas.getHtml());
    canvas.onInsert();
    canvas.api.startEditing();

    // Custom code - this is what you're looking for!
    var t = new fabric.IText('Lorem Ipsum');
    t.top = 50;
    t.left = 50;
    // be sure to pick font family defined in pluginsConfig->Text
    t.fontFamily = 'Arial, Helvetica, sans-serif';
    t.fontSize = 15;
    t.fill = '#000';
    t.fillRule = 'nonzero';
    t.fontWeight = 'normal';
    t.editable = true;
    canvas.fCanvas.add(t);
    // you can omit next line - it just highlights the newly 
    // added object and allows user to change the text right away 
    canvas.fCanvas.setActiveObject(t);

    // And this is how you can change anything 
    // later on - on 'click' event for example
    t.text = 'Different Text';
    canvas.fCanvas.renderAll();
});

Fire event after your changes have been rendered into canvas

Lets say you want to change background through code – you look at their documentation and find out this is the way to do it

drawer.api.setBackgroundImageByUrl(url)

but – if you use bigger image, it may take a while, 2-3 seconds to render. If you save the image before that, you end up with base64 without the new image.
Events are not covered in their documentation at all, so this is the trick:

// add event listener first
canvas.fCanvas.on('after:render', function(){ 
    console.log('Done, we can export the image now'); 
});

// make changes to canvas.. 
drawer.api.setBackgroundImageByUrl(url)

Remove focus – unhighlight object

If you are exporting image you don’t want the default blue border around highlighted object

if(temp = canvas.api.getSelectedObject()){
    temp.active = false;
}
canvas.fCanvas.renderAll();

Export canvas into base64

var base64Output = canvas.api.getCanvasAsImage();

.. and you can send this through $.post() to backend

Resize canvas and all DrawerJS objects in it

// Set up same base ground ..
var canvas = new DrawerJs.Drawer(null, {
    // I recommend to keep this at 'false', 
    // latest version of DrawerJS has a bug related to this
    exitOnOutsideClick: false,
    backgroundCss: 'transparent',
    // you can load as many plugins as you want, 
    // this for this example, we will only need 'Text'
    plugins: [ 'Text' ],
    pluginsConfig: {
        Text: {
            fonts: {
                'Arial': 'Arial, Helvetica, sans-serif',
            },
            defaultFont: 'Arial'
        }
    },
    basePath: '/',
    transparentBackground: true,
    align: 'center' // equivalent of margin: 0 auto
}, 500, 500);
// do what you have to do..
// ..
// now you want to resize everything?


// set up new canvas size - note that we are going to use
// canvas twice the original size, therefore we will
// need to resize all objects to twice their size
canvas.setSize(1000, 1000);
// check if there are any objects inserted 
// this could be text, images, lines, rectangles, triangles, pencil objects etc..
if(canvas.fCanvas._objects.length > 0) {
    // there are some, loop through them
    for (var i = 0; i < canvas.fCanvas._objects.length; i++) {
        var o = canvas.fCanvas._objects[i];
        o.setScaleX(o.scaleX * 2); // twice the original size
        o.setScaleY(o.scaleY * 2);
        o.setTop(o.top * 2);
        o.setLeft(o.left * 2);
    }
    // render our changes
    canvas.fCanvas._objects[0].canvas.renderAll();
}

How to center and scale image when adding it through API

You can use addImageFromUrl like this:

canvas.api.addImageFromUrl('/1.png', {'centerImage': true, 'scaleX': 2, 'scaleY': 2});

This is just an example, you can use any other parameter - left, top, width, height, rotate, etc..

How to load older canvas when needed ( e.g. when going back in form )

The official documentation is buggy and will end in Uncaught ReferenceError: serializedCanvas is not defined(…)

Best way to get around it, is to use these 2 functions appropriately:
1st/ store canvas data when needed ( e.g. when you are navigating away from this page )

localStorage.setItem('ourdata', JSON.stringify(canvas.getCanvasData()));

2nd/ then you can bring it up next time you go back to that page by placing canvas.loadCanvas(localStorage.getItem('ourdata')); after append. See example:

$(document).ready(function () {
     $('#canvas-editor').append(canvas.getHtml());
    canvas.onInsert();
    canvas.api.startEditing();
    canvas.loadCanvas(localStorage.getItem('ourdata'));
});

Uncaught TypeError: Cannot read property 'find' of null(…)

If you are using backgroundImage plugin, make sure you use

exitOnOutsideClick: false

You can have it automatically turned on like this

$(document).ready(function () {
    $('#canvas-editor').append(canvas.getHtml());
    canvas.onInsert();
    canvas.api.startEditing();

.. and just keep it that way.

Change default drag&drop border color in canvas

canvas.fCanvas.on('after:render', function(){ 
    if(canvas.fCanvas._objects.length > 0){
        for(var i = 0, len = canvas.fCanvas._objects.length; i < len; i+=1){
            canvas.fCanvas._objects[i].borderColor = 'rgba(251,182,74,1)';
            canvas.fCanvas._objects[i].cornerColor = 'rgba(251,182,74,1)';
        }
    }
});

Where 255,181,74 is your new rgb color. Be sure to place this after $('#canvas-editor').append(canvas.getHtml());