WordPress – Creating Custom Post Types

Today I am working with custom post types. I want to allow the admin of the site I am creating to easily create various types of posts with different properties. None of the posts will be too complicated – in fact, many of them may just be a title and body text – but I want the admin to easily choose the exact post type from the left-hand nav. I don’t want him or her to have to create a basic “Post” then choose a category. It may seem like a nitpick-y distinction (and probably a less flexible solution) but I think it will make it easier for the admin to create specific types of posts.

I found three plugins that I’m considering using for custom post types:

I didn’t even try Pods. The overview video was sort of tedious and the plugin just didn’t seem like what I was looking for.

I played around a bit with Types and it seemed ok, but the interface to create new types felt a little clunky to me.

Wordpress - Types plugin

I guess it seemed too complicated. That may very well mean it’s more powerful than other plugins, but I’ll have to discover for myself if I need that power.

I decided to go with Custom Content Type Manager. The overview video made the plugin easy to use and indeed, my first experiments were straightforward. I’m probably going to move forward either with CCTM or a custom solution.

One thing that I think is common to all these plugins: When I am creating a custom type and adding custom fields, the fields always appear after the body text editor. Is there any way to reposition fields in WordPress’ new post editor?

I found this post on StackOverflow that describes how hide the body text editor. That seems like a good place to start.

< … trying that solution … >

Hmm .. it removes the body text editor if I set $post_type = “page” but it doesn’t work if I set it to “story”. And when I use this debugging statement:

echo "_wp_post_type_features = " . print_r($_wp_post_type_features, true) . "\n";

I can see that the only post types are “post,” “page,” “attachment,” “revision,” and “nav_menu_item.” Where is “story”? 

I found a couple other forum threads that seem to be looking to do exactly what I’m trying to do, but their solutions aren’t working for me or would only work for plain Posts. They suggest a number of global variables that could be useful, but none of them want to work for my scenario. Here are the variables I am trying to use and their values when I am editing a Story (a custom content type):

  • $post->post_type = empty
  • $post_type = empty
  • $current_screen = empty
  • $wp_post_types = big array of post types and their details; Stories not among them.
  • $_wp_post_type_features = more simple array of post types and some details; Stories not among them.
Lots of questions being raised here. The first three variables don’t display anything when I’m editing a plain Post either. Are these variables deprecated or something?

< … lots of research and tinkering … >

For some reason the CCTM plugin just wasn’t registering my new post type correctly (could very well be user error), so I began researching creating custom post types manually. I’ve found some good resources that explain the process pretty well, so I think I’m going to try to go this route instead.

For starters, I followed this tutorial by Richard Shepherd. The tutorial resulted in a barebones post type – good enough for starters. While going through the tutorial, I sidetracked into a bunch of WordPress function reference pages that are extremely useful and clearly explained:

One thing I can’t figure out and can’t find any information about: If I add several new post types to my functions.php file, it’s going to get quite long and unruly. How can I properly organize my it file in this case?

I have seen an offhanded suggestion that post types should be created within the context of a plugin, but not much more information beyond that. One of the benefits, apparently, of moving the creation of post types to a plugin is that the plugin can be shared across all themes, whereas the functions.php file is specific to the theme in which it is created. That sounds good to me.

Another question I have at this point: How do I create more complex custom fields like images or videos (or fields that can either be an image or a video)?

To hedge my bets – and I can do this because I’m basic in experimentation mode and everything I’m doing can just be thrown away if necessary – I am creating skeleton custom post types and I am also creating corresponding categories that can be used with generic Posts. I have kept my functions.php file somewhat clean by extracting the code for each of the custom types into their own PHP files, then included them in the functions.php file.

It makes a lot of sense to me to get these post types out of the theme, but for now I still don’t see how to do that. Do I create a plugin called client-name that includes the custom post types? Do I create a separate plugin for each post type? I don’t think I need to figure this out now, but eventually I do.

For now I am going to work on learning how to add the appropriate custom fields to each post type. As things stand, each of the four post types I created (Products, Stories, Locations, People) is just like a standard Post: A title and an editor (body text editor). There’s a chance things could be left just like this and still work. The admin would then to add things like images, videos, and secondary headers into the big editor.

Before getting into custom fields, I have run across a strange issue: I cannot get the excerpts from one of my custom posts (a product) to update. I added a second product and it works fine. If I update it’s body text the excerpt updates along with it. But the initial product’s doesn’t.

Update: Deleted the post and re-created it and it works fine. That was a dumb waste of time.

Update 2: Good blog post by Eric Mann about putting custom post types in plugins and keeping them out of themes. His Stacked theme gives a quick example of how he practices what he preaches.

Migrating a WordPress Site – Day 1

Starting a new project today: Migrating an existing WordPress site. I will be …

  • bringing over the existing data
  • creating some new data types
  • turning a new design into a theme
  • creating a intuitive-as-possible admin experience

First steps: Bring over the existing site.

This started out very straight forward:

  • I brought over the old files en masse
  • I set up a virtual host in apache
  • Edited my hosts file for my new dev domain (client.dev)
  • Looked at the wp-config.php file for the database name
  • Created a new, empty db with the same name (It’s not necessary to keep the db name the same, but it’s not big deal to me and it might make things install more smoothly. Does it?)
  • Changed wp-config.php to include my local db name and password.

The site popped right up, but I ran into two significant issues:

  1. I couldn’t access the admin side of things because I didn’t know the admin’s password.
  2. Everything I clicked on in the site was taking me to the live site: clientname.com

I came to find out these two issues were related. For one thing, submitting the login form was sending the info the the live client site. So I couldn’t tell if my attempts to override the admin’s password in the DB were working or not. Also, if I tried to retrieve the admin’s password using WordPress’ basic “lost password” mechanism, I would actually be calling the live site and the old admin would be getting the emails generated by the site. Not good.

I remedied the second issue by doing a search in PhpMyAdmin on the client’s domain in the DB. I found it in a couple places in the wp_options table and replaced it with my local dev domain. Voila! The site was at least no longer redirecting to the client’s domain.

Then I was able to overwrite the admin’s password by following some instructions I found on several different forums. Pretty easy stuff.

Now that I was in the system, I needed to get the site and its plug-ins up to date. The core files were already current (v3.3.2 as I write). Check. Now to the plug-ins. I see a few of them need updating, but when I choose to update them automatically I run into some FTP and/or permissions issues.

I try to turn on XAMPP’s FTP services, but I get a message telling me that I need to turn off a currently running FTP service that’s hogging port 21. I don’t think I have any FTP services, but a quick google search finds the crux of the issue. I need to turn of file sharing on my Mac. That same thread tells me the default XAMPP FTP user name and password are “nobody” and “xampp,” respectively. I like it when problems get cleared up this easily.

Whoops … not so fast. No I’m getting errors from WP about not being able to find the “wp-content” directory. Google to the rescue again. A WP forum thread suggests I need to add these two lines to my wp-config.php file:

define('FS_METHOD', 'ftpsockets');
define('FTP_BASE', 'path_to_my_wp_install');

That doesn’t quite work though, so I do another Google search to see if there are other options besides ‘ftpsockets’ for my filesystem (FS) method. The codex.wordpress.org site lets me know that there are other options: “direct”, “ssh2”, or “ftpext”. I try “direct” and it works! I am able to easily update my plugins now.

My final addition looks like this:

define('FS_METHOD', 'direct');
define('FTP_BASE', dirname(__FILE__) );

One odd note about changing the FS method. The codex page I linked to above says the following about using “direct” as my FS option:

this is fraught with opening up security issues on poorly configured hosts

Yet WP also lists “direct” as the “Primary Preference”. I don’t get it? If it’s so dangerous why is it the primary preference?

I’m not worried about this for now because it’s just my local environment, but I’ll need to push this to a production server at some point.

So the site is up and running and everything has been brought up to date. Now on to create some new data types.

UPDATE: I have run into this problem again and again and I seem to forget about this blog entry. Anyway, an additional note: Sometimes I am not able to update or install a plugin. I sometimes need to turn on full permissions to allow WP to do what it needs to do. There must be a way to allow WP admin to administer plugins with running chmod 777, but I can’t figure it out. For now, I have more or less had to do this:

chmod -R 777 wp-content

Yipes.

Drupalcon SF 2010 Day 3 Review

My third day at Drupalcon started with a most curious session: “Top 100 modules.” How was the presenter going to discuss 100 modules in only 60 minutes? To my pleasant surprise Deborah Fuzetto did about as good a job as one could be expected to do. Her presentation was especially good for a relative novice like me, a quick overview of popular modules and a description of how they are most commonly used. I hurriedly took lots of notes.

Next up was Wednesday’s keynote by Whitehouse.gov representative David Cole. The presentation was brief but informative. It’s reassuring to see Drupal being used for such a high-profile Web site that serves up lots of data.

I struck out during the post-keynote session, I attended a contrib development session that was over my head, then I jumped over to a session about UX development within Drupal. I had been keeping an eye on the #drupalcon Twitter posts and saw good reviews coming from that session, but by the time I got there it was over.

My last session of the day – and the conference as a whole – was “Module Building for Beginners.” The intention of the session was to show the development of a very simple module from scratch. The presenters moved very quickly. I was trying to follow along but it was very difficult. I encountered a hiccup early in the development of the module and the session was almost lost. I managed to get things working again and barely hung on for the rest. As I had hoped, I came away with the very basics for building a module.

All in all, Drupalcon 2010 was three days well spent. I learned more about theming, module development, key contributed modules and how to use them, what’s coming in Drupal 7, and some SEO info. The level of knowledge I gained wasn’t deep in any one area, but it was about all I could have expected with my current level of experience.

Perhaps most importantly, I left the conference with a good feel for the outstanding and growing Drupal community. Drupal developers and contributors are passionate about what they’re doing. I came away very confident that Drupal is in for a long, successful ride.

Drupalcon SF 2010 Day 2 Review

Started off Day 2 strong with “Search Engine Optimization (SEO) for your Drupal site,” a good presentation about SEO and Drupal. The session had tons of good information, but was marred by a few session-goers interrupting with questions. Possibly the most important element of the session – a chart showing what modules to use for what SEO benefits – was glossed over because the main presenter (Jen Lampton of Chapter 3) took questions during her talk. Overall very informative though.

Next came another information-packed session given by Todd Nienkerk of Four Kitchens. The session was “Accelerated grid theming using NineSixty.” Todd moved pretty quickly and it was hard to take proper notes, but again, lots of great info.

The third session I attended was “Views for developers” by Larry Garfield of Palantir.net. I’m sure this session was quite good for an experienced Drupal user but I was lost. I used the time to do some work.

Tim O’Reilly’s keynote “Open Source in the Cloud Era” was entertaining and thought-provoking. He provided a context for the value of Drupal and the Drupal community. Comparing it to the growth pattern Linux went through, he basically put Drupal at a tipping point where the community might take it to be a true major player CMS. He also looked ahead to the day when Drupal might add so many features that the acquired bloat/feature set may make it more appealing for enterprise solutions, but less appealing to users looking for a lightweight, fast solution. “Work on stuff that matters” were his last words to the crowd.

My last session of the day (I left a little early) was “2.4 million page views per day, 60 M per month, one server!” by Khalid Baheyeldin of 2bits.com. Khalid described some really clever ways he streamlined the performance of a site built for an unnamed entertainment company. Replacing little-used CCK module with some custom code, putting separate tasks (DB, Logs, etc.) on separate disks (rather than separate servers), and doing an end-around on the Drupal’s default way of handling 404 redirects were just some of the creative ways he found to keep the site zippy.

All in all a pretty great day. I attended sessions from 2bits.com, Chapter 3, and Four Kitchens.

Drupalcon SF 2010 Day 1 Review

Day 1 for me started off pretty well with a campy Intro to Druapl(con), then a great presentation from Lullabot’s Jeff Eaton, who gave a high level overview of Drupal architecture. Things were choppy after that with a session about Theme preprocess functions that was plagued by a malfunctioning demo and a presenter who spoke too fast.

Lunch (burrito) was good, Dries’ keynote was solid, and a lively session about Drupal 7 delivered by Angie Byron had things moving along well again. But a simplistic and hastily delivered CCK session and a session about executing a Drupal implementation that was little more than common sense provided a frustrating end to the day.

Getting ready for an SEO session now that will hopefully kick off an improved Day 2.

Drupalcon 2010 SF Beckons

I’m off to my first Drupal con in just a few hours. Not at all sure what to expect. Being essentially a novice, I just hope I am able to grasp enough during the sessions to make the three days worthwhile.

I’ve been tracking all the #drupalcon tweets and the “Drupalistas” are nothing if not enthusiastic (the hard core pre-conference stuff started Saturday, two days before the “regular” conference). I’m terrible at networking, but I hope to meet a few Drupal folk. Groove 11 can always use more Drupal resources.

I also have a nagging feeling that in two or three months I will wish I could go back to Drupalcon SF 2010 and do it over again with the knowledge gained after the conference.

Actionscript: Finding the Width of the First Line in a Dynamic Text Field

This is so ugly (or is it?) that I had to post it.

How does one find the width of the first line of a multi-line dynamic text field via Actionscript (AS2, specifically)? I couldn’t find a good solution to this via the usual forums, so I did it myself.

Here’s what I came up with. Pass in the string from the dynamic text field.

function getFirstLineWidth(_str:String):Number
{
	var firstLineWidth = 0;

	var wordArray:Array = new Array();
	wordArray = _str.split(" ");

	// "test_text" is a dummy text field on the stage. It must be
	//  the same width as the text field we're trying to measure.
	// It may be better to create a new text field on the fly then
	//  destroy it, but I needed to run this function a lot and wanted
	//  avoid the overhead.
	test_text._width = _textFieldWidth;
	test_text.text = "";

	while(wordArray.length > 0)
	{
		test_text.text += wordArray.shift() + " ";

		// Once the text goes to two lines, return the last width we recorded
		if(test_text.textHeight <= singleLineTextHeight)
		{
			firstLineWidth = test_text.textWidth;
		}
		else
		{
			break;
		}
	}

	return firstLineWidth;
}

Adobe CS4 Annoyances

This will be (maybe) an ongoing list of things I find annoying in CS4. If anyone out there knows of workarounds for these items, please let me know. (And yes, I will submit these items to Adobe.)

  • The Splash Screen. Why? The splash screen sits on top of everything else on my desktop, preventing me from doing any work for as long as 10 seconds. Thanks. Knowing that my user profile is loading is really some top notch information. At least let me turn this off in Preferences. Update: I just noticed that the Dreamweaver splash screen does not stay on top of other applications. Why does the Flash splash screen do so? Update2: A comment on this site suggests using F11 (on a mac) to bring up the desktop, then creating a new window in whatever program you’re using. This doesn’t seem to work for me, but I did discover that if I use Leopard’s “Spaces” feature and open Flash in its own space, I can move back to other spaces and the splash window is not present. Hooray!
  • Default Save Location. When I choose “Save As” (in Flash, at least) the default location to save files is the last folder I saved a file. Why isn’t it the folder containing the file I just opened? I am always jumping from project to project so the default folder is almost always incorrect. I can’t imagine any benefit for choosing the last used folder. Lame. Again, can’t we make this a preference setting?
  • Saving as CS3. I don’t know of too many people working in CS4. Almost none of my co-workers use it. Can’t I choose to always save as CS3 by default? Once again, a simple preference setting would make this so easy.
  • Default keyboard shortcuts in Flash. By default, “Z” brings up the “Bind Tool” instead of the Zoom Tool. Whatever that tool does I’m sure it’s great, but why does it get the “Z” shortcut?? I can only imagine the ratio of Zoom Tool usage to Bind Tool usage. 1000 to 1? Maybe 10000 to 1? And, hello, “Zoom” starts with “Z”. Duh. And “Z” still brings up the Zoom Tool in Photoshop. Annoying inconsistency. Update: When I went to specify my own shortcuts under preferences, I saw that the Zoom Tool is called “Magnify”. That sort of explains the “M” shortcut, but for all the other reasons I’ve listed, it’s a dumb default.
  • Speaking of keyboard shortcuts, why is Command-R the option to view rulers in Photoshop, but to view rulers in Flash it’s like Command-Control-Shift-Function-Alt-R? Command-R in Flash is “Import to Stage”. Two things wrong here: 1) Why don’t the commands match? and 2) Viewing rulers must be a more common action than importing to stage, isn’t it? Please, somebody set me straight if I’m wrong here.

I know keyboard shortcuts can be customized but why are they so goofy out of the box?

Update (5/7/9): According to a comment to this blog entry, the “Save As” issue goes back several versions. Adobe’s excuse is “something like saving as an earlier version wipes out your undo history.” Lame.

Dashes (Hyphens) vs. Underscores – Which is better for SEO?

I can’t find a solid answer on this potentially important SEO topic.

The most referenced source seems to be this blog entry from Matt Cutts (a Google employee). That entry, however, is from 2005.

That’s ancient in internet terms. That article advocates for dashes over underscores, but it’s based on rather flimsy data.

There’s a follow-up entry of sorts from August 2007 where Matt seems to say underscores are fine, but dashes are slightly better.

And that’s it. I can’t find any definitive information from either side of the fence since then. That’s over a year and a half ago.

Arguments (from people who have some evidence to back it up, as well as people who are just guessing) on the side of dashes:

  • It looks better.
  • Dashes are used in everyday language (i.e. natural language).
  • Sites with dashes in their URLs show up higher in search results than sites with underscores.

Pros (again, from people who may or may not know better) for underscores:

  • Underscores are not used in everyday language, so they’re a good replacement for spaces.
  • Plenty of sites (Wikipedia, TypePad, etc.) use underscores.
  • Sites with underscores in their URLs show up higher in search results than sites with dashes.

Ugh. Can’t anyone provide a definitive answer? I have sites to build!

SQL For Creating States, Provinces, Districts, and Territories

INSERT INTO `state` (`state_id`, `abbr`, `name`) VALUES
(1,’AL’,’Alabama’),
(2,’AK’,’Alaska’),
(3,’AB’,’Alberta’),
(4,’AZ’,’Arizona’),
(5,’AR’,’Arkansas’),
(6,’BC’,’British Columbia’),
(7,’CA’,’California’),
(8,’CO’,’Colorado’),
(9,’CT’,’Connecticut’),
(10,’DE’,’Delaware’),
(11,’DC’,’District of Columbia’),
(12,’FL’,’Florida’),
(13,’GA’,’Georgia’),
(14,’HI’,’Hawaii’),
(15,’ID’,’Idaho’),
(16,’IL’,’Illinois’),
(17,’IN’,’Indiana’),
(18,’IA’,’Iowa’),
(19,’KS’,’Kansas’),
(20,’KY’,’Kentucky’),
(21,’LB’,’Labrador’),
(22,’LA’,’Louisiana’),
(23,’ME’,’Maine’),
(24,’MB’,’Manitoba’),
(25,’MD’,’Maryland’),
(26,’MA’,’Massachusetts’),
(27,’MI’,’Michigan’),
(28,’MN’,’Minnesota’),
(29,’MS’,’Mississippi’),
(30,’MO’,’Missouri’),
(31,’MT’,’Montana’),
(32,’NE’,’Nebraska’),
(33,’NV’,’Nevada’),
(34,’NB’,’New Brunswick’),
(35,’NL’,’Newfoundland’),
(36,’NH’,’New Hampshire’),
(37,’NJ’,’New Jersey’),
(38,’NM’,’New Mexico’),
(39,’NY’,’New York’),
(40,’NC’,’North Carolina’),
(41,’ND’,’North Dakota’),
(42,’NT’,’Northwest Territories’),
(43,’NS’,’Nova Scotia’),
(44,’NU’,’Nunavut’),
(45,’OH’,’Ohio’),
(46,’OK’,’Oklahoma’),
(47,’ON’,’Ontario’),
(48,’OR’,’Oregon’),
(49,’PA’,’Pennsylvania’),
(50,’PE’,’Prince Edward Island’),
(51,’QC’,’Quebec’),
(52,’RI’,’Rhode Island’),
(53,’SK’,’Saskatchewan’),
(54,’SC’,’South Carolina’),
(55,’SD’,’South Dakota’),
(56,’TN’,’Tennessee’),
(57,’TX’,’Texas’),
(58,’UT’,’Utah’),
(59,’VT’,’Vermont’),
(60,’VA’,’Virginia’),
(61,’WA’,’Washington’),
(62,’WV’,’West Virginia’),
(63,’WI’,’Wisconsin’),
(64,’WY’,’Wyoming’),
(65,’YT’,’Yukon Territory’);