├── README.md
├── gravityformstimesheet
└── gravityformstimesheet.php
├── screenshot-01.jpg
├── screenshot-02.jpg
└── screenshot-03.jpg
/README.md:
--------------------------------------------------------------------------------
1 | Gravity Forms Timesheet Field
2 | =============================
3 |
4 | A new type of field that allows timesheets to be submitted via Gravity Forms.
5 |
6 | Features
7 | --------
8 |
9 | - Date calendar popup and various date and time formats support
10 | - Sane input validation
11 | - Comments per time entry
12 | - Time totals in Form Entry list, detail, notifications and confirmations
13 | - Works with the [Saved Forms](https://github.com/soulseekah/Gravity-Forms-Saved-Forms-Addon) plugin correctly
14 | - Ready to be styled to suit any theme out there
15 |
16 | Screenshots
17 | -----------
18 |
19 | 
20 | 
21 | 
22 |
23 | Installation
24 | ------------
25 |
26 | Download the latest release from the [Releases](https://github.com/soulseekah/gravityformstimesheet/releases) page, unzip and copy the `gravityformstimesheet/` directory into your `wp-content/plugins` directory. Activate the plugin and enjoy.
27 |
28 | Requires at least Gravity Forms 1.9 and WordPress 4.0.
29 |
--------------------------------------------------------------------------------
/gravityformstimesheet/gravityformstimesheet.php:
--------------------------------------------------------------------------------
1 | timeFormat == '24' ? 6 : 8;
45 | $values = array_chunk( $value, $chunksize );
46 |
47 | $value = array();
48 | foreach ( $values as $chunk ) {
49 | while ( count( $chunk ) < $chunksize ) {
50 | $chunk []= '';
51 | }
52 | $value = array(
53 | 'date' => array_shift( $chunk ),
54 | 'checkin_hour' => array_shift( $chunk ), 'checkin_minute' => array_shift( $chunk ), 'checkin_24' => $this->timeFormat == '24' ? '' : array_shift( $chunk ),
55 | 'checkout_hour' => array_shift( $chunk ), 'checkout_minute' => array_shift( $chunk ), 'checkout_24' => $this->timeFormat == '24' ? '' : array_shift( $chunk ),
56 | 'comment' => array_shift( $chunk )
57 | );
58 |
59 | if ( !$this->isRequired ) {
60 | if ( empty( $value['date'] ) && empty( $value['checkin_hour'] ) && empty( $value['checkin_minute'] ) && empty( $value['checkout_hour'] ) && empty( $value['checkout_minute'] ) && empty( $value['comment'] ) ) {
61 | continue;
62 | }
63 | }
64 |
65 | $date_info = GFCommon::parse_date( $value['date'], $this->dateFormat );
66 | if ( GFCommon::is_empty_array( $date_info ) || !checkdate( $date_info['month'], $date_info['day'], $date_info['year'] ) ) {
67 | $this->failed_validation = true;
68 | $this->validation_message = __( 'Invalid date or date format', self::$_translation_domain );
69 | return;
70 | }
71 |
72 | if ( !is_numeric( $value['checkin_hour'] ) || !is_numeric( $value['checkin_minute'] )
73 | || !is_numeric( $value['checkout_hour'] ) || !is_numeric( $value['checkout_minute'] )
74 | ) {
75 |
76 | $this->failed_validation = true;
77 | $this->validation_message = __( 'Invalid time or time format', self::$_translation_domain );
78 | return;
79 | }
80 |
81 | if ( $this->timeFormat != '24' ) {
82 | if ( $value['checkin_24'] == 'am' && intval( $value['checkin_hour'] ) == 12 ) $value['checkin_hour'] = 0;
83 | if ( $value['checkin_24'] == 'pm' && intval( $value['checkin_hour'] ) != 12 ) $value['checkin_hour'] += 12;
84 | if ( $value['checkout_24'] == 'pm' && intval( $value['checkout_hour'] ) != 12 ) $value['checkout_hour'] += 12;
85 | }
86 |
87 | if (
88 | ( intval( $value['checkin_hour'] ) < 0 || intval( $value['checkin_hour'] ) > 23 )
89 | || ( intval( $value['checkout_hour'] ) < 0 || intval( $value['checkout_hour'] ) > 23 )
90 | || ( intval( $value['checkin_minute'] ) < 0 || intval( $value['checkin_minute'] ) > 59 )
91 | || ( intval( $value['checkout_minute'] ) < 0 || intval( $value['checkout_minute'] ) > 59 )
92 | ) {
93 | $this->failed_validation = true;
94 | $this->validation_message = __( 'Invalid time or time format', self::$_translation_domain );
95 | return;
96 | }
97 |
98 | if ( intval( $value['checkin_hour'] ) >= intval( $value['checkout_hour'] ) ) {
99 | if ( intval( $value['checkin_minute'] ) >= intval( $value['checkout_minute'] ) ) {
100 | $this->failed_validation = true;
101 | $this->validation_message = __( 'Invalid time or time format', self::$_translation_domain );
102 | return;
103 | }
104 | }
105 | }
106 | }
107 |
108 |
109 | /**
110 | * Rendering the UI of the timesheet field.
111 | */
112 | public function get_field_input( $form, $value = '', $entry = null ) {
113 |
114 | wp_enqueue_style( 'gforms_datepicker_css', GFCommon::get_base_url() . '/css/datepicker.css', null, GFCommon::$version );
115 | wp_enqueue_script( 'gform_datepicker_init' );
116 |
117 | if ( is_admin() ) {
118 | ob_start();
119 |
120 | echo esc_html__( 'Timesheet fields are not editable.' );
121 | ?>
122 |
123 | '',
134 | 'checkin_hour' => '', 'checkin_minute' => '', 'checkin_24' => '',
135 | 'checkout_hour' => '', 'checkout_minute' => '', 'checkout_24' => '',
136 | 'comment' => ''
137 | ) );
138 | else {
139 | $value = $this->unserialize( $value );
140 | }
141 |
142 | ob_start();
143 | ?>
144 |
243 | calendarIconType = wp_strip_all_tags( $this->calendarIconType );
267 | $this->calendarIconUrl = wp_strip_all_tags( $this->calendarIconUrl );
268 | if ( ! $this->dateFormat || ! in_array( $this->dateFormat, array( 'mdy', 'dmy', 'dmy_dash', 'dmy_dot', 'ymd_slash', 'ymd_dash', 'ymd_dot' ) ) ) {
269 | $this->dateFormat = 'mdy';
270 | }
271 | }
272 |
273 | /**
274 | * Render the lead view of the timesheet field.
275 | */
276 | public function get_value_entry_detail( $value, $currency = '', $use_text = false, $format = 'html', $media = 'screen' ) {
277 | $value = maybe_unserialize( $value );
278 | $chunksize = $this->timeFormat == '24' ? 6 : 8;
279 | $values = array_chunk( $value, $chunksize );
280 | $value = array();
281 | foreach ( $values as $chunk ) {
282 | while ( count( $chunk ) < $chunksize ) {
283 | $chunk []= '';
284 | }
285 | $entry = array(
286 | 'date' => array_shift( $chunk ),
287 | 'checkin_hour' => array_shift( $chunk ), 'checkin_minute' => array_shift( $chunk ), 'checkin_24' => $this->timeFormat == '24' ? '' : array_shift( $chunk ),
288 | 'checkout_hour' => array_shift( $chunk ), 'checkout_minute' => array_shift( $chunk ), 'checkout_24' => $this->timeFormat == '24' ? '' : array_shift( $chunk ),
289 | 'comment' => array_shift( $chunk )
290 | );
291 | if ( !empty( $entry['date'] ) )
292 | $value []= $entry;
293 | }
294 |
295 | ob_start();
296 | ?>
297 |
298 |
299 |
300 | |
301 | |
302 | |
303 | |
304 |
305 |
306 |
307 |
311 |
312 | |
313 | timeFormat == '24' ? '' : ' ' .$entry['checkin_24'] ); ?> |
314 | timeFormat == '24' ? '' : ' ' .$entry['checkout_24'] ); ?> |
315 | |
316 |
317 | timeFormat != '24' ) {
319 | if ( $entry['checkin_24'] == 'am' && intval( $entry['checkin_hour'] ) == 12 ) $entry['checkin_hour'] = 0;
320 | if ( $entry['checkin_24'] == 'pm' && $entry['checkin_hour'] != 12 ) $entry['checkin_hour'] += 12;
321 | if ( $entry['checkout_24'] == 'pm' && $entry['checkout_hour'] != 12 ) $entry['checkout_hour'] += 12;
322 | }
323 |
324 | $minutes += ( ( $entry['checkout_hour'] * 60 ) + $entry['checkout_minute'] ) - ( ( $entry['checkin_hour'] * 60 ) + $entry['checkin_minute'] );
325 | endforeach;
326 | ?>
327 |
328 |
329 |
330 | |
331 | |
332 |
333 |
334 |
335 | unserialize( html_entity_decode( $value ) );
345 | $minutes = 0;
346 | foreach ( $value as $entry ):
347 | if ( $this->timeFormat != '24' ) {
348 | if ( $entry['checkin_24'] == 'am' && intval( $entry['checkin_hour'] ) == 12 ) $entry['checkin_hour'] = 0;
349 | if ( $entry['checkin_24'] == 'pm' && $entry['checkin_hour'] != 12 ) $entry['checkin_hour'] += 12;
350 | if ( $entry['checkout_24'] == 'pm' && $entry['checkout_hour'] != 12 ) $entry['checkout_hour'] += 12;
351 | }
352 | $minutes += ( ( $entry['checkout_hour'] * 60 ) + $entry['checkout_minute'] ) - ( ( $entry['checkin_hour'] * 60 ) + $entry['checkin_minute'] );
353 | endforeach;
354 |
355 | return sprintf( '%d entries, %02d:%02d total', count( $value ), $minutes/60, $minutes % 60 );
356 | }
357 |
358 | /**
359 | * Renders the timesheet table wherever used; mostly email
360 | * notifications and confirmations. But who knows where else...
361 | */
362 | public function get_value_merge_tag( $value, $input_id, $entry, $form, $modifier, $raw_value, $url_encode, $esc_html, $format, $nl2br ) {
363 | $value = $this->unserialize( $raw_value );
364 | ob_start();
365 | $minutes = 0;
366 | ?>
367 |
368 |
369 |
370 | |
371 | |
372 | |
373 | |
374 |
375 |
376 |
377 |
381 |
382 | |
383 | timeFormat == '24' ? '' : ' ' .$entry['checkin_24'] ); ?> |
384 | timeFormat == '24' ? '' : ' ' .$entry['checkout_24'] ); ?> |
385 | |
386 |
387 | timeFormat != '24' ) {
389 | if ( $entry['checkin_24'] == 'am' && intval( $entry['checkin_hour'] ) == 12 ) $entry['checkin_hour'] = 0;
390 | if ( $entry['checkin_24'] == 'pm' && $entry['checkin_hour'] != 12 ) $entry['checkin_hour'] += 12;
391 | if ( $entry['checkout_24'] == 'pm' && $entry['checkout_hour'] != 12 ) $entry['checkout_hour'] += 12;
392 | }
393 |
394 | $minutes += ( ( $entry['checkout_hour'] * 60 ) + $entry['checkout_minute'] ) - ( ( $entry['checkin_hour'] * 60 ) + $entry['checkin_minute'] );
395 | endforeach;
396 | ?>
397 |
398 |
399 |
400 | |
401 | |
402 |
403 |
404 |
405 |
415 |
416 |
417 |
418 | :
419 |
420 |
421 |
422 |
423 |
424 |
425 | timeFormat != '24' ) {
427 | ?>
428 |
429 |
433 |
434 |
437 |
438 | timeFormat == '24' ? 6 : 8;
446 | $values = array_chunk( maybe_unserialize( $value ), $chunksize );
447 | $value = array();
448 | foreach ( $values as $chunk ) {
449 | while ( count( $chunk ) < $chunksize ) {
450 | $chunk []= '';
451 | }
452 | $entry = array(
453 | 'date' => array_shift( $chunk ),
454 | 'checkin_hour' => array_shift( $chunk ), 'checkin_minute' => array_shift( $chunk ), 'checkin_24' => $this->timeFormat == '24' ? '' : array_shift( $chunk ),
455 | 'checkout_hour' => array_shift( $chunk ), 'checkout_minute' => array_shift( $chunk ), 'checkout_24' => $this->timeFormat == '24' ? '' : array_shift( $chunk ),
456 | 'comment' => array_shift( $chunk )
457 | );
458 | if ( !empty( $entry['date'] ) )
459 | $value []= $entry;
460 | }
461 | return $value;
462 | }
463 |
464 | }
465 |
466 | GF_Fields::register( new GF_Field_Timesheet() );
467 |
--------------------------------------------------------------------------------
/screenshot-01.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/soulseekah/gravityformstimesheet/2e8294e3f4cccb8fcf0d108c12f62127284040ea/screenshot-01.jpg
--------------------------------------------------------------------------------
/screenshot-02.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/soulseekah/gravityformstimesheet/2e8294e3f4cccb8fcf0d108c12f62127284040ea/screenshot-02.jpg
--------------------------------------------------------------------------------
/screenshot-03.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/soulseekah/gravityformstimesheet/2e8294e3f4cccb8fcf0d108c12f62127284040ea/screenshot-03.jpg
--------------------------------------------------------------------------------