Edit/Delete Comment

At times, it’s annoying to have to go into the Dashboard, just to delete a Comment that has appeared, or to Edit a comment I have made (or fix the text of someone else’s comment). Luckily, you can create links or buttons to allow you to do these two jobs while viewing a Post page: ✍ Edit ✗ Delete In your Comments.html template, find the location you want to put the links. To just have the Edit Comment link (you can delete a comment from it’s editing page), insert the following:

1
    {edit_comment_link}

To have both an Edit and a Delete link, try the following:

    {capture name=edit_comment}{edit_comment_link link="✍ Edit"}{/capture}
    {if $smarty.capture.edit_comment != ""}
        {$smarty.capture.edit_comment}
        <a href="http://schinckel.net/wp-admin/post.php?action=confirmdeletecomment&comment={comment_ID}">Delete</a>
    {/if}

I have mine all nicely styled, using the following (and some CSS):

    {capture name=edit_comment}{edit_comment_link link="&#9997; Edit" before='<span class="button">' after="</span>"}{/capture}
    {if $smarty.capture.edit_comment != ""}
        <div class="right">
            {$smarty.capture.edit_comment}
            <span class="button"><a href="http://schinckel.net/wp-admin/post.php?action=confirmdeletecomment&comment={comment_ID}">&#10007; Delete</a></span>
        </div>
    {/if}

Fancy Archive Page

Ages ago, I wrote about how to (a) pass Pages through the Post template, and (b) use Smarty Tags in special Pages. I had an Archives page, that had a list of every Post I’d ever made. It’s getting kind of long, so I wrote a script that parses this list, and creates a structured list, dividing the posts up according to the month they were published. It then makes this list so that you can hide/show a whole month’s worth of posts in one go. In the Posts Template, I have the following lines:

    {elseif $smarty.server.REQUEST_URI == '/archives/' || $smarty.server.REQUEST_URI == '/archives'}
        <ul>{get_archives type='postbypost' limit='' format='html'}</ul>{$content}

Note that this is out of context: see my whole Posts template file for details. This is in the actual Page:

    <script type="text/javascript">
    var months = new Array("","January","February","March","April","May","June","July","August","September","October","November","December")
    function getYear(li){
        return li.innerHTML.split("/")[3]*1;
    }
    function getMonth(li){
        return li.innerHTML.split("/")[4]*1;
    }
    
    function showKids(id){
        var unit = getById(id);
        for (var i=1;i<unit.childNodes.length;i++){
            unit.childNodes[i].style.display="block";
        }
    }
    function hideKids(id){
        var unit = getById(id);
        for (var i=1;i<unit.childNodes.length;i++){
            unit.childNodes[i].style.display="none";
        }
    }
    function toggleKids(id){
        var unit = getById(id);
        if (unit.childNodes[1].style.display == "none")
            showKids(id)
        else
            hideKids(id)
    }
       
    function Restructure(){
        var pc = getByClass("post-content")[0];
        var items = pc.getElementsByTagName("li");
        var list = items[0].parentNode;
        var month_nodes = document.createElement("ul");
        
        var month_node = document.createElement("li");
        month_node.className = "month";
        month_node.innerHTML = months[getMonth(items[0])] + " " + getYear(items[0]);
        month_node.id = month_node.innerHTML.replace(" ","_");
        month_node.innerHTML = "<h3><a onclick='toggleKids(\""+ month_node.id +"\");'>" + month_node.innerHTML + "</a></h3>";
        month_nodes.appendChild(month_node);
        
        var this_month;
        var next_month;
        
        while (items.length) {
            this_month = items[0];
            next_month = items[1];
            month_node.appendChild(this_month);
            if (next_month && (getMonth(this_month) != getMonth(next_month))){
                month_node = document.createElement("li");
                month_node.className = "month";
                month_node.innerHTML = months[getMonth(next_month)] + " " + getYear(next_month);
                month_node.id = month_node.innerHTML.replace(" ","_");
                month_node.innerHTML = "<h3><a onclick='toggleKids(\""+ month_node.id +"\");'>" + month_node.innerHTML + "</a></h3>";
                month_nodes.appendChild(month_node);
            }
        }
        
        pc.replaceChild(month_nodes,list);
        
        var all = getByClass("month")
        for (var i=0;i<all.length;i++) hideKids(all[i].id);
    }
    
    Restructure();
    </script>

You’ll notice a couple of strange comments, and what looks to be a closing all tag: these are because the Blogsome post editor kindly closes tags for me, even when they aren’t tags!

Movin’ Out (Anthony’s Song) • Billy Joel • Greatest Hits ★★

I’m off to Karaoke now, I might have to sing that song!

Fixing Generated Invalid XHTML

I had a standard Smarty function, {list_cats}, that under certain circumstances generates invalid XHTML. Specifically, when a feed_image is supplied, not alt tag is generated. This annoys me, as I have worked hard to make my template generate “nice” code. Smarty to the rescue. Whilst you cannot pass the results of a Smarty function through a Smarty filter, like replace, you can capture the results, and then pass this through the filter:

    <h2><a href="/categories/">Main Categories</a></h2>
    <ul>
        {capture name=cats}{list_cats optionall='1' all='All' sort_column='name' optioncount='0' children='0' hierarchical='1' feed_image='/images/feedicon10x10.gif'}{/capture}
        {$smarty.capture.cats|replace:"/></a>":"alt='Live Bookmark (RSS Feed)' /></a>"}
    </ul>

By the way, I used a similar technique to convert a list of (list) items into a list of selects:

    <h2>Links Dropdown</h2>
    <ul>
        <li><form name="linksform" action="" method="post" style="margin: 0px; padding: 0px;">
            <select id="link_list">
            <option value=''>Select Link to View</option>
            {capture name="linklist"}{get_links}{/capture}
            {$smarty.capture.linklist|replace:'<a':'<option'|replace:'</a><br />':'</option>'|replace:'href':'value'}
            </select>
            <input type="button" class="button" value="Go" onclick="window.location = (document.forms.linksform.link_list[document.forms.linksform.link_list.selectedIndex].value);" />
        </form></li>
    </ul>

Conditional Styling

I have an Asides category, posts in which appear differently on my site. That’s all well and good, but I want these posts to appear normally if viewing the Asides category, or an individual Asides post. So, I need to be able to style stuff differently depending on a couple of factors. The most obvious method for this would be to have CSS changing if certain conditions are met. However, in practice this seems to be somewhat difficult. You cannot access the equivalent of a DOM tree in CSS. You can add new entries to a style description, but not find out much real information about the current styles. Approaching this from the other direction, however, looks to be more promising. Especially if you examine the code I use to style differently to begin with:

    <div class="post {is_aside}{if $is_aside=='true'}Asides{/if}" id="post-{the_ID}">

This snippet could be used to have different styles for any category, using something like:

    <div class="post {the_category seperator=' '}" id="post-{the_ID}">

I’m not examining now the mechanics of how to change these styles, as that can be found in another post on my site: Styling Asides Differently. To remove the Aside class entry, I’ve restructured my post.html file to start with:

    {is_aside}
    {if $smarty.server.REQUEST_URI|truncate:17:'':1 == '/category/asides/'}
        {assign var=is_aside value=false}
    {/if}
    
    <div class="post {if $is_aside=='true'}Asides{/if}" id="post-{the_ID}">

But how do we find out if we are viewing a single post? One easy method is to test using the {single_post_title} function:

    {capture name=title}{single_post_title}{/capture}
    {if $smarty.capture.title != ''}
        {assign var=is_aside value=false}
    {/if}

Bingo. All Done. My Mum is right. I am a star.

Styling Asides Differently

I thought I’d already written up a post on this, since I discovered it about a month ago, but apparently not. Blogsome has a nice little function called {is_asides}. It allows for easy alternate formatting of posts within a category called Asides. So, to have these fancy little numbers, the first thing you’ll need is an Asides category, with a post in it. Then, in your Post Template, try the following code: <div class="post {is_aside}{if $is_aside=='true'}Asides{/if}" id="post-{the_ID}"> This sets up the class of the post to also be Asides if it is in that category. I’ll make a note here that this could be done with any category, and just use {the_category seperator=" "}. This would allow alternate styling for any given category, but I wanted to use the {is_asides} Smarty function. That’s all of the code you need, the rest is just pure CSS. In my stylesheet, I have the following code, that looks after all of the Aside related stuff:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
    .Asides
    {
        border:#E1D6c6 1px dashed;
        padding:6px;
    }
    .Asides .post-info
    {
        display:none;
    }
    .Asides .post-footer
    {
        background:none;
        padding-top:0px;
    }
    .Asides .post-content
    {
        border-top:none;
        padding:2px;
        background: url(/images/blockquote.gif) no-repeat left top;
    }

The first stanza sets up the border and layout for the actual post. The second hides all of the post-info, such as Date, Title, etc. I later decided to move the Comments Link, else there is no way to view/add comments. The third removes the fancy symbol that appears between posts, and the last one removes the line at the top, and puts some lovely quotes into the background. I’m still going to tweak this a little: on an individual post page, the next/previous post links overlap with the bottom of the border.

Gravatar Smarty Modifier

I wrote a Gravatar modifier for Smarty: {$comment->comment_author_email|gravatar:"default":     size:"rating":border} For example, to use no default image, and limit the size to 40x40 pixels, you’d use: {$comment->comment_author_email|gravatar:"":"40":"":""} Notice the double quotes where the argument is missing, and that (in this version) you actually need to include all of the arguments. (I’ve updated this, but haven’t tested it fully yet). Anyway, here’s the code:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
    <?php
    /**
     * Smarty plugin
     * @package Smarty
     * @subpackage plugins
     */
    
    
    /**
     * Smarty gravatar plugin
     *
     * Type:     modifier<br>
     * Name:     gravatar<br>
     * Author:   Matt Schinckel<br>
     *           mailto:matt@schinckel.net<br>
     *           aim:mschinckel<br>
     *           http://schinckel.net<br>
     * Purpose:  convert email address to gravatar
     * @param string
     * @return string
     */
    function smarty_modifier_gravatar($email, $default=false, $size=false, $rating=false, $border=false)
    {
        $gravurl = "<img src='http://www.gravatar.com/avatar.php?gravatar_id=".md5($email);
        if ($default)
        {
            $gravurl = $gravurl."&amp;default=".urlencode($default);
        }
        if ($size)
        {
            $gravurl = $gravurl."&amp;size=".$size;
        }
        if ($rating)
        {
            $gravurl = $gravurl."&amp;rating=".$rating;
        }
        if ($border)
        {
            $gravurl = $gravurl."&amp;border=".$border;
        }
        return $gravurl."' alt='Gravatar Image' />";
    }
    
    ?>

Blogsome Templates

Say you find a Blogsome site, with a template you really like. You ask the author for the data, but they don’t reply to you. Never fear. You can always get the data from a Template, as this data is world-readable:

You may need to right-click and Save As…, or view source to see them properly. Obviously, for blogs other than mine, replace _schinckel _with the relevant word… I’m working on getting this so the source of the current templates can be viewed in another web page, but there are some issues with this. The iframe/object will only display the rendered value, and CSS files don’t display at all.

{todayayearago}

Another Blogsome user was wanting to use {todayayearago} to get posts from a week ago, which reminded me I do it with a month ago. Looking through the source to see if a weekly one exists (it doesn’t, as yet), I came across this little nugget:

1
    function todayayearago( $when, $wpblog, $spacer ='<br /' )

Now, ignoring the apparent typo (I think there should in fact be a closing tag to that there BR tag…), what do you see that is notable? That’s right, you can choose a different blog. So I tried this with my test blog:

    {todayayearago when='month' wpblog='schinckel'}
    {if $todayayearago != ''}
        <h2>A Month Ago</h2>
            <ul>
                {foreach from=$todayayearago key=id item=details}
                    <li>
                        <a href="{get_permalink id=$id}" title="{$details.content|truncate:25:"..."}">
                            {$details.title|truncate:20:"..."}
                        </a>
                    </li>
                {/foreach}
            </ul>
    {/if}

Now, this gives some very interesting results. Firstly, it works, except for the part that tries to get the permalink:

href="{get_permalink id=$id}"

This fails, because it (naturally) tries to grab the permalink from the current blog, not the other one. My next step was to see if {get_permalink} can handle an argument like wp_blog. The sad news is it can’t. So, the next question is: does the URL get returned in the data structure along with the content and title. I suspect so, but need to see how. Looking through the source of wp-db.php doesn’t throw much light on the topic, so it’s time for trial and error. That’s what a test blog is for, after all! Aha! You can see most of what happens from the todayayearago file itself:

1
2
3
4
5
    foreach( $reqhistory as $row )
    {
     $todayayearago[ $row->ID ] = array( "title" => strip_tags( stripslashes($row->post_title) ),
      "content" => strip_tags( stripslashes( $row->post_content ) ) );
    }

Which clearly shows that only the title and content are ‘grabbed’. So, until I rewrite this function (so it includes the URL, and perhaps even so it allows for other intervals), it’s use is still limited to posts within your own blog, from either a year or a month ago. Unless I can find a way to get post data from another blog’s database…

$smarty.get.*

I don’t know how I never found this before… You can use {$smarty.get.<var>} to get the URL variable you want. For instance, you can use the following ones in WordPress MultiUser:

  • year
  • monthnum
  • day
  • name
  • paged/page
  • category_name
  • wpblog

Unfortunately, these variables don’t seem to be set with Pages, rather than Posts. However, this has given me some tips as to how to fix the .htaccess RewriteRule problems causing Blogsome not to display subsequent pages of monthly archives. Possibly something to do with the fact it uses page, rather than paged, and that for some reason it parses the word page as the name of the post. This looks like not a .htaccess bug at all, now that I think of it.

Category Pages

I want to add some functionality to my site. I used to just have a few categories, but as I wrote more, I wanted to sub-categorize a bit. So now, I have a handful of parent categories, and under (most of) these I have one or more child categories. In some cases this goes three or four deep. But, so the category list isn’t too long, I only show the parent categories in the sidebar. What I want is that when a category page is shown, at the top is a list of the child categories. I can (relatively) easily find out if I am viewing a category page: {if $smarty.server.REQUEST_URI|truncate:10::1 == '/category/'} I can also quite easily find the name of the category, but not the id. This is what I need for creating the category list. I’ve just had a thought. Checks something. The following displays the info that is sent to the server: {foreach from=$smarty.server.argv item=var} {$var} {/foreach} I was hoping it would give the category id. But it doesn’t, only the name. Back to the drawing board.