diff --git a/include/class.dynamic_forms.php b/include/class.dynamic_forms.php
index 5b76646420b5e4a9420f6ae1537657af3f290d9a..0e529729c764c638257144113a32a342c5936a8a 100644
--- a/include/class.dynamic_forms.php
+++ b/include/class.dynamic_forms.php
@@ -283,7 +283,7 @@ class DynamicFormField extends VerySimpleModel {
      * field of a custom form. The latter would be isValidEntry()
      */
     function isValid() {
-        if (count($this->errors()) || !parent::isValid())
+        if (count($this->errors()))
             return false;
         if (!$this->get('label'))
             $this->addError(
diff --git a/include/class.forms.php b/include/class.forms.php
index 4dc69b993ee80473a35691c5fdf55589c88c3d97..b5e53d9eee4e9646a9abcc8c3f33efb45837313f 100644
--- a/include/class.forms.php
+++ b/include/class.forms.php
@@ -23,7 +23,7 @@ class Form {
     var $title = 'Unnamed';
     var $instructions = '';
 
-    var $_errors;
+    var $_errors = null;
     var $_source = false;
 
     function Form() {
@@ -61,7 +61,7 @@ class Form {
      *      boolean true if the field's errors are significant
      */
     function isValid($include=false) {
-        if (!is_array($this->_errors)) {
+        if (!isset($this->_errors)) {
             $this->_errors = array();
             $this->getClean();
             foreach ($this->getFields() as $field)
diff --git a/include/class.orm.php b/include/class.orm.php
index 05201c6682bc38cb4579b14492e6f62c3d7c406e..be6a46f3e89cfd3902913d37a352a7345d002a81 100644
--- a/include/class.orm.php
+++ b/include/class.orm.php
@@ -206,17 +206,6 @@ class VerySimpleModel {
                 $i->set($field, $value);
         return $i;
     }
-
-    /**
-     * isValid
-     *
-     * Validates the contents of $this->ht before the model should be
-     * committed to the database. This is the validation for the field
-     * template -- edited in the admin panel for a form section.
-     */
-    function isValid() {
-        return true;
-    }
 }
 
 class SqlFunction {
diff --git a/include/class.ticket.php b/include/class.ticket.php
index 13fea02f055e0b16baa0e9ed85a59164157ac315..ea04eac12ab5ff9af0dd083c1a5cd61dc6a2149d 100644
--- a/include/class.ticket.php
+++ b/include/class.ticket.php
@@ -1888,12 +1888,28 @@ class Ticket {
     function create($vars, &$errors, $origin, $autorespond=true, $alertstaff=true) {
         global $ost, $cfg, $thisclient, $_FILES;
 
+        // Don't enforce form validation for email
+        $field_filter = function($f) use ($origin) {
+            // Ultimately, only offer validation errors for web for
+            // non-internal fields. For email, no validation can be
+            // performed. For other origins, validate as usual
+            switch (strtolower($origin)) {
+            case 'email':
+                return false;
+            case 'web':
+                return !$f->get('private');
+            default:
+                return true;
+            }
+        };
         // Identify the user creating the ticket and unpack user information
         // fields into local scope for filtering and banning purposes
         $user_form = UserForm::getUserForm();
         $user_info = $user_form->getClean();
-        if ($user_form->isValid())
+        if ($user_form->isValid($field_filter))
             $vars += $user_info;
+        else
+            $errors['user'] = 'Incomplete client information';
 
         //Check for 403
         if ($vars['email']  && Validator::is_email($vars['email'])) {
@@ -1930,20 +1946,6 @@ class Ticket {
                 $field->value = $field->parse($vars[$fname]);
         }
 
-        // Don't enforce form validation for email
-        $field_filter = function($f) use ($origin) {
-            // Ultimately, only offer validation errors for web for
-            // non-internal fields. For email, no validation can be
-            // performed. For other origins, validate as usual
-            switch (strtolower($origin)) {
-            case 'email':
-                return false;
-            case 'web':
-                return !$f->get('private');
-            default:
-                return true;
-            }
-        };
         if (!$form->isValid($field_filter))
             $errors += $form->errors();
 
@@ -2005,9 +2007,6 @@ class Ticket {
                 || !isset($user_info['email']) || !$user_info['email']) {
             $user_info = $vars;
         }
-        elseif (!$user_form->isValid()) {
-            $errors['user'] = 'Incomplete client information';
-        }
 
         //Any error above is fatal.
         if($errors)  return 0;
diff --git a/include/staff/dynamic-form.inc.php b/include/staff/dynamic-form.inc.php
index 7d1a19fe441825c34ea4058bbb5140245f7c4d70..654050a7aebddd42e7818dd07bf81da37b81808c 100644
--- a/include/staff/dynamic-form.inc.php
+++ b/include/staff/dynamic-form.inc.php
@@ -107,13 +107,13 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
         $force_privacy = $f->isPrivacyForced() ? 'disabled="disabled"' : '';
         $force_required = $f->isRequirementForced() ? 'disabled="disabled"' : '';
         $fi = $f->getImpl();
-        $errors = $f->errors(); ?>
+        $ferrors = $f->errors(); ?>
         <tr>
             <td><i class="icon-sort"></i></td>
             <td><input type="text" size="32" name="label-<?php echo $id; ?>"
                 value="<?php echo $f->get('label'); ?>"/>
                 <font class="error"><?php
-                    if ($errors['label']) echo '<br/>'; echo $errors['label']; ?>
+                    if ($ferrors['label']) echo '<br/>'; echo $ferrors['label']; ?>
             </td>
             <td><select name="type-<?php echo $id; ?>" <?php
                 if (!$fi->isChangeable()) echo 'disabled="disabled"'; ?>>
@@ -151,7 +151,7 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
                 <input type="text" size="20" name="name-<?php echo $id; ?>"
                     value="<?php echo $f->get('name'); ?>" <?php echo $force_name ?>/>
                 <font class="error"><?php
-                    if ($errors['name']) echo '<br/>'; echo $errors['name'];
+                    if ($ferrors['name']) echo '<br/>'; echo $ferrors['name'];
                 ?></font>
                 </td>
             <td><input type="checkbox" name="delete-<?php echo $id; ?>"
@@ -164,24 +164,34 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
     }
     for ($i=0; $i<$newcount; $i++) { ?>
             <td><em>+</em>
-                <input type="hidden" name="sort-new-<?php echo $i; ?>"/></td>
-            <td><input type="text" size="32" name="label-new-<?php echo $i; ?>"/></td>
+                <input type="hidden" name="sort-new-<?php echo $i; ?>"
+                    value="<?php echo $info["sort-new-$i"]; ?>"/></td>
+            <td><input type="text" size="32" name="label-new-<?php echo $i; ?>"
+                value="<?php echo $info["label-new-$i"]; ?>"/></td>
             <td><select name="type-new-<?php echo $i; ?>">
                 <?php foreach (FormField::allTypes() as $group=>$types) {
                     ?><optgroup label="<?php echo Format::htmlchars($group); ?>"><?php
                     foreach ($types as $type=>$nfo) {
                         if (isset($nfo[2]) && !$nfo[2]) continue; ?>
-                <option value="<?php echo $type; ?>">
-                    <?php echo $nfo[0]; ?></option>
+                <option value="<?php echo $type; ?>"
+                    <?php if ($info["type-new-$i"] == $type) echo 'selected="selected"'; ?>>
+                    <?php echo $nfo[0]; ?>
+                </option>
                     <?php } ?>
                 </optgroup>
                 <?php } ?>
             </select></td>
             <td><input type="checkbox" name="private-new-<?php echo $i; ?>"
-                <?php if ($form && $form->get('type') == 'U')
+            <?php if ($info["private-new-$i"]
+                || (!$_POST && $form && $form->get('type') == 'U'))
                     echo 'checked="checked"'; ?>/></td>
-            <td><input type="checkbox" name="required-new-<?php echo $i; ?>"/></td>
-            <td><input type="text" size="20" name="name-new-<?php echo $i; ?>"/></td>
+            <td><input type="checkbox" name="required-new-<?php echo $i; ?>"
+                <?php if ($info["required-new-$i"]) echo 'checked="checked"'; ?>/></td>
+            <td><input type="text" size="20" name="name-new-<?php echo $i; ?>"
+                value="<?php echo $info["name-new-$i"]; ?>"/>
+                <font class="error"><?php
+                    if ($errors["new-$i"]['name']) echo '<br/>'; echo $errors["new-$i"]['name'];
+                ?></font>
             <td></td>
         </tr>
     <?php } ?>
diff --git a/open.php b/open.php
index 0035c38e8510f39d1140631faa3515eda72b853a..927a4534920034a1c8c4228e2d90b0f746186658 100644
--- a/open.php
+++ b/open.php
@@ -38,12 +38,6 @@ if($_POST):
                 $errors += $form->errors();
         }
     }
-    // Don't process contact information for logged-in clients
-    if (!$thisclient) {
-        $contact_form = UserForm::getInstance();
-        if (!$contact_form->isValid())
-            $errors += $contact_form->errors();
-    }
 
     if (!$errors && $cfg->allowOnlineAttachments() && $_FILES['attachments'])
         $vars['files'] = AttachmentFile::format($_FILES['attachments'], true);
diff --git a/scp/forms.php b/scp/forms.php
index 6b1aba8976927be360c0d74897e01c7bc4f25106..5305eeb57e89487437954a44f5b49b94cc73707e 100644
--- a/scp/forms.php
+++ b/scp/forms.php
@@ -51,8 +51,6 @@ if($_POST) {
                 // Keep track of the last sort number
                 $max_sort = max($max_sort, $field->get('sort'));
             }
-            if ($errors)
-                $errors['err'] = 'Unable to commit form. Check validation errors';
             break;
         case 'add':
             $form = DynamicForm::create(array(
@@ -102,11 +100,15 @@ if($_POST) {
             ));
             if ($field->isValid())
                 $field->save();
+            else
+                $errors["new-$i"] = $field->errors();
         }
         // XXX: Move to an instrumented list that can handle this better
         if (!$errors)
             $form->_dfields = $form->_fields = null;
     }
+    if ($errors)
+        $errors['err'] = 'Unable to commit form. Check validation errors';
 }
 
 $page='dynamic-forms.inc.php';
diff --git a/scp/lists.php b/scp/lists.php
index 81cf2663d2e4d3cfc3f26bc48dbee0da150cb679..fc6f95dbfe53664648439033a63547e43ee907a5 100644
--- a/scp/lists.php
+++ b/scp/lists.php
@@ -13,8 +13,7 @@ if($_POST) {
             foreach ($fields as $f)
                 if (isset($_POST[$f]))
                     $list->set($f, $_POST[$f]);
-            if ($list->isValid())
-                $list->save(true);
+            $list->save(true);
             foreach ($list->getItems() as $item) {
                 $id = $item->get('id');
                 if ($_POST["delete-$id"] == 'on') {
@@ -24,8 +23,7 @@ if($_POST) {
                 foreach (array('sort','value','extra') as $i)
                     if (isset($_POST["$i-$id"]))
                         $item->set($i, $_POST["$i-$id"]);
-                if ($item->isValid())
-                    $item->save();
+                $item->save();
             }
             break;
         case 'add':