Posted... (human time display)

Following on from the previous post, I’ve also shamelessly poached another idea from Dunstan: human-readable timestamps. Just pop this into your post.html file, where you want the ’time’ to appear.

    {capture name=hour}{the_time d="G"}{/capture}
    {assign var=hour value=$smarty.capture.hour}
    Posted
    {if $hour eq "00" or $hour eq "01" or $hour eq "02"}
        in the wee hours,
    {elseif $hour eq "03" or $hour eq "04" or $hour eq "05" or $hour eq "06"}
        terribly early in the morning,
    {elseif $hour eq "07" or $hour eq "08" or $hour eq "09"}
        early in the morning,
    {elseif $hour eq "10"}
        mid-morning,
    {elseif $hour eq "11"}
        late morning,
    {elseif $hour eq "12" or $hour eq "13"}
        mid-morning,
    {elseif $hour eq "14"}
        early afternoon,
    {elseif $hour eq "15" or $hour eq "16"}
        mid-afternoon,
    {elseif $hour eq "17"}
        late afternoon,
    {elseif $hour eq "18" or $hour eq "19"}
        early evening,
    {elseif $hour eq "20" or $hour eq "21"}
        evening,
    {elseif $hour eq "22"}
        late evening,
    {elseif $hour eq "23"}
        late at night,
    {/if}

Time Since (...after the fact).

I had noticed lots of blogs had a nice little Posted x hours, y minutes after the fact tag attached to Comments. I thought this was pretty cool, and had a very short attempt at this some time ago. Then, over on Binary Bonsai, Michael mentioned how the plugin was broken, and how it needs fixing. Well, I didn’t fix the PHP version, but I did write a pure Smarty version!

    {* 
    
    "Time Since" Smarty Code 
    
    Author: Matt Schinckel <matt@schinckel.net>
        http://schinckel.net
    
    Based on a WordPress Plugin "Time Since" 
        http://binarybonsai.com/wordpress/timesince
    
    Notes: Insert this whole text where you want the
    text to appear.  If keen, you could move the first
    pair of lines to a place outside of the comment loop,
    but still inside the post.  This might save some
    precious server seconds.
    
    The accuracy of the 'time since' decreases over time:
    there aren't 30.4 days in every month, for instance.
    
    *}
    
    {capture name=post_time}{the_time d="U"}{/capture}
    {assign var=post_time value=$smarty.capture.post_time}
    
    {capture name=comment_time}{comment_date d='U'}{/capture}
    {assign var=comment_time value=$smarty.capture.comment_time}
    
    
    {assign var=since value=$comment_time-$post_time}
    
    
    {if $since < 3600}
        {assign var=name1 value="minute"}{assign var=sec1 value=60}
        {assign var=name2 value="second"}{assign var=sec2 value=1}
    {elseif $since < 86400}
        {assign var=name1 value="hour"}{assign var=sec1 value=3600}
        {assign var=name2 value="minute"}{assign var=sec2 value=60}
    {elseif $since < 604800}
        {assign var=name1 value="day"}{assign var=sec1 value=86400}
        {assign var=name2 value="hour"}{assign var=sec2 value=3600}
    {elseif $since < 2626560}
        {assign var=name1 value="week"}{assign var=sec1 value=604800}
        {assign var=name2 value="day"}{assign var=sec2 value=86400}
    {elseif $since < 31536000}
        {assign var=name1 value="month"}{assign var=sec1 value=2626560}
        {assign var=name2 value="week"}{assign var=sec2 value=604800}
    {else}
        {assign var=name1 value="year"}{assign var=sec1 value=31536000}
        {assign var=name2 value="month"}{assign var=sec2 value=2626560}
    {/if}
    {math equation='floor(a/b)' a=$since b=$sec1 assign=count1}
    {math equation='floor((a-floor(a/b)*b)/c) a=$since b=$sec1 c=$sec2 assign=count2}
    Posted {$count1} {$name1}{if $count1 != 1}s{/if},
           {$count2} {$name2}{if $count2 != 1}s{/if} after the fact.

Another Gravatar Implementation

I recalled at some stage there was a Smarty Modifier called escape. I think it was when I was looking for one called rot13. Anyways, you can use this and the JavaScript function unescape() to obfuscate the email address. You’ll need this code early in your template: I stick it at the start just after <html>

1
2
3
    <script type="text/javascript" 
        src="http://schinckel.net/images/md5.jpg">
    </script>

This fragment will insert the Gravatar Image:

    {capture name=reader}{comment_author_email}{/capture}
    <script type="text/javascript">
    document.write('<div class="right">');
    document.write('<img src="http://www.gravatar.com/avatar.php?gravatar_id='); 
    document.write(hex_md5(unescape("{$smarty.capture.reader|escape:"hex"}"))); 
    document.write('&size=40" alt="" />');
    document.write('</div>');
    </script>

This seems to more reliably display the Gravatars, so I’d suggest you use it instead. Either that, or Gravatar just fixed up their servers…

Autofill Acronyms in Comments

I created (or rather modified) some code to allow for quicktags, so commenters can have bold, italic and code text, amongst other features. I also added in abbr and acronym tags, just for fun. Today, I made this even more kick-ass. If you select some text, and click on abbr or acronym, and there is a valid acronym in the list in the script, it autofills the definition in the dialog for you. I got rather excited after doing this. But, I’m a nerd. • Note: The seperate Quicktags toolbar is not supported. Please use the full toolbox script, or hack it any way you like. The remainder of this post remains for posterity only. • Anyway, you can get the button version here, and the CSS link version here. Remember to Right-click and download, rather than just clicking on them.

Automation of XHTML Cleanup

I use SubEthaEdit all of the time, and the feature I like just about most is the Copy As XHTML ⇧⌘C. This will create some nice marked up text that accurately represents what SubEthaEdit looks like - it takes your current syntax styling layout and creates is as XHTML. There are a couple of issues, at least with Blogsome. Firstly, for some reason Blogsome needs all style tags inside the block to use ‘, not “. I think it might be to do with the fact it is a <pre> block. I did notice it was screwing with some double-quotes on another script I was posting. My other hassle is that the syntax highlighting isn’t quite right for AppleScript: it doesn’t take into account terms used from applications, so sometimes the wrong colour appear. I will write an Automator action that grabs the XHTML from SubEthaEdit, replaces " with ‘, and pastes it into the current active text box, I think. I also started using Convert Script To Markup Code - don’t recall where I found this, but it does a much better job of marking up the text from Script Editor, and everything looks much nicer.

Simple Catchpa

Note: This has been updated to reflect most of the feedback I received from the comments and emails. One of the ways to combat comment spam is to use a Catchpa: or a Completely Automated Turing Test to Tell Humans and Computers Apart. I have implemented one with a simple bit of JavaScript. You need to have two sections of code in your comments.html:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
    function checkCatchpa()
    {
        var catchpaResponse = document.getElementById("catchpa").value;
            if( catchpaResponse == theAnswer )
            {
                return true;
            }
        return false;
    }
    
    function SubmitComment()
    {
        if (checkCatchpa() == true)
        {
            document.commentform.submit();
        }
    }

This one needs to be inside a <script> block: I have it where I also use a couple of functions to show a comment preview. You will also need to surround the script block with {literal} tags to prevent it from screwing up your template. The next one creates the puzzle. It should go after the URI box in your comment form:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
    <p>
        <input type="text" name="catchpa" id="catchpa" value="" size="28" tabindex="4" />
        <label for="catchpa">{_e text="<acronym title='Completely Automated Turing Test to Tell Humans and Computers Apart'>Catchpa</acronym>: "}</label> 
        <script type="text/javascript">
            var firstNumber = Math.ceil(Math.random()*10); 
            var secondNumber = Math.ceil(Math.random()*10); 
            document.write("What is "+firstNumber+" plus "+secondNumber+"?");
            var theAnswer = firstNumber + secondNumber;
        </script>
    </p>

You will also then need to tell the form itself to call the checkCatchpa() function, rather than just submitting:

1
         <form action="{$siteurl}/wp-comments-post.php" method="post" id="commentform" name="commentform" onSubmit="return checkCatchpa()">

Depending on your setup, you may also need to use the SubmitComment() call on your link or button that actually submits the form.

1
    <a class='button' href='javascript:SubmitComment();'> Post Reply </a>

I’ve tested this and it works: I’ll leave it on my site for a couple of days so you can test it out: if you have any problems, leave a response here (if you can!), or AIM/email me.

WordPress PHP files

Since someone on the forums mentioned that you can change some hardcore options with /wp-admin/options.php, I got a little interested, and discovered there are other filest that you can run, and do interesting stuff with. All of these PHP files are located in http://yourblogname.blogsome.com: /wp-admin/install-xxx.php, where xxx can be: b2, blogger, greymatter, livejournal, mt, rss, textpattern. These will allow you to import the contents of your blog directly into blogsome, I assume. I haven’t done this, so cannot tell if they will work - I imported mine via ecto, an offline reader. Actually, it looks like the b2, blogger, greymatter ones might work - the others require you to edit the files that you open. And I cannot seem to identify these files in the editing screen, so I’m stuck. /wp-admin/plugin-editor.php This would be cool, except you cannot actually change any files. Oh well, at least you can examine a plugin and see how it works… Also interesting are the Smarty Template files. I may learn something here about what extra things I can do from Smarty in Blogsome. custom_fields.enclosure.php & custom_fields.photoblog.php I already use enclosure, but I didn’t know about photoblog. Have to investigate that one. function.blogroll.php, function.cork.php, function.eightball.php, function.googleit.php, function.photoblog.php, function.pirate.php & function.relatedstories.php {blogroll} allows you to use blo.gs to track your blogroll. I’m pretty happy with RSS at home, so I’ll leave it there. {cork} - don’t know what this does yet. {eightball} looks like it wants to be a magic eightball simulator, but only ever seems to give me the one result: Maybe in your reality. {googleit}, {photoblog} & {pirate} will require further study. {relatedstories} looks interesting, but I cannot get any result as yet: this I may work on. I think it’s pretty much like {todayayearago}. outputfilter.protect_email.php {'string'|protect_email} does not work: it causes the pages not to load.

Arguments that don't work

I’ve come across several Smarty Tags that call WordPress functions that have listed arguments that don’t work. I didn’t bother too much about it - usually I can live with it. Then, I realised how I solved one instance of this happening: the Recent Comments plugin.

I downloaded the source to this, and looked at it. Besides there being some spelling mistakes, it had argument names which differed from the documented ones. No wonder it was failing when I tried to change the number of comments, and the comment length! So, looking at the code helped me solve the problem. Maybe it will with the other issues I have come across: most notably {previous_post_link} and {next_post_link}, and {edit_post_link}.

I’ll start with the {edit_post_link}. The codex says the argument I want to change is called text, but the source reveals it to be link. Changing this enabled me to change the text that is presented to whatever I want. The same goes for {edit_comment_link}.

I was originally using the tags {previous_post} and {next_post}, but was unable to change the previous post:|next post: text that appeared. Changing the name of the argument from text to previous and next (as applicable) fixed this. Similarly, since {previous_post} and her sister are deprecated, {previous_post_link} has arguments that differ from those detailed in the Codex. The arguments it (and {next_post_link}) can handle are:

  • format - defaults to &laquo; %link. You need to have the %link where you want the URL to appear! You can add more stuff that you want to appear but not be part of the link itself.
  • link - defaults to %title. Add other text that you want to add into the link area.
  • in_same_cat
  • excluded_categories

Depending upon if you want an image clickable, you can either insert the code into the format or link argument. Just for fun, I included my favicon in the non-link section of the link text (ie, the format argument). I’ll leave it there for a while, just to prove it can be done…in the meantime, I’m going to fix the Codex.

Blogsome Gravatars

Note: this post is now out of date. Go to Gravatars in Blogsome instead. I did get Gravatars working in Blogsome to some extent a while ago, but it exposed the email addresses. What I’ve done now is obscure the email addresses, and it should be safe to use: <script type="text/javascript"> {capture name=reader}{comment_author_email}{/capture} var ob_email = "{$smarty.capture.reader|replace:'@':';'}"; var email = ob_email.replace(/;/g,"@"); document.write('<div class="right"><img src="http://www.gravatar.com/avatar.php?gravatar_id='); document.write(hex_md5(email)); document.write('&size;=50" /><\/div>'); </script> Basically, it grabs the Commenter’s email address, and changes it in Smarty from email@domain.com to email;domain.com - then JavaScript is used to change it back before passing to the hex_md5(); function. You will need to have the following code inserted in your template somewhere before this: <script type="text/javascript" src="/images/md5.jpg"></script> And the file md5.jpg stored on your server, or the following line (using the copy on my server): <script type="text/javascript" src="http://schinckel.net/images/md5.jpg"></script> If you download my version, clicking on the links won’t work: you’ll need to right-click and choose Save…

Comment Preview for Blogsome!

I’ve implemented Comment Previewing from Blogsome blogs. There is no way to install 3rd party plugins in WordPress MultiUser, so everything has to be done in JavaScript. But really, the plugin is just JavaScript packaged up nice anyway. You need four code fragments, all in your comments.html file. The first one I suggest goes after the line: {if 'open' == $post->comment_status} Because it is a JavaScript that uses { and }, you need to remember the {literal} tags. {literal}<script type="text/javascript"> <!-- function ReloadTextDiv() { var UseInstantPreview = document.getElementById("use_instant_preview").checked; if( UseInstantPreview == true ) { var NewText = document.getElementById("comment").value; splitText = NewText.split(/\n/).join("<br />"); var DivElement = document.getElementById("commentpreview"); DivElement.innerHTML = splitText; } } // --> </script>{/literal} It probably doesn’t matter exactly where it goes, but having it after the {if} clause means it will only be included in the file if comments are open. The second code fragment is: onkeyup="ReloadTextDiv();" And it goes in the <textarea id=comment … > tag. In context, mine is: <textarea name="comment" id="comment" cols="60" rows="12" tabindex="4" onkeyup="ReloadTextDiv();"></textarea> The third fragment is the checkbox for enabling or disabling Comment Preview. It can go wherever looks good. <input onclick='ReloadTextDiv();' name="use_instant_preview" type="checkbox" id="use_instant_preview" value="1" checked /> <label for='use_instant_preview'>Use Instant Preview</label> The final fragment tells the browser where the Comment Preview goes: <div><p id="commentpreview"></p></div> And it goes where you want the Comment Preview to actually go. I suggest just after the Submit button, or other instructions. Righto, all of that in there, and it should work. You may need to add an entry to your Site Style Sheet to make the Comment Preview box look the same as your actual comments box. • If you wanted to, you can also have a Preview button that will preview what is in the text area then, rather than having Live Preview. This is good for a couple of reasons: I find that long comments slow down when trying to update every keypress. The big problem is that you cannot have a normal input field inside the form set to do this, it will just try to submit it (or at least, mine did!). So, I’ve replaced my input tags in my form with the following (You may need to insert name='commentform' into the form start tag.): <a class='button' href='javascript:document.commentform.submit();'> Post Reply </a> <a class='button' href='javascript:ForceReloadTextDiv();'> Preview </a> You’ll also need to add the following in just after the ReloadTextDiv function definition: function ForceReloadTextDiv() { var NewText = document.getElementById("comment").value; splitText = NewText.split(/\n/).join(" "); var DivElement = document.getElementById("commentpreview"); DivElement.innerHTML = splitText; }