ClockInfo.com
Commentary about clock repair and clock history (with some tidbits on web site development)

ClockInfo.com

Modifying WP PageNavi Plugin

November 22, 2007 . by Bill

I wanted the navigation elements of WP-Pagenavi to be centered on the page, and the current page number to be above the previous - next navigation, and not have a box around it.

In pagenavi.php, change line 8 from:

echo ‘<span class=”pages”>’.$pages_text.’</span>’;

to:

echo ‘<p class=”pages”>’.$pages_text.’</p>’;

Add the following to pagenavi-css.css:

.wp-pagenavi {
text-align: center;
}

Change the following lines in pagenavi-css.css from:

.wp-pagenavi span.pages {
padding: 2px 4px 2px 4px;
margin: 2px 2px 2px 2px;
color: #000000;
border: 1px solid #000000;
background-color: #FFFFFF;
}

to:

.wp-pagenavi p.pages {
padding: 2px 4px 2px 4px;
margin: 2px 4px 6px 2px;
color: #000000;
background-color: #FFFFFF;
}

You can see it on this web page on the Flora First Christian Church website.


Removing the Self Links on the Home Page

November 3, 2007 . by Admin

On a web site, there is no need to have a link to the home page on the home page itself! (It makes no sense for a web page to link to itself). This is a commonly known usability guideline, yet nearly all WordPress blogs and web sites have links on the home page to the home page.

In a new blog I am creating, I fixed this by modifying the header.php file in the theme. I did similar fixes to this blog as well.

Original code:

<div id=”h1″><h1>
<a href=”<?php bloginfo(’url’); ?>” title=”<?php bloginfo(’name’); ?>”><?php bloginfo(’name’); ?></a>
</h1></div>

Modified Code:

<div id=”h1″><h1>
<?php
if (!is_home()) { ?>
<a href=”<?php bloginfo(’url’); ?>” title=”<?php bloginfo(’name’); ?>”><?php bloginfo(’name’); ?></a>
<?php }
else {
echo bloginfo(’name’);
}
?>
</h1></div>

Similarly, on the home page, “Home” should not be listed with the list of pages.

Original code:

div id=”tabs1″>
<ul>
<li><a href=”<?php bloginfo(’url’); ?>” title=”Home”>Home</a></li>
<?php wp_list_pages(’depth=1&title_li=’); ?>
</ul>
</div>

Modified Code:

<div id=”tabs1″>
<ul>
<?php if (!is_home()) { ?>
<li><a href=”<?php bloginfo(’url’); ?>” title=”Home”>Home</a></li>
<?php } ?>
<?php wp_list_pages(’depth=1&title_li=’); ?>
</ul>
</div>


Ajax In Place Autocomplete Editor for CakePHP

July 29, 2007 . by Bill

The Scriptaculous InPlaceEditor and Autocompleter are very useful, and I needed a combination of them: when you click on a field to edit it, the Autocompleter comes up with a list of options, then after you choose an option and click “ok”, the ID of the selected element is sent to the server and the new text is sent back for display.

Here is the code used in my view:

// data to be displayed for editing
$fk_data = $input_data[$ForeignModelName][$foreign_column_name];

$editor_data =
“<td $display_style>\n
<div id=\”{$ModelName}_{$ForeignModelName}_
{$foreign_column_name}_{$rowId}\”>$fk_data</div>\n
<div id=\”{$ModelName}_{$ForeignModelName}_
{$foreign_column_name}_{$rowId}_ac_choices\”
class=\”autocomplete\”
style=\”opacity: 1; display: none;\”>
</div>
<script type=\”text/javascript\”>
var editor=new Ajax.InPlaceEditor(
‘{$ModelName}_{$ForeignModelName}_
{$foreign_column_name}_{$rowId}’,
‘/devadmin/{$controllerName}/editInPlaceDropDown/{$ForeignModelName}/
{$foreign_column_name}/{$ModelName}/{$fieldName}/{$rowId}’,
{cols: $size,
callback:function(form,value){
var request=\”value=\”+id;
return request;
}
}
);
Object.extend(editor, {
_createEditField: editor.createEditField,
createEditField: function() {
this._createEditField();
new Ajax.Autocompleter(
this.editField,
‘{$ModelName}_{$ForeignModelName}_
{$foreign_column_name}_{$rowId}_ac_choices’,
‘/devadmin/{$controllerName}/autocomplete/{$ForeignModelName}/
{$foreign_column_name}’,
{paramName: ‘q’ ,minChars: 2, frequency: 0.2,
afterUpdateElement: function(txt, li)
{
id = li.id.replace(’auto_’,”);
}
});}
});
</script>
</td>\n”;

$output .= $editor_data;

Here is the function editInPlaceDropDown, which is located in appController.php. It receives the ID of the row being edited as part of the URL, and receives the new value as the request variable ‘value’.

function editInPlaceDropDown($ForeignModelName, $foreign_column_name, $ModelName, $col_name, $rowId)
{

$ForeignModelName = text_input_filter($ForeignModelName);
$foreign_column_name = text_input_filter($foreign_column_name);
$ModelName = text_input_filter($ModelName);
$column_name = text_input_filter($col_name);
$rowId = integer_input_filter($rowId);
$value = integer_input_filter($_REQUEST['value']);

$this->layout = ‘ajax’;

if (!$this->RequestHandler->isAjax()) {
return true;
}

$this->$ModelName->id = $rowId;

$this->$ModelName->saveField($column_name, $value, true);

$new_value = $this->$ModelName->find(”$rowId = $ModelName.id”);

$new_value = $new_value[$ForeignModelName][$foreign_column_name];

$this->set(’new_value’, $new_value);
$this->render(’../common/ajax_update_field’);
}

Here is the autocomplete function, located in appController.php. It receives parameter “q” and returns the selection list, in the format documented in the comment.

function autocomplete($ForeignModelName, $foreign_column_name)
{

$ForeignModelName = text_input_filter($ForeignModelName);
$foreign_column_name = text_input_filter($foreign_column_name);

$this->layout = ‘ajax’;

if (!$this->RequestHandler->isAjax()) {
return true;
}

$text = text_input_filter($_REQUEST['q']);

$text = strtolower($text);
$data = $this->$ForeignModelName->findall(”lower($foreign_column_name) LIKE ‘%$text%’”, ”, “$ForeignModelName.$foreign_column_name ASC”);

$new_value = “<ul>\n”;
foreach ($data as $row=>$value) {
$new_value .= “<li id=\”auto_{$value[$ForeignModelName]['id']}\”>
{$value[$ForeignModelName][$foreign_column_name]}</li>\n”;
}
$new_value .= “</ul>\n”;

/*Sample output:
“<ul>
<li id=\”auto_12\”>Hi Bill</li>
<li id=\”auto_3\”>Hi Hairy!</li>
<li id=\”auto_5\”>Hi Holly</li>
<li id=\”auto_14\”>Hi Lovey</li>
</ul>”; */

$this->set(’new_value’, $new_value);
$this->render(’../common/ajax_update_field’);
}

The first <div> displays the text to be edited. The second <div> is used to display the drop down option list (by autocompleter). It has an initial style to not be visible.

The basic operation is this: Moving the cursor over the text field with the ajax InPlaceEditor causes it to be highlighted in yellow. Clicking on it changes it to an input form and activates the ajax autocomplete, via the object.extend, which causes inPlaceEditor’s internal function createEditField to be overridden by the one we define here (thanks to reference 1 for this approach!). The autocompleter sends parameter q, containing the text that has been typed into the input field, to the autocomplete function on the server; which returns the option choices in the following format:

<ul>
<li id=\”auto_12\”>Hi Bill</li>
<li id=\”auto_3\”>Hi Hairy!</li>
<li id=\”auto_5\”>Hi Holly</li>
<li id=\”auto_14\”>Hi Lovey</li>
</ul>

The afterUpdateElement function called by autoComplete gets the ID of the selected <li>. When “ok” is clicked, the callback function in inPlaceEditor sends a parameter in the form of value=ID to the editInPlaceDropDown function on the server, which saves the field in the database, then reads the new text value and returns it to the inPlaceEditor for display.

Many thanks to the following sources for their help:

  1. inplaceeditor + autocompleter on Ruby on Rails: Spinoffs
  2. Ajax Autocomplete With Scriptaculous by MetaPundit
  3. Extending Prototype.js by Elf M. Sternberg
  4. Ajax.In Place Editor on Scriptaculous Wiki
  5. Ajax.Autocompleter on Scriptaculous Wiki
  6. Ajax.In Place Collection Editor on Scriptaculous Wiki

WordPress Permalink Format

July 6, 2007 . by Admin

Today I changed my WordPress permalink format to /posts/post_id

At first, I used the default date format /year/month/day/post_name but then decided that dates were not useful information in the URL.

Next I tried /category/post_name, but the URLs were just too long to look “pretty”. (And I thought that if I ever re-named a post, the URL would change. I learned that this is not necessarily the case, as the post_name in the URL is actually the “slug”, which does not change when the post name changes, but can be changed manually if desired).

Then I used /category/post_id, which seemed very good, until I realized that If I ever reorganize my categories, the permalinks will change, leading to bad links. As the blog grows, I can foresee the categories changing. For example, if one category gets many, many entries, it could make sense to divide it into sub-categories.

Finally (I hope its final!), I changed the permalink format to /posts/post_id, which I believe will actually result in permanent permalinks. The post_id will never change, even if the post’s date, name or category is changed. Having the word “posts” in the URL is a good idea, so there will be no confusion with the URL for your “pages” such as “About” which do not have any prefix in the URL (for example the URL for my “About” page is http://clockinfo.com/about, but a typical URL for a post is http://clockinfo.com/posts/18).

There is lots of debate over whether keywords in the URL help with search engine indexing. In my opinion, the content of a web page should matter to the search engine, not the URL, otherwise people could use all kinds of spam words in the URL to make a web page rank better. I will take my chance with short, simple permalinks and see what happens.

I hope now that I can leave my permalink format alone, so that the Google indexing will stabilize. If you think that I am making a big mistake (or agree with me), please comment!

(Note: don’t change your permalink format if your site has been active for a while unless you install a plugin to redirect old URLs to new URLs. This blog is just a few weeks old so I felt free to make changes.)


CakePHP - Do not name a table “models”!

July 5, 2007 . by Bill

I’m making a clock model database. Naturally enough, I named one of my tables “models”. Using CakePHP, I could enter data into the table, but neither data validation nor table associations would work. I renamed the table to “item” and everything is fine. Likewise, I suppose, a table should not be named “views” or “controllers”. I wonder what other names will not work.


CakePHP: Many views - one controller

July 4, 2007 . by Bill

If you want multiple controllers to be able to share a view, do this:

  1. Put the shared views in the views/common directory
  2. Call a shared view like this: $this->render(’../common/view_name’);

Setting up WordPress

June 14, 2007 . by Admin
  1. When trying to install the Independence Day theme, the following error message appeared: Warning: array_merge() [function array_merge]: Argument 2 is not an array in: …/wp-includes/widgets.php on line 53. Based on the comments on this post:
    http://www.gudlyf.com/2005/01/14/wordpress-plugin-technotag/feed/
    I changed line 53 of wp-includes/widgets.php to:
    $sidebar = array_merge($defaults, (array)$args);
    The change casts argument 2 to the array type, and seems to work fine.
  2. I have multiple links categories (Blogroll, Clock History Links, etc) and my pages would not pass XHTML validation, due to repeated use of an id by the widget code. The WordPress forum gave the following fix: Insert the following line of code as the first statement after the else { on line 360 of wp-includes/widgets.php:
    $before_widget = preg_replace('/id="[^"]*”/’,'id=”%id”‘, $before_widget);

The above applies to WordPress version 2.2.

A side note: Dreameaver MX was adding multiple attributes such as mmTranslatedValueHiliteColor=”HILITECOLOR=%22Dyn%20Untranslated%20Color%22″ to the page, so I used jEdit instead for editing, and used Dreamweaver only for site management such as uploading files. I can’t explain why Dreamweaver is messing things up, I have the preferences set for it not to do code rewriting.

Another problem I had (never solved) with Dreamweaver MX editing php files was that in some cases it was replacing a require_once statement withe contents of the included file! I hope to try the latest version of Dreamweaver later this year and see if it is fixed.


Query Caching Using query($sql) Breaks getNumRows()

March 16, 2007 . by Bill

I am using Cakephp 1.1.11.4064 and a Postgresql database. I was having trouble in my application where the value returned from getNumRows() was incorrect in certain places.

The problem turned out to be Cake’s query caching. Example code

$sql_1 = “sql statement 1;”;
$parent_result_1 = $this->query($sql_1);
.
.
.
Lots of code here
.
.

$sql_2 = “sql statement 2;”;
$parent_result_2 = $this->query($sql_2);
$num_rows_2 = $this->getNumRows();

$sql_1 = “sql statement 1;”;
$parent_result_1 = $this->query($sql_1);
$num_rows_1 = $this->getNumRows();

During the execution of the application, the query for $sql_1 is put in the cache. Later on, the query for $sql_2 executes. Then when the query for $sql_1 in encountered again, the query is not executed, but the results are pulled from the cache. Unfortunately, however, the getNumRows function returns the number of rows from the previous database query, which happens to be the query for $sql_2. Thus, $num_rows_1 ends up being the same as $num_rows_2, which breaks my application.

The solution I found is to disable query caching for any query that will be followed by a getNumRows command, as follows:

$sql_1 = ” sql statement 1;”;
$parent_result_1 = $this->query($sql_1, ‘false’);
$num_rows_1 = $this->getNumRows();


Next Entries »