Tag Archive: APIs

WordPress Form API

The short version: I made a Form API for WordPress. Use it in your plugin. Make better forms. Give back and help us all make better forms.

Introduction

If you’ve every written a WordPress plugin, chances are you’ve had to create a form, be it for a settings page, custom post/user meta, widget configuration, front-end user input, or a myriad of other possibilities. If you look at WordPress core or most plugins, you’ll see all of them using pretty much the same method for creating a form field, something very similar to:

 
sprintf( '<input type="text" value="%s" name="%s" />', $current_value, $field_name ');

There are a few special kinds of fields that have pre-existing functions, such as wp_dropdown_pages() or wp_dropdown_categories(). But generally speaking, we’re writing HTML in our PHP (maybe dressed up as a template include).

Lament

I want something better than that. I want a robust API that lets me create forms (or individual form elements), modify them, validate, and process user input. I want themes to have control over the display of forms. I want other plugins to be able to modify and extend my forms.

I tried a variety of existing libraries. Zend_Form from the Zend Framework has a lot to offer, in terms of a robust, object-oriented API. But it’s not very pluggable, and loading the entire Zend Framework just for the Form API is overkill.

I used to spend a lot of time in Drupal, and its Form API is somewhat pleasurable to work with. Forms are amazingly extensible and themeable. But I’m not thrilled with the array-based syntax, and porting it to WordPress would be inappropriate for a multitude of reasons.

Toward a Solution

In the grand hacker tradition, I was dissatisfied with the existing options, so I made my own. I’ve dubbed it WP Forms, and you can download/clone/fork it from its home on GitHub.

What does it do? It’s an API for forms in WordPress. You can use it to create simple form elements. You can use it to create entire forms. You can validate your forms. You can process the submitted information. You can change how elements are rendered. You can wrap elements in themeable markup.

There’s a lot of documentation. It should answer a lot of your questions. And those that I didn’t anticipate, I’d be delighted to answer.

Request for Feedback

WP Forms is surely incomplete. I’m personally not thrilled with the API around adding optgroups to select elements, but I’m not yet sure how to improve it. The API for decorating elements is probably a little complicated for beginning developers, so I’m open to suggestions for a better way to handle that (or at least provide a facade for most common operations). Beyond that, I just don’t know how people would want to use the API. I know how I would use it, but I’m not “people”, and I’m definitely not you; I’m just me.

I can think of several features to add: conditional fields/content, ajax submissions, multipage forms, media uploads, more built-in field types/validators. What features would you want to see?

Request for Contributions

WP Forms will be much more powerful if we can get behind it as a community, extending it, improving it, using it, testing it, documenting it. Do you want an awesome form API in WordPress? I hope you’ll help me make one.

Fun with Acrobat

In my last post, I noted the need to convert some PDFs from a format suitable for a printer to a format suitable for online reading. The PDFs of the Muncie Times that I receive are laid out as spreads for each printed sheet of paper. So, for example, the first spread of the PDF includes pages 48 and 1, the next spread includes pages 2 and 47, etc. Many of the pages also have various printer’s marks along the edge.

First, I established a general algorithm for tidying this up.

  1. Make a copy of the document in reverse order and append it to the end of the document.
  2. Crop off the unneeded half of each spread (left for the odd-numbered spreads, right for the even-numbered spreads).
  3. Delete the printer’s marks from the margins.
  4. Add top and bottom margins.

If you’ve tried to do much automation with Adobe CS applications, you’ve probably encountered the well-documented JavaScript APIs that make the job much easier. Acrobat is special. Its API is very different, much more limited, and boasts horrible, often inaccurate documentation. Even getting Acrobat to recognize and run a script can be such a chore that I’ve taken to copying code into its JavaScript console and running it from there.

That rant aside, it wasn’t too difficult to accomplish the first couple of steps. Step 1 (assuming you’ve already opened the document):

var nPages = this.numPages;
for (i = 0; i < nPages; i++) {
	this.insertPages({
		nPage: nPages-1,
		cPath: this.path,
		nStart: i
	});
}

Step 2:

for (i = 0; i < this.numPages; i++) {
	if (i % 2 == 0) {
		this.setPageBoxes({
			cBox: "Crop",
			nStart: i,
			rBox: [11.25*72, 0*72, 22.5*72, 13*72]
		});
	} else {
		this.setPageBoxes({
			cBox: "Crop",
			nStart: i,
			rBox: [0*72, 0*72, 11.25*72, 13*72]
		});
	}
}

Note that all measurements must be in picas. Since 1 inch = 72 picas, I just multiply all of my values by 72. I probably could have made this more universal by letting the script calculate the width of the page and then divide that in half.

At this point I discovered an oddity of Acrobat. In other Adobe programs (and any image-editing program I’ve ever used), when you crop something, you define and area and remove everything outside of that area. Acrobat never removes any part of a page, it merely hides it. So while you have this document that looks like it has 48 pages, each 11.25 in. x 13 in., you really have a document that has 48 pages, each 22.5 in. x 13 in., which is to say a document twice the size that it needs to be.

In my search for a fix to this, I eventually came across this handy tip from the Acrobat 7 PDF Bible (p. 388):

If you want to eliminate the excess data retained from the Crop tool, you can open the PDF in either Adobe Photoshop or Adobe Illustrator. Both programs honor the cropped regions of PDF files cropped in Acrobat. When you open a cropped page in either program, resave it as a PDF.

Very helpful information, that, if the cure weren’t worse than the disease.

  1. Neither program can open more than one page of a document at a time. But I could write another script to do this part if that were the only problem.
  2. Photoshop rasterizes all of the text. Needless to say, that’s unacceptable.
  3. Illustrator can’t use embedded fonts if you don’t have them on your system and will replace them with whatever fonts are available. Since they have a Mac and I have a PC, this won’t work.

After mulling this over a bit more, I had an epiphany: print it! “Gasp,” you say, “wasn’t the whole point of this to avoid having to go through a print version?” Yes, but printing doesn’t have to go to a physical medium. In this case, I used the Adobe PDF printer that comes with Acrobat to print my PDF to a PDF. Incredibly, this worked. By setting a paper size to 11.25 in. x 13 in., I could print the document to a new, appropriately-sized document while discarding the excess data (and doing some optimization for online viewing while I was at it). Step 2 complete.

After discovering how to accomplish step 2, I realized that steps 3 and 4 could be accomplished in a similar manner. Crop the margins off and print to a new PDF with the margins I want, clear of any printer’s marks. As a matter of fact, these steps could be rolled into step 2. Simply take off an extra 0.45 in. from each side of the page, then print to a 11.25 in. x 13.75 in. page. So the new combined code for steps 2 and 3:

for (i = 0; i < this.numPages; i++) {
	if (i % 2 == 0) {
		this.setPageBoxes({
			cBox: "Crop",
			nStart: i,
			rBox: [11.70*72, 0*72, 22.05*72, 13*72]
		});
	} else {
		this.setPageBoxes({
			cBox: "Crop",
			nStart: i,
			rBox: [0.45*72, 0*72, 10.80*72, 13*72]
		});
	}
}

After that’s run, you create your custom paper size and print to PDF, centering the content on the slightly-larger page.

Off-Line Web Applications With Google Gears

One of the most frequent criticisms of the modern crop of web- and AJAX-based applications is the need for an Internet connection for them to work. After all, what good are Google Docs or webmail to you if you are on an airplane or facing a temporary connection interruption. Google has brought us one step closer to fixing that this week with its new Google Gears browser extension.

As others have pointed out, Google is not the first to develop something like this. But putting their weight behind it should help increase the development and adoption of off-line web applications.

I can imagine several potential uses for Gears within the library. Someone could conceivably save a set of records within an OPAC web interface, and still have access to those records while taking their laptop through the stacks of the library (presuming the library doesn’t have adequate Wi-Fi, of course). Or a student could save several items from a digital collection and still have access to those pages when presenting them to a class later. These things can already be done, of course, but Gears should make them easier and more user-friendly.

Like many Google products, Gears is still in Beta (much like Google Reader, which has implemented Gears), which means there are still some bugs to work out. There is some suspicion that it was rushed out the door to meet the deadline of Google Developer Day. But hopefully Gears will soon be a stable, robust, functional API for delivering off-line web applications.