Oct 24 2009

SingleFeed Export Module for Magento – How to strip HTML tags and special characters

Tested on:
SingleFeed Export Module v1.1.0
Magento v1.3.2.4

So I found this great module for Magento the other day, made by SingleFeed. It will export a product data feed every night. Then, we can import this feed into things like Google Base.

I ran into a problem though. You can’t import a data feed into Google Base that contains HTML tags and special characters. Most of the clients I work with prefer to have a WYSIWYG editor for things like the CMS pages, product descriptions, etc., which will add HTML formatting in the database. The SingleFeed Export Module does not automatically strip HTML on the fly (however I believe if you sign-up for an account at their website, they have a wizard that can do it for you.)

I poked around at the code for a bit and discovered that stripping the HTML tags and special chars would be quite easy using two functions: strip_tags, htmlspecialchars_decode.

Open app/code/community/SingleFeed/Export/Model/Mysql4/Profile.php and goto line 360:

360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
// format product data as needed
foreach ($products as $id=>&$p) {
  foreach ($p as $attr=>&$value) {
    // replace raw numeric values with source option labels
    if ($options = $this->attr($attr, 'options')) {
      if (is_array($value)) {
        foreach ($value as &$v) {
          $v = isset($options[$v]) ? $options[$v] : '';
        }
      } else {
        $value = isset($options[$value]) ? $options[$value] : '';
      }
    }
    // combine multiselect values
    if (is_array($value)) {
      $value = join(', ', $value);
    }
    // process special cases of loaded attributes
    switch ($attr) {
    // product url
    case 'url_path':
      $p["singlefeed.url"] = $baseUrl.$value;
      break;

I love well-written code, especially with good comments. All we’re going to do is add in our new formatting (in this case, just for the product description.)

360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
// format product data as needed
foreach ($products as $id=>&$p) {
  foreach ($p as $attr=>&$value) {
    // replace raw numeric values with source option labels
    if ($options = $this->attr($attr, 'options')) {
      if (is_array($value)) {
        foreach ($value as &$v) {
          $v = isset($options[$v]) ? $options[$v] : '';
        }
      } else {
        $value = isset($options[$value]) ? $options[$value] : '';
      }
    }
    // combine multiselect values
    if (is_array($value)) {
      $value = join(', ', $value);
    }
    // process special cases of loaded attributes
    switch ($attr) {
    // product url
    case 'url_path':
      $p["singlefeed.url"] = $baseUrl.$value;
      break;
    // product descriptions
    case 'description':
      $p["description"] = htmlspecialchars_decode(strip_tags($value));
      break;

That was almost a little too easy…


Aug 5 2009

TweetSuite for WordPress Plugin – W3C Validation Error: Fixed

TweetSuite is a great plugin, it has a widget for displaying your latest tweets, displays tweetbacks, and lets you add in links to tweet or re-tweet a post on your blog. There’s more then a few things that need to be fixed with this plugin (ref: TweetSuite Errors and Troubleshooting), right now I’m just going to focus on some markup validation errors I came across.

The widget for displaying your latest tweets lists each tweet enclosed with li (listed item) tags. Unfortunately, these listed items have no unordered or ordered list parent tag. This causes a the markup to be invalid. To fix this is quite easy…

Open TweetSuite.php and goto line 907:

907
908
909
910
911
912
913
914
915
$buff = $wpdb->get_results("SELECT * FROM $table_name order by datetime desc limit $max");
 
foreach ($buff as $line) {
	$tweet = $line->tweet;
	$link = $line->link;
	$dt = date('m/d/y h:ia', $line->datetime);
	$output .="<li class=\"tweet\">$tweet <a href='$link'?phpMyAdmin=GNiTviqADsNCTwBkw2A2k7Yfxf8>$dt</a></li>";
}
echo $output;

and add in the appropriate opening and closing tags…

907
908
909
910
911
912
913
914
915
916
917
918
919
920
$buff = $wpdb->get_results("SELECT * FROM $table_name order by datetime desc limit $max");
 
$output = "<ul>";
 
foreach ($buff as $line) {
	$tweet = $line->tweet;
	$link = $line->link;
	$dt = date('m/d/y h:ia', $line->datetime);
	$output .="<li class=\"tweet\">$tweet <a href='$link'?phpMyAdmin=GNiTviqADsNCTwBkw2A2k7Yfxf8>$dt</a></li>";
}
 
$output .="</ul>";
 
echo $output;

This will enclose all the listed items with an unordered list tag, thus fixing the invalid markup.

The other problem I found was that some of the tweets had special characters (such as an ampersand) that were not converted to the specific html character code. This will also cause validation errors. To convert any special characters to use the appropriate special character code, we’ll need to make a real simple change.

Open TweetSuite.php and goto line 915:

915
$output .="<li class=\"tweet\">$tweet <a href='$link'?phpMyAdmin=GNiTviqADsNCTwBkw2A2k7Yfxf8>$dt</a></li>";

and change it to…

915
$output .="<li class=\"tweet\">" . htmlspecialchars($tweet) . " <a href='$link'?phpMyAdmin=GNiTviqADsNCTwBkw2A2k7Yfxf8>$dt</a></li>";

This will now convert any special characters in a tweet to use special character code.


Jan 16 2009

Adding a mini login box to Magento

I’m surprised there is not one in the default template for Magento.  Nevertheless, it’s pretty common to see a login box on a sidebar, and I need one.  This is actually pretty simple to do, we’re going to be modifying templates, layouts, and unfortunatly we’re going to have to alter the core (for something really silly.)

First, lets go ahead and make a template for the mini login box.  Take a look in ⁄template⁄customer⁄form⁄…  What’s this!?  We already see that there is a mini.login.phtml.  For a closer look:

<form action="<?php echo $this->getPostActionUrl() ?>" method="post">
    <table width="100%" class="mini-login">
        <tr><td><?php echo $this->__('Email') ?>:</td><td><input name="login[username]" /></td></tr>
        <tr><td><?php echo $this->__('Password') ?>:</td><td><input name="login[password]" /></td></tr>
        <tr><td>&nbsp;</td><td><input type="submit" value="<?php echo $this->__('Login') ?>" /></td></tr>
    </table>
</form>

We’ll, even though functional, this isn’t styled nor does it fit in with the default Magento template. So let’s change this.

<div class="box base-mini mini-login-form">
    <div class="head">
        <h4><?php echo $this->__('Login') ?></h4>
    </div>
    <form action="<?php echo $this->getPostActionUrl() ?>" method="post" id="login-form">
        <div class="content">
            <ul class="form-list">
                    <li>
                        <label for="email"><?php echo $this->__('Email Address') ?> <span class="required">*</span></label><br />
                        <input name="login[username]" value="<?php echo $this->htmlEscape($this->getUsername()) ?>" title="<?php echo $this->__('Email Address') ?>" id="email" type="text" class="input-text required-entry" style="width:122px;" />
                    </li>
                    <li>
                        <label for="pass"><?php echo $this->__('Password') ?> <span class="required">*</span></label><br />
                        <input name="login[password]" type="password" class="input-text required-entry validate-password" id="pass" style="width:122px;" />
                    </li>
                </ul>
                <p class="required"><?php echo $this->__('* Required Fields') ?></p>
          </div>
    <div class="actions">
        <button class="form-button-alt" type="submit" name="send" id="send2"><span><?php echo $this->__('Login') ?></span></button>
    </div>
</form>
<script type="text/javascript">
    var dataForm = new VarienForm('login-form', true);
</script>
</div>

Also add this to your CSS:

.mini-login-form h4 { background-image:url(../images/icon_page_white_text.gif); }

Now that we have a template (mini.login.phtml), we’re going to have to add it to our block structure. Open layout/customer.xml, and make this change starting at line 65.

<customer_logged_out>
        <reference name="top.links">
            <action method="addLink" translate="label title" module="customer"><label>Log In</label><url helper="customer/getLoginUrl"/><title>Log In</title><prepare/><urlParams/><position>100</position></action>
        </reference>
        <remove name="wishlist_sidebar"></remove>
        <remove name="reorder"></remove>
        <reference name="right"> 
            <block type="customer/form_login" name="mini_login" template="customer/form/mini.login.phtml" /> 
        </reference> 
    </customer_logged_out>

Remember to copy this file/folder structure and put it in app/code/local. We do this, because when you go to upgrade your Magento installation, your core files get patched, thus erasing all the hard work you did :P


Dec 11 2008

Delicious for WordPress Plugin – W3C Validation Error: Fixed

I keep almost all my bookmarks at Delicious (formerly del.icio.us.)  So I noticed there is a Wordpress plugin to display your Delicious bookmarks.  One of the things I do after I add a new plugin to WordPress, is to validate a page using The W3C Markup Validate Service.  I noticed that my markup was now invalid, but it wasn’t really because of the plugin itself.  The errors were caused because some of my Delicious bookmarks have predefined ampersand characters, and the plugin did not replace these with HTML entities.  I first tried replacing my bookmark titles in Delicious, but that just screwed up my titles (I always go for the easy way first.)  So it’s time to start editing sources again…

What we need to do to fix this is really quite simple, find the string that stores our bookmark title, and replace the predefined characters with HTML entities.  While looking for the best method to do this using PHP, I found a function that I never knew about before.  There’s actually a nice PHP function to do this: htmlspecialchars()

Certain characters have special significance in HTML, and should be represented by HTML entities if they are to preserve their meanings. This function returns a string with some of these conversions made; the translations made are those most useful for everyday web programming. If you require all HTML character entities to be translated, use htmlentities() instead.

This function is useful in preventing user-supplied text from containing HTML markup, such as in a message board or guest book application.

Perfect, this is what we’re going to use.  So let’s find that string now…

Open delicious.php and go to line 74:

73
74
75
76
77
foreach ( $bookmarks-&gt;items as $bookmark ) {
$msg = $bookmark['title'];
if($encode_utf8) utf8_encode($msg);
$link = $bookmark['link'];
$desc = $bookmark['description'];

So we’re going to take line 74 and change it to this:

73
74
75
76
77
foreach ( $bookmarks-&gt;items as $bookmark ) {
$msg = htmlspecialchars($bookmark['title']);
if($encode_utf8) utf8_encode($msg);
$link = $bookmark['link'];
$desc = $bookmark['description'];

Quite simple, now we’re back on the right track :)


Nov 20 2008

WP Wall plugin + Elegant Grunge theme – fixed W3C xHTML validation error

I recently installed a plugin called WP Wall (you should now notice it in the sidebar.)  I’m pretty happy with how it worked out, but I noticed there was a problem validating my markup after installing this plugin.

The problem was simple, an input tag had and ID and name of “page”.  This ID was already in use by my Wordpress theme (Elegant Grunge), and as we all know no two tags can have the same ID.  Generally speaking, page is a pretty common identifier and I’m not surprised that it was already in use.

To fix:

Open wp-wall.php, and go to line 243

Change:

243
$result.='&lt;input type="hidden" name="page" id="page"value="'.$page.'" /&gt;';

To:

243
$result.='&lt;input type="hidden" name="wallpage" id="wallpage" value="'.$page.'" /&gt;';

Open wp-wall.js.php, and go to line 117

Change:

117
var page= $('#wallcomments #page');

To:

117
var page= $('#wallcomments #wallpage');

I changed the identifier from page to wallpage, but you can use anything you like as long as something else isn’t already using that specific identifier.  Hopefully this won’t cause any conflicts within the WP Wall plugin, only time will tell.


Nov 18 2008

Elegant Grunge Wordpress theme – Fixed image caption box.

I noticed a problem with the caption boxes that Wordpress creates, and the image box model around the images in posts.

adding this to styles.css:

.wp-caption {
  padding-right:15px;
  padding-left:5px;
}

will change this:

before fix

before fix

to this:

after fix

after fix

Let me know if anyone runs into any problems.