scriptygoddess

One feature I'm extremely excited to see in WordPress 3.0 is the new "Menus" feature. It's pretty easy to add and use in your theme. I was having trouble finding documentation on it, so this is not "official" but this is as far as I can tell, how you can go about using it.

First, if your theme doesn't already have a functions.php file, go ahead and create one. Then add the following PHP code:

register_nav_menus( array(
'mainnav' => 'Main Nav'
) );

"mainnav" (which is the menu's "slug" and shown as "Main Nav" in the admin) is just what I came up with – but you can name it whatever you want, and you can have multiple nav menus if you want. Just register them all in that functions file. Here's an example with 3 nav menus:

register_nav_menus( array(
'mainnav' => 'Main Nav',
'navtwo' => 'Nav Bar Two',
'navthree' => 'Nav Bar Three',
) );

That's it – What that does is tell your theme you're going to have three different/unique menus. You can use them as many times as you want, wherever you want in your theme.

You'll create your menus in the WordPress admin – this is pretty self explanatory (and described pretty well here) – add pages, categories, custom links that point outside your blog, whatever you want. Give the menu a name and "apply" it to a location:

Now – to add it to your theme… You get a whole bunch of options so if you need the menu to display one way in one location, and a different way in another location – you can do that!

Here's a simple example where I've stripped out the nav "wrapper" and any automatic styling it would add – just drop this in your theme file where you want the menu to show up (like your header.php, or footer.php… wherever)

$args = array( 'menu' => 'mainnav', 'container' => false, 'menu_id' => false, 'menu_class' => false);
wp_nav_menu($args);

But you can insert an ID or a class. This is detailed pretty well here.

I've already started to use this and it's great. Clients have been really happy that they can now manage their own menus without requiring edits to a template.

Updated to add: As pointed out by Stephen in the comments – if you are creating themes for general public use and you're not sure what version of WordPress your userbase will be running – you will want to wrap these new functions in a "if (function_exists('new-fancy-function-name-here')) { … }". He has details on this on his site here. In there, he linked to another article that would have helped me out a lot had Google liked the page more so I could have found it when I was working on this recently – but there's some additional reading here on how to set all this up (it's a lot more in depth than I got into – I guess my version is the "Cliff Notes") 😉

29 May, 2010

Test Credit Card Numbers

Posted by: Jennifer In: Lessons learned|shopping cart

When you are working with an online store, sometimes you need to enter a credit card number that will pass the "logic" of how the card number should be structured so that you can test the flow of your site. These card numbers are not valid for purchase, and if validated against a gateway – it will return as being invalid – however, that's fine if all you're testing is the front end process of the store (before the gateway). In cleaning out my office today, I found a few numbers I used to use for this purpose. I can't remember if all of them worked (and the next time I have to run a test, I'll remove any I use that seem not to) – but wanted to keep these safer than in the dark corners of my office closet…

Visa:
4444 3333 2222 1111

MasterCard:
5424 0000000000 15
(there's 10 zero's in there)

Discover:
6011 0000000000 12
(Again, 10 zero's)

Amex:
37 000000000000 2
(12 zero's in there)

There's also a bunch of other test credit card numbers here in case you need them.

One of the projects I've been working on recently is to move a client's Blogger blog into WordPress. The blog is a few years old, but it has an ENORMOUS amount of comments. Doing the standard import from within WordPress wasn't bringing over all the posts and it barely scratched the surface of bringing over the comments.

I found this post on ArtLung: Migrating an old Blogger Blog To WordPress – which was a HUGE help. The gist of that was you need to download an export file from Blogger, then get this script you run from the terminal (on Mac) which will convert the Blogger xml into a xml that WordPress will understand. (Just to give you an idea what we're talking about – the Blogger XML file I downloaded was over 40MB.)

THEN the fun began. After the conversion to WordPress XML – the file was still about 30MB. This meant that I had to run the import over a dozen times before it could chew through the whole file. When the import times out and you run it again, it recognizes that some posts are already there, so it doesn't import them a second time – but for some reason, it seemed to have trouble with a bunch of comments. Some of the comments DID get imported more than once. As well – the comment counts for each post weren't getting updated. SO! Here's the fix I pieced together for those issues.

First, to remove the duplicate comments – in PHPMyAdmin – I ran the following SQL command: (*DISCLAIMER: make sure you backup your database before attempting any of this!!)

CREATE TABLE temp_table AS SELECT * FROM wp_comments WHERE 1 GROUP BY `comment_post_ID`,`comment_content`,`comment_date`;

What that does is create a duplicate of the wp_comments table – but it's only grabbing the unique entries. If a comment is posted to the same post, has the same content and the same date – we'll just be grabbing one of those and ignoring the rest.

UPDATED TO ADD: One important thing I need to add in here is that you need to set the primary keys and a few indexes for this new table – This is the structure of a normal wp_comments table:

CREATE TABLE `wp_comments` (
`comment_ID` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`comment_post_ID` bigint(20) unsigned NOT NULL DEFAULT '0',
`comment_author` tinytext NOT NULL,
`comment_author_email` varchar(100) NOT NULL DEFAULT '',
`comment_author_url` varchar(200) NOT NULL DEFAULT '',
`comment_author_IP` varchar(100) NOT NULL DEFAULT '',
`comment_date` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`comment_date_gmt` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`comment_content` text NOT NULL,
`comment_karma` int(11) NOT NULL DEFAULT '0',
`comment_approved` varchar(20) NOT NULL DEFAULT '1',
`comment_agent` varchar(255) NOT NULL DEFAULT '',
`comment_type` varchar(20) NOT NULL DEFAULT '',
`comment_parent` bigint(20) unsigned NOT NULL DEFAULT '0',
`user_id` bigint(20) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`comment_ID`),
KEY `comment_approved` (`comment_approved`),
KEY `comment_post_ID` (`comment_post_ID`),
KEY `comment_approved_date_gmt` (`comment_approved`,`comment_date_gmt`),
KEY `comment_date_gmt` (`comment_date_gmt`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=2 ;

THEN, I ran this SQL command;

DROP TABLE wp_comments;
RENAME TABLE temp_table TO wp_comments;

What that does is delete the wp_comments table, then we rename our new and improved "temp_table" so that it is now the official wp_comments table.

NEXT – we want to update the comment counts. To save having to recount the comments each time – there is a field in the wp_posts table that stores the total number of comments. However, with the way this import worked, those numbers did not get updated so most were saying there were 0 comments on posts that did have comments. To fix that issue I ran the following SQL command: (which I found here on Planet MySQL)

UPDATE wp_posts wpp
LEFT JOIN
(SELECT comment_post_id AS c_post_id, count(*) AS cnt FROM wp_comments
WHERE comment_approved = 1 GROUP BY comment_post_id) wpc
ON wpp.id=wpc.c_post_id
SET wpp.comment_count=wpc.cnt
WHERE wpp.post_type IN ('post', 'page')
AND (wpp.comment_count!=wpc.cnt OR (wpp.comment_count != 0 AND wpc.cnt IS NULL));

Which as far as I can tell gets the comment counts for each post in wp_posts. (I can't tell you more than that because once you start getting into the "LEFT JOIN" stuff in sql, my brain shuts off)

The other piece advice I'll give is if you have a ginormous blog that you have to move like the one I was working with – set the blog up locally using MAMP, do the imports, all the database correcting stuff – then just export the database and import it onto your server. The database file ended up only being 14MB uncompressed – way better than trying to chew through a 30MB import file. Once the database is up on your server, a few more SQL commands (just like if you're moving your blog to a new domain) to change the local version (probably http://localhost:8888 ) to your actual domain name, and you're done!

Another tidbit to add: if you need to redirect blogger formatted url (that may include ".html" in the end) – add this to your htaccess file and it should redirect to the new (non extension ending) URL:

RewriteEngine On
RewriteRule (.*)\.html $1 [R=301,L]

(I tooke off the first line and put the second line under the "RewriteEngine On" that WordPress has in it's htaccess block and it worked great)

On a project I was working on recently, I was pulling in some css for iPhone users using PHP with the following code:

<php if (strpos($_SERVER['HTTP_USER_AGENT'],"iPhone")) { ?>
... CUSTOM CSS FOR IPHONE...
<php } ?>

This will also work for iPhones and iPod Touch:

<php if (strstr($_SERVER['HTTP_USER_AGENT'],'iPhone') || strstr($_SERVER['HTTP_USER_AGENT'],'iPod')) { ?>
... CUSTOM CSS...
<php } ?>

That's great and all – but then suddenly one day it stopped working. Going back through what changed on the site, I realized one thing we added was a cache plugin. DOH! So the page gets cached without the custom CSS for the iPhone – the iPhone calls up the site but gets served the cached page (non-iPhone version)… Yeah, that would do it.

So I found this solution:

<!--[if !IE]>-->
<style type="text/css">
@media only screen and (max-device-width: 480px) {
.... CUSTOM CSS HERE....
}
</style>
<!--<![endif]-->

or of course you can pull in a whole stylesheet for the iphone:

<!--[if !IE]>-->
<link media="only screen and (max-device-width: 480px)" rel="stylesheet" type="text/css" href="iphone.css" />
<!--<![endif]-->

Comments Off on CSS for iPhone's eyes only (watch out for the cache)

A project I was working on recently required the use of a membership plugin. I had done some research on membership plugins awhile back and remembered only finding ones that were pretty pricey. One last ditch effort searching through the plugin repository on WordPress.org – I found one that I hadn't remembered seeing before: S2Member. This plugin really is packed with features and gives the others a run for their money. If you are in the market for a membership plugin – definitely give this one a try first. (And if you're happy with it, make sure you contribute to it's development. If we all chip in, we all benefit!) (Here's the download page on wordpress.org)

Here's the plugin description taken from the download page:

s2Member is a full-featured membership management system for WordPress®. It provides a very tight integration with PayPal® Subscriptions, and fully supports recurring billing with the ability to track affiliate commissions on a recurring basis. s2Member supports up to 4 different levels of membership with custom labels. It supports custom Pages for signup, account access, and many others. It also supports the ability to protect certain Pages, certain Posts, certain Categories/Tags, certain parts of content, and even includes advanced documentation on how to utilize the PHP runtime constants provided by the s2Member API. s2Member also supports protected file downloads with limitations on the how many files each user ( or each level ) can download in a given period of time.

01 Apr, 2010

Showing multiple random quotes

Posted by: Jennifer In: PHP|Script snippet

Showing random quotes isn't anything new. When I needed to do something similar on a site recently, there were plenty of pre-written scripts to choose from. The trick however, was that I wanted to show more than one quote at a time (and of course I didn't want to show the same quote twice. That wasn't as easy to find. (I'm sure there's variations out there, but now I'll always have a place to find mine) 😉

First step is to load all the quotes you want into an array:

$quotes[] = "This is line 1";
$quotes[] = "This is line 2";
$quotes[] = "this is line 3";
$quotes[] = "This is another line";
$quotes[] = "This is yet another line";
$quotes[] = "Line 6";

Now get a handful of keys using array_rand:

$rand_keys = array_rand($quotes, 2);

We specified to get two random keys from the $quotes array – (You can grab more if you want, just change the "2")

Now that we have our random keys – you can either list them out one by one like this:

//show the first quote...
echo $quotes[$rand_keys[0]];
//show the second quote
echo $quotes[$rand_keys[1]];

Or you can loop through the keys like this:

foreach ($rand_keys as $value) {
echo $quotes[$value]."<br />";
}

That's all there is to it.

I can't speak for anyone else who has run into this problem, but I know I have run into it on more than one occasion. Having just figured out my particular issue this time, I'm making a note for myself (and anyone else who may have the same problem).

You may run into this problem if you have a template that you have "hardcoded" the header (in my case – it was a custom page template that actually needed a completely different header than the rest of the site – so I opted not to use "get_header()" on this template and just put the custom header right there in my custom page template…)

I *did* remember to include the "wp_head()" – so that wasn't the issue (although I have fogotten to do that on other occasions and that will cause all kinds of trouble, including seo plugin stuff not working) – but in this case – the other meta tags were coming in – but the titles weren't being rewritten.

The problem was the fact that I wasn't using get_header() – this must be the function that kicks off the search for that title tag and replaces it with the rewritten titles. If you don't use get_header() – your titles will not be rewritten.

You will run into the same problem even if you don't "hardcode" your header – and use the "include" line instead:

include( TEMPLATEPATH . '/header2.php' );

Whatever happens with "get_header()" – you need to run it to get those titles working.

(I've since updated this post – scroll down to the bottom for the simplest solution!!)
So if you have a different header for your page template – what you need to do is within your header.php – determine which header file it should load in… but ONLY AFTER you have the title tags written out… You could even use the "is_page_template()" function to figure out which header to pull in.

So my header.php looked something like this for this project I was running into with this:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title><?php wp_title('«', true, 'right'); ?> <?php bloginfo('name'); ?></title>
<?php
if (is_page_template('my-custom-page-template1.php') || is_page_template('my-custom-page-template2.php')) {
include( TEMPLATEPATH . '/my-custom-page-template-header.php' );
} else {
?>
... rest of the header is here...
<?php } // endif custom page template checking... ?>

Now you can put your custom header in that "my-custom-page-template-header.php" (or whatever you want to call it) and on your "my-custom-page-template1.php and my-custom-page-template2.php, etc just use get_header() at the top like normal.

Actually – here's an even better/simpler option:

Name your custom header like this:
header-my-customheader.php.

Then when you call "get_header()" – do so like this:

get_header('my-customheader');

When using WordPress as a CMS, I often repurpose the "posts" as other types of content a site may need. For example, news or press releases, or any information that might need the ability to be catgorized and/or tagged (like testimonials). However, this may mean that you need a completely different template for your news page than you would want for your testimonials page.

WordPress gives you the ability to create category specific templates. So let's say your "news" category has an ID of 5 – if you create a category.php page to be used by all the other categories, and also created a category-5.php page – then just your news page will use that template for the category archive page.

But – what if you have a huge handful of subcategories and you want them all to use the same category template as it's parent? (Let's also assume that we can't just make this the default template) Here's what I came up with. Let's say that Testimonials is our category – it has an id of 12. It also has a dozen or so subcategories (for argument's sake, lets say we've sorted our testimonials into groups from what types of companies these testimoinals have come from "Consulting Firms", "Web Host Providers", "Design Firms", etc.

We don't want to duplicate our category template for every subcategory we have. That's a nightmare to manage. So lets do this instead: In your category.php template file – before ANYTHING ELSE – even before you call get_header() – we add the following:

$thecategory = get_category($cat);
if ($thecategory->category_parent == '12' || $thecategory->cat_ID == '12') {
include(TEMPLATEPATH.'/testimonials-template.php');
} else {
/* include... default template file here like we included the "testimonials-template.php - or you can just wrap this around your actual template code... */
}

So what this does is it gets information about the category – if the current category's PARENT is 12 OR we are in fact looking at category 12 – then we pull in that special testimonials-template.php file… Otherwise the other code would be executed. (In the file I was using I just wrapped that around my existing category.php template code…

Please note: I have not tested this on if you have a SUB SUB category – I'm thinking $thecategory->category_parent probably only looks one level above the current category… so keep that in mind.

(I make the note above that this does not include a plugin because when I was trying to get this to work – one solution I had found online involved installing a plugin that kind of messed with my category heirarchy in a way I wasn't crazy about. Personally, I think this is a much simpler solution)

Updated to add: This article was translated to Belorussian here.

13 Jan, 2010

Never Update the Copyright Year Again (on a PHP page)

Posted by: Jennifer In: PHP

This is a really silly little trick – but if you have a PHP page that has a © copyright year at the bottom – there is no reason you should be updating that every year (unless it's just something you overlooked initially) :) As you get requests from clients now that we're in a new year to change the copyright year in the footer – do yourself a favor and use this instead so you never have to do it again. :)

<?php echo date("Y"); ?>

Ran into a bizarre problem today using swfobject. A lot of wasted time, but I'll give you the short story / solution.

I'm not sure of what other factors played a role (the fact that the element was in a absolute positioned container, or that the immediate container to the flash element was in a float) but I had the call to the swfobject javascript in the BODY tags of the html (not within the head tags). This was apparently causing Firefox to not display the flash. Simply moving the swfobject javascript code within the head tags of the html instantly fixed the problem.

I know I've used swfobject inside the body before – so I'm sure there's something else that contributed to the problem.

Featured Sponsors

Genesis Framework for WordPress

Advertise Here


  • Scott: Just moved changed the site URL as WP's installed in a subfolder. Cookie clearance worked for me. Thanks!
  • Stephen Lareau: Hi great blog thanks. Just thought I would add that it helps to put target = like this:1-800-555-1212 and
  • Cord Blomquist: Jennifer, you may want to check out tp2wp.com, a new service my company just launched that converts TypePad and Movable Type export files into WordPre

About


Advertisements