Monday, December 14, 2015

Lentillas ¡Sí!

No comments:
¡¡LentillasSi ya está aquí!! 
¿Usas lentillas? ¿Te salen muy caras y las estiras más de la cuenta? No sufras más, nosotros te vendemos lentillas de reemplazo, es decir, tus mismas lentillas pero a precios de internet. ¿No eres habitual de las compras online? ¿No sabes qué modelo usas? Contáctenos por email: Susana@LentillasSi.es o por teléfono a nuestro número gratuito 900 834 479 y te indicamos.
Además, disponemos de óptica colegiada en plantilla para resolver todas las dudas que puedan surgir.
Síguenos y podrás participar en nuestros concursos y llevarte tus lentillas gratis, enterarte de nuestras ofertas y ¡muchas cosas más!





LentillasSi - Venta de Lentillas Online

Wednesday, December 09, 2015

TPV Virtual, ING Direct, y PrestaShop

No comments:
Soy muy "fan" de ING Direct. Tengo mi cuenta corriente allí desde 2005, y una hipoteca allí. No dudaba en abrir una cuenta negocios con ellos a abrir un nuevo S.L. este año, y también utiliza su TPV virtual.

En general, todo ha sido muy fácil (aún que entre pipas y flautas, tienes que planear con 1 o 2 semanas entre pedir el TPV y empezar a cobrar... ellos primero necesitan unos días para comprobar tu negocio, después pruebas, etc.). Hacen los pagos a través de RedSýs, y RedSýs tiene un modulo gratis para PrestaShop. No pagas por un modulo... los que cobran no te dan nada mas de lo que tiene RedSýs gratis.

El soporte tanto de ING como RedSýs esta muy bien, ofrecen también IUPay, y ahora mismo es lo que estoy utilizando para nuestra tienda.

Pero...

Cuando programaba para los sitios webs www.visiondirect.co.uk, www.lensbase.es, y www.lenshome.es, teníamos 2 opciones a través de PayPoint (que es como RedSýs) que ING no ofrece:

  • "Pago en 1 clic" (clicktopay): después de la primera vez que el cliente paga con su tarjeta, puede hacer futuro pagos con un solo clic, sin la necesidad de entrar todo los datos de su tarjeta. (Ds_Merchant_Identifier)
  • La posibilidad de quitar 3D Secure (Verified by Visa, SecureCode, etc.) en ventas que sabemos que son seguros. (Ds_SecurePayment)
Las dos opciones lo hacia mas simple para el usuario a la hora de pagar, que subía el porcentaje de visitantes que compraba algo. Ahora estoy en búsqueda de un banco con precios razonables que tienen estas opciones. Publicaré todos los resultados cuando los tengo.

Total: si quieres un TPV virtual rápido, barato, y seguro, ING Direct no es mal opción.

Tuesday, December 01, 2015

Redsýs "Auto Return" with PrestaShop

No comments:
A couple of weeks ago, I wrote about my experiences with PayPal Auto Return, and commented that I had the same problem with Redsýs. Redsýs to the rescue... they pointed out that if I entered in my account at https://canales.redsys.es/, click on "Comercios" (sorry, their control panel is in Spanish), Edit, and look for the option "Parámetros en las URLs" (parameters in the URLs). There, they have the option "SI,sin mostrar recibo Redsys" (yes, without showing Redsýs receipt). Choosing "SI,sin mostrar recibo Redsys" will get you Auto Return.

Their auto return IS a bit clumsy... it seems to go through 2 other pages first. However, the first time the client sees that the payment worked (or failed) is on my website instead of somewhere else. This ensures that my Google Tag Manager tags fire correctly.

Thursday, November 26, 2015

PrestaShop Delivery Slip Table

No comments:
This is basically a note to myself: I want a bit crazy searching for where the "delivery slips" were stored in the PrestaShop database. It turns out that there is no "delivery slip" table, rather the delivery slip ID is actually part of the ps_order_invoice table (field delivery_number). The value is filled out whenever an order is set to "Shipped" or "Processing in progress".

Which basically means that PrestaShop is not set up for making multiple shipments on the same order. Not very handy, especially for B2B orders.

Wednesday, November 25, 2015

Composer Packages in PrestaShop (pre-1.7.x)

No comments:
Yesterday, I needed a Composer component for use in my PrestaShop application (I could have used sFTP in PHP in a number of different ways, but after reading the excellent book Modern PHP, I of course wanted a Composer solution to my problem). From reading the PrestaShop Developer's Blog, I knew that version 1.7.x will have Composer integrated into the program, so I needed to set it up in such a way as to avoid future problems.

To do this, I created a "composer" folder deep within my shop (but available from everywhere in case I needed future components), along with a "composer/vendor" folder. I created a composer/composer.json file that looked like this...

{
    "require": {
    }
}

I then set up Composer support in PHPStorm, chose Tools->Composer->Add Composer Dependency, and installed the phpseclib/phpseclib 2.0.0 package. PHPStorm think of everything ;->

My code was then able to use the phpseclib by requiring {full path}/composer/vendor/autoload.php, and creating a new \phpseclib\Net\SFTP class. From there, things just worked.

I then added the composer/vendor folder to .gitignore (as recommended by getcomposer.org), and added, committed, and pushed composer.json and composer.lock (whether to add composer.lock or not is a controversial issue... YMMV).

After reading these two excellent articles, it's clear that composer.lock SHOULD be added to git for my circumstances.

On my Linux server, I pulled the latest code. I found that Composer was already installed, so I navigated to the new /composer directory, and ran sudo composer update install (update when you have not checked in composer.lock, install when you have. Install obeys composer.lock). My new package was added to the Linux server, and the code worked out of the box.

For efficiency, I may decide to adapt this in PrestaShop 1.7.x, but I believe I will be able to use this as-is in future PrestaShop versions if needed.

Tired of using an old SwiftMailer version in PrestaShop? Want to get better logging?  What easier date time handling? With Composer and it's packages, you've got it, plus a lot more.

Wednesday, November 18, 2015

PayPal Auto Return with PrestaShop

No comments:
Kim from Colillas Branding (whose English was so good that I was surprised to see he was Spanish) asked today how to get PayPal to return directly to the website instead of first showing a "confirm payment" page. Returning to the site insures that you have a chance to show your tracking code, as the extra step that PayPal puts in can keep that from happening.

I googled and found the PayPal Auto Return feature, which looked like exactly what I needed. However, the location described in the above link does not exist in my PayPal account (I needed to look under Profile -> Account Settings -> Selling Options -> Website Preferences).

There I could turn on Auto Return, but I couldn't find what the return URL should be set to. There are questions on the PrestaShop forum asking what the return URL needs to be, but no useful replies.

So, time to "use the force.... read the source". In the PayPal module (the official PrestaShop one from 1.6.1.2), they set PAYPAL_RETURN_LINK to /modules/paypal/paypal_login/paypal_login_token.php. I added my domain to the front of that (i.e. I set "Return URL" in PayPal to http://www.mysite.com/modules/paypal/paypal_login/paypal_login_token.php), and it works... I was immediately sent to my shop on payment, the order confirmation page was shown (I'll need to look for that template in the PayPal module and customize it... another item for my to do list), the Google Tag Manager code got called, and the order is marked as paid PrestaShop. Bingo.

Now if I only knew how to do the same with RedSys for my ING payments... Kim! Help! 

Tuesday, November 17, 2015

Contributing to PrestaShop

No comments:
Ever since I started using open source software, I've gotten a lot of help in the various support forums, and try to help others in the forums whenever possible in return.

However, when I posted my "forgotten password" change for PrestaShop, and someone from Bellini Services suggest that I submit it as a pull request to the PrestaShop team, I thought "Yea, well, actually, why is it that I've never contributed to an open source project?" Maybe now is the time to start.

After reading the PrestaShop guide for making pull requests, I decided to wait until after work some day when I wasn't expected home for dinner. However, late yesterday I found a quick one line bug fix in the core PrestaShop code that looked like a good place to get my feet wet.

Following the guide was quicker and easier than I thought, and I had my pull request up in no time. First thing this morning, Maxime from the PrestaShop core code team pointed out that I had actually used the wrong branch for my pull request (I used 1.6 instead of 1.6.1.x), which was simple to fix. Maxime also indicated they would update the documentation to avoid future problems like this. Actually, if I had read this article, I could have saved myself some time.

He also indicated that a new forgotten password feature was already checked into the development branch. This one appears to be pretty much the same as what I coded, so I will skip sending it as a pull request.

All in all, I was surprised at how easy contributing is (thanks to the miracle of git), and how quickly PrestaShop (or at least Maxime) responded. Bottom line: contributing to PrestaShop is easy. I would encourage anyone with the talent to take it up as a hobby 

Wednesday, November 11, 2015

htaccess Tester - Way Cool

No comments:
This is cool... a great htaccess tester from a company called "Made With Love". Looks like the Belgians are not as dumb and clunky as all my Dutch friends say they are ;->

When I lived in Holland, the Dutch busting on the Belgians always reminded me of my favorite Philly DJ's comment (heating up the Philadelphia - Pittsburgh rivalry): "Pittsburgh--where the sky is yellow and brown and the plants are as smart as the people".

Tuesday, November 10, 2015

PrestaShop: Improved Customer Password Recovery

No comments:
Ever since I started using PrestaShop, I hated the password recovery method: send email with link, clicking on link sends you a new password via email.

For me, this method has various problems:
  • Two emails to the client are needed. Not all emails arrive instantly, so this can slow down a customer that wants to do business with you.
  • A password is being sent as plain text to the user.
  • The password auto-generated by PrestaShop is hard for the user to remember.
  • The customer's secure key is sent out as plain text (it's the "token" parameter in the URL of the first email).
Therefore, I decided to change the "forgotten password" feature. My goal was to send ONE email to the user, which directs them to a page to change their password.

The link which allows the password must be unique to the user, can only be used once, and additionally will only work if used within some arbitrary amount of time... let's say one hour.

FORGOT YOUR PASSWORD?


Looking at the code, I decided that a complete override of the PasswordController was needed. I did this as an override. I created the file /override/controllers/front/PasswordController.php, with public function postProcess, and deleted the /cache/class_index.php to make sure my overridden controller gets called.

I also extensively changed my theme's password.tpl to handle the new method. In addition, the text of the template, the error message, and the email needed to be changed to reflect the new implementation.

In order to limit the tokens to 1 hour, I needed to add a new MySQL table.

CREATE TABLE `customer_extra_info` (
  `id_customer` int(10) unsigned NOT NULL,
  `datetime_password_request` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
  `token_password_request` varchar(32) NOT NULL DEFAULT '-1',
  PRIMARY KEY (`id_customer`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

I plan to use this table for more customer specific info, which explains it's "non-specific" name.


Why I switched from Mandrill to Mailgun for PrestaShop

No comments:
I was working on an override of PrestaShop's "forgotten password" feature (article to arrive here shortly) when I ran into a problem... the "forgotten password" email that I was sending to my Gmail account via Mandrill from my RackSpace Cloud server was taking up to 10 minutes to arrive in my Gmail account! 10 minutes may be fine for sending newsletters, but if a customer is in the middle of the checkout process and has to wait 10 minutes for us to respond to his request for help on a forgotten email, we've lost the client.

I started by checking my Mandrill account. I have the free account (up to 12,000 emails a month for free), since I only use it for transactional emails. DKIM and SPF were working, domain was verified, reputation excellent... I saw nothing there that indicated that there was a problem. Their knowledge base had no info on the problem, and since I have a free account, they don't offer support (and I can't blame them ;->).

When reading about the problem, I saw that other Mandrill users were having the same problem. I also saw that Mailgun (owned by RackSpace) offered 50,000 free emails per month for RackSpace cloud users, and thought I would give it a whirl.

After setting up the DNS records and getting the domain verified, I realized that I had PrestaShop configured to send emails via the PHP mail function, and then had Mandrill set up via Postfix. I would assume that is slower than using SMTP directly (which means that my problem may have been a configuration problem), but since I had come this far (and since Mailgun has more free emails per month), I decided to set up Mailgun as my PrestaShop SMTP server.

My tests with Mailgun were mostly arriving in my Gmail account within a couple of seconds, with one taking almost 30 seconds, but it looked acceptable. Gmail's DKIM and SPF authentication tests all passed.

For the moment, I'll stay with Mailgun. I will keep an eye on delivery times, and switch back to Mandrill if I have problems.

Monday, November 02, 2015

How to Make a Copy of the Prestashop 1.6 Bank wire Module

No comments:
In order to make a copy of the Bank wire module (making a Bank transfer module, in my case), I did the following.
  • Make a copy of the \modules\bankwire\ folder and replace the name "wire" in all the file names to "transfer"
  • Search and replace (case sensitive) all instances of "wire" in the \modules\bankwire\ to "transfer"
  • Make copies of bankwire files in \mail and switch the names of the files, and the contents, from wire to transfer.
  • Make a copy of the bankwire folder in \{your_theme}\modules\, and rename the folder banktransfer
  • Search and replace (case sensitive) all instances of "wire" in the files in the \{your_theme}\modules\bankwire\ directory to "transfer"
  • Delete all files (EXCEPT index.php) from /{your_theme}/modules/banktransfer/translations/
  • Add PS_OS_BANKTRANSFER (I used value 99) to the configuration table, imitating PS_OS_BANKWIRE
  • Add values to order_state and order_state_lang imitating bankwire, using the same id_order_state value as PS_OS_BANKWIRE (99 in my case)

Friday, October 30, 2015

PrestaShop 1.6 Shopping Cart Sorting

No comments:
By default, PrestaShop orders the items in the shopping cart by the datetime they were added (order by date_add, id_product, id_product_attributes, from \classes\Cart.php). However, it drove me nuts that changing the quantity of the items in the cart changes their ps_cart_products::date_add, thereby causing the sorting order in the cart to change! Since the normal functioning of the code updates the basket with Ajax, it's usually not noticed by the visitor, but my code (for various reasons) actually performs a full update, which causes the items to jump visibly in the basket.

Although the default PrestaShop sorting is perfectly fine for the majority of users, I have seen people asking about how to change the sort order, and see the questions either unanswered or with answers that change the core code (something I try to avoid).

To "correct" this, I first created the following table:

CREATE TABLE `ps_cart_product_sorting` (
  `id_cart` int(10) unsigned NOT NULL,
  `id_product` int(10) unsigned NOT NULL,
  `original_date_add` datetime NOT NULL,
  UNIQUE KEY `ix_cart_product` (`id_cart`,`id_product`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

I then overrode \classes\Cart.php (by creating \overrides\classes\Cart.php), function getSummaryDetails. I first call the base class to return the $summary_details array. I then add the original date add to each product, and finally sort the array by the original date add.

<?php

function summary_compare (array $one, array $two)
{
    return strcmp ($one['original_date_add'], $two['original_date_add']);
}

class Cart extends CartCore
{
    //----------------------------------------------------------------------------
    public function getSummaryDetails($id_lang = null, $refresh = false)
    {
        $summary_details = parent::getSummaryDetails($id_lang, $refresh);
        if (isset ($summary_details['products'])) {
            for ($jj = 0; $jj < count($summary_details['products']); $jj++) {
                $summary_details['products'][$jj]['original_date_add'] =
                    $this->getOriginalDateAdd(
                        $summary_details['products'][$jj]['id_product'],
                        $summary_details['products'][$jj]['date_add']);
            }

            //Rather than letting prestashop sort by last modified (which moves things
            //around in the cart when changing qty there), sort by the original add_date.
            //Note that prestashop modifies cart_products::date_add every time the qty
            // changes, setting it to currente time.
            uasort($summary_details['products'], 'summary_compare');
        }

        return $summary_details;
    }

    //----------------------------------------------------------------------------
    protected function getOriginalDateAdd($id_product, $date_add)
    {
        $original_date_add = Db::getInstance()->getValue("
            select
                original_date_add
            from
                ps_cart_product_sorting
            where
                id_cart = {$this->id}
                and id_product = $id_product");

        if (!$original_date_add) {
            $original_date_add = $date_add;
            Db::getInstance()->insert('ps_cart_product_sorting', array (
                'id_cart' => $this->id,
                'id_product' => $id_product,
                'original_date_add' => $original_date_add
            ));
        }
        return $original_date_add;
    }
}

Finally, I added the sorting function

<?php
function summary_compare (array $one, array $two)
{
    return strcmp ($one['original_date_add'], $two['original_date_add']);
}

Wednesday, September 16, 2015

NimbleText

No comments:
As a programmer, you always run into situations where you need to process raw text into usable data. If you're a regex genius, or have a lot of free time, you can always write code to handle this. Or you can quickly get results with NimbleText.

It has about a 5 minute learning curve, and for me, "it just works". Highly recommended.

Yet another jewel I first read about on Scott Hanselman's Ultimate Developer and Power Users Tool List for Windows.

Thursday, September 10, 2015

PrestaShop /img dir Backup to S3

No comments:

I have my PrestaShop code plus all my modifications saved in BitBucket and my database backups in S3 (I keep last 7 days, Monday from the last 5 weeks, monthly and yearly backups on S3). However, I didn't want to back up my PrestaShop /img dir in either of the above ways... I don't need img history, just an rsync of the /img folder to S3.


Searching for solutions led me to S3Tools and the like... open source or paid wrappers to bring S3 to the command line. I was more inclined to write something myself... I'm not real happy putting my S3 keys in programs like this.

Then I found AWS CLI from Amazon. It just works! I did a pip install, filled in my credentials, and 2 minutes later had a differential backup working from Linux to S3. Testing with changes, additions, and deletions all worked as expected.

Once tested, I added the below to my nightly cron backup script...

aws s3 sync /var/www/html/img s3://my_prestashop_bucket/img

Friday, August 28, 2015

New GIT Repository -> BitBucket -> Windows

No comments:
Just added my WordPress code to a Bitbucket Git repository. As always when I want to init a new project, I first head over to gitignore.io to quickly get a decent .gitignore file. If you use the service, and your starting from Linux, the tutorial video is worth watching before you start.

After setting up the .gitignore file, in Linux, the following will create your repository...

sudo git init
sudo git add .
sudo git commit -m 'initial commit'

After that, create a new empty repository in Bitbucket, select the "I have an existing project" link, and follow the instructions to your new repository on Linux added to the empty repository on Bitbucket.

Sidenote: when I switched from Mercurial to Git (Mercurial was fine for me... just wanted to get my feet wet with Git), my idea was to use GitHub. However, being in a startup, with a small team, I decided to keep some Euros in my bank account and use Bitbucket, which is free for up to 5 users. I used Bitbucket with Mercurial, so I was already familiar with it, and I'm very happy to stay there.

Next, since I develop on Windows (10), I needed to get the code locally. To do that, I use SourceTree, which makes cloning the repository on Windows a no-brainer.

Friday, August 21, 2015

Quickly Toggle MySQL Logging

No comments:
MySQL logging is a lifesaver when trying to understand applications at a low level. However, since I use it infrequently, I always have to consult the Google doc I have with the details on how to toggle the setting, and where to find the output.

For Windows, I've switched to a BAT file to speed up the process (which I call from SlickRun).

BEFORE using the script, you will want to have the following in your MySQL config file (in Laragon, use the right button menu -> mysql -> my.ini) in the [mysqld] section.

log-output=FILE
general_log_file = "C:/whatever/mylog.txt"
general_log      = OFF

@echo off
set /p state="Set MySQL Logging state ON or OFF: "
c:\xampp\mysql\bin\mysql -u "root" -e "SET GLOBAL general_log = '%state%';
%SystemRoot%\explorer.exe "C:\whatever"

A better alternative is to output to a table. In your MySQL config file (in Laragon, use the right button menu -> mysql -> my.ini) in the [mysqld] section, add

log-output=TABLE (see docs (MySQL 5.7))
general_log      = OFF

Then your script would be

@echo off
set /p state="Set MySQL Logging state ON or OFF: "
c:\xampp\mysql\bin\mysql -u "root" -e "SET GLOBAL general_log = '%state%';

You will find the data in the mysql.general_log table. What I do to make is easier to grok is to create a table with queries that I want to ignore (e.g. the standard PrestaShop code at the beginning of a page load).

create table mysql.general_log_ignores
(
argument_to_ignore mediumblob null
);

and then select only the interesting queries with


select 
       event_time, 
       convert(argument using utf8)
from 
    general_log gl 
    left join general_log_ignores gli on gl.argument = gli.argument_to_ignore
where
    gli.argument_to_ignore is null
order by 
    gl.event_time;

Wednesday, August 12, 2015

AWS S3, PHP, XAMPP, and cURL error 60

No comments:
Due to problems with VirtualBox and Vagrant on Windows 10, I've temporarily moved back to XAMPP for local development. While restoring the backed up databases to my local MySQL, I hit a cURL error 60.

The correct response to this problem was to download a CA Bundle and tell PHP to use it in the php.ini file, e.g.

[curl]
curl.cainfo="C:\xampp\php\extras\ssl\cacert.pem"

However, even after downloading a pem file from http://curl.haxx.se/docs/caextract.html, setting the above, and restarting apache, I was still getting the same error. Since I'm using a phar file for the AWS SDK, debugging the problem was difficult.

A post by GeoffGordon finally solved this for me... downloading a zip file of the pem, and then using the extracted version, fixed this for me. Thanks, Geoff!

--------------------

When using WampServer, I had the same problem, with a different cause. The php.ini file indicated by a php file served from my local server was different than the php.ini file being used by PHPStorm for debugging. I extracted the php.ini used by PHPStorm by debugging a file with the following code.

<?php
ob_start();
phpinfo();
$phpinfo = ob_get_contents();

Wednesday, July 29, 2015

Code Highlighting for Blogger

No comments:
I don't want to change my template. I don't want to pull in the code via JavaScript like gist embedding does. I just want an HTML snippet of formatted code compatible with blogger. Today I'm using hilite.me to format my code. Anyone using anything better?

PHPStorm + xdebug + ScotchBox 2.0

No comments:
ScotchBox 2.0, by design, does not have xdebug installed. They give the following install instructions:

sudo apt-get install php5-xdebug
sudo service apache2 restart

Which works as far as it goes, but even successfully using PHPStorm's "Web Server Debug Validation", and installing and using the Xdebug bookmarklet, I was not able to get the debugger working.

This post gave me the insight that I needed, so I added the following code to the end of my php.ini (sudo nano /etc/php5/apache2/php.ini).

[xdebug]
zend_extension="/usr/lib/php5/20131226/xdebug.so"
xdebug.remote_enable=on
xdebug.remote_connect_back=on
xdebug.remote_host=192.168.33.10

Restart apache (sudo service apache2 restart), run PHPStorm's "Web Server Debug Validation" again, and Bob's your uncle.

Thanks to Joao Paulo for making it simplier.

Saturday, July 11, 2015

mRemoteNG

No comments:
Vagrant boxes, linux servers, and SSH session terminals, oh my! To clean up the mess, I installed mRemoteNG, to put the PuTTY sessions in tabs. Still get to keep my custom settings... just have it all boxed up for neatness now. Recommended.

Note that there are a lot of alternatives, and I just don't have time to try them. A quick trip through Wikipedia has an article on programs, and I see a lot of people using SuperPuTTY.

I'll also have to check out KiTTY on some rainy day, but really I have no complaints with PuTTY at the moment. Should I care about KiTTY if I already have PuTTY working nice?

Wednesday, July 08, 2015

Enable the PrestaShop 1.6 Smarty Debug Console

No comments:
  1. In /config/defines.inc.php, changed _PS_MODE_DEV_ to true.
  2. In /config/smarty.config.inc.php, after the assignment of the $smarty variable, add the following code:
    if (defined('_PS_MODE_DEV_') && _PS_MODE_DEV_)
        $smarty->debugging = true;
  3. In the template (.tpl file) you want to see debug info, add the following line at the very end of the template
    {debug}
  4. MAKE SURE there is a return after {debug}
  5. In the back office / advanced parameters / performance, click the "Clear Cache" button at the top right.
  6. In the URL that you are testing, add the param SMARTY_DEBUG (e.g. http://ls/index.php?id_product=57&controller=product&SMARTY_DEBUG).
  7. Make sure that you are not getting a pop-up blocked by your browser. Once you allow the popup, you will get your console.
  8. If you are still having problems, set the "PS_SMARTY_CONSOLE" value in the configuration table to 1.

Note that San Binario wrote up an alternative method to get the debug console working which changes the core code, which I wanted to avoid. I didn't try their method... but maybe it works better for you.

Thursday, July 02, 2015

PHPStorm Autocomplete for PrestaShop Classes

No comments:
Hmmm, doing a find in files for "public static function isInt" to try to find the validation class (or optionally hitting ctrl+N and looking for the ValidateCore class) is not what I want... I want autocomplete for Validate::(I need the "isDecimal" version).

Julien Bourdeau has the solution, PhpStorm-PrestaShop-Autocomplete. Quick install and just works. Thanks, Julien!

Ah! It's "Validate::isFloat".

Wednesday, July 01, 2015

PrestaShop Admin Area Hook Error Reporting

No comments:
I needed to validate data, report any errors found, and stop the submission of the form while developing a module for the PrestaShop 1.6(.0.14) admin area. However, the documentation was a bit thin on how to do this, and I needed quite a bit of digging before I found what I needed.

I can only tell you 100% for sure that this works for the actionProductUpdate hook, but I imagine it's valid everywhere. Here's a quick snippet to show you the general idea....
 
public function hookActionProductUpdate($params)
{
  if (!Validate::isInt (Tools::getValue('pwr_start')))
  {
    $this->context->controller->errors[] = "Ya screwed up!";
  }
}

There are 3 main things you want to take note of:
  • Use the Validate class to validate your input data
  • Use Tools::getValue instead of directly pulling things from $_GET / $_POST. This does some light purification of the input data.
  • If you want to stop the submit of the form, add the error to the controller's error list. Unfortunately, this is only reported at the top of the form.

Sunday, May 31, 2015

Download a RackSpace Server Image

No comments:
I needed to download one of my Rackspace cloud backup images to my computer for use with VirtualBox. I assumed I would be able to simply download it, but to my surprise, that´s not possible. Rackspace suggested I use their API and their "getting started" tutorial, and upvote the request to add direct image download as a Rackspace feature, which I did.

NOTE: Be aware that, at least with a CentOS 7 Cloud Server, the image you download with the following method is ONLY compatible with XenServer, a Type 1 Hypervisor. It simply did not work with VirtualBox. I saw one report that you can load it with VirtualBox, but Rackspace themselves says it will not work and suggests this method instead.

I got my Rackspace cloud API token, and used curl from my Rackspace server to do the following:

  • Get export endpoint (which is based on your server region) and authentication token using these docs. The export endpoint is the "cloudImages" "publicURL", and the authentication token is the "access" "token" "id".
    curl -X POST https://auth.api.rackspacecloud.com/v2.0/tokens -d '{ "auth":{ "RAX-KSKEY:apiKeyCredentials":{ "username":"RACKSPACE_USER_NAME", "apiKey":"API_TOKEN" } } }' -H "Content-type: application/json" |python -m json.tool
  • Export your account and authentication token (NOT your API token).
    export account="RACKSPACE_USER_NAME"
    export token="
    AUTHENTICATION_TOKEN"
  • Combine your endpoint URL with the calls from this article to get your list of images.
    curl -s https://lon.images.api.rackspacecloud.com/v2/images -H "X-Auth-Token: $token" |python -m json.tool
  • Asynchronously export the image your interested in (check the "image" "name" field to find the one you want) by using the image "id" and the name of you Cloud Files container. If you don't have a Cloud Files container (I didn't), you have to sign up for it to get exported images.
    curl -s https://lon.images.api.rackspacecloud.com/v2/tasks -X POST -d '{"type": "export","input":{"image_uuid": "IMAGE_ID","receiving_swift_container": "YOUR_CLOUD_FILE_CONTAINER"}}' -H "Content-Type: application/json" -H "X-Auth-Token: $token" |python -m json.tool
  • You can now simply wait for your image to appear in your cloud file container, or you can actively check the status of you export job by using the id returned by the export command.
    curl -s https://lon.images.api.rackspacecloud.com/v2/tasks/EXPORT_JOB_ID -H "X-Auth-Token: $token" |python -m json.tool
  • If all goes well, you can pick up your image from the cloud file container. Mine took about 5 to 10 minutes to appear.

Friday, May 29, 2015

Adjustable Height Desks - cheaper version

No comments:

Ever since I started reading about it years ago, the idea of an adjustable height desk really intrigued me. Back when I wanted to be a writer, I remember reading about Hemingway using a standing desk, and I've since learned that luminaries such as Ben Franklin and Winston Churchill did the same.

I badly wanted to switch both myself and my staff to adjustable height desks, but could never convince myself to pay the cost. However, in 2012, Susana was able to buy motor driven adjustable height tables for everyone at 443 EUR each from http://www.schaefershop-industrie.es/. These tables have been great for sitting less, and also for breaking up the day.

Standing can be overused (standing for long periods of time can cause varicose veins), and I could not find any long term, detailed studies that back up claims that switching between sitting and standing is healthier and makes you more productive (the standard claims), but I do like having the option to switch between both, and I DO feel that it makes me healthier and more productive.

When I was on my flight back from Düsseldorf yesterday via Air Berlin, I saw an ad for Veridesk that I wish I had seen back before we bought our desks. If you want the benefits of a standing desk without as much cost, then Veridesk might be a useful alternative.

Hmm... looking at their site, maybe I should look into getting a standing mat....

Monday, May 18, 2015

PuTTY - Script Output in Different Color

No comments:
I was writing a shell script with rather verbose output, and was getting confused with which output was from which invocation of the command. I started clearing the screen between commands, but sometimes forgot. There's got to be a better way....

How about if I changed the color of the output? This article turned me onto the basic method, which had to be fine tuned due to my use of the zenburn color theme. Also, I found that, for some reasons, the color macros that work on the command line were not working in the scripts. Doesn't matter... I can now start and end scripts with commands to change color, and get the output in a different color....

So, a shell script (myscript.sh) like this...

#!/bin/bash
echo -e "\e[0;32m----------------------------------------------------"
echo "My Script Output"
echo -e "----------------------------------------------------\e[0m"

Will output the following (assuming you are using the zenburn color theme)....
[root@local ~] ~/myscript.sh
----------------------------------------------------
My Script Output
----------------------------------------------------
[root@local ~]

Friday, May 15, 2015

CentOS 7 Hostname Resetting on Reboot - SOLVED

No comments:

Problem

Setting the hostname was working without problems in CentOS 7 (including latest updates), but the hostname would revent back to the old hostname on every reboot. Nothing I read about worked, and I see lots of other people with the same problems (although RackSpace could not reproduce the problem on a newly spun up CentOS 7).

Solution

Assumes you're running as root. Otherwise, sudo the commands
  • Backup /etc/hosts, /etc/sysconfig/network, /etc/sysconfig/network-scripts/ifcfg-eth0 and /etc/cloud/cloud.cfg
  • execute "hostnamectl set-hostname yourdomain.com"
  • execute "hostnamectl set-hostname --static yourdomain.com"
  • Change old hostname to yourdomain.com in /etc/hosts
  • In /etc/sysconfig/network, add
    HOSTNAME=yourdomain.com
  • In /etc/sysconfig/network-scripts/ifcfg-eth0, add
    HOSTNAME=yourdomain.com
    DHCP_HOSTNAME=yourdomain.com
  • in /etc/cloud/cloud.cfg, set
    preserve_hostname=true
  • Reboot
  • hostname and hostname -f should now correctly give yourdomain.com

Wednesday, May 13, 2015

Windows PuTTY Tips

No comments:

  • Make a .reg file with your color scheme and font to easily apply it to new sessions (since the default dark blue folder names on black background is just a pain in the butt). Just add the name of the session and run the .reg file. I use the zenburn color theme with a larger font.
    I also change my LineCodePage to UTF-8, which is necessary on CentOS7 - ymmv.
    Here is a gist of my customized zenburn.
  • F6 gets you the tilde character in putty (useful for non-US keyboards), which is the path to your home directory.
  • nano ~/.bashrc opens a file where you can define aliases to make your work easier. Of course, this will only be available on the machine you are working on, but if you work on the machine a lot, it's well worth the time to make aliases. Much, much more can be added... search bashrc some day when you're bored
  • I like: alias dir="ls -CFhal"
  • Also, alias bashrc="nano ~/.bashrc && source ~/.bashrc && { echo -e 'Success--'; cat ~/.bashrc; } | mail -s 'bashrc backup' 'you@yourdomain.com'". This open bashrc for editing, puts any changes you make live, and emails you the script so you have a backup. Like, wow!
  • Add scripts to bashrc, which are available from the command line. To backup a file by sending it to an email address (always a good idea before you make any changes to files via the shell), add this to .bashrc
    bufile() {
            file_to_backup=$1
            { cat $file_to_backup; }  | mail -s "'$file_to_backup' Backup" 'you@yourdomain.com'
    }

    ...and then call it from the shell
    bufile index.php

Thursday, May 07, 2015

PrestaShop 1.5/1.6 and the Google Tag Manager

No comments:

Adding Page View Tracking

Most PrestaShop themes use one header.tpl for all pages on the site. This post assumes that is the case with your theme... if not, apply everything about header.tpl to all your headers.
  • Set up a GTM (Google Tag Manager) container, etc., and copy out the GTM snippet
  • open header.tpl
  • Look for the body tag
  • IMMEDIATELY after the end of the body tag, add...
     {literal}
    [your GTM snippet]
    {/literal}

    e.g.
  • NOTE FROM 2018: This article is rather old, and the newest GTM installation code from Google also talks about adding code right after the "head" tag, which could also be done in the header.tpl file. Thanks to Oliver Gerber for pointing that out.
  • Add a tracking tag to GTM
  • Preview and debug your GTM code.
  • Publish the GTM container

Adding Transaction (Conversion) Tracking

Adding page view tracking is super simple. Adding conversion tracking requires a data layer, which I added with a module.
IMPORTANT: For this code to fire, your payment method modules need to be calling PrestaShop after payment. E.g. here are the changes I needed to make to get this to happen with PayPal. As far as I can tell, this "problem" exists for both my module, and for the PrestaShop Google Analytics module.
  • Install the PrestaShop module "Data Layer Module" (instructions for installing a PrestaShop module can be found in the PrestaShop Documentation). This is simply a copy of the ganalytics module with lots of code removed and analytics JavaScript adapted to the GTM. It's a VERY basic module that any PHP coder can understand and expand on.
  • In GTM, add a new Google Analytics transaction tag... named something like "PrestaShop Conversion"
  • Add a firing rule (a.k.a. a Trigger) named e.g. "Order Confirmation" with values {{event}} equals prestashop_order_confirmation (prestashop_order_confirmation is an event that I trigger in the Data Layer Module) for the conversion tag.
  • Preview and debug your conversion tracking.
  • Publish the GTM container

Adding Site Speed Tracking

Speed of your website is fundamental to a good conversion rate. In addition, it effects your ranking in the serps. Monitoring your page speed is an important KPI.
By default, GTM and GA track your site speed, but using only a 5% sampling rate. That's perfect if your Amazon, but many sites need 100% sampling to get good data. Here's how to get this up.

  • In GTM, open your page view tracking tag
  • In the "Fields to Set" section, add a new field called "siteSpeedSampleRate"
  • Set the value to 100 (= 100%) 
  • Preview and debug your GTM code.
  • Publish the GTM container

Notes

  • Always push when using the data layer! See Simo Ahava's article on the subject. Actually, read all of Simo Ahava's articles... he's a great resource.
  • This code was written for a site which only has PayPal as a payment option. Theoretically, it should work for other gateways (it's not at all PayPal specific). I would be interested in hearing of your results if you use this with other payment gateways.

Friday, March 06, 2015

Spidering and Parsing

No comments:
I needed to pull English product reviews from an English language version of a site and put them in Excel files for translation to Dutch, and rather than doing things one by one, I decided to code the work, resulting in this quick note on spidering and parsing in PHP.

For my purposes, PHPCrawl "just worked". I'll post again if I find something better, but so far, no need to look.

Rather than regexing the page contents, I wanted to to query the HTML. There are an AMAZING number of options, and the first two I tried "just broke" (one was Simple HTML DOM, and the other I'm not sure), since the pages I'm trying to parse are rather complicated.
Simple HTML DOM also had the additional disadvantage of being dead slow.

I am now working with the DOMDocument class, based on the comments on this excellent stack overflow post. So far, so good.

Update: This article by Ersin Kandemir was helpful as is, but additionally sent me to the XPath Helper Chrome extension (by Adam Sadovsky), which was also a big help (hint: not only does it show you xpath commands, it also lets you test your own commands on the current page). Thanks guys!