Add affiliate window to Magento

It’s straight forward to add affiliate window into Magento, there are a few extensions but you don’t need them.

Edit your checkout success page which would usually be in app/design/frontend/yourpackage/yourtheme/checkout/success.phtml

Add near the top inside the php tags

// get the order
$order = Mage::getModel('sales/order')->loadByIncrementId($this->getOrderId());
// get the total
$total = $order->getGrandTotal();
// get order data
$_totalData = $order->getData();
// helper for the price formatting
$helper = Mage::helper('core');

Then add anywhere in html part of the page (replace MERCHANT_ID with your merchant ID). I’ve omitted the Category here as it’s optional

<!-- Image Pixel Tracking - Mandatory -->
    <img src="https://www.awin1.com/sread.img?tt=ns&tv=2&merchant=MERCHANT_ID&amount=<?php echo $helper->currency($order->getGrandTotal(),false,false); ?>&cr=<?php echo $_totalData['order_currency_code']; ?>&ref=<?php echo $this->getOrderId() ?>&parts=default:<?php echo $helper->currency($order->getGrandTotal(),false,false); ?>&vc=<?php echo $_totalData['coupon_code']; ?>&ch=aw&testmode=0&cr=<?php echo $_totalData['order_currency_code']; ?>" />

    <form style="display:none;" name="aw_basket_form">
        <textarea wrap="physical" id="aw_basket">
            <?php

            $items = $order->getAllItems();

            foreach ($items as $item) {

                echo "AW:P|MERCHANT_ID|".$this->getOrderId()."|".$item->getProductId()."|".$item->getName()."|".$helper->currency($item->getPrice(),false,false)."|".$item->getQtyToInvoice()."|".$item->getSku()."|default|";

            }

            ?>
        </textarea>
    </form>
    <!-- Javascript Tracking - Mandatory -->
    <script type="text/javascript">
        //<![CDATA[
        /*** Do not change ***/
        var AWIN = {};
        AWIN.Tracking = {};
        AWIN.Tracking.Sale = {};

        /*** Set your transaction parameters ***/
        AWIN.Tracking.Sale.amount = '<?php echo $helper->currency($order->getGrandTotal(),false,false); ?>';
        AWIN.Tracking.Sale.currency = '<?php echo $_totalData['order_currency_code']; ?>';
        AWIN.Tracking.Sale.orderRef = '<?php echo $this->getOrderId() ?>';
        AWIN.Tracking.Sale.parts = 'default:<?php echo $helper->currency($order->getGrandTotal(),false,false); ?>';
        AWIN.Tracking.Sale.voucher = '<?php echo $_totalData['coupon_code']; ?>';
        AWIN.Tracking.Sale.test = '0';
        AWIN.Tracking.Sale.channel = 'aw';
        //]]>
    </script>

Finally in your footer app/design/frontend/yourpackage/yourtheme/page/html/footer.phtml

<script src="https://www.dwin1.com/5715.js" type="text/javascript" defer="defer"></script>

How to redirect simple products to grouped product in Magento

For a quick and dirty way of doing this, you can modify the viewAction() on the product controller tested in 1.7,1.8,.19

Make a copy of

app/code/core/Mage/Catalog/controllers/ProductController.php

and place it in

app/code/local/Mage/Catalog/controllers/ProductController.php

Modify the viewAction() after this section:

// Prepare helper and params
 $viewHelper = Mage::helper('catalog/product_view');

$params = new Varien_Object();
 $params->setCategoryId($categoryId);
 $params->setSpecifyOptions($specifyOptions);

Add the following:

// Does the product have a parent product?
 $p = Mage::getModel('catalog/product_type_grouped')->getParentIdsByChild($productId);

if(!empty($p)) {

// redirect to parent

$prod = Mage::helper('catalog/product')->getProduct($p[0], null, null);
 header('HTTP/1.1 301 Moved Permanently');
 header('Location: '.$prod->getData('url_path'));
 exit;

 }

This will give you a 301 redirect to the parent.

Character encoding issues utf8 & MySQL – How To

Any developer working with php and MySQL will have come across this issue whilst developing.
And often the problem doesn’t rear it’s ugly head until after you’ve captured a lot of data.

If your getting strange characters in your database like question marks and , then follow this simple guide to check each part is set to UTF8.

UT8 is best practice for handling all types of characters and that’s the charset we will be using.

If your just trying to retrieve the unreadable data then see a solution at  the bottom of this post.

MySQL DB

First let’s check the MySQL server, open up your favourite GUI like MySQL Tools or via command line and run:

SHOW SESSION VARIABLES LIKE 'character_set%';

charset

The important parts to notice here

  • character_set_database
  • character_set_results
  • character_set_connection.

These should all be utf8 , if they aren’t then you need configure your database to use utf8.

You can reverse engineer your table using

SHOW CREATE TABLE table_name;

At the very end you will see “DEFAULT CHARSET=charset” change this to utf8.

As further final checks run

show variables like "collation_database";

This should show ‘utf8_general_ci’

And you can check each column individually like so.

SHOW FULL COLUMNS FROM table_name;

PHP Connection

All connections to MySQL need to use utf8, you can do this by using SET NAMES.

For PDO connections you can either include this in the SQL statement before “SET NAMES UTF8;” or you can include it in the connection e.g

$pdo = new PDO('mysql:host=myhost.com;dbname=db_name', 'db_user', 'db_password',array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8");

For standard mysqli connections use:

$mysqli->set_charset("utf8");

It’s important you place that straight after the connection before any queries are run.

What to do if you haven’t set this up from the start?

Thankfully there is a way to retrieve data that might otherwise look garbled in php you can use:


//ISO code for most browsers default encoding

mb_convert_encoding($text, "ISO-8859-1")

Note that you must connect to the DB the way you where doing before you fixed any issues. If you try and retrieve data using SET NAME utf8 then the above will not work as your requesting the data in a different format.

ISO-8859-1 is the character encoding used for most browsers, however there are others so this may not work in every case.

Forwarding the User IP from a Rackspace Cloud Load Balancer

If you have a setup which includes one of the rackspace cloud load balancers you will notice that in apache or php the ip of the client is the load balancers, the easiest way to fix this is install an apache module called mod_rpaf.

Here’s how under Ubuntu & Apache 2.2:

Install the apache dev tools (may not be required)

Check which version of apache your running

apache2 -l

The output here tells me i’m using the perfork module.

Compiled in modules:
  core.c
  mod_log_config.c
  mod_logio.c
  prefork.c
  http_core.c
  mod_so.c

Install the prefork development tools

apt-get install apache2-prefork-dev

The alternative here is to install apache2-threaded-dev if you see threaded instead of prefork.c

 

Install the mod_rpaf 

Download the mod_rpaf module and extract the latest version to check the latest see http://stderr.net/apache/rpaf/download/

wget http://stderr.net/apache/rpaf/download/mod_rpaf-0.6.tar.gz
tar -xzf mod_rpaf-0.6.tar.gz

Install and compile the apache module

cd apache-2.2-mod_remoteip.c
apxs2 -i -c -n mod_rpaf-2.0.so mod_rpaf-2.0.c

The script will compile and install the module giving you the output of the path to the module e.g

/usr/lib/apache2/modules/mod_rpaf-2.0.so

Configure

Make a new config file for rpaf and edit

touch /etc/apache2/conf.d/rpaf.conf
nano /etc/apache2/conf.d/rpaf.conf

Enter the following details in rpaf.conf, change 10.000.000.0 to your load balancer IP comma seperate for more than one

# Your module path
LoadModule rpaf_module /usr/lib/apache2/modules/mod_rpaf-2.0.so


RPAFenable On
RPAFsethostname On
# Your loadbalancer IP seperate with a space for more than one
RPAFproxy_ips 10.000.000.0
RPAFheader X-CLUSTER-CLIENT-IP

 Check the apache configuration

service apache2 reload

If you see any errors here check your configuration.

 Restart apache and apply the changes

service apache2 restart

You should then see the correct user ip showing up in $_SERVER[‘REMOTE_ADDR’] for php

 Update:

To get the correct IP from the Load Balancer to .htaccess

If your looking to restrict access from .htaccess this still doesn’t give apache the correct IP to do that you simply use a pre configured environment variable:

order deny,allow
deny from all
allow from env=allowclient
SetEnvIf X-Cluster-Client-Ip 000.000.000.000 allowclient

Magento fix for Unable to reindex Product Flat Data – Stuck on Processing. ‘SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or update a child row

If you’ve moved across sites from a development to live site or your encountering this error after importing/exporting then here’s the solution that works every time.

1. Search for “catalog_product_flat” . Under my installation its called catalog_product_flat_1

2. Then in mysql run:

SET FOREIGN_KEY_CHECKS=0;

DROP TABLE catalog_product_flat_1

3. Last step open up SSH and run (or do this from the Magento admin)

php path/to/shell/indexer.php --reindex catalog_product_flat or navigate to the /shell directory and run php indexer.php --reindex catalog_product_flat

You should get “Product Flat Data index was rebuilt successfully”

Checking for a whole number in php

There may be a simpler way but I didn’t come across one except this handy function when dealing with decimal numbers.

////////////////////////////////////////////////////////////////////////////////////////////// 
//is_wholeNumber(string $value)
//Returns TRUE if a WHOLE NUMBER
//Returns FALSE if anything else (Float, String, Hex, etc)
//////////////////////////////////////////////////////////////////////////////////////////////   
function is_wholeNumber($value)
{
	if(preg_match ("/[^0-9]/", $value))
	{	return FALSE;	}
	return TRUE;
}

There is also ctype_digit but this seems to return false when using addition like so:

$numeric_string = '1'+'1';
$integer = 1+1;

if(ctype_digit($numeric_string)) { echo "true";} else { echo "false"; }  // false
if(ctype_digit($integer)){ echo "true";} else { echo "false"; }          // false 

if(is_numeric($numeric_string)){ echo "true";} else { echo "false"; }    // true
if(is_numeric($integer)){ echo "true";} else { echo "false"; }           // true

Both equal 2 yet ctype_digit returns false? , is_numeric works here but as i’m dealing with decimal places this returns true when it is not a whole number.

Credit for the function due to http://davidwalsh.name/php-validatie-numeric-digits