Google Customer Reviews and Woocommerce

Google Customer Reviews are available for selected countries now, including The Netherlands and Belgium. At the moment i’m not sure if this service should replace or extend other review services like Trustpilot and The Feedback Company.

To use the Google Customer Review service a is Google Merchant account is required.

To use this service you’ll have to add some JavaScript code to the order confirmation page of your webshop. For Woocommerce you can easily use the woocommerce_thankyou hook to add the JavaScript code. To get the required information of the order you can create a new instance of the WC_Order class inside your custom function of the hook as follows:

$order = new WC_Order( $order_id );

The WC_Order class inherit properties from WC_Abstract_Order which provide you the required information about the customer. Properties for both the customer’s e-mail address and shipping address are available.

The final code for the hook may look like that shown beneath. You can add this code in the functions.php file in your theme directory:

add_action( ‘woocommerce_thankyou’, ‘my_google_reviews’ );
function my_google_reviews( $order_id ) {

// Lets grab the order
$order = new WC_Order( $order_id );
?>
<script src=”https://apis.google.com/js/platform.js?onload=renderOptIn” async defer></script>

<script>
window.renderOptIn = function() {
window.gapi.load(‘surveyoptin’, function() {
window.gapi.surveyoptin.render(
{
“merchant_id”: 11111111,
“order_id”: “<?php echo $order_id; ?>”,
“email”: “<?php echo $order->billing_email; ?>”,
“delivery_country”: “<?php echo $order->shipping_country; ?>”,
“estimated_delivery_date”: “<?php echo my_delivery_date(); ?>”
});
});
}
</script>
<?php
}

As you can see in the above the estimated delivery date value is dynamically set by an other custom function. My custom my_delivery_date() look like that shown below:

function my_delivery_date($send_day = 1) {

if (date(‘N’) === “5” && date(“G”) >= 16) { //vrijdag
$send_day += 3;
}
elseif (date(‘N’) === “6”) { //zaterdag
$send_day += 2;
}
elseif (date(‘N’) === “7”) { //zondag
$send_day += 1;
}
elseif ( date(“G”) >= 16) {
$send_day += 1;
}
return date(‘Y-m-d’,time()+24*60*60*$send_day);
}

The above function is used for my webshops at Webvrouw.nl and Menstruatiecups.nl. For Menstrualcups.eu which has many international orders i can used the same code, after setting $send_day to for instance 3 days.

You can also use the following JavaScript code to set the language of the service.

<!– BEGIN GCR Language Code –>
<script>
window.___gcfg = {
lang: ‘nl’
};
</script>
<!– END GCR Language Code –>

Because of the same code is used to set the language of the badge, i’ve add the language code only to the footer.php file of my theme. The footer.php file also contains the JavaScript code for the Badge. The badge will look like that shown in the figure below:

Badge Google review service

Save

WordPress Development: Properly load your Javascript and set dependency

Theme and Plugin developers should wp_enqueue_script() to load the Javascript sources used in their code. Why should you enqueue? In the first place you should prevent conflict between your scripts. Secondly you should only load the resources you need per page. Load the right scripts only will reduce your load time.

WordPress offers a list of bundled resources like jQuery. So you don’t have to load jQuery every time, but you will have to set the dependency of jQuery of the sources you add.

Enqueueing you scripts proper will also help other theme and plugin developers. When two plugin need the same Javascript library you will load it only once. You will have to realize this in not guaranteed and documented well. If two plugins for example need some plugins of Twitter’s Bootstrap there will be no rules to describe the source already loaded. A solution can be both plugins depends on a third plugin which loads the resources. This kind of dependency is outside the scope of this blog post.

Although the reasons for proper loading seems clear many plugins and themes haven’t enqueued all their code.

Why do developers skip wp_enqueue_script()?

The main reason i found was the use of dynamic variables. Enqueued scripts load before the theme or plugin functions have been parsed in many situations. For example you will set the width of an element by javascript where the width will be user defined. The easiest but wrong solution will be to write it direct to source. Write javascript to source and for example make use of jQuery’s document ready will create a dependency of jQuery.

Solutions to use dynamic variables with wp_enqueue_script:

The first solution will be to write your code in native javascript not dependent of any library.
The second, and preferred solution in my opinion, is to (mis)use the wp_localize_script() function. wp_localize_script() localizes a script, but only if script has already been added. Can also be used to include arbitrary Javascript data in a page. The latest can be used to set your dynamic variables. Also read: Use wp_localize_script, It Is Awesome
Some example:

/** set parameters for display **/

$options = array();
$options[‘color’] = get_option( ‘color’, ‘blue’ );

wp_register_script( ‘color_display’, plugin_dir_url( __FILE__).’display_color.js’, array( ‘jquery’ ), ‘20131108’ );
wp_enqueue_script( ‘color_display’ );
wp_localize_script(‘color_display’, ‘color_display_options’,$options)

With display_color.js:

jQuery(document).ready(function($) {
$('colored').css('background-color',color_display_options.color);
};

Defer loading plugin

Recent i wrote a plugin for Defer loading. This plugin requires scripts are enqueued proper. Testing this i found many issues with different

plugins:

Project met JQuery en phpjs

Voor een project heb ik gebruik gemaakt van JQuery en phpjs. Door gebruik te maken van Jquery als abstractielaag had ik natuurlijk gehoopt incompatibiliteit tussen verschillende browsers te kunnen oplossen. Op de eerst testversie kreeg ik toch te horen dat alles in Internet Explorer niet zo werkt als gemoeten had.

In eerste instantie werd ik gewezen op de live()-functie. Om deze functie te kunnen gebruiken moest ik Jquery updaten van versie 1.2.3. naar 1.3.2. Toen ik dat gedaan had , kreeg ik nog veel meer problemen……

De laatste versie bleek niet 100% backwards compatibel, jammer. Probleem leek hier in te zitten: Old, XPath, style attribute selectors: [@attr=value]. These have been deprecated for quite some time – and we’re finally removing them. To fix it just remove the @!.

Mijn eerste probleem bleek overigens ook niet met de live()-function te worden opgelost. Probleem bleek het uitlezen van een href-attribuut in een link. In dit attribuut plaatste ik een woord wat ik later weer uitlas. Internet Explorer bleek automatische de complete URL voor dit woord te plaatsen. Of dat logisch is vraag ik mij af. Toen kon ik het oplossen door mijn woord te verplaatsen naar het rev-attribuut.

Phpjs spaart nu toch wel wat tijd, al zag ik eerste instantie het nut niet zo. Ik zag het vooral als een leuk project. Tot mijn spijt ontdekte ik alleen dat zowel preg_replace en preg_match nog niet geïmplementeerd waren. Dat waren nu net de functies die ik nodig had…… In eerste instantie leek het mij logisch om deze functie gewoon te schrijven m.b.v. de javascript regular expressions. Kevin van Zonneveld wees meer er echter terecht op dat de javascript (ECMA-262 standard) regular expressions niet gelijk zijn aan de uit perl ontleende versie (The open source PCRE library) gebruikt voor PHP (zie ook: http://www.regular-expressions.info/refflavors.html). Ondanks deze beperking heb ik nu zelf twee functies geschreven, die voorlopig i.i.g. doen waar ik ze voor nodig heb. Beide functies staan hieronder en maken gebruik van: toRegexp(), omdat een regular expression in javascript geen string is. RegExp is een apart type, met twee parameters, daarom is casting van een string naar een RegExp niet mogelijk.


function toRegexp(regexpstring)
{

var result = regexpstring.match(/(\/)(.+)(\/)(.*)/);
return new RegExp(result[2],result[4]);
}

function preg_replace(search, replace, subject,limit,countername)
{
//
// version: 0.0001
// discuss at: http://phpjs.org/functions/preg_replace
// + original by: Bas Jobsen (http://www.w3masters.nl/)
// * example 1: preg_replace(['/^test | test | test$/g','/ +/g'],[' ',' '],'boektest andertest test');
// * returns 1: 'boektest andertest'
//
// * use a global var with 'countername' to count replacements
// * var counter=0;

var s = [].concat(search);
var r = [].concat(replace);
var lim = 0;

var end = s.length;

var j=0;
var k=0;
for(var i=0; i0)?limit:-1;
searchstr = toRegexp(search[i]);
while(lim-- && subject!=(subject=subject.replace(searchstr,replace[j]))){k++;};
}
if(countername)eval(countername+'=k');

return subject;
}
function preg_match(pattern,subject,matchesname,flags,offset)
{
//
// version: 0.0001
// discuss at: http://phpjs.org/functions/preg_match
// + original by: Bas Jobsen (http://www.w3masters.nl/)
// * example 1: var matches = new Array();
// * example 1:alert(preg_match('/boek/','tes/t boektest andertest test','matches',1));
// * example 1:alert (matches[0]);
// * example 1:alert (matches[1]);
// * alerts 1: 1
// * alerts 1: 'boek'
// * alerts 1: 6
// * use a global var (array) with 'matchesname' to get matches
// * var matches = new Array();

if(offset>0)
{
subject=subject.substring(offset);
pattern=pattern.replace(/\^/,'');
}

var result = subject.match(toRegexp(pattern));

if(!result) return 0;

for(i = 0; i < result.length; i++) { eval(matchesname+'['+i+']=\''+result[i]+'\''); } if(flags==1) { eval(matchesname+'['+i+']='+subject.indexOf(result[0])); } return 1; }

Reverse Ajax

Voor een project wil ik het volgende testen: door het oproepen van een URL met parameter, bijvoorbeeld http://www.w3masters.nl/opslaan/?woord=test, wordt de parameter opgeslagen in de database. Na het opslaan in de database wordt in een webapplicatie een pop-up geopend, die de opgeslagen parameter toont.

Dit betekent dus dat de webserver de data naar de webapplicatie (browser) moet pushen. Deze techniek heeft de naam Comet gekregen. (zie ook: http://ajaxpatterns.org/HTTP_Streaming) Het is daarbij niet wenselijk dat er steeds een mysql-query gedaan moet worden om te controleren over er nieuwe data is.

Om dit te bereiken is een extra Comet server nodig. De clients maken een connectie naar deze server en tonen een pop-ups als er nieuwe data beschikbaar is. Bij het samenstellen van de pop-up kan extra data uit de database worden opgehaald. Het script (php) dat wordt aangeroepen bij de eerder genoemde URL, schrijft de parameter naar de database en geeft het ID van de parameter door aan de Comet server. De clients ontvangen het ID en kunnen dus vervolgens de pop-up tonen.

Voor het opzetten van een comet server lijkt Jetty zeer geschikt. Jetty is opensource webserver geschreven in Java. Jetty bevat tevens een servlet implementatie van het Bayuex protocol van cometd. Cometd is een implementatie comet van de Dojo Foundation. Bij Jetty zittten tevens een aantal cometd demo’s, zie http://docs.codehaus.org/display/JETTY/Cometd+(aka+Bayeux). Net als de meeste andere comet voorbeelden, zit hier ook een chat applicatie bij. Met enige aanpassing zou deze applicatie de gezochte functionaliteiten kunnen leveren. Een eenvoudige “hello world” is hier te vinden.
Het Bayuex protocol voorziet niet in autorisatie en/of authentificatie. Autorisatie zou dus via de webserver zelf geregeld moeten worden. Jetty kan dit o.a. met JAAS, zie http://docs.codehaus.org/display/JETTY/JAAS.

Een alternatieve Comet server zou Comep kunnen zijn. Comep is een comet server geschreven in PHP. Comep levert ook enkele voorbeelden mee. Deze voorbeelden leken in eerste instantie niet te werken. Ook Meteor zou geschikt zijn, Meteor is geschreven in Perl. Meteor moet onder poort 80 draaien, wat een nadeel kan zijn als je deze dus wilt gebruiken op een server waar ook bijvoorbeeld Apache draait. De reden die hiervoor gegeven werd was dat Meteor anders vatbaar was voor cross-site scripting. Ik vraag mij af waarom dat op port 80 dan niet zo is? En als dat inderdaad niet zo is hoe dat dan zit met de andere hier besproken servers? Het artikel “Real Time Angst” geeft een zeer mooi voorbeeld van de kracht en mogelijkheden van Comet. Dit voorbeeld is ook op Meteor gebouwd. Hoewel ik dus niet opzoek was naar live data streaming is wel me wel duidelijk geworden dat Meteor een goed opensource alternatief is voor bijvoorbeeld het commerciële Lightstreamer.

Overigens lijkt een server zoals Jetty voor een eerste prototype van mijn project toch nog wat te complex. Het artikel
How to implement COMET with PHP” komt met twee eenvoudigere voorbeelden. De comet server is hier feitelijk een php-script in een ‘oneindige’ loop. Ook wordt geen gebruik gemaakt van het Bayuex protocol. Toch heeft het tweede voorbeeld wel ongeveer de functionaliteit die ik nodig heb. Je kunt regel tekst aan een .txt bestand toevoegen (in mijn geval dus het ID). Op de client wordt deze regel getoond, de laatst toegevoegde regel en alle regels die nieuw worden toegevoegd.