Web Development

Posted by Eddie

The following code shows how I went about limiting core drupal search results to two content types, and then grouping content from those types together. In this case I stacked the content types so all of content type a would show first, followed by all content from content type b and so on. You could display the results side by side or whatever. This was done at the theme level in search-results.tpl.php


<?php 
$i=count($results);
if ($i > 0) { ?>
<h1>Search Results</h1>
<h3>You searched for <span id="query"></span></h3>
<?php } ?>

<?php print $keys; 


 for($x=0;$x<=$i;$x++){ 
	if ($results[$x]['node']->type == 'product') { ?>
	    <div class="search-box">
	        <div class="search-image">
				<img src="/<?php print $results[$x]['node']->field_productimage[0]['filepath']?>"/>
	        </div>
	        <div class="search-text">
				<div class="product-headline">
					<div class="product-headline-title">
						<a href="/node/<?php print $results[$x]['node']->nid;?>"><?php print $results[$x]['node']->field_productname[0]['safe'];?></a>
					</div>
					<div class="product-code">
						<?php print $results[$x]['node']->field_productcode[0]['value'];?>
					</div>
				</div>
				<div class="product-body">
					<?php if ($results[$x]['node']->content['body']['#value'] != NULL) { 
						print $results[$x]['node']->content['body']['#value'];
						} else {
						print 'Product information coming soon';
						} ?>
						<div class="product-details"><a href="/node/<?php print $results[$x]['node']->nid;?>">View Product Details</a></div>
				</div>
				
			</div>
		</div>
	<?php 	}
} ?>
<?php
 for($x=0;$x<=$i;$x++){ 
	if ($results[$x]['node']->type == 'animal') { ?>
	<div class="search-box animal">
		<div class="search-image">
			<img src="/<?php print $results[$x]['node']->field_thumbnail_photo[0]['filepath']?>"/>
		</div>
		<div class="search-text">
				<div class="product-headline">
					<div class="product-headline-title">
						<a href="/animals/<?php print $results[$x]['node']->title;?>"><?php print $results[$x]['node']->title;?> Care Info and FAQs</a>
					</div>

				</div>
				<div class="product-body">
					Find out more about this animal and the care needed
					<div class="product-details"><a href="/animals/<?php print $results[$x]['node']->title;?>">View <?php print $results[$x]['node']->title;?> Information</a></div>
				</div>
		</div>
	</div>
<?php	
	}
}


?>




</dl>
<?php print $pager; ?>

<script type="text/javascript">
$(document).ready(function() {
    var query = $('#edit-keys-wrapper input.form-text').val();
	$('#query').replaceWith('<span id="query">' + query + '</span>');
});

</script>

The jQuery at the end basically is just a quick way of showing the user what they searched for without having to split atoms in template.php

Posted by Eddie

One of the sites I'm working on needs a photo gallery consisting of about 300 images. However, the images they need in the gallery are stored on their old server which we don't readily have access to. So rather than copying each photo by hand, we can use PHP to copy them directly to our server without having to move each one manually. Here is a script I wrote yesterday that saved me a ton of time.

Once again, I opted to use the simple_html_dom parser, which uses selectors like jQuery to match elements on a page and allows one to do fun stuff to manipulate the data.

On the site I need to take the images from, they are listed like this:

<a href='full/photo055.jpg' rel='lightbox' style='color:#ffffff;'><img src='thumbs/photo055.jpg' border='0' width='100' height='100'>	055	</a>
<a href='full/photo294.jpg' rel='lightbox' style='color:#ffffff;'><img src='thumbs/photo294.jpg' border='0' width='100' height='100'>	294	</a>
...

And so on about 300 more times. It's a thumbnail image linked to a larger image that appears in a lightbox when the user clicks. All we're interested in, really, is grabbing the large image and copying to our server.

So here's a script that parses this page and matches each <a> tag. It examines each match again, this time only using matches that end with 'jpg'. Then each of those matches are striped of extraneous code, starting with <a href='full/photo055.jpg' rel='lightbox' style='color:#ffffff;'><img src='thumbs/photo055.jpg' border='0' width='100' height='100'> 055 </a> and whittling down to just 'full/photo055.jpg'. Once that's done, we can add on a new path of where we want the copied photo to live on our server.

<?php 
include ('includes/simple_html_dom.php');
$html = file_get_html('http://www.somedomain.com/photos/index.html');
$frontremove = "<a href='";
$backremove = "' rel='lightbox' style='color:#ffffff;'>";
$x=0;
foreach($html->find('a') as $element) {
	if(preg_match('/jpg/',$element)) {
		$image[$x] = str_replace($frontremove,"",$element);
		$image[$x] = str_replace($backremove,"",$image[$x]);
		$image[$x] = substr($image[$x], 0, 17);
		$x++;
	}
}
for($n=0;$n<=$x;$n++) {
	$file = 'http://www.somedomain.com/photos/'.$image[$n];
	$newfile = $_SERVER['DOCUMENT_ROOT'] . '/photos/'.$image[$n];
	echo $newfile;
	fopen($newfile, "w");
	if (!copy($file, $newfile)) {
		echo "failed to copy $file...\n";
	}
	fclose($newfile);
}
?>

Now that I'm looking at this script again under a well-rested mindset, I think I could simplify this and avoid using DOM parsing altogether since we know the remote directory. This simpler method would save memory and probably work more efficiently. I probably overcomplicated this script.

However, an advantage to using DOM parsing is that you would only copy over the files that you want from the page, rather than running the risk of copying any other files that may be living in that directory that you may not want.

Oh well, it's all a learning experience. I'll play with a simplified version later.

Posted by Eddie

This post shows you how to render the markup needed for an animated drop down menu in Wordpress based on your nested parent/child page hierarchy using PHP.

OK, first let's see an example in action of what exactly we are trying to do here. The way wp_list_pages() renders the menu list items needs to be rewritten in order to power the structure of this menu:

Dynamic Menu Demonstration

Click on the link above and interact with the menu. That should do some pretty interesting things. It has a nice info area when you mouse over the menu items.

Now the need arises to be able to manage the content of this menu without having to edit the code in the template. The wp_list_pages() template tag has some pretty nice parameters to work with, but in this case, it really isn't robust enough to render the necessary markup for this menu as is. So I had to write a script to explode wp_list_pages and check each menu item for possible submenu items based on the page structure define by the administrator in the wordpress administrative panel:

<div id="quicklinks">
  <ul class="kwicks horizontal" >
    <?php $toppages = wp_list_pages('echo=0&title_li=&depth=1');
        $menuitem = explode('<li class',$toppages); 
        $n = count($menuitem);
        for ($i = 1;$i<$n;$i++){
            preg_match('/page-item-[0-9]*/', $menuitem[$i],$id); 
            $id2 = str_replace("page-item-","",$id);
            $x = $id2[0];
            $submenu = wp_list_pages('echo=0&title_li=&depth=2&child_of='.$x);
            echo '<li id="kwick_'.$i.'">
					<div class="wrapper">
						<div class="col1"><h3><li class'.$menuitem[$i].'</h3>
						<ul class="menu2">'.$submenu.'</ul></div> 
						 <div id="info_'.$x.'" class="col2" style="display: none;"> This is an info area. </div>
					</div>
				     </li>';
	     
        }
     ?> 
  </ul>
</div>

The script basically takes the list of pages, explodes it into pieces delineated by the <li> tag, counts the number of pieces, then loops through each item, checking it to see if there are subpages for that menu item by determining the page ID, running wp_list_pages() again and rendering those subpages underneath - all with the proper markup needed for the menu to work.

This was a bit of a challenge, but a great exercise in PHP. Using the script above could likely be adapted and improved to whatever you would need for a unique menu of your own powered by the Wordpress paging system.

I'm sure there are plugins for drop downs - sometimes it's more rewarding to build it yourself.

Posted by Eddie

These are the tags assigned to a sample post. The tag "sonoma" appears slightly larger than the other tags assigned to this post because it appears more frequently throughout all other posts.

A recent development project called for a tag cloud on the right rail. Easy to do generally; drupal has plenty of taxonomy modules available to take care of this for the most part.

What I needed that was different than any existing functionality I found was a tag cloud that showed:

1) A list of the node's terms in a block. These would be terms assigned to this post rather than an entire vocabulary.
2) The relative weights of those terms (and displayed visually using font size) as in a typical tag cloud.

The challenge was combining parts one and two. If you needed to apply this, the only thing in theory you'd need to change would be the vid = 5 in the database query to what ever vocabulary ID in which you want to run your query. So here is some code that does the trick (it could be simplified I think):


<?php
class tag
{
    var $name = "";
    var $count = 0;
    var $tid = 0;

    function getCount()
    {
        return $this->count;
    }
    function getName()
    {
        return $this->name;
    }
    function setCount($var)
    {
        $this->count = $var;
    }
    function setName($var)
    {
        $this->name = $var;
    }
    function setTID($var)
    {
        $this->tid = $var;
    }
    function getTID()
    {
        return $this->tid;
    }
}
$count = 0; // Overall count of used tags
$threshold = 0; // How many tags are needed to get displayed
$font_size = 0.8;
$node = node_load(arg(1));
$nid = $node->nid;
$query = "SELECT d.name,d.tid, dn.nid FROM {term_data} d, {term_node} dn WHERE dn.tid=d.tid and d.vid='5';";
$result = db_query($query);
$tags['Test'] = 0;
while($node = db_fetch_array($result))
{
    
    if ($tags[$node['name']] == NULL)
    {
        $tags[$node['name']] = new tag();
        $tags[$node['name']]->setName($node['name']);
        $tags[$node['name']]->setCount(1);
        $tags[$node['name']]->setTID($node['tid']);
        $count = $count + 1;
    }
    else
    {
        $tags[$node['name']]->setCount(
            $tags[$node['name']]->getCount() + 1
        );
        $count = $count + 1;
    }
}

$query2 = "SELECT d.name,d.tid, dn.nid FROM {term_data} d, {term_node} dn WHERE dn.tid=d.tid and dn.nid = '$nid' and d.vid='5';";
$result2 = db_query($query2);
$match1 =  $node['name'];
$match2 = $tag->name;
	while($node = db_fetch_array($result2)) {
			$termnames[] = $node['name'];
	}

foreach($tags as $tag)
{
    foreach($termnames as $termname){              
                 if($tag->name == $termname){
                 $matches[] = $tag; 
				}	
		}
}

foreach($matches as $match)
 {
    $mycount = $match->count;

    if($mycount > $threshold) 

    {
        $fraction = ((int)(($mycount / $count) * 60)) / 10;
        if($fraction < $font_size)
        {
            $fraction = $font_size;
        }
        echo '<span style="font-size: ' . $fraction . 'em;">' . l($match->name,'taxonomy/term/' . $match->tid,array('title="' . $match->count . ' Nodes"')).'</span> ';
    }
}

?>

The first half of the code I lifted from a snippet or forum post on Drupal.org many months ago, and the second half I managed to cobble together somehow on a cloudy day when the code gods were looking the other way.

Continue reading...
Posted by Eddie

Though I personally loathe twitter because of the distraction it breeds, it has a very powerful API which allows developers to create cool apps like twhirl or tweetdeck. Here is one that runs in a browser.

Background:

The client has a website built on a Drupal 6 platform and needs users to be able to tweet to their account from his Website. The tweet box on his Web site has a sports hashtag already entered into the tweetbox, and entries with that hashtag will flow through the real-time stream of that sports category. The real time twitter stream is shown to the left of the tweet box on the homepage of the site, so users can see their tweet go through the twitter river in fairly short order.

I tried a few drupal modules, but they just aren't there yet to both allow users to sign in from twitter AND tweet from the drupal site. The twitter 6.x-3.x module is still in development and I don't know enough about module development to try to offer a patch to make it work for this purpose. This module does allow you to sign in with twitter, but I was unsuccessful in getting a tweet to post using it. The official release, 6.x-2.6 doesn't have oauth support, so that isn't possible for this task.

Application overview:

This application leverages a PHP code library developed by Jaison Mathai. In fact the library pretty much is the app, with a few tweaks for my own purposes.

The application uses oauth to let twitter handle all of the login and authentication stuff, so users don't have to enter in their password to anyone but twitter. Twitter then sends back a token to requesting website, which then sets a cookie in the user's browser. The user, with cookie stored now, can now tweet in the box on the site. No passwords are ever stored - just an authentication token that expires after you log out of twitter.

For more on the behavior and security of oauth, read about it here.

Here is the very cool code library I used.

Demonstration

If you'd like to test this out how it works, go ahead and authenticate my site by signing in with Twitter
.

Once that's done, you can tweet into this box here:


Extending the Application?

The Drupal twitter module is very powerful and hooks into the core user module to create a user account for someone signing into the drupal site using twitter sign in. However, what if you don't need or want to create a user account from every authorization? What if the goal is simply to allow users to tweet and not create an account on your site?

I just picked up a copy of Pro Drupal Development, and I'm finding it very resourceful and full of great knowledge. I have yet to wrap my head around building modules for Drupal and perhaps this would be a good exercise to turn this application into a plug-and-play module, even if it isn't committed back to drupal.org.

Continue reading...