spivurno of Gravity Wiz
4/29/2014 - 2:58 PM

Gravity Wiz // Gravity Forms User Timezone Converter

Gravity Wiz // Gravity Forms User Timezone Converter

<?php
/**
* Gravity Forms User Timezone Converter
*
* Converts the date-based values/labels of a any choice-based field (i.e. selects, radios) to the user's timezone.
* The value/label of the field must be parseable by PHPs strtotime function.
*
* A thank you to Stack Overflow for this article:
* http://stackoverflow.com/questions/4186868/convert-timestamp-to-timezones
*
* @author    David Smith <david@gravitywiz.com>
* @license   GPL-2.0+
* @link      http://gravitywiz.com/...
* @copyright 2013 Gravity Wiz
*/
class GWUserTimezoneConverter {

    var $use_user_timezone = false;
    var $field_timestamps = array();

    function __construct( $args ) {
		
        $this->_args = wp_parse_args( $args, array(
            'form_id' => false,
            'field_id' => false,
            'format' => 'm/d/y',
            'notifications' => array()
        ) );
		
        extract( $this->_args ); // gives us $form_id, $field_id, and $format

        if( ! $form_id || ! $field_id )
            return;

        add_filter( 'wp', array( $this, 'set_user_timezone' ) );
        add_filter( 'gform_pre_render_' . $form_id, array( $this, 'pre_render' ) );
        add_filter( 'gform_get_input_value', array( $this, 'format_timestamp' ), 10, 3 );

        // set/reset flag to determine when to use user timezone
        add_filter( 'gform_notification_' . $form_id, array( $this, 'maybe_set_use_user_timezone_flag' ) );
        add_action( 'gform_after_email', array( $this, 'reset_use_user_timezone_flag' ) );
        add_filter( 'gform_merge_tag_filter', array( $this, 'maybe_reformat_timestamp' ), 10, 4 );

    }

    function pre_render( $form ) {

        $user_timezone = $this->get_user_timezone();
        if( ! $user_timezone )
            return $form;

        foreach( $form['fields'] as &$field ) {

            if( $field['id'] != $this->_args['field_id'] )
                continue;

            foreach( $field['choices'] as &$choice ) {

                $date = $choice['value'];
                if( ! $date )
                    continue;

                $server_timezone = get_option( 'timezone_string' );
                if( ! $server_timezone )
                    $server_timezone = 'UTC';

                $utc_timestamp = strtotime( $date );
                $server_datetime = new DateTime( date( 'Y-m-d H:i:s', $utc_timestamp ), new DateTimeZone( $server_timezone ) );

                // be aware $server_datetime is still modified by any manipulation down to $user_datetime
                $user_datetime = $server_datetime;
                $user_datetime->setTimezone( new DateTimeZone( $user_timezone ) );

                $choice['text'] = $user_datetime->format( $this->_args['format'] );
                $choice['value'] = $utc_timestamp;

            }

        }

        return $form;
    }

    function set_user_timezone() {
		
        if( $this->get_user_timezone() )
            return;
		
        add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_timezone_script' ) );
        add_action( 'wp_footer', array( $this, 'init_timezone_script' ) );

    }

    function enqueue_timezone_script() {
        wp_enqueue_script( 'jstz', '//cdnjs.cloudflare.com/ajax/libs/jstimezonedetect/1.0.4/jstz.min.js', array(), '1.0.4', false );
    }

    function init_timezone_script() {
    	
        ?>

        <script type="text/javascript">

            var tz = jstz.determine(),
                exDate = new Date(),
                exDays = 60,
                value = null;

            exDate.setDate( exDate.getDate() + exDays );
            value = escape( tz.name() ) + '; expires=' + exDate.toUTCString();
			
            document.cookie = 'gwutc_user_timezone=' + value + '; path=/';
			
        </script>

        <?php
    }

    function get_user_timezone() {
        return rgar( $_COOKIE, 'gwutc_user_timezone' );
    }

    function format_timestamp( $value, $lead, $field ) {
		
		if( ! $this->is_applicable_field( $field ) || ! $this->is_timestamp( $value ) )
			return $value;
			
        $utc_timestamp = $value;
        $this->field_timestamps[$field['id']] = $utc_timestamp;
		
        $server_datetime = new DateTime( date( 'Y-m-d H:i:s', $utc_timestamp ), new DateTimeZone( get_option( 'timezone_string' ) ) );
		
        if( $this->use_user_timezone ) {

            $user_timedate = $server_datetime;
            $user_timedate->setTimezone( new DateTimeZone( $this->get_user_timezone() ) );
            $value = $user_timedate->format( $this->_args['format'] );

        } else {

            $value = $server_datetime->format( $this->_args['format'] );

        }

        return $value;
    }

    function maybe_reformat_timestamp( $value, $lead, $options, $field ) {

        if( $this->is_applicable_field( $field ) && $this->use_user_timezone ) {
            $value = $this->format_timestamp( $this->field_timestamps[$field['id']], $lead, $field );
        }

        return $value;
    }

    function is_applicable_field( $field ) {

        if( $field['formId'] != $this->_args['form_id'] )
            return false;

        if( $field['id'] != $this->_args['field_id'] )
            return false;

        return true;
    }

    function maybe_set_use_user_timezone_flag( $notification ) {

        if( ! in_array( $notification['name'], $this->_args['notifications'] ) )
            return $notification;

        $this->use_user_timezone = true;

        return $notification;
    }

    function reset_use_user_timezone_flag() {
        $this->user_user_timezone = false;
    }
	
  	function is_timestamp( $timestamp ) {
  	    return ( (string) (int) $timestamp === $timestamp ) 
  	        && ( $timestamp <= PHP_INT_MAX )
  	        && ( $timestamp >= ~PHP_INT_MAX );
  	}
	
}