Drupal Lightbox2 and Paging

So I had a strange problem with an ecommerce site Im developing. The site shows in the front page some products. The Owner told me to put a button with the magnifying glass over there, and when clicked, make it appear a modal box that shows more info of the product.

The Magnifying Glass in all it splendor

So hands at work, i use the lightbox2 and views module to make something like the owners command. The frontpage must show 8 products and if we have more, use a pager to navigate between products.

This is the pager, just in case youre asking what is a pager.

The problem? The view use paging so i show only the first eight products in the first page but if we go to the second page, problems occurs. The lightbox show all the modal boxes with the information of the first page. Oh god i smell some bug induced headache soon


The Solution
So after an entire day of debuging I found the problem: Lightbox2 is not taking in account the page you are when it retrieve the data. Basically lightbox2 use the load() function of jquery to get the WHOLE page it need to extract the info. The url of the page is inserted by lightbox2 usign the template in the file lightbox2_handler_field_lightbox2.inc

You have to change the line 124 like this:
Before:

// We don't actually use the link, but we need it there for lightbox to function.
if (empty($link)) {
// Get the path name.
$path = isset($_GET['q']) ? $_GET['q'] : '';
//Created By Carlos
}

After:

// We don't actually use the link, but we need it there for lightbox to function.
if (empty($link)) {
// Get the path name.
$path = isset($_GET['q']) ? $_GET['q'] : '';
//Created By Carlos
if(isset($_GET['page'])){
$path = $path .'?page='.$_GET['page'];
}
$link = url($path, array('absolute' => TRUE));
}


I just get the GET value of the current page and if it have a variable called page, append ?page= and the number of the page to the path that will be inserted in the lightbox trigger. Question anyone?

Adding new fields to the Ubercart Checkout module

So, you are using Ubercart and Drupal, but the checkout address fields isnt enough for you. Lets say, you need to add some more fields like a cellphone number or a district field. Well you have come to the right place, but before this, let me give you some advice.

Before the hack/slash
  • There is a module called Extra Fields, that give you the ability to input some extra fields to your checkout page. But you can't insert your fields to the billing and delivery panel. It just create a new panel to put that extra info. Maybe with some CSS and JS you can move the extrafields to the biling and/or delivery panel.
  • There is a webform to ubercart checkout module, its in beta stage, if you need more thant text boxes maybe this is the module you are looking for.

Into the Abyss
This tutorial is not for beginners, but with a little know of copy and paste you can do the magic. User with a cpanel hosting can use the file manager and phpmyadmin to easily modified the required files and tables.

Also remember that hacking your Drupal Files is not something that i recommend, but in some cases, its the only way to do things here. I didnt know too much about hooks in Drupal, but for what can i see in the code, i think it isnt possible for this Ubercart version to create hooks to modify the delivery and billing panels.

Step o : Requisites:
Obviously you will need to install
Ubercart 2.X with all the required modules. I used Drupal 6.15 for this tutorial, but I think it will work well with any Drupal 6 version.

Then, fill your Drupal+ Ubercart installation with some products and the info of your store. Make sure you install the checkout module of Ubercart.

Next step is creating a backup of your files and your database. You are not going to advance to the next step until you make your lifesaver backup. Seriously dont go ahead without your backup.

Also, before we going any further, theres something strange i need to explain first. The checkout panel contains two important panels, the delivery panel and the billing panel. Essencially those panels share the same fields, and, for some strange reason in ubercart, if you only need a field in one panel, you are going to create it in both panels and save that info in your database of both fields.You can hide one of them if you dont need it anyway.

In this example I'm going to create a new cellphone field for the billing and delivery address.

Step 1 : The database

First we need an identifier name for our new field. It should be a word in lower case. In my example I will just call it cellphone. Next thing is insert that variable in our database.
  1. Use any DB manager (here im using phpMyAdmin) to update the table called variable and search for the row with the name uc_address_fields. This row contain the list of all the variables used in the checkout panel. Dont be scare, the text here is just a serialized php array. Now add a line containing something like this: s:9:"cellphone";s:9:"cellphone" (sic) somewhere between two semicolons, just like my image. Notice that you are going to repeat twice your new field. And for the curious s:9 means [s]tring of nine spaces. cellphone is a word with 9 letters. Just look how the other fields are stored here.
s:9:"cellphone";s:9:"cellphone";

2. Add the fields billing_identifiername and delivery_identifiername. to the uc_orders table. In this example im going to create billing_cellphone and delivery_cellphone. Its doesn't matters if you are going to use only one of them, you will need to create both.

The new fields on the uc_orders table

And thats its for the database. The next step is modifiendo the uc_store.module file.

Step 2 : Playing with ubercart/uc_store/uc_store.module file
Here is where the copy&paste party begin:
  1. Search for the function uc_store_address_fields_form() that should be around the line 702. Now you see that big array? just add a field that identify your new field. I suggest using your identifiername for the array.

$fields = array(
'first_name' => array(t('First name'), TRUE),
'last_name' => array(t('Last name'), TRUE),
'phone' => array(t('Phone number'), TRUE),
'cellphone' => array(t('Cellphone number'), TRUE),
'company' => array(t('Company'), TRUE),
'street1' => array(t('Street address 1'), TRUE),
'street2' => array(t('Street address 2'), TRUE),
'city' => array(t('City'), TRUE),
'zone' => array(t('State/Province'), TRUE),
'country' => array(t('Country'), TRUE),
'postal_code' => array(t('Postal code'), TRUE),
'address' => array(t('Address'), FALSE),
'street' => array(t('Street address'), FALSE),
);

What is that t() function surrounding the text? It just a drupal functions that allow that text to be translated. Just
copy it as you see here.

2.- Now, next to that big array you just modified, there is a line under it,with a function called variable_get, it could be the line 728 but in any case it should be nearby. Add your identifier name inside single quotes as a parameter of the drupal_map_assoc function, like this:
$current = variable_get('uc_address_fields', drupal_map_assoc(array('first_name', 'last_name', 'phone', 'company', 'street1', 'street2', 'city', 'zone', 'postal_code', 'country','cellphone')));
3. Now go to the function uc_get_field_name that should be near the line 1177 and you will see another array. Just copy and item of the array and paste it and change it using your identifier name like this: 'cellphone' => t('Cellphone number'),

4.Next, go to the function uc_address_field_enabled near the line 1207 and you will find something like step two. Just add your identifier name as the last parameter of the drupal_map_assoc function.

5. This is the most important step on store.module, coz this is where you tell the database to obtain the address values. Go to the function uc_get_addresses near the line 1442 and you will see two database queries one for Mysql and the other one for Postgres. Modified the sql that you use, should be like this using the mysql select:

$result = db_query("SELECT DISTINCT ". $type ."_first_name AS first_name, "
. $type ."_last_name AS last_name, ". $type ."_phone AS phone, "
. $type ."_company AS company, ". $type ."_street1 AS street1, "
. $type ."_street2 AS street2, ". $type ."_city AS city, "
. $type ."_zone AS zone, ". $type ."_postal_code AS postal_code, "
. $type ."_country AS country, "
. $type ."_cellphone AS cellphone FROM {uc_orders} WHERE uid = %d "
."AND order_status IN ". uc_order_status_list('general', TRUE)
." ORDER BY created DESC", $uid);

6. Now lets get back to line 336, here we are going to copy and paste one of those lines below, copy it and change it. With the cellphone example it should be like this:
  $conf['i18n_variables'][] = 'uc_field_cellphone';  

Step 3 : Playing with ubercart/uc_order/uc_order_order_pane.inc
This is easiest. There are two modifications, one for the delivery and one for the billing:

1. For Delivery: Go to the function uc_order_pane_ship_to and you will see a switch case. Look for the 'edit_form' case in line 27, this is where you have to copy&paste one of the if, and make 4 changes. Heres an example of before (phone) and after (cellphone).

    Before:
if (uc_address_field_enabled('phone')) {
$form['ship_to']['delivery_phone'] = uc_textfield(uc_get_field_name('phone'), $arg1->delivery_phone, FALSE, NULL, 32, 16);
}
After:
if (uc_address_field_enabled('cellphone')) {
$form['ship_to']['delivery_cellphone'] = uc_textfield(uc_get_field_name('cellphone'), $arg1->delivery_cellphone, FALSE, NULL, 32, 16);
}
Once you have done this, you can modified the line 24 (the view case) if you want that the info fo your field appears in the Orders options of ubercart, the page where you see the data of your order as an admin. This is an example with the line 24 modified for cellphone

$output = uc_order_address($arg1, 'delivery') .'
'. check_plain($arg1->delivery_phone) .'
'. check_plain($arg1->delivery_cellphone);


2. For Billing, just repeat this step but look out in the line 122. if you want the billing data to show in your Order page, just modified the line 112 like in the delivery example.

Step 4 : Playing with ubercart/uc_order/uc_order.module file

1. (Optional) Add our field as a token. go to the line 407 inside the function uc_order_token_values. Here you should copy one of those lines, paste and modified it. Create one line for the billing and one for the delivery. In my example it should be like this (the red part is the new):

$values['order-shipping-phone'] = check_plain($order->delivery_phone);
$values['order-shipping-cellphone'] = check_plain($order->delivery_cellphone);
$values['order-billing-cellphone'] = check_plain($order->billing_cellphone);
$values['order-shipping-method'] = is_null($ship_method) ? t('Standard delivery') : $ship_method;


2. (Optional) Give a description of that token. Go to the function uc_order_token_list, near line 441 copy an paste one of those lines. Heres an example for the billing an delivery description:

$tokens['order']['order-shipping-cellphone'] = t('The cellphone number for the shipping address.');
$tokens['order']['order-billing-address'] = t('The order billing address.');
$tokens['order']['order-billing-phone'] = t('The phone number for the billing address.');
$tokens['order']['order-billing-cellphone'] = t('The cellphone number for the billing address.');


3.The code that save your field in the db. Go to the function uc_order_new near line 1013 and search inside it for an sql with the insert command. Modified it so it insert data into the rows create in step1. Remenber one for the delivery and one for the billing field. The sql would look like ( the ... is a resume, dont take it literally!!!)

db_query("INSERT INTO {uc_orders} (..., created, modified,billing_cellphone,delivery_cellphone) VALUES " ."(..., %d, '', '')",

4. The code that update your field in the db. go to the function uc_order_save near the line 1046 and look for the sql that update your data. Modified it so it update your field.

Step 5 : Playing with ubercart/uc_cart/uc_cart_checkout_pane.inc file
1. Modifing the checkout_pane_delivery hook. This hook is called to interact in the checkout module of Ubercart. Go to the function uc_checkout_pane_delivery near the line 224, copy and paste one of those if statement inside it and modified it according to your identifier word, like this:

if (uc_address_field_enabled('cellphone')) {
$contents['delivery_cellphone'] = uc_textfield(uc_get_field_name('cellphone'), $arg1->delivery_cellphone,uc_address_field_required('cellphone'), NULL, 32, 16);
}


2. Go to the case 'process' near line 292 and copy and paste one of those $arg1, modified it accordly:
$arg1->delivery_phone = $arg2['delivery_phone'];
$arg1->delivery_cellphone = $arg2['delivery_cellphone'];


3. Reviewing your field (optional). Go to the case 'review' near line 293. This line is called to review the data of your field when a client make an order.I just copy and paste some text there but maybe you would need some more exotic validations here.

if (uc_address_field_enabled('cellphone') && !empty($arg1->delivery_cellphone)) {
$review[] = array('title' => t('Cellphone'), 'data' => check_plain($arg1->delivery_cellphone));
}

4,5,6 This is the same as 1,2,3 but is for the billing panel. Go to the function uc_checkout_pane_billing in line 371 and modified it if you wish to have an field in the billing pane.

NOTE: you can choose here to do only a field in the delvery or the billing panel, or maybe both. Just follow instruction 1,2,3 for the delivery panel and/or 4,5,6 for the billing panel.


Step 6 : Some js in ubercart/uc_cart/cart.js file
Have you seen that checkbox that copy the billing field to the delivery field? Well you can modified it if you want to copy your new billing_field into your delivery_field. Go to the line 129 and see some repetitive code of the fields. Heres the code i create for copying my new cellphone field.

$('#edit-panes-' + temp + '-phone').val(address.phone).trigger('change');
$('#edit-panes-' + temp + '-cellphone').val(address.cellphone).trigger('change');
$('#edit-panes-' + temp + '-company').val(address.company).trigger('change');



Thats it folks, its not easy but with this we are covering all the step to create a new checkout field in ubertcart. Enjoy

Create a Design for PHP Classes


You have until 15 of december to create a http://www.phpclasses.org/design.html , using only CSS and PHP, not javascript, to improve the old (and ugly) design of PHP Classes. The prizes are 3000$ to your Paypal and fame as the saviour of PHP Classes. Well hope this work better than the Postgres Contest, that well sucked big time, they just dissapear withouth telling much more info than "Because the few design you send suck we are not going to continue with the contest", and yes i was a contester XD, an no, my design didnt suck.

Directoy Problems with Drupal

So im testing Drupal, the uber CMS. Its so great to have a tool like Drupal to create webpages. But well im new into this and i had an interesting problem.

I create a site called Akami*, and made the mistake of creating it in a subdirectory called Amaki, notice the 'm' and the 'k'. In my localhost the page works as it should, but then i deployed it on a real server, in his REAL subdirectory "Akami", so i was having problems because all the routes where pointing at Amaki instead of Akami.

The Solution:
Flush the cache. For this I recommend to install the Admin Menu Module, it will make you life easy, and well if you use Drupal 6.14 (the last version) use the Alpha.3 version of the AdminMenu, or the latest alpha. Anyway in orden to recreate the menu you have to flush it. In this case you have to go to the url pointing that is pointing to the Flush button in the admin menu:


And the go to that site, of course here amaki is wrong so you have to manually change the wrong name to the true name. In this case from amaki to akami.Then press the flush all caches and youre done. Hope this will be helpfull for someone.

* The true site name is hidden for security reasons ^^

Custom Css Tips for Jquery Tabs

I love Jquery Tabs , it just make your life easier... well, only when you use his custom CSS.

But how about integrating it with your custom CSS, instead of his restrictive-gun-in-head Themes? , of course we know how to create a Tab Menu in CSS, but integrate it with Jquery Tabs is not so easy. So after one day of debugging my own code i will give you some tips to create your custom css for jquery tabs.

Tip 1: Know the classes for the Navigation Tab Bar: There is only one class that you will need to know little grasshoper:
  • ui-state-active: As the name implied, this class is added to the tab that is currently selected, dont mind the other classses, you will not need them, this is the silver bullet class for jquery tabs.
So we will need 4 css for know
  1. The Default Navigation Bar Css
  2. The Css for the a tag inside tha navbar
  3. The Css of the ui-state-active bar
  4. And the a tag inside the active navbar

So the css for this navigation bar(1) will go like this:


ul.grindyMenu li{
background:white;
color:#D09984;
display:inline;
list-style:none;
padding:1px 15px 1px 15px;
}


Then we add the a tag css(2)


ul.grindyMenu a{
text-decoration:none;
font-size:0.7em;
font-weight:bolder;
}



And for the active tab css(3), it will be like this :


ul.grindyMenu li.ui-state-active{
background:#D09984;
}


Finally the a tag inside the active tab (4):


ul.grindyMenu li.ui-state-active a{
color:white;
}


Now there is a small catch, your css file should have those rules written in that order. Maybe here you will not need to follow that tip, but what if you need to create a rule for the ui-state-default class. Do you notice how the active and not active tabs, both have the ui-state-default class? If you declare ui-state-default after ui-sate-active, it will override it:


So make your life easier and put those rules in order, first the default class, and then the active class in your css file.

Tip 2: Know the classes for the Panels, here also we wil only need one class:
  • ui-tabs.hide: This is the most important class, this class make the non active panels to hide


.ui-tabs-hide{
display:none;
}

And that's it. Put this class and everything will be allright. Happy coding!

Fixing WAMP 2.0 i and not so friendly extensions

WAMP2 is like a defacto standard for developing and testing PHP in a Windows enviroment. Particulary i used to use Wamp 2.0A in a WinXP SP2 platform. Also i use Postgres instead of Mysql, just because Pg owns Mysql big time. But there was a problem...

Also it didnt work in other WAMP versions

Like a year ago i wanted to use the next version of Wamp2... the B version. But I couldn't. Well i could install the Wamp server but there was an error when i wanted to activate the php_pgsql extension, an error like...

PHP Unable to Load the muthaphucking Dynamic Library 'c:\blah\blah\ext\php_pgsql.dll' - The specified module could not be found.


Yup, something like that. So after a lot of search and falses promises in google, i found the solution not only for that postgres extension, but for all other extensions that doesnt want to be loaded dinamically.

The Solution: Make sure that you are using the right php.ini file when you....

Ah Ha..Just kidding, the fast and furious solution is to search for this file libpq.dll in your wamp directory and then copy it to WINDOWS/system32 if youre using win XP(sorry for those using Vista, btw Vista sucks).
Hate & Love this file

And its done, you can now use Postgres with WAMP2 version I (yes version I, not 2.. long story).

I dont know exactly why its works, but it works and that the only thing i want to know. And for fixing others extensions, well u got to look for the access library of that extension and put it on system32, and replace it, if it is the case. Hope it helps someone. =)

I found it looking here., but they fix mysql, so this is my sand grain for the Postgres Project.

PostgreSQL.org Website Design Contest

Yup my favorite database is making a contest to redesign his Website. Of course im givin' it a try so you will see me with one of my design there. This is the first time I go to a contest like this but i will make my best there.

Of course there's a 2000$ prize that make me like much more Postgres, but the initial love is there. The price is divided between 1000$ for the winner Design and 1000$ for makin that Design go online.

My strategy is to create the CSS without hacks, and then use some jquery to make it web 2.0

So if youre a Web Designer you can go ahead and make your best.