Posted by Eddie

Amid South Carolina Gov. Mark Sanford's newsmaking affair with an Argentine woman last week, we decided to run an online poll asking our readers whether Sanford should resign. We used a widget developed by Vizu to run our unscientific poll. I like their service because it's very fast, fairly customizable and produces a cool Google map of voters' locations.

This was working great as is, until the top editor of the paper said we need to show the vote totals on the site. Well, that info doesn't come as part of the Vizu widget directly, but it is visible on the page where the poll was created - but that's on Vizu's site. On a fast-moving news day (or any other day), the last thing you want to do is update anything every fifteen minutes by hand when you don't have to.

Enter Simple_HMTL_Dom - a PHP parser that does what is says - it simply parses HTML from the DOM of a given Web page. In plainer English - it scrapes a Web page and allows you to extract the information you need.

Here is the end result of what I was trying to achieve:

Poll: Should Sanford resign?

 Click here to see map of votes

That vote total above is generated by a javascript which was generated using PHP. A cron hits the PHP script every 15 minutes, which in turn writes the result to javascript. The reason for that is to keep server hits to Vizu to a minimum. It also lightens the load on your own server because you're only serving a few lines of code and since we're using drupal to write the script, doesn't hit the MYSQL database in the process.

In any event, notice the Vizu page where this poll was created. It's here:

http://www.vizu.com//poll-results.html?n=170479

Notice just above the bar chart you'll see the vote totals. That's the information we want to show dynamically.

There's really not much to Simple_HTML_Dom. Just download the script and save it to your server, include() it in a PHP script and rock and roll.

Here you go:

include ('simple_html_dom.php');
$html = file_get_html('http://www.vizu.com/poll-results.html?n=170479');
$es = $html->find('td[align=right]');
$votes = "document.write(".$es[0].");";
$FileName2 = "votecount.js";
$FileHandle2 = fopen($FileName2, 'w') or die("can't open file");
fwrite($FileHandle2, $votes);
fclose($FileHandle2);

So a few things here. The line that says $es = $html->find('td[align=right]'); is just looking at the source code of the Vizu page and matching elements it finds. In this case, the first match is the Vote total. This is signified in the next line, when we define the one line of javascript that will right the first matched element: $votes = "document.write(".$es[0].");";

Finally, we write it to a file (don't forget to first create the blank file and save it with the correct read/write/execute permissions).

The last thing you'd want to do, is set up a cron job to hit the URL of the php script every so often - in our case 15 minutes. There is tons of documentation on this step and I'll leave you to google to sort that out.

Now, in the HTML of the page where you want the dynamic info to show up, it's simply:

<script src="http://blogs.islandpacket.com/sites/default/files/votecount.js?1" type="text/javascript">

The "?1" was originally going to be a randomly generated number appended to the script to ensure the script doesn't get cached, but I ran out of time. It still updated regularly on cron and over to the users' browser without caching so I let that part be.

There you have it. Once you've done this once or twice, it doesn't take long to do something like this on the fly under pressure.

Continue reading...
Posted by Eddie

I was recently trying to figure out how to get certain categories of staff blog posts, run on drupal 6, out of the database and written to a javascript so they could be embedded on our main site, with the headline, content category and post date intact.

I started out going the PHP db_query() function route - which uses SQL and is frankly pretty intimidating to me. For those unfamiliar, it looks something like this:

$tidQuery = db_query('SELECT td.name FROM{term_node}tn, {term_data}td, {term_hierarchy}th WHERE tn.tid = td.tid AND tn.tid = th.tid AND th.parent = 0 AND tn.nid = $Row->nid');

This would then be looped and written to a javascript in some more code that I won't bother posting.

Everytime something needed to be tweaked, the database query would have to be modified, and I'd spend time trying to figure out which database table needed to match.

Um...while structured query language is starting to make more sense to me, and is something I'd like to learn, a faster method of getting the desired result was to leverage Drupal Views and the powerful templating system to output the views query as a javascript.

So again - the ultimate result of this to use drupal views module to produce an embeddable widget for other sites.

Step 1 - In your view, create a page and assign it a path that you'll use specifically for the purpose. I called mine myviewname/custom.js. Then, in the page.tpl.php file, use an if statement to determine if the URL ends with "custom.js". This is done using arguments and should look something like this:


<?php if(arg(1) !== 'custom.js') { ?>
STANDARD PAGE TEMPLATE HERE
<?php } else {
print $content;
} ?>

The last part tells us that the only thing needed for the URL ending in custom.js is the content (which the view will return when we built it)

Step 2 - In my view, I configured it to use fields of exactly what I want, and I created three new tpl.php files to alter the output of the view - stripping away even further the html wrappers and content unnecessary for this purpose and replacing it with a javascript document.write() wrapper.

For example, in the new view-view-fields.tpl.php I added to my theme folder, all I have is :

<?php foreach ($fields as $id => $field): ?>
document.write('<inline_html;?>><?php print $field->content; ?>inline_html;?>>');
<?php endforeach; ?>

My view looks like this on the backend:

The other template files I created were more specific versions of

view-view.tpl.php

view-view-unformatted.tpl.php

Step 3 - So now we have a view that spits out its output like this:


document.write('
'); document.write('
USCB men's golf team awaits word on nationals
'); document.write('Sharkbites | '); document.write('May 8, 2009'); document.write('
'); document.write('
'); document.write('
Beaufort LB Justin Parker cracks Sporting News Today's list of top recruits
'); document.write('Footblog | '); document.write('May 7, 2009'); document.write('
'); document.write('
'); document.write('
Does your dog look like an Ewok? He could be a winner Saturday
'); document.write('The Pack | '); document.write('May 7, 2009'); document.write('
'); document.write('
'); document.write('
Bluffton continues search for new town manager
'); document.write('Bluffton Blog | '); document.write('May 7, 2009'); document.write('
');

So yeah, there are a few too many document.write() statements in there, but the result is the same.

What we want to do to keep our database hits to a minimum, is prevent views from running the db query everytime our main site is hit, so we'll write this view to another javascript, which will then be included on the main site. I created a drupal page to do that, using this php code to write it to file:


$o = file_get_contents('custom.js');
$FileName = "files/blogfeed.js";
$FileHandle = fopen($FileName, 'w') or die("can't open file");
fwrite($FileHandle, $o);
fclose($FileHandle);

A cron job then hits this new page every 10 minutes, and writes it to file. The result is a low-impact, view-created javascript widget of the latest posts that we can use on any other site.

There is probably a better way to do all of this. But this way just sort of clicked for me as something cool you can do with views and templating to export customized data out of drupal.

Continue reading...
Tags: |  

The Garden - Week 7

18 Apr 2009
Posted by Eddie

  • The Garden - Week 7

    The tomatoes and broccoli are much bigger. This plant is already producing broccoli. I've enjoyed about a half-dozen strawberries, and the rosemary has done wonders to potato-based dishes. The garden is becoming my favorite place to spend my free time and it's fascinating to look back and see how much it's grown over the last two months.
Posted by Eddie

I haven't been posting much lately. I've been super busy, and when I have downtime, it's so tempting to just chill and not update on the blog. Recently, I started a garden with a little help from my neighbors and Laney. This gallery is what we accomplished last weekend.

Posted by Eddie

Would society start paying for something that they've had for free all along, at least since the dawn of the internet? Probably not, but it worked for bottled water. Maybe it's all in the packaging.

Continue reading...