You are here: Home » Programming » Web Tricks » Web Tricks: 2007 Archives

Web Tricks: 2007 Archives

I recently posted an entry on making static hierarchies in MovableType. I came up with a much better way of doing this, so I am replacing that entry with this one.

First off, let's create a relationship between a category and the entry which is going to represent it. Create a new category "About Me" and save it. Now create a new entry and call it ".About Me" - the period in UNIX syntax for hidden files, and we are going to hijack it here. :) Attach the entry to category "About Me." You can set this entry to allow comments and trackbacks - it's up to you. You may not like the look of comments at the bottom of a long page of blog entries.

Now we get to alter the templates! First, open Archive Template "Entry Listing" and add the following code to the top of the code:

<MTSetVar name="cat_desc" value="">
<MTSetVar name="cat_extra" value="">
<MTSetVar name="use_short_list" value="0">
<MTSetVar name="use_no_list" value="0">
<MTIfArchiveType archive_type="Category">
 <MTEntries>
  <MTSetVarBlock name="keywords"><$MTEntryKeywords$></MTSetVarBlock>
  <MTIf name="keywords" like="_shortlist"><MTSetVar name="use_short_list" value="1"></MTIf>
  <MTIf name="keywords" like="_nolist"><MTSetVar name="use_no_list" value="1"></MTIf>
  <MTSetVarBlock name="title"><$MTEntryTitle$></MTSetVarBlock>
  <MTSetVarBlock name="cat_title">.<$MTArchiveCategory$></MTSetVarBlock>
   <MTIf name="title" eq="$cat_title">
    <MTSetVarBlock name="cat_desc"><$MTInclude module="Entry Detail"$></MTSetVarBlock>
    <MTSetVarBlock name="cat_extra">
        <$MTInclude module="TrackBacks"$><$MTInclude module="Comments"$>
    </MTSetVarBlock>
   </MTIf>
 </MTEntries>
</MTIfArchiveType>

This establishes our basic variable values if we are dealing with a category entry. Then scroll down and look for the section that prints out the entries. It should look something like this:

<MTIf name="datebased_archive">
    <MTEntries>
<$MTEntryTrackbackData$>
<$MTInclude module="Entry Summary"$>    
    </MTEntries>
<MTElse>
        <MTEntries limit="auto">
<$MTEntryTrackbackData$>
<$MTInclude module="Entry Summary"$>    
        </MTEntries>
</MTIf>

We are going to edit the second bit inside the <MTElse>. Basically take everything from <MTEntries> to </MTEntries> and replace it with this:

 <MTVar name="cat_desc">
 <MTUnless name="use_no_list">
  <!--print out entries inside category:-->
  <MTIf name="use_short_list"><ul class="cat-short-list">
  <MTElse><hr /></MTIf>
  <MTEntries limit="auto">
   <MTSetVarBlock name="title"><$MTEntryTitle$></MTSetVarBlock>
   <MTUnless name="title" like="^\.">
    <MTIf name="use_short_list">
     <li><a href="<$MTEntryPermalink$>"><$MTEntryTitle$></a></li>
    <MTElse>
     <$MTEntryTrackbackData$>
     <$MTInclude module="Entry Summary"$>
    </MTIf>   
   </MTUnless>  
  </MTEntries>
  <MTIf name="use_short_list"></ul></MTIf>
 </MTUnless>

And then tack on the following just below the last </MTIf> from <MTIf name="datebased_archive">:

<MTVar name="cat_extra"><!--:comments and trackbacks if selected-->

You can save the "Entry Listing" template now and republish your site. If you go to category "About Me" now, you should see the entry you created for ".About Me" at the top, followed by a horizontal separator and any other entries you may have listed in that category, blog-style. There are a few things that may still be bothering you. First, your page says "Recently in About Me Category." Just go back to "Entry Listing" and look for where that is printed in the template and replace "Recently in <em><$MTArchiveTitle$></em> Category" with just "<$MTArchiveTitle$>" - that should fix that. Second, you may not like all your entries listed blog-style up against your pretty category entry. Since this is entirely a matter of preference, I set this up as a per-category option. If you add "_shortlist" to the keywords field in the ".About Me" entry, then it will print out the entries as a short list of linked titles instead. If you add "_nolist" to the keywords, it will not print the entries out all (and you can add them to the entry itself in any order or format you like).

You could also easily alter the "Entry Listing" template to always do one of these options - just set the default value to "1" in the first <MTSetVar> at the top of the template code.

So now we have an entry that is tied one-to-one with a category. There's one problem still. Movable Type published the entry in addition to the entry-category. If you click "View Published Entry" from ".About Me," you can see that there is a duplicate page there, which we don't want. This is also the landing page after a user leaves a comment (if you have set up ".About Me" to allow comments). So we are going to edit another template to fix this. Open Archive Template "Entry" now and put this code at the very top of that template:

<MTSetVar name="redirect" value="0">
<MTSetVarBlock name="title"><$MTEntryTitle$></MTSetVarBlock>
<MTIf name="title" like="^\.">
  <MTSetVarBlock name="redirect"><$MTBlogURL$></MTSetVarBlock>
</MTIf>
<MTIf name="redirect">
 <MTEntryCategories>
  <MTSetVarBlock name="cat_title">.<$MTArchiveCategory$></MTSetVarBlock>
  <MTIf name="title" eq="$cat_title">
   <MTSetVarBlock name="redirect"><$MTCategoryArchiveLink$></MTSetVarBlock>
 </MTIf>
 </MTEntryCategories>
</MTIf>
<MTIf name="redirect">
<HTML><HEAD><TITLE><$MTBlogName$></TITLE>
<META HTTP-EQUIV=REFRESH CONTENT="0;URL=<MTVar name="redirect">">
</HEAD>
<BODY><script type="text/javascript">
  location.replace("<MTVar name="redirect">");
</script>
</BODY></HTML>
<MTElse>

You'll want to throw in a final </MTIf> at the very bottom on the template as well. Save this change and republish.

Now when you go to the url for ".About Me," it automatically redirects you back to the category-entry "About Me."

There is one caveat to my solution here: all the category-entries are listed in archives. I wanted it that way, because I view them as entries in their own right (why I set mine up to allow comments). You may not feel the same way. Unfortunately, due to the way most archives are published, I could not find a way to set this on a per-category level. If you want to block/hide all category-entries from archives, edit "Entry Listing" to look like this:

<MTIf name="datebased_archive">
 <MTEntries>
   <MTSetVarBlock name="title"><$MTEntryTitle$></MTSetVarBlock>
   <MTUnless name="title" like="^\.">
     <$MTEntryTrackbackData$>
     <$MTInclude module="Entry Summary"$>    
   </MTUnless>
 </MTEntries>

And edit the Individual Template "Archives" as well. Search for "<li" wherever it mentions "<$MTArchiveTitle$>" and wrap it up like this:

   <MTSetVarBlock name="title"><$MTArchiveTitle $></MTSetVarBlock>
   <MTUnless name="title" like="^\.">
            <li class="archive-list-item"><$MTArchiveDate format="%Y.%m.%d"$>: 
               <a href="<$MTArchiveLink$>"><$MTArchiveTitle$></a></li>
   </MTUnless>

You won't need to change every archive option - I think only Individual actually lists each entry. Per-month archives are handled in "Entry listing" instead.

Anyway, I hope this helps someone. It was a lot of fun to create and I am much happier with MovableType now. Version 4 is really pretty damn good!

Resources: MovableType 4 Templating, MovableType Template Tag Reference

If you are using regular Pear SOAP, it doesn't work in document/literal. I tried. So I turned to NuSOAP, which unfortunately has very little in the way of documented examples, especially in document/literal. I am including the server that worked for me (discovered largely through trial and error), as well as a test client. This is designed to mirror Pear SOAP as much as possible (since I was converting from one to the other). Note: document/literal in NuSOAP does not verify data types, so int, string, boolean, etc. are all converted to strings between the client and server.

SERVER:

require_once("nusoap/nusoap.php");

$server = new soap_server;
$server->configureWSDL('servicename', 'urn:servicename','','document'); 

myRegister($server,'DoSomething',
		array('in' => array('Name' => 'xsd:string',
					'Age' => 'xsd:int'),
		'out' => array('Pass' => 'xsd:boolean')
		));

//if in safe mode, raw post data not set:
if (!isset($HTTP_RAW_POST_DATA)) $HTTP_RAW_POST_DATA = implode("\r\n", file('php://input'));
$server->service($HTTP_RAW_POST_DATA);

function myRegister(&$server,$methodname,$params) 
{
	$server->register($methodname,$params["in"],$params["out"],
	'urn:servicename', // namespace
	$server->wsdl->endpoint.'#'.$methodname, // soapaction
	'document', // style
	'literal', // use
	'N/A' // documentation
	);
}

function DoSomething($Name,$Age)
{
	$result=false;
	if ($Name=="mleiv" && $Age==35) $result=true;
	return array('Pass'=>$result); 
}

CLIENT:

require_once("nusoap/nusoap.php");

$ns="urn:servicename";
$client = new soapclient('http://localhost/wherever/SOAPServer.php?wsdl','wsdl'); 
if ($client->getError())
{
 	print "<;h2>Soap Constructor Error:<;/h2><;pre>".
                $client->getError()."<;/pre>";
}
$params=array("Name"=>"mleiv","Age"=>35);
$result = $client->call("DoSomething",array("parameters"=>$params),$ns);	
if ($client->fault) //soap_fault
{
	print "<;h2>Soap Fault:<;/h2><;pre>(".$client->fault->faultcode.")  ".
                $client->fault->faultstring."<;/pre>";
}
elseif ($client->getError())
{ 	
	print "<;h2>Soap Error:<;/h2><;pre>".$client->getError()."<;/pre>";
}
else
{ 	
	print "<;h2>Result:<;/h2><;pre>".$result["Pass"]."<;/pre>";
}
print '<;h2>Details:<;/h2><;hr />'.
		'<;h3>Request<;/h3><;pre>' . 
              htmlspecialchars($client->request, ENT_QUOTES) . '<;/pre>'.
		'<;h3>Response<;/h3><;pre>' . 
              htmlspecialchars($client->response, ENT_QUOTES) . '<;/pre>'.
		'<;h3>Debug<;/h3><;pre>' . 
              htmlspecialchars($client->debug_str, ENT_QUOTES) . '<;/pre>';	

Issue: In IE, when using links with display:block overtop of images, the block setting disappears and only the link text is clickable.

There are a few CSS tricks running around these days to replace the old image maps (which are a big pain in the ass to write). My personal favorite is to write a text link, then hide the text, size it, and place it over the image-to-be-mapped. Then the html makes complete sense and you always know which link is which. And people without css can still navigate. Excellent all around.

I created the following ultra-simplified example of my image-map substitute below. The blue-bordered area is a relatively-positioned wrapper div. The image inside is absolutely-positioned, and the red-bordered link is relatively positioned on top. You could reverse this: I didn't see a difference in the results. The link is set to be a block (not inline) so it will fill the dimensions specified. A span surrounds the text inside the link and that span is set display:none.

Sample #1: (initial attempt)

This works in all browsers but IE, where the image covers up the link. At first I thought this was a z-index issue (which IE has some well-documented issues with). But after exploring that for several hours, I found that this was not the case. When I set the background color of the link, it shows above the image (proving it is above the image in z-index).

Sample #2: (with background color)

I thought this might be one of those IE things where you can fix the element by setting width or display:inline-block. But not the case. Nothing helped but background-color. Then I let the text become visible again to see what would happen. This is really entertaining.

Sample #3: (showing text)

If you hover (in IE) over the text, it becomes immediately apparent that the block status of the link is being ignored - you can only click on the text area of the link. But this is only true in the area where the lower-level image is visible. So basically, IE will only see visible stuff inside the link (background-color or link text) and ignores the link block otherwise. Joy. So it was a quick matter to find an invisible element that IE sees as visible in order to overcome this problem: a blank gif! It doesn't matter if you use it as a background image or an inline-element set to the right size: IE sees this as a link object and shows the link. Yay!

Fix #4: (fixed - with blank background image in CSS) Fix #5: (fixed, with inline blank image)

If you would like to see these 5 simplified examples with no other interfering html see the IE Display Block Link Test Page.