WP All Import cron from CLI (update)

My previous post about executing the WP All Import cron jobs with PHP cli didn’t work too well. Apparently the processing part still stops executing after a while. I ended up with import jobs stating “last activity 5 hours ago”.

Still I don’t want to run this through the webserver. So I wrote a little wrapper shell script to execute my imports in cron. It checks if the line “is not triggered” was partially returned. The wp cron script would return “<p>Import #26 is not triggered. Request skipped.</p>” if you execute the processing action without triggering it first. In other words: the import is really complete now.

I put the shell script outside my document root, and it uses the “logs” directory to store the log files. So make sure this directory is writable and points to the right path.

Now just put this in your /etc/cron.d/yoursite:

 

WooCommerce: remove empty SKU products

At work, we got ourselves a nice WooCommerce shop. Using WP All Import, it automagically imports the products and updates stock. But somehow in we ended up with products in our database with no SKU.

Removing one of those products, and then rerun the import, seemed to work. So maybe these products where in the product feed once without a SKU. Who knows. Anyways, I wanted them gone, and didn’t want to delete the entire database, afraid of what Google may think of that.

So I checked the database a bit and came up with a SQL query. First, to check if you have products with empty SKU’s as well, you could run something like this:

To remove the products, I think this should do. Of course this wouldn’t delete the files in your upload folder. If you want to delete those as well, you might want to write a script that selects the records, and then removes the images as well.

 

Forms in Symfony2: dependent selectboxes

My wish was simple: I wanted to have an extra dropdown box, to be able to filter a table, so the second dropdown box would have less items. So the second dropdown box depends on the first. I found two nice articles about this, but I missed a few things before I got it to work. This post tries to describe what my pitfalls were.

The great articles I found were: Symfony2.4: Dependent Forms and Symfony2 – Dynamic forms, an event-driven approach

The difference with my approach is: building the lists of the selectboxes should be inside the form builder. This way I think it’s more reusable and code is in one place. I don’t want to write extra methods in my controller to fill the selectboxes with javascript. My idea was just to submit the form, and let the form figure out what it should do: save the object, or fill the second list with options.

To describe my pitfall’s, I better first describe my situation. I changed the use case for the sake of this article, but it’s the same with my problem. Suppose you have a Person who can own several cars. On the person edit page, where you can edit his name and other properties, I wanted to add a table with the cars he owns. Under this table I have action buttons for New, Edit and Delete. When you use new, the div on that page is reloaded with the form, so the page isn’t reloaded, you are still on the edit Person page.

This would be my database model:

Forms in Symfony2: model used in this example

The list of cars with all their types would be huge, so I wanted to select the Brand (Opel, Mercedes, BMW) first. This wasn’t a value that I should save to my Person_has_Car model, so I set mapped to false. This was my main problem, because now this value wouldn’t be mapped to the entity, so how should I read it?

Initially I wanted to post the BrandId to the form, and based on this BrandId I wanted to build the select. I found that the PRE_SUBMIT and POST_SUBMIT weren’t called when you don’t submit the entire form. Probably because of CSFR that doesn’t match.

Then after a long search I found that at the PRE_SUBMIT Form Event, the data was just an array instead of an object.

Well, after a few days of frustration, googling, trying, googling and trying, this is what I came up with. Maybe it’s not the best approach, but it seems to work.

So Image that you are on a “User edit” page, and you want to add a car to his account.

Form

My form class PersonHasCarType would be something like this:

Twig template

The (simplified) twig form would look something like this:

The $.parseHtmlBlock is just a little code snippet that replaces HTML based on a json response. It also does some initialisation. The snippet looks like this:

Note the clearOnChange in the javascript that clears the second selectbox (if it exists) with empty values. If I don’t do this, the form has validation errors the second time you change the brand of the car. This was an easy hack to prevent this, and also I think it’s actually not that bad to reset invalid fields.

Controller

Now my controller is something like this:

So basically we now have a form that submits itself whenever the first selectbox changes. The controller checks if the form is fully entered by checking if the car object is set. This approach will probably conflict if you use validation. But for me this seems to work in my application.

WP All Import cron from CLI

The WP All Import plugin can be used to import data from xml feeds. We use it in combination with WooCommerce. To automatically update your products and/or stock information, you should run this from a cron job. Unfortunately WP All Import didn’t do a very nice job on integrating this with the WordPress cron system, because I feel that the scheduling should be manager from your WordPress install instead of cronjob settings on the server.

WP All Import suggests that you set a cron job where you request an URL with wget. They already noticed a possible issue with this approach, which is timeouts. Therefore they created two actions: one to trigger the import, and a second one to process the import. When a timeout occurs, the process action should continue where it left of.

In our situation (nginx + php-fpm) this didn’t seem to work very well. The script was aborted after 30 seconds (which is what we have configured on the server ourselves), but when I re-requested the processing action, it said I should run the trigger action first. So, did the processing complete or not?

Since I don’t like running web requests from cron anyways, I searched for a method to run the import with PHP cli. This way we don’t have timeouts and the script will execute nicely. Also you can skip the “The processing URL should be run every two minutes because it may not finish your import in one run.” because it’s very unlikely that the script will timeout.

Enough chichat, here’s the line I added to /etc/cron.d/mywebshop:

Don’t forget to change the path to your WordPress install, and the import_key.

Dynamic path tags in twig template

So I wanted to create a twig template that would render a table, just by defining the table headers, and pass an array of entities. The problem was that I also wanted to add action buttons like edit and delete, but the URL should be created dynamically with a changing ID. This is what I came up with.

So along with the array of entities that are passed to the twig template, an array with table Headers is being added too. The array with headers contains the id inside the entity, the name of the header, and the third element is the ‘type’. This way I can render the field as a date/time object. I also use this to set the type to action, which means I have an array with action buttons.

Then in Twig, I render the table like this:

The array with options that is being passed to Twig’s path tag, is being build up in Twig itself.

Solution to: Sender ID (PRA) Not Permitted

I knew that Microsoft’s Sender ID wasn’t a perfectly implemented solution, but I never investigated why. Now I know. Because despite using a dedicated company to send our mails through (SendGrid at this moment), we still got a bounce saying “Sender ID (PRA) Not Permitted”.

The reason is that Microsoft uses the SPF policies wrong. You can read all about it at the SPF vs Sender ID article. From what I understand from this article, all you have to do is add an extra TXT record to the DNS of your domain, with the contents “spf2.0/pra”.

Microsoft’s Sender ID Framework SPF Record Wizard recommends “spf2.0/pra ?all” though, so I went with that.

Of course you need to have already working SPF records for this to work.

Clickable panel titles at Metronic theme

I wanted the panel titles to be clickable as well, instead of just the little icon on the far right side of the panel. This is easy with just a little javascript.

This is specific for the Metronic theme. This code was placed in the /assets/scripts/core/app.js ..

HP Laserjet 400 issues with PDF on os x

Although we kind of regret we purchased this printer when we switched to MacBook’s, here’s one thing I seem to have ‘solved’. We received an invoice in PDF that could not be printed to our HP printer. We also tried our old HP Laserjet 1320, and a collegue also tried at home. All it printed was garbage high ascii stuff.

I figured it must we a problem with PCL drivers and HP. Maybe a problem of CUPS, or bad os x drivers, who knows?

Then we received a PDF from our Chamber of Commerce, and it said it was digitally signed. So then I realised it could also be a problem with this signature.

I installed Adobe Reader to open the PDF instead of the default Preview app that was already installed. Now I was able to print the Chamber of Commerce document just fine.

So now only the problem of really really slow job processing (or no processing at all) remains. Usually this can be fixed with turning the printer off and on again, but for a device that costs a few hundred euro’s this isn’t what we expected.

Active menu determination in Metronic theme

So we bought the Metronic theme from keenthemes. It’s fully featured and packed, but I was wondering how the theme determines what the active link is. Browsing through the comments I found out that we’re supposed to handle this ourselves, server sided. No fancy javascript that handles this from itself.

Fortunately I found a way to determine the route in Symfony. This returns the name of the route, not the result form path. So now it’s easy to compare your current page. All I had to do is put this in Twig:

But if I use submenu’s, how would I know what parent menu should have the active class as well? Easy: just check for the first part of the route (if you set your routes smart enough though). So if you have a menu called “promotion” where you have sub menu’s like “create, list”, you might want to name your routes like _promotion_new and _promotion_list. At the parent menu item promotion you could easily check if the route starts with _promotion_. The substr equivalent is slice. So the HTML for the parent menu item would have something like this:

If you named your router less ‘smart’, you could use a larger OR compare in the if statement.

Easy does it.

Symfony translations using PoEdit

For my Symfony project, that has to support two languages, I started with created a xliff file manually. This was really annoying. Not only the creation of the xml, but also the inability to see if you didn’t already translate this string. So, I wanted to use Poedit. But this wasn’t so easy.

I needed to create .po files, which are the uncompiled language files that contain all translations. Actually, a .pot file would even be better. I didn’t know how to extract the strings.

The LeaseWeb gettext bundle looked great, but I already had used normal translation strings in twig, like {% trans %} and {% endtrans %}. I didn’t want to refactor my whole project, just to be able to use gettext (with a third party bundle anyways). It might be a good option if you start your project from scratch though.

So then I found the Twig Gettext Extractor. This seemed rather complicated, as I never worked with Poedit before too. I am working on a Mac, and my code is on a virtual machine. This project seems to be about a tool that extracts the language strings from Twig. I decided to give it a try, and installed the project standalone.

When I tried to run through the project in Poedit, it came up with an error. I copy and pasted the commands in my terminal, and found out that it couldn’t render the Twig template, because I was using KnpPaginatorBundle. It didn’t understand a twig function that it was using.

Ok, fair enough, so I decided to add the bundle to my Symfony project. It didn’t help much: it was still throwing php errors, so it couldn’t extract anything.

Then I tried the JMSTranslationBundle for a second time. I had already tried this, but when I ran

as stated in the docs, it would output to xliff again. I don’t exactly remember why, but I installed the bundle again, and ran this extract again. This time, a .mo en .po file were present in my /Resource/translations bundle. To my great surprise, it now updated this .po file!

I was also surprised, because the website says the bundle doesn’t support .mo files.

 

Anyways, it turns out it is supported. At least on Symfony 2.3.6. The command you need to issue on an empty translations directory is this:

After that you can update your translations with this command:

Still, I think I am missing something in the workflow. When I add new strings to be translated to my project, the strings are added to the .po file, but they are not marked as “new” in Poedit. So it’s difficult to see what strings still need to be translated.

But, it’s much better than creating those language files by hand.