lautr.com

Hannes Blog for Development and Stuff besides

4. März 2010
von Hannes
Keine Kommentare

modifying the zend framework router, an example for a simple website

I’m currently working on a new Site on the base of zend framework (again ;) ). But since the normal url Structure (controller/action) has a little bit of an overhead i looked into how to modify the router. To my surprise i found out that is extremely simple. I decided to go with the “Zend_Controller_Router_Route_Regex” as the name suggests it uses regexp.

The Url structure i was aiming for is this:

http://www.example.com

http://www.example.com/some-article.html

http://www.example.com/somepage

http://www.example.com/taxonomyvocabulary/taxonomyelement

For that purpose i added the following to my bootstrap.php

$ctrl  = Zend_Controller_Front::getInstance();
$router = $ctrl->getRouter(); // returns a rewrite router by default

$route['index'] = new Zend_Controller_Router_Route_Regex(
'',
array(
'controller' => 'index',
'action'     => 'index'
)
);
$route['page'] = new Zend_Controller_Router_Route_Regex(
'([^/\.]+)',
array(
'controller' => 'index',
'action'     => 'page'
)
);
$route['article'] = new Zend_Controller_Router_Route_Regex(
'([^\.]+)\.html',
array(
'controller' => 'index',
'action'     => 'article'
)
);
$route['taxonomy'] = new Zend_Controller_Router_Route_Regex(
'([^/\.]+)/([^/\.]+)',
array(
'controller' => 'index',
'action'     => 'taxonomy'
)
);
$route['error404'] = new Zend_Controller_Router_Route_Regex(
'.*',
array(
'controller' => 'index',
'action'     => 'error404'
)
);
$router->addRoute('error404',   $route['error404']);
$router->addRoute('index',      $route['index']);
$router->addRoute('page',       $route['page']);
$router->addRoute('article',    $route['article']);
$router->addRoute('taxonomy',   $route['taxonomy']);

Not that zend automatically adds a ^ to the start and an $ to the end of any regexp so there is no need to do that. I also added an 404 Action to take care of any Request that does not match one of the given patterns, the routes are checked in the order they are added, the last match is used, so i added the 404 Action at first.

2. März 2010
von Hannes
Keine Kommentare

UXCamp 2010 Ticket “sell” starts tomorrow 3rd of March at 5 gmt

ux campJust got the Mail from mixxt informing about the opening of the UX Camp 2010, i enjoyd id pretty much last time and can only recommend it. Here are some pics i took last year, and here would be all the Information you could need.

“Hello UXcamper,

please prepare yourself to grab your UXcamp ticket next Wednesday, 3rd of March, at about 5pm Berlin time (4pm UK time). You’ll find the events listed on http://www.uxcampeurope.org/networks/wiki/index.tickets2010 . Add yourself to the days you wish to join the UXcamp. We will provide two lists, one for all Germans and one for our international guests. Once you appear on the list, please check your profile. The profile answers will be used for your name tag at the UXcamp.

All the best,
Your UXcamp Team”

1. März 2010
von Hannes
2 Kommentare

Adding Menu and Option Points in WordPress Backend, different possibilities

There are different Ways to add Navigation Points to the WordPress Backend, most of them are explained here. Basically you have:

add_options_page

This will basically create another navigation Point under setting as most Plug-ins do. Its best suited for scenarios where your Plug-in provides Options/Settings for your blog.

The Parameters are the following

  1. the Title you want to display in the Menu
  2. the Title you want to display on the Page itself
  3. the Userlevel required to see the Link
  4. as the name says, a unique string,  basename(__FILE__) works just fine also
  5. a callback function for the page it should lead to, you can use a simple function name (as string) or use an object and its method, as i did

the syntax could look like:

add_options_page('Menu Title', 'Page Title', 9,'an-uniq-string-as-key', array('wp_my_awesome_class','optionPage'));

add_submenu_page

As the Name suggests this function is used to add Sub Menus to any Main Option, besides and including what add_options_page does, why are there two different functions then? Lets say legacy Reason – yeah sounds fine.

As you may see, its basically the same, besides you need to give the unique-key of the parent you want to attend to, for the basics that would be:

For Write: add_submenu_page(‘post-new.php’,…)
For Manage: add_submenu_page(‘edit.php’,…)
For Design: add_submenu_page(‘themes.php’,…)
For Comments: add_submenu_page(‘edit-comments.php’,…)
For Settings: add_submenu_page(‘options-general.php’,…)
For Plugins: add_submenu_page(‘plugins.php’,…)
For Users: add_submenu_page(‘users.php’,…)

Or, anything you set up as a Main-Menu-Point / Parent yourself.

And it, for an example, looks like:

add_submenu_page('an-uniq-string-as-key-of-the-parent','Page Title','Menu Title',9,'an-uniq-string-as-key', array('wp_my_awesome_class','adminPage'));

add_menu_page

And thats where the fun starts, with this nice function you can add a Main-Navigation-point to your menu.

The most stuff should be clear by now, the only difference is that you add a path to an icon you use. Well, isnt that just too nice to be true? Yes, yes it is, because you will notice that your Nice new so important Main Navigation Point will always appear on the very bottom of the Navigation.

So lets, see, in the End you can add Navigation Points to every Main Navigation Points (in the Bottom) and an Main Navigation Point itself, in the bottom.

the syntax could look like:

add_menu_page('Page Title', 'Main Title',4,'an-uniq-string-as-key', array('wp_my_awesome_class','adminPage')),'http://www.example.com/favicon.ico');

Now, if you want to Add an Main Navigation Point on another Position it is possibile, but only in a not documented manner!

add_menu_page extended

The Code is the same as for the regular use of add_menu_page, but in release 2.9 they added a new Parameter that can be used to choose the Position of the Entry:

add_menu_page('Page Title', 'Main Title',4,'an-uniq-string-as-key', array('wp_my_awesome_class','adminPage')),'http://www.example.com/favicon.ico',1);

This would then Appear on top, even before Dashboard. However, unfortunately  you can not just use every Position.

Since most of them are already taken by Existing Menu Points and Separators if you do so anyway you’ll overwrite them.

Some free Positions you can use are: 1,3,6,7,8,9,11,12,13,14,16,17,18,19.

If you want to be more free you must do the following, first we must activate the “custom_menu_order” Hook.

Just add this Code in a Plugin, of the functions.php of your template:

add_filter('custom_menu_order','custom_menu_order_function');
function custom_menu_order_function(){
return true;
}

Now we can use the menu_order Filter to add our an-uniq-string-as-key at any position we want

add_filter('menu_order','menu_order_my_function');
function menu_order_my_function($menu_order){
$new_menu_order = array();

foreach($menu_order as $position => $menu_element){
if($position == 4){
$new_menu_order[] = 'an-uniq-string-as-key';
}elseif($menu_element != 'an-uniq-string-as-key'){
$new_menu_order[] = $menu_element;
}
}
return $new_menu_order;
}

4 is of course the example Position, you can use any you want. To move separators just use the strings “separator1″, “separator2″ and “separator-last” unfortunately it seams you can only move the existing Separators, not add new ones.

But like i said, this is not documented, so use it carefully if you choose so. And most important, think if your Plug-in “add-alt-seo-title-to-dohikkie” really need the number one Position.

Access Limitations

You See in all this functions always an numeric value for the Access Rights, wich value Reflects witch user type you can see at the Capability vs. Role Table

2652836937_ff9e579e01

12. Februar 2010
von Hannes
Keine Kommentare

Drupal Finder doesnt find anything, and how I used Yahoo BOSS to work around it aka, BOSS Site Search

I’m working on a Drupal Project and I currently have to deal with the Fact that the in-build Search Engine (finder) doesn’t find jack squat. There are some Modules that use Lucene, and of course if you have the Time to walk that extra Mile – good for you! Buuut, in my case i just wanted an fast and easy Way to get some relevant Search Results in case Finder fails to deliver (which it does more often then it does not).

And, quite honestly, I always wanted a reason to play with Yahoo BOSS (google offers something alike but for a (much higher) price). So basically what i did was:

  1. if finder didn’t return a result i made a Request @ BOSS
  2. then check the results for matches in the url_alias Table of Drupal (this will come in handy later, but also vital in the matter that you dont want to only spit out tag pages and so on)
  3. get everything related to nodes (the src would most likely be something like “node/12121″)
  4. Grep the ID and get the Node with all its related content (see, i say it would come in handy) to display

The Code could look something like this:

$search = 'http://boss.yahooapis.com/ysearch/web/v1/'.urlencode(arg(1)).'%20site:www.example.com?format=xml&appid=MYAPIKEXY&count=20&lang=de';
$xml = simplexml_load_file($search,'SimpleXMLElement', LIBXML_NOCDATA);
foreach($xml->resultset_web->result as $result){?>
<?php
$select = 'SELECT src FROM url_alias where dst = "'.str_replace('http://www.sparwelt.de/','',$result->url).'"';
$foo = db_query($select);
$bar = db_fetch_object($foo);
if(preg_match('#^node/([\d]+)#',$bar->src,$matchid)){
$node = node_load($matchid[1]);?>
<h1>
<a title="<?= $node->title ?>" href="/<?= $node->path ?>"><?= $node->title ?></a>
</h1>
<p>
<?php
if(strlen($node->teaser) > 1){
print $node->teaser;
}else{
print $result->abstract;
}?>
</p>
<?php }
}?>

note: you need to be a registered developer @ yahoo in order to get a BOSS API Key you can do that here

About the Query string, its quite simple:

http://boss.yahooapis.com/ysearch/web/v1/’.urlencode(arg(1)).’%20site:www.example.com?format=xml&appid=MYAPIKEXY&count=20&lang=de

arg(1) gets, in my case, the original finder query string, site:www.example.com tells yahoo only to look on this domain the rest should be clear, and everything is well documented.

9. Februar 2010
von Hannes
Keine Kommentare

Retrieving Top 10 query’s for my internal Search using Google Analytics and Zend Framework

The intention is, to filter the top internal searches for my Site using the Google Analytics API and Zend Framework , so i don’t have to track it myself  (so i could maybe use them to Build a Search-Cloud – SEO ..woohoo). But this can basically be modified to fit A LOT of needs.

Well first, unfortunately the Zend Framework  Zend_Gdata_Analytics Component is just a proposal at the moment, but it works anyhow using Zend_Gdata. First we need to open an connection aka get a client:

$email = 'user@googlemail.de';
$pass = 'pwpwpwpwpw';

$client = Zend_Gdata_ClientLogin::getHttpClient($email, $pass, "analytics");
$gdClient = new Zend_Gdata($client);

Then we build our Report, if you worked with custom reports this you will be kindaaa familiar with this, basically you work with dimensions and metrics, which represents different kind of values that you can request, combine, filter and search for. The basic Data Operation Stuff, you can find all the Information about the Dimensions and Metrics here and how to work with them (especially how to handle the filter) here. The last parameter (&ids=ga:xxxxxxxx) is the Table ID, you can (for example) se it when you are logged in to analytics ‘https://www.google.com/analytics/reporting/custom?id=xxxxxxx’.

$reportURL = 'https://www.google.com/analytics/feeds/data' .
'?start-date=2010-01-01' .
'&amp;end-date=2010-01-31' .
'&amp;dimensions=ga:pageTitle,ga:pagePath' .
'&amp;metrics=ga:pageviews' .
'&amp;sort=-ga:pageviews' .
'&amp;filters=ga:pagePath%3D~'.urlencode("/?s=").
'&amp;max-results=10' .
'&amp;ids=ga:xxxxxxxx';

$results = $gdClient->getFeed($reportURL);

… and there you go, here is also an short example for a basic xml Output:

					$content = new XMLWriter;
					$content->openMemory();
					$content->startDocument( '1.0" encoding="ISO-8859-1" standalone="yes');

					$highest = $results[0]->extensionElements[1]->extensionAttributes["value"]["value"] ;

					$content->startElement('searches');
					foreach ($results as $rep) {
						$content->startElement('search');
							$content->writeAttribute('hits',$rep->extensionElements[1]->extensionAttributes["value"]["value"]);
							$content->writeAttribute('rank',round($rep->extensionElements[1]->extensionAttributes["value"]["value"]/($highest/7)));
							$content->writeCData(str_replace('/finder/1/','',$rep->extensionElements[0]->extensionAttributes["value"]["value"]));
						$content->endElement();//e o Search
					}
					$content->endElement();//e o Searches
				} 

				$content->endDocument();

				header('Content-Type: text/xml; charset=iso-8859-1');
				print $content->outputMemory();