Take the 2-minute tour ×
WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. It's 100% free, no registration required.

I'm fairly new to WordPress. I'm creating a page with a form. It works, but being so new, I'm wondering if I'm doing it in the best way. I'll use Twenty Twelve as an example theme.

  1. copy 'page.php' from Twenty Twelve (we'll use 'xxx.php' as the new template page name);
  2. working in xxx.php from here forward, add '// Template Name: My Template' to the top;
  3. 'require' my class file (which handles drawing the form, handling $_POST, etc.) and create instance;
  4. copy contents of 'content-page.php' to 'xxx.php', overwriting where it says 'get_template_part( 'content', 'page' );'
  5. right below 'the_content()', call my class method that either draws the form or shows output after handling $_POST;
  6. create a new page in admin, using 'My Template'

So, is this the 'normal' way to do what I'm trying to do, or is there a better way? Also, where should I store the class file and related css/js? If I store them in the theme directory I'd have to remember to move them before deleting the theme.

share|improve this question
add comment

5 Answers

up vote 1 down vote accepted

As has been mentioned, your way works, but there are some ways you can decouple the form from the template, allowing more flexibility.

The Shortcode API allows you to create a shortcode for your form, so you can simply enter something like [my_form] in the page's content, then within the function that handles your shortcode you can render the form and enqueue the necessary scripts. For the CSS, you can hook an action before the template is rendered to perform some regex on the requested page's content to see if it contains the shortcode, so you only enqueue the stylesheet when it's needed.

In general, you should familiarize yourself with filters and actions, these are the basis for just about everything you'd want to do in WordPress. For example, to process your form data, you could add an action to init to check if your POST vars exist and do whatever processing, database writes, redirection, etc., that you'd need to do, keeping your form independent of the template or page it's rendered on, or you can filter the_content to check the current requested page and render your form that way.

share|improve this answer
    
Thanks, Milo. I chose yours as the answer since filtering the_content was the way I ended up going. See my answer. –  akTed Jan 3 '13 at 5:57
add comment

That's an acceptable way to do it, if it works it works right :).

But if you want things not to be 'template'-dependant. To answer 'where' to put it. You might be better of creating a plugin for your form. That way you could add your form to any page you want.. So it depends on your needs.

If you are making a fully custom theme , just for yourself, I believe the best way to do it, is to keep it how you feel most comfortable with it. Or is that to free-spirited? :)

share|improve this answer
add comment

Like woony said, that is a valid way to do things - but it does tie your page with the form to the theme. There are some decent plugins that provide a form on a page pretty easily.

I know that Wordpress Jetpack (free) has a simple contact form that usually gets the job done.

There is also Gravity Forms (paid) which provides just about every possible feature under the sun.

As to styling, since styling is a theme concept, it is not a problem to put your form styles in your theme. Just keep in mind that you made that customization and if you switch theme, you will need to add new form styles to your stylesheet (and will probably want to anyways).

share|improve this answer
add comment

I'll add a couple thoughts to the excellent, existing answers:

  1. I suggest naming your template file using the convention template-foobar.php. Doing so helps differentiate it from other template and template-part files.
  2. Unless you intend to make use of the Post Editor for your template file, you don't need to output the default Loop in your custom template file. For example, if you want your form, and nothing but your form, you would want to start with the following codebase:

    <?php
    /** 
     * Template Name: Foobar Form
     */
    
    get_header();
    
    // Your custom code goes here
    
    get_footer();
    
  3. Assuming you're working with your own Theme (or a child Theme, as with your example case in which you modify Twenty Twelve), you would add your functional code to functions.php, either directly in the file, or via an included file.

  4. If you want this code available outside of a specific Theme, then you probably want to implement your code via Plugin. And in that case, you probably won't want to use a custom page template at all, but would want to look at using a custom shortcode.
  5. That said, you could still use a Theme custom page template; you would just have to create a new one for each Theme you use, and I would strongly recommend that you wrap any Plugin function call in a if ( function_exists() ) conditional.
  6. You can define a custom page template in your Plugin, and then use a callback on template_redirect, template_include, or page_template to determine when to use it (for example, based on a specific page slug, or, better yet, via custom post meta defined by the Plugin).

I'll step through this last point.

In your Plugin, you'll need to define custom post meta for static pages:

function wpse77991_add_meta_boxes( $post ) {

    add_meta_box( 
        'wpse77991_display_form', 
        __( 'Display Form', 'textdomain' ), 
        'wpse77991_display_form_meta_box', 
        'page', 
        'side', 
        'default' 
    );

}
// Hook meta boxes into 'add_meta_boxes_page'
add_action( 'add_meta_boxes_page', 'wpse77991_add_meta_boxes' );

Then, define the callback:

function wpse77991_display_form_meta_box() {
    global $post;

    $custom = ( get_post_custom( $post->ID ) ? get_post_custom( $post->ID ) : false );
    $display_form = ( isset( $custom['_wpse77991_display_form'][0] ) ? 'true' : 'false' );

    <input type="checkbox" name="_wpse77991_display_form" <?php checked( 'true' == $display_form ); ?> value="true" /> 
    <label><?php _e( 'Display Form?', 'textdomain' ); ?></label>
}

Then, define the post-save callback:

function wpse77991_save_display_form_meta_data() {
    global $post;

    $custom = ( get_post_custom( $post->ID ) ? get_post_custom( $post->ID ) : false );
    $display_form = ( isset( $_POST['_wpse77991_display_form'][0] ) ? 'true' : 'false' );

    update_post_meta( $post->ID, '_wpse77991_display_form', $display_form );
}
add_action( 'publish_page', 'wpse77991_save_display_form_meta_data' );
add_action( 'draft_page', 'wpse77991_save_display_form_meta_data' );

Now, the edit-post page will display a meta box for static pages, that will allow the user to check a checkbox to "Display Form".

You can then query that custom meta data in a callback to template_redirect, template_include, or better yet, page_template:

function wpse77991_page_template_include( $template ) {
    global $post;

    $custom = ( get_post_custom( $post->ID ) ? get_post_custom( $post->ID ) : false );
    $display_form = ( isset( $custom['_wpse77991_display_form'][0] ) ? 'true' : 'false'

    if ( 'true' == $display_form ) {
        return( plugin_dir_path( __FILE__ ) . 'template-foobar.php' );
    }
}
add_filter( 'page_template', 'wpse77991_page_template_include', 1, 1 );

All of the above is untested code, used here as a proof-of-concept for the process.

share|improve this answer
    
Thanks, Chip, for your nice, long proof-of-concept. I kinda feel bad that so much of your time was put into a seemingly workable solution. See my answer for the route I ended up taking. –  akTed Jan 3 '13 at 5:05
add comment

Thank you all for taking the time to respond, especially woony & Milo for putting me on the path I eventually chose - a plugin. More specifically, a mu-plugin. While I started down the shortcode path, I decided to filter the_content instead.

The only hitch I came across filtering it was that my form is in it's own file - standard html with interspersed PHP. require'ing it (in the filter) would output it both immediately after <body> and after the_content.

I tried file_get_contents on form.php, but that doesn't allow for the PHP vars that are echo'd in there. I didn't want to stringify it as it's a pretty long form - I hate editing HTML while it's in a PHP string. Then I stumbled across ob_start, which I'd heard of but never had use of til now. Here's what I eventually came up with:

First, the full mu-plugin code:

// exit plugin if not on the page I want to output to
if ( $_SERVER['SCRIPT_URL'] != '/option-page-starter/' ) return;

// instantiate class; __construct either handles the $_POST or initializes form vars
require('ops/class.php');
$akt_ops = new akt_opsForm();

add_filter('the_content', array($akt_ops, 'output'));

and $akt_ops->output (abbreviated for clarity)

ob_start(); // buffer output
require('form.php');
$text .= ob_get_contents(); // $text is the_content; copy from buffer to string now that it's correctly populated with my vars
ob_end_clean(); // cancel the buffered content
return $text;

This solution is much better than my original idea of doing it in the theme. Too much upkeep when changing themes. Now, all I have to do is fix the CSS if I decide to change themes.

P.S. - I'm brand-new here at StackExchange. I thought I chose to have it email me a digest of answers every 3 hours, but didn't get any emails from any of the responses. How do I subscribe to a question I've created so I'm notified whenever someone answers?

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.