Visual Form Builder - Version 1.4

Version Description

Export entries to a CSV, file uploads, and various bug fixes.

Download this release

Release Info

Developer mmuro
Plugin Icon 128x128 Visual Form Builder
Version 1.4
Comparing to
See all releases

Code changes from version 1.3.1 to 1.4

class-entries-detail.php ADDED
@@ -0,0 +1,99 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Class that builds our Entries detail page
4
+ *
5
+ * @since 1.4
6
+ */
7
+ class VisualFormBuilder_Entries_Detail{
8
+ public function __construct(){
9
+ global $wpdb;
10
+
11
+ /* Setup global database table names */
12
+ $this->field_table_name = $wpdb->prefix . 'visual_form_builder_fields';
13
+ $this->form_table_name = $wpdb->prefix . 'visual_form_builder_forms';
14
+ $this->entries_table_name = $wpdb->prefix . 'visual_form_builder_entries';
15
+
16
+ add_action( 'admin_init', array( &$this, 'entries_detail' ) );
17
+ }
18
+
19
+ public function entries_detail(){
20
+ global $wpdb;
21
+
22
+ $entry_id = absint( $_REQUEST['entry'] );
23
+
24
+ $query = "SELECT forms.form_title, entries.* FROM $this->form_table_name AS forms INNER JOIN $this->entries_table_name AS entries ON entries.form_id = forms.form_id WHERE entries.entries_id = $entry_id;";
25
+
26
+ $entries = $wpdb->get_results( $query );
27
+
28
+ echo '<p>' . sprintf( '<a href="?page=%s&view=%s" class="view-entry">&laquo; Back to Entries</a>', $_REQUEST['page'], $_REQUEST['view'] ) . '</p>';
29
+
30
+
31
+
32
+ /* Loop trough the entries and setup the data to be displayed for each row */
33
+ foreach ( $entries as $entry ) {
34
+ $data = unserialize( $entry->data );
35
+
36
+ echo '<div id="poststuff" class="metabox-holder has-right-sidebar">
37
+ <div id="side-info-column" class="inner-sidebar">
38
+ <div id="side-sortables">
39
+ <div id="submitdiv" class="postbox">
40
+ <h3><span>Details</span></h3>
41
+ <div class="inside">
42
+ <div id="submitbox" class="submitbox">
43
+ <div id="minor-publishing">
44
+ <div id="misc-publishing-actions">
45
+ <div class="misc-pub-section">
46
+ <span><strong>Form Title: </strong>' . stripslashes( $entry->form_title ) . '</span>
47
+ </div>
48
+ <div class="misc-pub-section">
49
+ <span><strong>Date Submitted: </strong>' . $entry->date_submitted . '</span>
50
+ </div>
51
+ <div class="misc-pub-section">
52
+ <span><strong>IP Address: </strong>' . $entry->ip_address . '</span>
53
+ </div>
54
+ <div class="misc-pub-section">
55
+ <span><strong>Email Subject: </strong>' . stripslashes( $entry->subject ) . '</span>
56
+ </div>
57
+ <div class="misc-pub-section">
58
+ <span><strong>Sender Name: </strong>' . stripslashes( $entry->sender_name ) . '</span>
59
+ </div>
60
+ <div class="misc-pub-section">
61
+ <span><strong>Sender Email: </strong><a href="mailto:' . stripslashes( $entry->sender_email ) . '">' . stripslashes( $entry->sender_email ) . '</a></span>
62
+ </div>
63
+ <div class="misc-pub-section misc-pub-section-last">
64
+ <span><strong>Emailed To: </strong>' . preg_replace('/\b([A-Z0-9._%-]+@[A-Z0-9.-]+\.[A-Z]{2,4})\b/i', '<a href="mailto:$1">$1</a>', implode( ',', unserialize( stripslashes( $entry->emails_to ) ) ) ) . '</span>
65
+ </div>
66
+ <div class="clear"></div>
67
+ </div>
68
+ </div>
69
+
70
+ <div id="major-publishing-actions">
71
+ <div id="delete-action">'
72
+ . sprintf( '<a class="submitdelete deletion" href="?page=%s&view=%s&action=%s&entry=%s">Delete</a>', $_REQUEST['page'], $_REQUEST['view'], 'delete', $entry_id ) .
73
+ '</div>
74
+ <div class="clear"></div>
75
+ </div>
76
+ </div>
77
+ </div>
78
+ </div>
79
+ </div>
80
+ </div>';
81
+ echo '<div>
82
+ <div id="post-body-content">
83
+ <div class="postbox">
84
+ <h3><span>' . $entry->form_title . ' : Entry #' . $entry->entries_id . '</span></h3>
85
+ <div class="inside">';
86
+
87
+ foreach ( $data as $k => $v ) {
88
+ echo '<h4>' . ucwords( $k ) . '</h4>';
89
+ //echo '<pre>' . $v . '</pre>';
90
+ echo $v;
91
+ }
92
+
93
+ echo '</div></div></div></div>';
94
+ }
95
+
96
+ echo '<br class="clear"></div>';
97
+ }
98
+ }
99
+ ?>
class-entries-list.php CHANGED
@@ -25,9 +25,9 @@ class VisualFormBuilder_Entries_List extends WP_List_Table {
25
  'singular' => 'entry',
26
  'plural' => 'entries',
27
  'ajax' => false
28
- ) );
29
  }
30
-
31
  /**
32
  * Display column names. We'll handle the Form column separately.
33
  *
@@ -55,7 +55,7 @@ class VisualFormBuilder_Entries_List extends WP_List_Table {
55
 
56
  /* Build row actions */
57
  $actions = array(
58
- 'view' => sprintf( '<a href="#" id="%4$s" class="view-entry">View</a>', $_REQUEST['page'], $_REQUEST['view'], 'view', $item['entry_id'] ),
59
  'delete' => sprintf( '<a href="?page=%s&view=%s&action=%s&entry=%s">Delete</a>', $_REQUEST['page'], $_REQUEST['view'], 'delete', $item['entry_id'] ),
60
  );
61
 
@@ -107,7 +107,7 @@ class VisualFormBuilder_Entries_List extends WP_List_Table {
107
  * @since 1.2
108
  * @returns array() $cols SQL results
109
  */
110
- function get_entries( $orderby = 'date', $order = 'DESC' ){
111
  global $wpdb;
112
 
113
  switch ( $orderby ) {
@@ -126,9 +126,9 @@ class VisualFormBuilder_Entries_List extends WP_List_Table {
126
  }
127
 
128
  $where = '';
129
-
130
  /* If the form filter dropdown is used */
131
- if ( $this->current_filter_action() )
132
  $where = 'WHERE forms.form_id = ' . $this->current_filter_action();
133
 
134
 
@@ -166,7 +166,9 @@ class VisualFormBuilder_Entries_List extends WP_List_Table {
166
  */
167
  function get_bulk_actions() {
168
  $actions = array(
169
- 'delete' => 'Delete'
 
 
170
  );
171
 
172
  return $actions;
@@ -190,6 +192,166 @@ class VisualFormBuilder_Entries_List extends WP_List_Table {
190
  }
191
  }
192
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
193
  /**
194
  * Adds our forms filter dropdown
195
  *
@@ -241,6 +403,10 @@ class VisualFormBuilder_Entries_List extends WP_List_Table {
241
  /* Get screen options from the wp_options table */
242
  $options = get_option( 'visual-form-builder-screen-options' );
243
 
 
 
 
 
244
  /* How many to show per page */
245
  $per_page = $options['per_page'];
246
 
@@ -276,7 +442,7 @@ class VisualFormBuilder_Entries_List extends WP_List_Table {
276
  'sender_name' => stripslashes( $entry->sender_name ),
277
  'sender_email' => stripslashes( $entry->sender_email ),
278
  'emails_to' => implode( ',', unserialize( stripslashes( $entry->emails_to ) ) ),
279
- 'date' => $entry->date_submitted,
280
  'ip_address' => $entry->ip_address,
281
  'data' => unserialize( $entry->data )
282
  );
25
  'singular' => 'entry',
26
  'plural' => 'entries',
27
  'ajax' => false
28
+ ) );
29
  }
30
+
31
  /**
32
  * Display column names. We'll handle the Form column separately.
33
  *
55
 
56
  /* Build row actions */
57
  $actions = array(
58
+ 'view' => sprintf( '<a href="?page=%s&view=%s&action=%s&entry=%s" id="%4$s" class="view-entry">View</a>', $_REQUEST['page'], $_REQUEST['view'], 'view', $item['entry_id'] ),
59
  'delete' => sprintf( '<a href="?page=%s&view=%s&action=%s&entry=%s">Delete</a>', $_REQUEST['page'], $_REQUEST['view'], 'delete', $item['entry_id'] ),
60
  );
61
 
107
  * @since 1.2
108
  * @returns array() $cols SQL results
109
  */
110
+ function get_entries( $orderby = 'date', $order = 'ASC' ){
111
  global $wpdb;
112
 
113
  switch ( $orderby ) {
126
  }
127
 
128
  $where = '';
129
+
130
  /* If the form filter dropdown is used */
131
+ if ( $this->current_filter_action() && absint( $this->current_filter_action ) )
132
  $where = 'WHERE forms.form_id = ' . $this->current_filter_action();
133
 
134
 
166
  */
167
  function get_bulk_actions() {
168
  $actions = array(
169
+ 'delete' => 'Delete',
170
+ 'export-all' => 'Export All',
171
+ 'export-selected' => 'Export Selected'
172
  );
173
 
174
  return $actions;
192
  }
193
  }
194
 
195
+ /**
196
+ * Handle the entries CSV export
197
+ *
198
+ * @since 1.4
199
+ */
200
+ function export_entries( $selected = NULL ) {
201
+ global $wpdb;
202
+
203
+ /* Setup our query to accept selected entry IDs */
204
+ if ( is_array( $selected ) && !empty( $selected ) )
205
+ $selected = " WHERE entries.entries_id IN (" . implode( ',', $selected ) . ")";
206
+
207
+ $entries = $wpdb->get_results( "SELECT entries.*, forms.form_title FROM $this->entries_table_name AS entries JOIN $this->form_table_name AS forms USING(form_id) $selected ORDER BY entries_id DESC" );
208
+
209
+ /* If there's entries returned, do our CSV stuff */
210
+ if ( $entries ) :
211
+
212
+ /* Setup our default columns */
213
+ $cols = array(
214
+ 'entries_id' => array(
215
+ 'header' => 'Entries ID',
216
+ 'data' => array()
217
+ ),
218
+ 'form_title' => array(
219
+ 'header' => 'Form',
220
+ 'data' => array()
221
+ ),
222
+ 'date_submitted' => array(
223
+ 'header' => 'Date Submitted',
224
+ 'data' => array()
225
+ ),
226
+ 'ip_address' => array(
227
+ 'header' => 'IP Address',
228
+ 'data' => array()
229
+ ),
230
+ 'subject' => array(
231
+ 'header' => 'Email Subject',
232
+ 'data' => array()
233
+ ),
234
+ 'sender_name' => array(
235
+ 'header' => 'Sender Name',
236
+ 'data' => array()
237
+ ),
238
+ 'sender_email' => array(
239
+ 'header' => 'Sender Email',
240
+ 'data' => array()
241
+ ),
242
+ 'emails_to' => array(
243
+ 'header' => 'Emailed To',
244
+ 'data' => array()
245
+ )
246
+ );
247
+
248
+ /* Initialize row index at 0 */
249
+ $row = 0;
250
+
251
+ /* Loop through all entries */
252
+ foreach ( $entries as $entry ) {
253
+ /* Loop through each entry and its fields */
254
+ foreach ( $entry as $key => $value ) {
255
+ /* Handle each column in the entries table */
256
+ switch ( $key ) {
257
+ case 'entries_id':
258
+ case 'form_title':
259
+ case 'date_submitted':
260
+ case 'ip_address':
261
+ case 'subject':
262
+ case 'sender_name':
263
+ case 'sender_email':
264
+ $cols[$key]['data'][$row] = $value;
265
+ break;
266
+
267
+ case 'emails_to':
268
+ $cols[$key]['data'][$row] = implode( ',', maybe_unserialize( $value ) );
269
+ break;
270
+
271
+ case 'data':
272
+ /* Unserialize value only if it was serialized */
273
+ $fields = maybe_unserialize( $value );
274
+
275
+ /* Loop through our submitted data */
276
+ foreach ( $fields as $field_key => $field_value ) {
277
+
278
+ /* Replace quotes for the header */
279
+ $header = str_replace( '"', '""', ucwords( $field_key ) );
280
+
281
+ /* Replace all spaces for each form field name */
282
+ $field_key = preg_replace( '/(\s)/i', '', $field_key );
283
+
284
+ /* Find new field names and make a new column with a header */
285
+ if ( !array_key_exists( $field_key, $cols ) ) {
286
+ $cols[$field_key] = array(
287
+ 'header' => $header,
288
+ 'data' => array()
289
+ );
290
+ }
291
+
292
+ /* Get rid of single quote entity */
293
+ $field_value = str_replace( '&#039;', "'", $field_value );
294
+
295
+ /* Load data, row by row */
296
+ $cols[$field_key]['data'][$row] = str_replace( '"', '""', stripslashes( html_entity_decode( $field_value ) ) );
297
+ }
298
+ break;
299
+ }
300
+
301
+ }
302
+
303
+ $row++;
304
+ }
305
+
306
+ /* Setup our CSV vars */
307
+ $csv_headers = NULL;
308
+ $csv_rows = array();
309
+
310
+ /* Loop through each column */
311
+ foreach ( $cols as $data ) {
312
+ /* End our header row, if needed */
313
+ if ( $csv_headers )
314
+ $csv_headers .= ',';
315
+
316
+ /* Build our headers */
317
+ $csv_headers .= "{$data['header']}";
318
+
319
+ /* Loop through each row of data and add to our CSV */
320
+ for ( $i = 0; $i < $row; $i++ ) {
321
+ /* End our row of data, if needed */
322
+ if ( $csv_rows[$i] )
323
+ $csv_rows[$i] .= ',';
324
+
325
+ /* Add a starting quote for this row's data */
326
+ $csv_rows[$i] .= '"';
327
+
328
+ /* If there's data at this point, add it to the row */
329
+ if ( array_key_exists( $i, $data['data'] ) )
330
+ $csv_rows[$i] .= $data['data'][$i];
331
+
332
+ /* Add a closing quote for this row's data */
333
+ $csv_rows[$i] .= '"';
334
+ }
335
+ }
336
+
337
+ /* Change our header so the browser spits out a CSV file to download */
338
+ header('Content-type: text/csv');
339
+ header('Content-Disposition: attachment; filename="' . date( 'Y-m-d' ) . '-entries.csv"');
340
+ ob_clean();
341
+
342
+ /* Print headers for the CSV */
343
+ echo $csv_headers . "\n";
344
+
345
+ /* Print each row of data for the CSV */
346
+ foreach ( $csv_rows as $row ) {
347
+ echo $row . "\n";
348
+ }
349
+
350
+ die();
351
+
352
+ endif;
353
+ }
354
+
355
  /**
356
  * Adds our forms filter dropdown
357
  *
403
  /* Get screen options from the wp_options table */
404
  $options = get_option( 'visual-form-builder-screen-options' );
405
 
406
+ /* Get the date/time format that is saved in the options table */
407
+ $date_format = get_option('date_format');
408
+ $time_format = get_option('time_format');
409
+
410
  /* How many to show per page */
411
  $per_page = $options['per_page'];
412
 
442
  'sender_name' => stripslashes( $entry->sender_name ),
443
  'sender_email' => stripslashes( $entry->sender_email ),
444
  'emails_to' => implode( ',', unserialize( stripslashes( $entry->emails_to ) ) ),
445
+ 'date' => date( "$date_format $time_format", strtotime( $entry->date_submitted ) ),
446
  'ip_address' => $entry->ip_address,
447
  'data' => unserialize( $entry->data )
448
  );
css/sprite.png CHANGED
Binary file
css/visual-form-builder-admin.css CHANGED
@@ -31,6 +31,8 @@ label.error{color:red;display:block;}
31
  #form-element-digits{background:url(sprite.png) 0 -452px no-repeat transparent;}
32
  #form-element-time{background:url(sprite.png) 0 -489px no-repeat transparent;}
33
  #form-element-phone{background:url(sprite.png) 0 -529px no-repeat transparent;}
 
 
34
  #form-details-nav{font-size:1.0em;font-weight:bold;padding-top:10px;}
35
  #form-details-nav a{padding:5px 10px;text-decoration:none;}
36
  #form-details-nav a.current{
31
  #form-element-digits{background:url(sprite.png) 0 -452px no-repeat transparent;}
32
  #form-element-time{background:url(sprite.png) 0 -489px no-repeat transparent;}
33
  #form-element-phone{background:url(sprite.png) 0 -529px no-repeat transparent;}
34
+ #form-element-html{background:url(sprite.png) 0 -559px no-repeat transparent;}
35
+ #form-element-file{background:url(sprite.png) 0 -587px no-repeat transparent;}
36
  #form-details-nav{font-size:1.0em;font-weight:bold;padding-top:10px;}
37
  #form-details-nav a{padding:5px 10px;text-decoration:none;}
38
  #form-details-nav a.current{
css/visual-form-builder.css CHANGED
@@ -74,6 +74,7 @@ input.text, textarea.textarea, select.select{
74
  input.medium, select.medium{width:50%;}
75
  input.large, select.large, textarea.textarea{width:100%;}
76
  textarea.medium{height:10em;}
 
77
  .submit{font-size:1.1em;}
78
  input.checkbox, input.radio{
79
  font-size:1.1em;
@@ -92,4 +93,28 @@ p#form_success{
92
  color:green;
93
  font-weight:bold;
94
  }
95
- #ui-datepicker-div { display: none; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
74
  input.medium, select.medium{width:50%;}
75
  input.large, select.large, textarea.textarea{width:100%;}
76
  textarea.medium{height:10em;}
77
+ textarea.large{height:20em;}
78
  .submit{font-size:1.1em;}
79
  input.checkbox, input.radio{
80
  font-size:1.1em;
93
  color:green;
94
  font-weight:bold;
95
  }
96
+ #ui-datepicker-div { display: none; }
97
+ .ed_button{
98
+ font-family:Arial,"Bitstream Vera Sans",Helvetica,Verdana,sans-serif;
99
+ font-size:12px;
100
+ background-image: -moz-linear-gradient(top, #fcfcfc 0%, #e9e8e8 100%);
101
+ background-image: -o-linear-gradient(top, #fcfcfc 0%, #e9e8e8 100%);
102
+ background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0, #fcfcfc), color-stop(1, #e9e8e8));
103
+ background-image: linear-gradient(top, #fcfcfc 0%, #e9e8e8 100%);
104
+ min-width:26px;
105
+ margin:3px 1px 4px;
106
+ padding:2px 4px;
107
+ box-shadow:0 1px 0 #e3e3e3;
108
+ border-radius:3px 3px 3px 3px;
109
+ border:#C3C3C3 1px solid;
110
+ text-transform:lowercase;
111
+ }
112
+ .ed_button:hover{
113
+ background:none repeat scroll 0 0 #dddddd;
114
+ border-color:#aaaaaa;
115
+ cursor:pointer;
116
+ }
117
+ .ed_button.ed_bold{font-weight:bold;}
118
+ .ed_button.ed_italic{font-style:italic;}
119
+ .ed_button.ed_link{color:#0000FF;text-decoration:underline;}
120
+ .ed_button.ed_del{text-decoration:line-through;}
js/js_quicktags.js ADDED
@@ -0,0 +1,544 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // JS QuickTags version 1.3.1
2
+ //
3
+ // Copyright (c) 2002-2008 Alex King
4
+ // http://alexking.org/projects/js-quicktags
5
+ //
6
+ // Thanks to Greg Heo <greg@node79.com> for his changes
7
+ // to support multiple toolbars per page.
8
+ //
9
+ // Licensed under the LGPL license
10
+ // http://www.gnu.org/copyleft/lesser.html
11
+ //
12
+ // **********************************************************************
13
+ // This program is distributed in the hope that it will be useful, but
14
+ // WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16
+ // **********************************************************************
17
+ //
18
+ // This JavaScript will insert the tags below at the cursor position in IE and
19
+ // Gecko-based browsers (Mozilla, Camino, Firefox, Netscape). For browsers that
20
+ // do not support inserting at the cursor position (older versions of Safari,
21
+ // OmniWeb) it appends the tags to the end of the content.
22
+ //
23
+ // Pass the ID of the <textarea> element to the edToolbar and function.
24
+ //
25
+ // Example:
26
+ //
27
+ // <script type="text/javascript">edToolbar('canvas');</script>
28
+ // <textarea id="canvas" rows="20" cols="50"></textarea>
29
+ //
30
+
31
+ var dictionaryUrl = 'http://www.ninjawords.com/';
32
+
33
+ // other options include:
34
+ //
35
+ // var dictionaryUrl = 'http://www.answers.com/';
36
+ // var dictionaryUrl = 'http://www.dictionary.com/';
37
+
38
+ var edButtons = new Array();
39
+ var edLinks = new Array();
40
+ var edOpenTags = new Array();
41
+
42
+ function edButton(id, display, tagStart, tagEnd, access, open) {
43
+ this.id = id; // used to name the toolbar button
44
+ this.display = display; // label on button
45
+ this.tagStart = tagStart; // open tag
46
+ this.tagEnd = tagEnd; // close tag
47
+ this.access = access; // set to -1 if tag does not need to be closed
48
+ this.open = open; // set to -1 if tag does not need to be closed
49
+ }
50
+
51
+ edButtons.push(
52
+ new edButton(
53
+ 'ed_bold'
54
+ ,'B'
55
+ ,'<strong>'
56
+ ,'</strong>'
57
+ ,'b'
58
+ )
59
+ );
60
+
61
+ edButtons.push(
62
+ new edButton(
63
+ 'ed_italic'
64
+ ,'I'
65
+ ,'<em>'
66
+ ,'</em>'
67
+ ,'i'
68
+ )
69
+ );
70
+
71
+ edButtons.push(
72
+ new edButton(
73
+ 'ed_link'
74
+ ,'Link'
75
+ ,''
76
+ ,'</a>'
77
+ ,'a'
78
+ )
79
+ ); // special case
80
+
81
+ edButtons.push(
82
+ new edButton(
83
+ 'ed_block'
84
+ ,'B-QUOTE'
85
+ ,'<blockquote>'
86
+ ,'</blockquote>'
87
+ ,'q'
88
+ )
89
+ );
90
+
91
+ edButtons.push(
92
+ new edButton(
93
+ 'ed_img'
94
+ ,'IMG'
95
+ ,''
96
+ ,''
97
+ ,'m'
98
+ ,-1
99
+ )
100
+ ); // special case
101
+
102
+ edButtons.push(
103
+ new edButton(
104
+ 'ed_ul'
105
+ ,'UL'
106
+ ,'<ul>\n'
107
+ ,'</ul>\n\n'
108
+ ,'u'
109
+ )
110
+ );
111
+
112
+ edButtons.push(
113
+ new edButton(
114
+ 'ed_ol'
115
+ ,'OL'
116
+ ,'<ol>\n'
117
+ ,'</ol>\n\n'
118
+ ,'o'
119
+ )
120
+ );
121
+
122
+ edButtons.push(
123
+ new edButton(
124
+ 'ed_li'
125
+ ,'LI'
126
+ ,'\t<li>'
127
+ ,'</li>\n'
128
+ ,'l'
129
+ )
130
+ );
131
+
132
+ edButtons.push(
133
+ new edButton(
134
+ 'ed_code'
135
+ ,'CODE'
136
+ ,'<code>'
137
+ ,'</code>'
138
+ ,'c'
139
+ )
140
+ );
141
+
142
+
143
+
144
+
145
+
146
+ var extendedStart = edButtons.length;
147
+
148
+ function edLink(display, URL, newWin) {
149
+ this.display = display;
150
+ this.URL = URL;
151
+ if (!newWin) {
152
+ newWin = 0;
153
+ }
154
+ this.newWin = newWin;
155
+ }
156
+
157
+
158
+ edLinks[edLinks.length] = new edLink('alexking.org'
159
+ ,'http://www.alexking.org/'
160
+ );
161
+
162
+ function edShowButton(which, button, i) {
163
+ if (button.access) {
164
+ var accesskey = ' accesskey = "' + button.access + '"'
165
+ }
166
+ else {
167
+ var accesskey = '';
168
+ }
169
+ switch (button.id) {
170
+ case 'ed_img':
171
+ document.write('<input type="button" id="' + button.id + '_' + which + '" ' + accesskey + ' class="ed_button ' + button.id + '" onclick="edInsertImage(\'' + which + '\');" value="' + button.display + '" />');
172
+ break;
173
+ case 'ed_link':
174
+ document.write('<input type="button" id="' + button.id + '_' + which + '" ' + accesskey + ' class="ed_button ' + button.id + '" onclick="edInsertLink(\'' + which + '\', ' + i + ');" value="' + button.display + '" />');
175
+ break;
176
+ case 'ed_ext_link':
177
+ document.write('<input type="button" id="' + button.id + '_' + which + '" ' + accesskey + ' class="ed_button ' + button.id + '" onclick="edInsertExtLink(\'' + which + '\', ' + i + ');" value="' + button.display + '" />');
178
+ break;
179
+ case 'ed_footnote':
180
+ document.write('<input type="button" id="' + button.id + '_' + which + '" ' + accesskey + ' class="ed_button ' + button.id + '" onclick="edInsertFootnote(\'' + which + '\');" value="' + button.display + '" />');
181
+ break;
182
+ case 'ed_via':
183
+ document.write('<input type="button" id="' + button.id + '_' + which + '" ' + accesskey + ' class="ed_button ' + button.id + '" onclick="edInsertVia(\'' + which + '\');" value="' + button.display + '" />');
184
+ break;
185
+ default:
186
+ document.write('<input type="button" id="' + button.id + '_' + which + '" ' + accesskey + ' class="ed_button ' + button.id + '" onclick="edInsertTag(\'' + which + '\', ' + i + ');" value="' + button.display + '" />');
187
+ break;
188
+ }
189
+ }
190
+
191
+ function edShowLinks() {
192
+ var tempStr = '<select onchange="edQuickLink(this.options[this.selectedIndex].value, this);"><option value="-1" selected>(Quick Links)</option>';
193
+ for (i = 0; i < edLinks.length; i++) {
194
+ tempStr += '<option value="' + i + '">' + edLinks[i].display + '</option>';
195
+ }
196
+ tempStr += '</select>';
197
+ document.write(tempStr);
198
+ }
199
+
200
+ function edAddTag(which, button) {
201
+ if (edButtons[button].tagEnd != '') {
202
+ edOpenTags[which][edOpenTags[which].length] = button;
203
+ document.getElementById(edButtons[button].id + '_' + which).value = '/' + document.getElementById(edButtons[button].id + '_' + which).value;
204
+ }
205
+ }
206
+
207
+ function edRemoveTag(which, button) {
208
+ for (i = 0; i < edOpenTags[which].length; i++) {
209
+ if (edOpenTags[which][i] == button) {
210
+ edOpenTags[which].splice(i, 1);
211
+ document.getElementById(edButtons[button].id + '_' + which).value = document.getElementById(edButtons[button].id + '_' + which).value.replace('/', '');
212
+ }
213
+ }
214
+ }
215
+
216
+ function edCheckOpenTags(which, button) {
217
+ var tag = 0;
218
+ for (i = 0; i < edOpenTags[which].length; i++) {
219
+ if (edOpenTags[which][i] == button) {
220
+ tag++;
221
+ }
222
+ }
223
+ if (tag > 0) {
224
+ return true; // tag found
225
+ }
226
+ else {
227
+ return false; // tag not found
228
+ }
229
+ }
230
+
231
+ function edCloseAllTags(which) {
232
+ var count = edOpenTags[which].length;
233
+ for (o = 0; o < count; o++) {
234
+ edInsertTag(which, edOpenTags[which][edOpenTags[which].length - 1]);
235
+ }
236
+ }
237
+
238
+ function edQuickLink(i, thisSelect) {
239
+ if (i > -1) {
240
+ var newWin = '';
241
+ if (edLinks[i].newWin == 1) {
242
+ newWin = ' target="_blank"';
243
+ }
244
+ var tempStr = '<a href="' + edLinks[i].URL + '"' + newWin + '>'
245
+ + edLinks[i].display
246
+ + '</a>';
247
+ thisSelect.selectedIndex = 0;
248
+ edInsertContent(edCanvas, tempStr);
249
+ }
250
+ else {
251
+ thisSelect.selectedIndex = 0;
252
+ }
253
+ }
254
+
255
+ function edSpell(which) {
256
+ myField = document.getElementById(which);
257
+ var word = '';
258
+ if (document.selection) {
259
+ myField.focus();
260
+ var sel = document.selection.createRange();
261
+ if (sel.text.length > 0) {
262
+ word = sel.text;
263
+ }
264
+ }
265
+ else if (myField.selectionStart || myField.selectionStart == '0') {
266
+ var startPos = myField.selectionStart;
267
+ var endPos = myField.selectionEnd;
268
+ if (startPos != endPos) {
269
+ word = myField.value.substring(startPos, endPos);
270
+ }
271
+ }
272
+ if (word == '') {
273
+ word = prompt('Enter a word to look up:', '');
274
+ }
275
+ if (word != '') {
276
+ window.open(dictionaryUrl + escape(word));
277
+ }
278
+ }
279
+
280
+ function edToolbar(which) {
281
+ document.write('<div id="ed_toolbar_' + which + '"><span>');
282
+ for (i = 0; i < extendedStart; i++) {
283
+ edShowButton(which, edButtons[i], i);
284
+ }
285
+ if (edShowExtraCookie()) {
286
+ document.write(
287
+ '<input type="button" id="ed_close_' + which + '" class="ed_button ed_closetags" onclick="edCloseAllTags(\'' + which + '\');" value="Close Tags" />'
288
+ + '<input type="button" id="ed_spell_' + which + '" class="ed_button ed_spell" onclick="edSpell(\'' + which + '\');" value="Lookup" />'
289
+ );
290
+ }
291
+ else {
292
+ document.write(
293
+ '<input type="button" id="ed_close_' + which + '" class="ed_button ed_closetags" onclick="edCloseAllTags(\'' + which + '\');" value="Close Tags" />'
294
+ + '<input type="button" id="ed_spell_' + which + '" class="ed_button ed_spell" onclick="edSpell(\'' + which + '\');" value="Lookup" />'
295
+ );
296
+ }
297
+ for (i = extendedStart; i < edButtons.length; i++) {
298
+ //edShowButton(which, edButtons[i], i);
299
+ }
300
+ document.write('</span>');
301
+ // edShowLinks();
302
+ document.write('</div>');
303
+ edOpenTags[which] = new Array();
304
+ }
305
+
306
+ function edShowExtra(which) {
307
+ document.getElementById('ed_extra_show_' + which).style.visibility = 'hidden';
308
+ document.getElementById('ed_extra_buttons_' + which).style.display = 'block';
309
+ edSetCookie(
310
+ 'js_quicktags_extra'
311
+ , 'show'
312
+ , new Date("December 31, 2100")
313
+ );
314
+ }
315
+
316
+ function edHideExtra(which) {
317
+ document.getElementById('ed_extra_buttons_' + which).style.display = 'none';
318
+ document.getElementById('ed_extra_show_' + which).style.visibility = 'visible';
319
+ edSetCookie(
320
+ 'js_quicktags_extra'
321
+ , 'hide'
322
+ , new Date("December 31, 2100")
323
+ );
324
+ }
325
+
326
+ // insertion code
327
+
328
+ function edInsertTag(which, i) {
329
+ myField = document.getElementById(which);
330
+ //IE support
331
+ if (document.selection) {
332
+ myField.focus();
333
+ sel = document.selection.createRange();
334
+ if (sel.text.length > 0) {
335
+ sel.text = edButtons[i].tagStart + sel.text + edButtons[i].tagEnd;
336
+ }
337
+ else {
338
+ if (!edCheckOpenTags(which, i) || edButtons[i].tagEnd == '') {
339
+ sel.text = edButtons[i].tagStart;
340
+ edAddTag(which, i);
341
+ }
342
+ else {
343
+ sel.text = edButtons[i].tagEnd;
344
+ edRemoveTag(which, i);
345
+ }
346
+ }
347
+ myField.focus();
348
+ }
349
+ //MOZILLA/NETSCAPE support
350
+ else if (myField.selectionStart || myField.selectionStart == '0') {
351
+ var startPos = myField.selectionStart;
352
+ var endPos = myField.selectionEnd;
353
+ var cursorPos = endPos;
354
+ var scrollTop = myField.scrollTop;
355
+ if (startPos != endPos) {
356
+ myField.value = myField.value.substring(0, startPos)
357
+ + edButtons[i].tagStart
358
+ + myField.value.substring(startPos, endPos)
359
+ + edButtons[i].tagEnd
360
+ + myField.value.substring(endPos, myField.value.length);
361
+ cursorPos += edButtons[i].tagStart.length + edButtons[i].tagEnd.length;
362
+ }
363
+ else {
364
+ if (!edCheckOpenTags(which, i) || edButtons[i].tagEnd == '') {
365
+ myField.value = myField.value.substring(0, startPos)
366
+ + edButtons[i].tagStart
367
+ + myField.value.substring(endPos, myField.value.length);
368
+ edAddTag(which, i);
369
+ cursorPos = startPos + edButtons[i].tagStart.length;
370
+ }
371
+ else {
372
+ myField.value = myField.value.substring(0, startPos)
373
+ + edButtons[i].tagEnd
374
+ + myField.value.substring(endPos, myField.value.length);
375
+ edRemoveTag(which, i);
376
+ cursorPos = startPos + edButtons[i].tagEnd.length;
377
+ }
378
+ }
379
+ myField.focus();
380
+ myField.selectionStart = cursorPos;
381
+ myField.selectionEnd = cursorPos;
382
+ myField.scrollTop = scrollTop;
383
+ }
384
+ else {
385
+ if (!edCheckOpenTags(which, i) || edButtons[i].tagEnd == '') {
386
+ myField.value += edButtons[i].tagStart;
387
+ edAddTag(which, i);
388
+ }
389
+ else {
390
+ myField.value += edButtons[i].tagEnd;
391
+ edRemoveTag(which, i);
392
+ }
393
+ myField.focus();
394
+ }
395
+ }
396
+
397
+ function edInsertContent(which, myValue) {
398
+ myField = document.getElementById(which);
399
+ //IE support
400
+ if (document.selection) {
401
+ myField.focus();
402
+ sel = document.selection.createRange();
403
+ sel.text = myValue;
404
+ myField.focus();
405
+ }
406
+ //MOZILLA/NETSCAPE support
407
+ else if (myField.selectionStart || myField.selectionStart == '0') {
408
+ var startPos = myField.selectionStart;
409
+ var endPos = myField.selectionEnd;
410
+ var scrollTop = myField.scrollTop;
411
+ myField.value = myField.value.substring(0, startPos)
412
+ + myValue
413
+ + myField.value.substring(endPos, myField.value.length);
414
+ myField.focus();
415
+ myField.selectionStart = startPos + myValue.length;
416
+ myField.selectionEnd = startPos + myValue.length;
417
+ myField.scrollTop = scrollTop;
418
+ } else {
419
+ myField.value += myValue;
420
+ myField.focus();
421
+ }
422
+ }
423
+
424
+ function edInsertLink(which, i, defaultValue) {
425
+ myField = document.getElementById(which);
426
+ if (!defaultValue) {
427
+ defaultValue = 'http://';
428
+ }
429
+ if (!edCheckOpenTags(which, i)) {
430
+ var URL = prompt('Enter the URL' ,defaultValue);
431
+ if (URL) {
432
+ edButtons[i].tagStart = '<a href="' + URL + '">';
433
+ edInsertTag(which, i);
434
+ }
435
+ }
436
+ else {
437
+ edInsertTag(which, i);
438
+ }
439
+ }
440
+
441
+ function edInsertExtLink(which, i, defaultValue) {
442
+ myField = document.getElementById(which);
443
+ if (!defaultValue) {
444
+ defaultValue = 'http://';
445
+ }
446
+ if (!edCheckOpenTags(which, i)) {
447
+ var URL = prompt('Enter the URL' ,defaultValue);
448
+ if (URL) {
449
+ edButtons[i].tagStart = '<a href="' + URL + '" rel="external">';
450
+ edInsertTag(which, i);
451
+ }
452
+ }
453
+ else {
454
+ edInsertTag(which, i);
455
+ }
456
+ }
457
+
458
+ function edInsertImage(which) {
459
+ myField = document.getElementById(which);
460
+ var myValue = prompt('Enter the URL of the image', 'http://');
461
+ if (myValue) {
462
+ myValue = '<img src="'
463
+ + myValue
464
+ + '" alt="' + prompt('Enter a description of the image', '')
465
+ + '" />';
466
+ edInsertContent(which, myValue);
467
+ }
468
+ }
469
+
470
+ function edInsertFootnote(which) {
471
+ myField = document.getElementById(which);
472
+ var note = prompt('Enter the footnote:', '');
473
+ if (!note || note == '') {
474
+ return false;
475
+ }
476
+ var now = new Date;
477
+ var fnId = 'fn' + now.getTime();
478
+ var fnStart = myField.value.indexOf('<ol class="footnotes">');
479
+ if (fnStart != -1) {
480
+ var fnStr1 = myField.value.substring(0, fnStart)
481
+ var fnStr2 = myField.value.substring(fnStart, myField.value.length)
482
+ var count = countInstances(fnStr2, '<li id="') + 1;
483
+ }
484
+ else {
485
+ var count = 1;
486
+ }
487
+ var count = '<sup><a href="#' + fnId + 'n" id="' + fnId + '" class="footnote">' + count + '</a></sup>';
488
+ edInsertContent(which, count);
489
+ if (fnStart != -1) {
490
+ fnStr1 = myField.value.substring(0, fnStart + count.length)
491
+ fnStr2 = myField.value.substring(fnStart + count.length, myField.value.length)
492
+ }
493
+ else {
494
+ var fnStr1 = myField.value;
495
+ var fnStr2 = "\n\n" + '<ol class="footnotes">' + "\n"
496
+ + '</ol>' + "\n";
497
+ }
498
+ var footnote = ' <li id="' + fnId + 'n">' + note + ' [<a href="#' + fnId + '">back</a>]</li>' + "\n"
499
+ + '</ol>';
500
+ myField.value = fnStr1 + fnStr2.replace('</ol>', footnote);
501
+ }
502
+
503
+ function countInstances(string, substr) {
504
+ var count = string.split(substr);
505
+ return count.length - 1;
506
+ }
507
+
508
+ function edInsertVia(which) {
509
+ myField = document.getElementById(which);
510
+ var myValue = prompt('Enter the URL of the source link', 'http://');
511
+ if (myValue) {
512
+ myValue = '(Thanks <a href="' + myValue + '" rel="external">'
513
+ + prompt('Enter the name of the source', '')
514
+ + '</a>)';
515
+ edInsertContent(which, myValue);
516
+ }
517
+ }
518
+
519
+
520
+ function edSetCookie(name, value, expires, path, domain) {
521
+ document.cookie= name + "=" + escape(value) +
522
+ ((expires) ? "; expires=" + expires.toGMTString() : "") +
523
+ ((path) ? "; path=" + path : "") +
524
+ ((domain) ? "; domain=" + domain : "");
525
+ }
526
+
527
+ function edShowExtraCookie() {
528
+ var cookies = document.cookie.split(';');
529
+ for (var i=0;i < cookies.length; i++) {
530
+ var cookieData = cookies[i];
531
+ while (cookieData.charAt(0) ==' ') {
532
+ cookieData = cookieData.substring(1, cookieData.length);
533
+ }
534
+ if (cookieData.indexOf('js_quicktags_extra') == 0) {
535
+ if (cookieData.substring(19, cookieData.length) == 'show') {
536
+ return true;
537
+ }
538
+ else {
539
+ return false;
540
+ }
541
+ }
542
+ }
543
+ return false;
544
+ }
js/visual-form-builder.js CHANGED
@@ -59,14 +59,14 @@ jQuery(document).ready(function($) {
59
  });
60
 
61
  /* Display entries form data */
62
- $( '.view-entry' ).click( function( e ){
63
 
64
  var id = $( e.target ).attr( 'id' );
65
 
66
  $( e.target ).closest( 'td' ).children( '#entry-' + id ).slideToggle( 'fast' );
67
 
68
  return false;
69
- });
70
 
71
  /* Hide entries form data */
72
  $( '.visual-form-builder-inline-edit-cancel' ).click( function( e ){
59
  });
60
 
61
  /* Display entries form data */
62
+ /*$( '.view-entry' ).click( function( e ){
63
 
64
  var id = $( e.target ).attr( 'id' );
65
 
66
  $( e.target ).closest( 'td' ).children( '#entry-' + id ).slideToggle( 'fast' );
67
 
68
  return false;
69
+ });*/
70
 
71
  /* Hide entries form data */
72
  $( '.visual-form-builder-inline-edit-cancel' ).click( function( e ){
readme.txt CHANGED
@@ -3,7 +3,7 @@ Contributors: mmuro
3
  Tags: form, forms, form to email, email form, email, input, validation, jquery, shortcode
4
  Requires at least: 3.1
5
  Tested up to: 3.2.1
6
- Stable tag: 1.3.1
7
 
8
  Dynamically build forms using a simple interface. Forms include jQuery validation, a basic logic-based verification system, and entry tracking.
9
 
@@ -16,12 +16,14 @@ Dynamically build forms using a simple interface. Forms include jQuery validatio
16
  * Setup and organize your form using a drag-and-drop interface
17
  * Automatically includes a basic logic-based verification system
18
  * Store form entries in your WordPress database and can manage them via the dashboard.
 
19
  * Send form submissions to multiple emails
20
  * Utilizes jQuery Form Validation
21
  * Customized Confirmation Messages
22
  * Redirect to a WordPress Page or a URL
23
  * Standard and Advanced Fields
24
  * Easy date fields using the jQuery UI Date Picker
 
25
 
26
  == Installation ==
27
 
@@ -36,7 +38,7 @@ Dynamically build forms using a simple interface. Forms include jQuery validatio
36
  = How do I build my form? =
37
 
38
  1. Click on the + tab, give your form a name and click Create Form.
39
- 1. Select form fields from the box on the left and click Create Field to add it to your form.
40
  1. Edit the information for each form field by clicking on the down arrow.
41
  1. Drag and drop the elements to put them in order.
42
  1. Click Save Form to save your changes.
@@ -75,6 +77,23 @@ To use the more complex features of the Date Picker plugin, you will need to:
75
  1. Using the above example ID, paste the following into your javascript file: `$( '#start-date' ).datepicker();`
76
  1. Add and customize the [jQuery UI Date Picker configuration options](http://jqueryui.com/demos/datepicker)
77
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
78
  == Screenshots ==
79
 
80
  1. Visual Form Builder page
@@ -83,6 +102,15 @@ To use the more complex features of the Date Picker plugin, you will need to:
83
 
84
  == Changelog ==
85
 
 
 
 
 
 
 
 
 
 
86
  **Version 1.3.1**
87
 
88
  * Fix bug where new Confirmation screen was not being installed
@@ -121,6 +149,9 @@ To use the more complex features of the Date Picker plugin, you will need to:
121
 
122
  == Upgrade Notice ==
123
 
 
 
 
124
  = 1.3.1 =
125
  Recommended update immediately! Fix for bug where confirmation screen does not install.
126
 
3
  Tags: form, forms, form to email, email form, email, input, validation, jquery, shortcode
4
  Requires at least: 3.1
5
  Tested up to: 3.2.1
6
+ Stable tag: 1.4
7
 
8
  Dynamically build forms using a simple interface. Forms include jQuery validation, a basic logic-based verification system, and entry tracking.
9
 
16
  * Setup and organize your form using a drag-and-drop interface
17
  * Automatically includes a basic logic-based verification system
18
  * Store form entries in your WordPress database and can manage them via the dashboard.
19
+ * Export entries to a CSV file
20
  * Send form submissions to multiple emails
21
  * Utilizes jQuery Form Validation
22
  * Customized Confirmation Messages
23
  * Redirect to a WordPress Page or a URL
24
  * Standard and Advanced Fields
25
  * Easy date fields using the jQuery UI Date Picker
26
+ * File uploads
27
 
28
  == Installation ==
29
 
38
  = How do I build my form? =
39
 
40
  1. Click on the + tab, give your form a name and click Create Form.
41
+ 1. Click the form fields from the box on the left to add it to your form.
42
  1. Edit the information for each form field by clicking on the down arrow.
43
  1. Drag and drop the elements to put them in order.
44
  1. Click Save Form to save your changes.
77
  1. Using the above example ID, paste the following into your javascript file: `$( '#start-date' ).datepicker();`
78
  1. Add and customize the [jQuery UI Date Picker configuration options](http://jqueryui.com/demos/datepicker)
79
 
80
+ = How do I export my entries to a CSV? =
81
+
82
+ There are two ways to export your entries to a CSV: Export All or Export Selected.
83
+
84
+ To Export All:
85
+
86
+ 1. Go to the Entries screen
87
+ 1. Select the `Export All` option under the `Bulk Actions` dropdown
88
+ 1. Click Apply and save the file
89
+
90
+ To Export Selected:
91
+
92
+ 1. Go to the Entries screen
93
+ 1. Check boxes next to the entries you wish to export
94
+ 1. Select the `Export Selected` option under the `Bulk Actions` dropdown
95
+ 1. CLick Apply and save the file
96
+
97
  == Screenshots ==
98
 
99
  1. Visual Form Builder page
102
 
103
  == Changelog ==
104
 
105
+ **Version 1.4**
106
+
107
+ * Fix bug where database charset wasn't being set and causing character encoding issues
108
+ * Fix date submitted to match local date and time settings
109
+ * Fix Textarea CSS to respond to large size
110
+ * Add File Upload and HTML Form Items
111
+ * Add Entries Export feature
112
+ * Update View Entries to full page view instead of jQuery show/hide quick view
113
+
114
  **Version 1.3.1**
115
 
116
  * Fix bug where new Confirmation screen was not being installed
149
 
150
  == Upgrade Notice ==
151
 
152
+ = 1.4 =
153
+ Export entries to a CSV, file uploads, and various bug fixes.
154
+
155
  = 1.3.1 =
156
  Recommended update immediately! Fix for bug where confirmation screen does not install.
157
 
visual-form-builder.php CHANGED
@@ -3,7 +3,7 @@
3
  Plugin Name: Visual Form Builder
4
  Description: Dynamically build forms using a simple interface. Forms include jQuery validation, a basic logic-based verification system, and entry tracking.
5
  Author: Matthew Muro
6
- Version: 1.3.1
7
  */
8
 
9
  /*
@@ -27,7 +27,7 @@ $visual_form_builder = new Visual_Form_Builder();
27
  /* Restrict Categories class */
28
  class Visual_Form_Builder{
29
 
30
- public $vfb_db_version = '1.3.1';
31
 
32
  public function __construct(){
33
  global $wpdb;
@@ -44,7 +44,8 @@ class Visual_Form_Builder{
44
  add_action( 'admin_menu', array( &$this, 'save' ) );
45
  add_action( 'wp_ajax_visual_form_builder_process_sort', array( &$this, 'visual_form_builder_process_sort_callback' ) );
46
  add_action( 'admin_init', array( &$this, 'add_visual_form_builder_contextual_help' ) );
47
-
 
48
  /* Load the includes files */
49
  add_action( 'plugins_loaded', array( &$this, 'includes' ) );
50
 
@@ -91,8 +92,11 @@ class Visual_Form_Builder{
91
  * @since 1.2
92
  */
93
  public function includes(){
94
- /* Load the Entries class */
95
  require_once( trailingslashit( plugin_dir_path( __FILE__ ) ) . 'class-entries-list.php' );
 
 
 
96
  }
97
 
98
  /**
@@ -191,6 +195,24 @@ class Visual_Form_Builder{
191
  update_option( 'visual-form-builder-screen-options', $updated_options );
192
  }
193
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
194
 
195
 
196
  /**
@@ -205,6 +227,10 @@ class Visual_Form_Builder{
205
  $form_table_name = $wpdb->prefix . 'visual_form_builder_forms';
206
  $entries_table_name = $wpdb->prefix . 'visual_form_builder_entries';
207
 
 
 
 
 
208
  require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
209
 
210
  $field_sql = "CREATE TABLE $field_table_name (
@@ -220,9 +246,8 @@ class Visual_Form_Builder{
220
  field_required VARCHAR(25),
221
  field_size VARCHAR(25),
222
  UNIQUE KEY (field_id)
223
- );";
224
-
225
-
226
  $form_sql = "CREATE TABLE $form_table_name (
227
  form_id BIGINT(20) NOT NULL AUTO_INCREMENT,
228
  form_key TINYTEXT NOT NULL,
@@ -236,7 +261,7 @@ class Visual_Form_Builder{
236
  form_success_type VARCHAR(25) DEFAULT 'text',
237
  form_success_message TEXT,
238
  UNIQUE KEY (form_id)
239
- );";
240
 
241
  $entries_sql = "CREATE TABLE $entries_table_name (
242
  entries_id BIGINT(20) NOT NULL AUTO_INCREMENT,
@@ -249,7 +274,7 @@ class Visual_Form_Builder{
249
  date_submitted VARCHAR(25),
250
  ip_address VARCHAR(25),
251
  UNIQUE KEY (entries_id)
252
- );";
253
 
254
  /* Create or Update database tables */
255
  dbDelta( $field_sql );
@@ -287,6 +312,7 @@ class Visual_Form_Builder{
287
  wp_enqueue_script( 'jquery-form-validation', 'http://ajax.aspnetcdn.com/ajax/jquery.validate/1.8/jquery.validate.min.js', array( 'jquery' ), '', true );
288
  wp_enqueue_script( 'jquery-ui-core ', 'https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.13/jquery-ui.min.js', array( 'jquery' ), '', true );
289
  wp_enqueue_script( 'visual-form-builder-validation', plugins_url( 'visual-form-builder' ) . '/js/visual-form-builder-validate.js' , array( 'jquery', 'jquery-form-validation' ), '', true );
 
290
  }
291
 
292
  /**
@@ -500,7 +526,7 @@ class Visual_Form_Builder{
500
  $form_id = absint( $_REQUEST['form_id'] );
501
  $field_key = sanitize_title( $_REQUEST['field_name'] );
502
  $field_name = esc_html( $_REQUEST['field_type'] );
503
- $field_type = strtolower( esc_html( $_REQUEST['field_type'] ) );
504
 
505
  /* Set defaults for validation */
506
  switch ( $field_type ) {
@@ -611,12 +637,18 @@ class Visual_Form_Builder{
611
  if ( isset( $_REQUEST['view'] ) && in_array( $_REQUEST['view'], array( 'entries' ) ) ) :
612
 
613
  $entries_list = new VisualFormBuilder_Entries_List();
614
- $entries_list->prepare_items();
 
 
 
 
 
615
  ?>
616
  <form id="entries-filter" method="post" action="">
617
  <?php $entries_list->display(); ?>
618
  </form>
619
  <?php
 
620
  /* Display the Forms */
621
  else:
622
  echo ( isset( $this->message ) ) ? $this->message : ''; ?>
@@ -654,6 +686,8 @@ class Visual_Form_Builder{
654
  <li><input type="submit" id="form-element-digits" class="button-secondary" name="field_type" value="Number"<?php echo $disabled; ?> /></li>
655
  <li><input type="submit" id="form-element-time" class="button-secondary" name="field_type" value="Time"<?php echo $disabled; ?> /></li>
656
  <li><input type="submit" id="form-element-phone" class="button-secondary" name="field_type" value="Phone"<?php echo $disabled; ?> /></li>
 
 
657
  </ul>
658
  </div>
659
  </div>
@@ -868,8 +902,8 @@ class Visual_Form_Builder{
868
  <li id="form_item_<?php echo $field->field_id; ?>" class="form-item">
869
  <dl class="menu-item-bar">
870
  <dt class="menu-item-handle<?php echo ( $field->field_type == 'fieldset' ) ? ' fieldset' : ''; ?>">
871
- <span class="item-title"><?php echo stripslashes( $field->field_name ); ?><?php echo ( $field->field_required == 'yes' ) ? ' <span class="is-field-required">*</span>' : ''; ?></span> <span class="item-controls">
872
- <span class="item-type"><?php echo strtoupper( $field->field_type ); ?></span>
873
  <a href="#" title="Edit Field Item" id="edit-<?php echo $field->field_id; ?>" class="item-edit">Edit Field Item</a>
874
  </span>
875
  </dt>
@@ -886,7 +920,7 @@ class Visual_Form_Builder{
886
  <p class="description description-wide">
887
  <label for="edit-form-item-name-<?php echo $field->field_id; ?>">
888
  Name<br />
889
- <input type="text" value="<?php echo stripslashes( $field->field_name ); ?>" name="field_name-<?php echo $field->field_id; ?>" class="widefat" id="edit-form-item-name-<?php echo $field->field_id; ?>" />
890
  </label>
891
  </p>
892
  <p class="description description-wide">
@@ -922,7 +956,7 @@ class Visual_Form_Builder{
922
  <p class="description description-thin">
923
  <label for="edit-form-item-validation">
924
  Validation<br />
925
- <select name="field_validation-<?php echo $field->field_id; ?>" class="widefat" id="edit-form-item-validation-<?php echo $field->field_id; ?>"<?php echo ( in_array( $field->field_type, array( 'radio', 'select', 'checkbox', 'address', 'date', 'textarea' ) ) ) ? ' disabled="disabled"' : ''; ?>>
926
  <?php if ( $field->field_type == 'time' ) : ?>
927
  <option value="time-12" <?php selected( $field->field_validation, 'time-12' ); ?>>12 Hour Format</option>
928
  <option value="time-24" <?php selected( $field->field_validation, 'time-24' ); ?>>24 Hour Format</option>
@@ -1066,7 +1100,7 @@ class Visual_Form_Builder{
1066
 
1067
  foreach ( $forms as $form ) :
1068
 
1069
- $output = '<form id="' . $form->form_key . '" class="visual-form-builder" method="post">
1070
  <input type="hidden" name="form_id" value="' . $form->form_id . '" />';
1071
  $output .= wp_nonce_field( 'visual-form-builder-nonce', '_wpnonce', false, false );
1072
 
@@ -1100,13 +1134,14 @@ class Visual_Form_Builder{
1100
  $output .= '<span><input type="text" name="vfb-' . esc_html( $field->field_key ) . '" id="vfb-' . esc_html( $field->field_key ) . '" value="" class="text ' . $field->field_size . $required . $validation . '" /><label>' . $field->field_description . '</label></span>';
1101
  else
1102
  $output .= '<input type="text" name="vfb-' . esc_html( $field->field_key ) . '" id="vfb-' . esc_html( $field->field_key ) . '" value="" class="text ' . $field->field_size . $required . $validation . '" />';
 
1103
  break;
1104
 
1105
  case 'textarea' :
1106
 
1107
  if ( !empty( $field->field_description ) )
1108
  $output .= '<span><label>' . stripslashes( $field->field_description ) . '</label></span>';
1109
-
1110
  $output .= '<textarea name="vfb-'. $field->field_key . '" id="vfb-'. $field->field_key . '" class="textarea ' . $field->field_size . $required . '"></textarea>';
1111
 
1112
  break;
@@ -1255,7 +1290,28 @@ class Visual_Form_Builder{
1255
  /* AM/PM */
1256
  if ( $time_format == '12' )
1257
  $output .= '<span class="time"><select name="vfb-'. $field->field_key . '[ampm]" id="vfb-'. $field->field_key . '" class="select' . $required . '"><option value="AM">AM</option><option value="PM">PM</option></select><label>AM/PM</label></span>';
1258
- break;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1259
  }
1260
 
1261
  $output .= '</li>';
@@ -1355,12 +1411,12 @@ class Visual_Form_Builder{
1355
  $form_from = $_POST[ 'vfb-' . $email->field_key ];
1356
  }
1357
 
1358
-
1359
  /* Prepare the beginning of the content */
1360
  $message = '<html><body><table rules="all" style="border-color: #666;" cellpadding="10">';
1361
 
1362
  /* Loop through each form field and build the body of the message */
1363
  foreach ( $_POST as $key => $value ) {
 
1364
  /* Remove prefix, dashes and lowercase */
1365
  $key = str_replace( 'vfb-', '', $key );
1366
  $key = strtolower( str_replace( '-', ' ', $key ) );
@@ -1382,9 +1438,32 @@ class Visual_Form_Builder{
1382
  }
1383
  }
1384
 
1385
- /* Get the date/time format that is saved in the options table */
1386
- $date_format = get_option('date_format');
1387
- $time_format = get_option('time_format');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1388
 
1389
  /* Setup our entries data */
1390
  $entry = array(
@@ -1394,7 +1473,7 @@ class Visual_Form_Builder{
1394
  'sender_name' => $form_from_name,
1395
  'sender_email' => $form_from,
1396
  'emails_to' => serialize( $form_to ),
1397
- 'date_submitted' => date( $date_format . ' ' . $time_format),
1398
  'ip_address' => $_SERVER['REMOTE_ADDR']
1399
  );
1400
 
@@ -1411,7 +1490,7 @@ class Visual_Form_Builder{
1411
 
1412
  /* Send the mail */
1413
  foreach ( $form_to as $email ) {
1414
- $mail_sent = wp_mail( $email, esc_html( $form_subject ), $message, $headers );
1415
  }
1416
  elseif ( isset( $_REQUEST['visual-form-builder-submit'] ) ) :
1417
  /* If any of the security checks fail, provide some user feedback */
3
  Plugin Name: Visual Form Builder
4
  Description: Dynamically build forms using a simple interface. Forms include jQuery validation, a basic logic-based verification system, and entry tracking.
5
  Author: Matthew Muro
6
+ Version: 1.4
7
  */
8
 
9
  /*
27
  /* Restrict Categories class */
28
  class Visual_Form_Builder{
29
 
30
+ public $vfb_db_version = '1.4';
31
 
32
  public function __construct(){
33
  global $wpdb;
44
  add_action( 'admin_menu', array( &$this, 'save' ) );
45
  add_action( 'wp_ajax_visual_form_builder_process_sort', array( &$this, 'visual_form_builder_process_sort_callback' ) );
46
  add_action( 'admin_init', array( &$this, 'add_visual_form_builder_contextual_help' ) );
47
+ add_action( 'admin_init', array( &$this, 'export_entries' ) );
48
+
49
  /* Load the includes files */
50
  add_action( 'plugins_loaded', array( &$this, 'includes' ) );
51
 
92
  * @since 1.2
93
  */
94
  public function includes(){
95
+ /* Load the Entries List class */
96
  require_once( trailingslashit( plugin_dir_path( __FILE__ ) ) . 'class-entries-list.php' );
97
+
98
+ /* Load the Entries Details class */
99
+ require_once( trailingslashit( plugin_dir_path( __FILE__ ) ) . 'class-entries-detail.php' );
100
  }
101
 
102
  /**
195
  update_option( 'visual-form-builder-screen-options', $updated_options );
196
  }
197
  }
198
+
199
+ /**
200
+ * Runs the export_entries function in the class-entries-list.php file
201
+ *
202
+ * @since 1.4
203
+ */
204
+ public function export_entries() {
205
+ $entries = new VisualFormBuilder_Entries_List();
206
+
207
+ /* If exporting all, don't pass the IDs */
208
+ if ( 'export-all' === $entries->current_action() )
209
+ $entries->export_entries();
210
+ /* If exporting selected, pick up the ID array and pass them */
211
+ elseif ( 'export-selected' === $entries->current_action() ) {
212
+ $entry_id = ( is_array( $_REQUEST['entry'] ) ) ? $_REQUEST['entry'] : array( $_REQUEST['entry'] );
213
+ $entries->export_entries( $entry_id );
214
+ }
215
+ }
216
 
217
 
218
  /**
227
  $form_table_name = $wpdb->prefix . 'visual_form_builder_forms';
228
  $entries_table_name = $wpdb->prefix . 'visual_form_builder_entries';
229
 
230
+ /* Explicitly set the character set and collation when creating the tables */
231
+ $charset = ( defined( 'DB_CHARSET' && '' !== DB_CHARSET ) ) ? DB_CHARSET : 'utf8';
232
+ $collate = ( defined( 'DB_COLLATE' && '' !== DB_COLLATE ) ) ? DB_COLLATE : 'utf8_general_ci';
233
+
234
  require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
235
 
236
  $field_sql = "CREATE TABLE $field_table_name (
246
  field_required VARCHAR(25),
247
  field_size VARCHAR(25),
248
  UNIQUE KEY (field_id)
249
+ ) DEFAULT CHARACTER SET $charset COLLATE $collate;";
250
+
 
251
  $form_sql = "CREATE TABLE $form_table_name (
252
  form_id BIGINT(20) NOT NULL AUTO_INCREMENT,
253
  form_key TINYTEXT NOT NULL,
261
  form_success_type VARCHAR(25) DEFAULT 'text',
262
  form_success_message TEXT,
263
  UNIQUE KEY (form_id)
264
+ ) DEFAULT CHARACTER SET $charset COLLATE $collate;";
265
 
266
  $entries_sql = "CREATE TABLE $entries_table_name (
267
  entries_id BIGINT(20) NOT NULL AUTO_INCREMENT,
274
  date_submitted VARCHAR(25),
275
  ip_address VARCHAR(25),
276
  UNIQUE KEY (entries_id)
277
+ ) DEFAULT CHARACTER SET $charset COLLATE $collate;";
278
 
279
  /* Create or Update database tables */
280
  dbDelta( $field_sql );
312
  wp_enqueue_script( 'jquery-form-validation', 'http://ajax.aspnetcdn.com/ajax/jquery.validate/1.8/jquery.validate.min.js', array( 'jquery' ), '', true );
313
  wp_enqueue_script( 'jquery-ui-core ', 'https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.13/jquery-ui.min.js', array( 'jquery' ), '', true );
314
  wp_enqueue_script( 'visual-form-builder-validation', plugins_url( 'visual-form-builder' ) . '/js/visual-form-builder-validate.js' , array( 'jquery', 'jquery-form-validation' ), '', true );
315
+ wp_enqueue_script( 'visual-form-builder-quicktags', plugins_url( 'visual-form-builder' ) . '/js/js_quicktags.js' );
316
  }
317
 
318
  /**
526
  $form_id = absint( $_REQUEST['form_id'] );
527
  $field_key = sanitize_title( $_REQUEST['field_name'] );
528
  $field_name = esc_html( $_REQUEST['field_type'] );
529
+ $field_type = strtolower( sanitize_title( $_REQUEST['field_type'] ) );
530
 
531
  /* Set defaults for validation */
532
  switch ( $field_type ) {
637
  if ( isset( $_REQUEST['view'] ) && in_array( $_REQUEST['view'], array( 'entries' ) ) ) :
638
 
639
  $entries_list = new VisualFormBuilder_Entries_List();
640
+ $entries_detail = new VisualFormBuilder_Entries_Detail();
641
+
642
+ if ( isset( $_REQUEST['action'] ) && in_array( $_REQUEST['action'], array( 'view' ) ) ) :
643
+ $entries_detail->entries_detail();
644
+ else :
645
+ $entries_list->prepare_items();
646
  ?>
647
  <form id="entries-filter" method="post" action="">
648
  <?php $entries_list->display(); ?>
649
  </form>
650
  <?php
651
+ endif;
652
  /* Display the Forms */
653
  else:
654
  echo ( isset( $this->message ) ) ? $this->message : ''; ?>
686
  <li><input type="submit" id="form-element-digits" class="button-secondary" name="field_type" value="Number"<?php echo $disabled; ?> /></li>
687
  <li><input type="submit" id="form-element-time" class="button-secondary" name="field_type" value="Time"<?php echo $disabled; ?> /></li>
688
  <li><input type="submit" id="form-element-phone" class="button-secondary" name="field_type" value="Phone"<?php echo $disabled; ?> /></li>
689
+ <li><input type="submit" id="form-element-html" class="button-secondary" name="field_type" value="HTML"<?php echo $disabled; ?> /></li>
690
+ <li><input type="submit" id="form-element-file" class="button-secondary" name="field_type" value="File Upload"<?php echo $disabled; ?> /></li>
691
  </ul>
692
  </div>
693
  </div>
902
  <li id="form_item_<?php echo $field->field_id; ?>" class="form-item">
903
  <dl class="menu-item-bar">
904
  <dt class="menu-item-handle<?php echo ( $field->field_type == 'fieldset' ) ? ' fieldset' : ''; ?>">
905
+ <span class="item-title"><?php echo stripslashes( htmlspecialchars( $field->field_name ) ); ?><?php echo ( $field->field_required == 'yes' ) ? ' <span class="is-field-required">*</span>' : ''; ?></span> <span class="item-controls">
906
+ <span class="item-type"><?php echo strtoupper( str_replace( '-', ' ', $field->field_type ) ); ?></span>
907
  <a href="#" title="Edit Field Item" id="edit-<?php echo $field->field_id; ?>" class="item-edit">Edit Field Item</a>
908
  </span>
909
  </dt>
920
  <p class="description description-wide">
921
  <label for="edit-form-item-name-<?php echo $field->field_id; ?>">
922
  Name<br />
923
+ <input type="text" value="<?php echo stripslashes( htmlspecialchars( $field->field_name ) ); ?>" name="field_name-<?php echo $field->field_id; ?>" class="widefat" id="edit-form-item-name-<?php echo $field->field_id; ?>" />
924
  </label>
925
  </p>
926
  <p class="description description-wide">
956
  <p class="description description-thin">
957
  <label for="edit-form-item-validation">
958
  Validation<br />
959
+ <select name="field_validation-<?php echo $field->field_id; ?>" class="widefat" id="edit-form-item-validation-<?php echo $field->field_id; ?>"<?php echo ( in_array( $field->field_type, array( 'radio', 'select', 'checkbox', 'address', 'date', 'textarea', 'html', 'file-upload' ) ) ) ? ' disabled="disabled"' : ''; ?>>
960
  <?php if ( $field->field_type == 'time' ) : ?>
961
  <option value="time-12" <?php selected( $field->field_validation, 'time-12' ); ?>>12 Hour Format</option>
962
  <option value="time-24" <?php selected( $field->field_validation, 'time-24' ); ?>>24 Hour Format</option>
1100
 
1101
  foreach ( $forms as $form ) :
1102
 
1103
+ $output = '<form id="' . $form->form_key . '" class="visual-form-builder" method="post" enctype="multipart/form-data">
1104
  <input type="hidden" name="form_id" value="' . $form->form_id . '" />';
1105
  $output .= wp_nonce_field( 'visual-form-builder-nonce', '_wpnonce', false, false );
1106
 
1134
  $output .= '<span><input type="text" name="vfb-' . esc_html( $field->field_key ) . '" id="vfb-' . esc_html( $field->field_key ) . '" value="" class="text ' . $field->field_size . $required . $validation . '" /><label>' . $field->field_description . '</label></span>';
1135
  else
1136
  $output .= '<input type="text" name="vfb-' . esc_html( $field->field_key ) . '" id="vfb-' . esc_html( $field->field_key ) . '" value="" class="text ' . $field->field_size . $required . $validation . '" />';
1137
+
1138
  break;
1139
 
1140
  case 'textarea' :
1141
 
1142
  if ( !empty( $field->field_description ) )
1143
  $output .= '<span><label>' . stripslashes( $field->field_description ) . '</label></span>';
1144
+
1145
  $output .= '<textarea name="vfb-'. $field->field_key . '" id="vfb-'. $field->field_key . '" class="textarea ' . $field->field_size . $required . '"></textarea>';
1146
 
1147
  break;
1290
  /* AM/PM */
1291
  if ( $time_format == '12' )
1292
  $output .= '<span class="time"><select name="vfb-'. $field->field_key . '[ampm]" id="vfb-'. $field->field_key . '" class="select' . $required . '"><option value="AM">AM</option><option value="PM">PM</option></select><label>AM/PM</label></span>';
1293
+ break;
1294
+
1295
+ case 'html' :
1296
+
1297
+ if ( !empty( $field->field_description ) )
1298
+ $output .= '<span><label>' . stripslashes( $field->field_description ) . '</label></span>';
1299
+
1300
+ $output .= '<script type="text/javascript">edToolbar("vfb-' . $field->field_key . '");</script>';
1301
+ $output .= '<textarea name="vfb-'. $field->field_key . '" id="vfb-'. $field->field_key . '" class="textarea vfbEditor ' . $field->field_size . $required . '"></textarea>';
1302
+
1303
+ break;
1304
+
1305
+ case 'file-upload' :
1306
+
1307
+ if ( !empty( $field->field_description ) )
1308
+ $output .= '<span><input type="file" size="35" name="vfb-' . esc_html( $field->field_key ) . '" id="vfb-' . esc_html( $field->field_key ) . '" value="" class="text ' . $field->field_size . $required . $validation . '" /><label>' . $field->field_description . '</label></span>';
1309
+ else
1310
+ $output .= '<input type="file" size="35" name="vfb-' . esc_html( $field->field_key ) . '" id="vfb-' . esc_html( $field->field_key ) . '" value="" class="text ' . $field->field_size . $required . $validation . '" />';
1311
+
1312
+
1313
+ break;
1314
+
1315
  }
1316
 
1317
  $output .= '</li>';
1411
  $form_from = $_POST[ 'vfb-' . $email->field_key ];
1412
  }
1413
 
 
1414
  /* Prepare the beginning of the content */
1415
  $message = '<html><body><table rules="all" style="border-color: #666;" cellpadding="10">';
1416
 
1417
  /* Loop through each form field and build the body of the message */
1418
  foreach ( $_POST as $key => $value ) {
1419
+
1420
  /* Remove prefix, dashes and lowercase */
1421
  $key = str_replace( 'vfb-', '', $key );
1422
  $key = strtolower( str_replace( '-', ' ', $key ) );
1438
  }
1439
  }
1440
 
1441
+ /* Prepare the attachments */
1442
+ if ( isset( $_FILES ) ) {
1443
+ foreach ( $_FILES as $k => $v ) {
1444
+ if ( $v['size'] > 0 ) {
1445
+ /* Options array for the wp_handle_upload function. 'test_upload' => false */
1446
+ $upload_overrides = array( 'test_form' => false );
1447
+
1448
+ /* We need to include the file that runs the wp_handle_upload function */
1449
+ require_once( ABSPATH . 'wp-admin/includes/file.php' );
1450
+
1451
+ /* Handle the upload using WP's wp_handle_upload function. Takes the posted file and an options array */
1452
+ $uploaded_file = wp_handle_upload( $v, $upload_overrides );
1453
+
1454
+ /* If the wp_handle_upload call returned a local path for the image */
1455
+ if ( isset( $uploaded_file['file'] ) ) {
1456
+ $attachments[$k] = $uploaded_file['file'];
1457
+
1458
+ $key = str_replace( 'vfb-', '', $k );
1459
+ $key = strtolower( str_replace( '-', ' ', $key ) );
1460
+ $fields[$key] = $uploaded_file['url'];
1461
+
1462
+ $message .= '<tr><td><strong>' . ucwords( $key ) . ': </strong></td><td><a href="' . $uploaded_file['url'] . '">' . $uploaded_file['url'] . '</a></td></tr>';
1463
+ }
1464
+ }
1465
+ }
1466
+ }
1467
 
1468
  /* Setup our entries data */
1469
  $entry = array(
1473
  'sender_name' => $form_from_name,
1474
  'sender_email' => $form_from,
1475
  'emails_to' => serialize( $form_to ),
1476
+ 'date_submitted' => date_i18n( 'Y-m-d G:i:s' ),
1477
  'ip_address' => $_SERVER['REMOTE_ADDR']
1478
  );
1479
 
1490
 
1491
  /* Send the mail */
1492
  foreach ( $form_to as $email ) {
1493
+ $mail_sent = wp_mail( $email, esc_html( $form_subject ), $message, $headers, $attachments );
1494
  }
1495
  elseif ( isset( $_REQUEST['visual-form-builder-submit'] ) ) :
1496
  /* If any of the security checks fail, provide some user feedback */