diff --git a/classes/PodsComponents.php b/classes/PodsComponents.php
index 85edb3f75c..05693719d2 100644
--- a/classes/PodsComponents.php
+++ b/classes/PodsComponents.php
@@ -705,38 +705,98 @@ public function admin_ajax () {
die(); // KBAI!
}
- public function admin_ajax_settings ( $component, $params ) {
- if ( !isset( $this->components[ $component ] ) )
- wp_die( 'Invalid Component', '', array( 'back_link' => true ) );
- elseif ( !method_exists( $this->components[ $component ][ 'object' ], 'options' ) )
- pods_error( 'Component options method does not exist', $this );
+ public function admin_ajax_settings( $component, $params ) {
- $options = $this->components[ $component ][ 'object' ]->options( $this->settings[ 'components' ][ $component ] );
+ if ( ! isset( $this->components[ $component ] ) ) {
+ wp_die( 'Invalid Component', '', array( 'back_link' => true ) );
+ } elseif ( ! method_exists( $this->components[ $component ]['object'], 'options' ) ) {
+ pods_error( 'Component options method does not exist', $this );
+ }
- if ( empty( $this->settings[ 'components' ][ $component ] ) )
- $this->settings[ 'components' ][ $component ] = array();
+ $options = $this->components[ $component ]['object']->options( $this->settings['components'][ $component ] );
- foreach ( $options as $field_name => $field_option ) {
- $field_option = PodsForm::field_setup( $field_option, null, $field_option[ 'type' ] );
+ if ( empty( $this->settings['components'][ $component ] ) ) {
+ $this->settings['components'][ $component ] = array();
+ }
- if ( !is_array( $field_option[ 'group' ] ) ) {
- $field_value = pods_var_raw( 'pods_setting_' . $field_name, $params );
+ // @todo Use save_pod_item() functionality instead, this doesn't cover much
- $this->settings[ 'components' ][ $component ][ $field_name ] = $field_value;
- }
- else {
- foreach ( $field_option[ 'group' ] as $field_group_name => $field_group_option ) {
- $field_value = pods_var_raw( 'pods_setting_' . $field_group_name, $params );
+ foreach ( $options as $field_name => $field_option ) {
+ $field_option = PodsForm::field_setup( $field_option, null, $field_option['type'] );
- $this->settings[ 'components' ][ $component ][ $field_group_name ] = $field_value;
- }
- }
- }
+ if ( ! is_array( $field_option['group'] ) ) {
+ $field_value = pods_var_raw( 'pods_setting_' . $field_name, $params );
- $settings = version_compare( PHP_VERSION, '5.4.0', '>=' ) ? json_encode( $this->settings, JSON_UNESCAPED_UNICODE ) : json_encode( $this->settings );
+ if ( in_array( $field_option['type'], array( 'pick', 'file' ), true ) ) {
+ $field_value = $this->handle_pick_file_value_saving( $field_value, $field_option );
+ }
- update_option( 'pods_component_settings', $settings );
+ $this->settings['components'][ $component ][ $field_name ] = $field_value;
+ } else {
+ foreach ( $field_option['group'] as $field_group_name => $field_group_option ) {
+ $field_value = pods_var_raw( 'pods_setting_' . $field_group_name, $params );
+
+ if ( in_array( $field_group_option['type'], array( 'pick', 'file' ), true ) ) {
+ $field_value = $this->handle_pick_file_value_saving( $field_value, $field_group_option );
+ }
+
+ $this->settings['components'][ $component ][ $field_group_name ] = $field_value;
+ }
+ }
+ }
+
+ $settings = version_compare( PHP_VERSION, '5.4.0', '>=' ) ? json_encode( $this->settings, JSON_UNESCAPED_UNICODE ) : json_encode( $this->settings );
+
+ update_option( 'pods_component_settings', $settings );
+
+ return '1';
+
+ }
+
+ /**
+ * Handle saving for file/pick fields which requires some array work
+ *
+ * @param array|string $value
+ * @param array $field
+ *
+ * @return array|string
+ */
+ public function handle_pick_file_value_saving( $value, $field ) {
+
+ if ( empty( $value ) ) {
+ $value = array();
+ } elseif ( ! is_array( $value ) ) {
+ $value = array( $value );
+ }
+
+ if ( 'file' === $field['type'] && ! empty( $value ) ) {
+ // Fix file upload saved values coming from submission
+ $first_value = current( $value );
+
+ if ( is_array( $first_value ) && ! empty( $first_value['id'] ) ) {
+ $value = wp_list_pluck( $value, 'id' );
+ $value = array_map( 'absint', $value );
+ }
+ }
+
+ if ( $value ) {
+ $single = false;
+
+ if ( 'single' === pods_v( $field['type'] . '_format_type', $field, 'single', true ) ) {
+ $single = true;
+ } elseif ( 1 === (int) pods_v( $field['type'] . '_limit', $field ) ) {
+ $single = true;
+ }
+
+ if ( $single ) {
+ $value = current( $value );
+ }
+ } else {
+ $value = '';
+ }
+
+ return $value;
+
+ }
- return '1';
- }
}
diff --git a/classes/PodsField.php b/classes/PodsField.php
index 63aecbffa6..9e10a959d0 100644
--- a/classes/PodsField.php
+++ b/classes/PodsField.php
@@ -188,7 +188,7 @@ public function value( $value = null, $name = null, $options = null, $pod = null
}
/**
- * Change the way the value of the field is displayed with Pods::get
+ * Change the way the value of the field is displayed with Pods::field
*
* @param mixed|null $value
* @param string|null $name
diff --git a/classes/PodsForm.php b/classes/PodsForm.php
index bef9c3f555..47c9be92d3 100644
--- a/classes/PodsForm.php
+++ b/classes/PodsForm.php
@@ -953,15 +953,38 @@ public static function display( $type, $value = null, $name = null, $options = n
$tableless_field_types = self::tableless_field_types();
- if ( method_exists( self::$loaded[ $type ], 'display' ) ) {
- if ( is_array( $value ) && !in_array( $type, $tableless_field_types ) ) {
- foreach ( $value as $k => $display_value ) {
- $value[ $k ] = call_user_func_array( array( self::$loaded[ $type ], 'display' ), array( $display_value, $name, $options, $pod, $id, $traverse ) );
- }
- }
- else
- $value = call_user_func_array( array( self::$loaded[ $type ], 'display' ), array( $value, $name, $options, $pod, $id, $traverse ) );
- }
+ if ( method_exists( self::$loaded[ $type ], 'display_list' ) ) {
+ $value = call_user_func_array( array( self::$loaded[ $type ], 'display_list' ), array(
+ $value,
+ $name,
+ $options,
+ $pod,
+ $id,
+ $traverse
+ ) );
+ } elseif ( method_exists( self::$loaded[ $type ], 'display' ) ) {
+ if ( is_array( $value ) && ! in_array( $type, $tableless_field_types ) ) {
+ foreach ( $value as $k => $display_value ) {
+ $value[ $k ] = call_user_func_array( array( self::$loaded[ $type ], 'display' ), array(
+ $display_value,
+ $name,
+ $options,
+ $pod,
+ $id,
+ $traverse
+ ) );
+ }
+ } else {
+ $value = call_user_func_array( array( self::$loaded[ $type ], 'display' ), array(
+ $value,
+ $name,
+ $options,
+ $pod,
+ $id,
+ $traverse
+ ) );
+ }
+ }
$value = apply_filters( 'pods_form_display_' . $type, $value, $name, $options, $pod, $id, $traverse );
@@ -1398,6 +1421,7 @@ public static function field_types() {
'boolean',
'color',
'slug',
+ 'address',
);
$field_types = array_merge( $field_types, array_keys( self::$field_types ) );
diff --git a/classes/fields/address.php b/classes/fields/address.php
new file mode 100644
index 0000000000..042fca101b
--- /dev/null
+++ b/classes/fields/address.php
@@ -0,0 +1,559 @@
+ array(
+ 'label' => __( 'Address Type', 'pods' ),
+ 'default' => 'address',
+ 'type' => 'pick',
+ 'data' => array(
+ 'address' => __( 'Address Field Group', 'pods' ),
+ 'text' => __( 'Freeform Text', 'pods' )
+ ),
+ 'dependency' => true
+ ),
+ self::$type . '_address_options' => array(
+ 'label' => __( 'Address Options', 'pods' ),
+ 'depends-on' => array( self::$type . '_type' => 'address' ),
+ 'group' => array(
+ self::$type . '_address_line_1' => array(
+ 'label' => __( 'Enable Address Line 1', 'pods' ),
+ 'default' => 1,
+ 'type' => 'boolean'
+ ),
+ self::$type . '_address_line_2' => array(
+ 'label' => __( 'Enable Address Line 2', 'pods' ),
+ 'default' => 0,
+ 'type' => 'boolean'
+ ),
+ self::$type . '_address_postal_code' => array(
+ 'label' => __( 'Enable ZIP / Postal Code', 'pods' ),
+ 'default' => 0,
+ 'type' => 'boolean'
+ ),
+ self::$type . '_address_city' => array(
+ 'label' => __( 'Enable City', 'pods' ),
+ 'default' => 1,
+ 'type' => 'boolean'
+ ),
+ self::$type . '_address_region' => array(
+ 'label' => __( 'Enable Region (State / Province)', 'pods' ),
+ 'default' => 1,
+ 'type' => 'boolean',
+ 'dependency' => true
+ ),
+ self::$type . '_address_country' => array(
+ 'label' => __( 'Enable Country', 'pods' ),
+ 'default' => 0,
+ 'type' => 'boolean',
+ 'dependency' => true
+ )
+ )
+ ),
+ self::$type . '_address_region_input' => array(
+ 'label' => __( 'Region Input Type', 'pods' ),
+ 'depends-on' => array( self::$type . '_address_region' => true, self::$type . '_type' => 'address' ),
+ 'default' => 'text',
+ 'type' => 'pick',
+ 'data' => array(
+ 'text' => __( 'Freeform Text', 'pods' ),
+ 'pick' => __( 'Drop-down Select Box (US States)', 'pods' )
+ ),
+ 'dependency' => true
+ ),
+ self::$type . '_address_region_output' => array(
+ 'label' => __( 'Region Output Type', 'pods' ),
+ 'depends-on' => array(
+ self::$type . '_address_region_input' => 'pick',
+ self::$type . '_address_region' => true,
+ self::$type . '_type' => 'address'
+ ),
+ 'default' => 'long',
+ 'type' => 'pick',
+ 'data' => array(
+ 'long' => __( 'Full name', 'pods' ),
+ 'short' => __( 'State / Province code', 'pods' )
+ )
+ ),
+ self::$type . '_address_country_input' => array(
+ 'label' => __( 'Country Input Type', 'pods' ),
+ 'depends-on' => array( self::$type . '_address_country' => true, self::$type . '_type' => 'address' ),
+ 'default' => 'text',
+ 'type' => 'pick',
+ 'data' => array(
+ 'text' => __( 'Freeform Text', 'pods' ),
+ 'pick' => __( 'Drop-down Select Box', 'pods' )
+ ),
+ 'dependency' => true
+ ),
+ self::$type . '_address_country_output' => array(
+ 'label' => __( 'Country Output Type', 'pods' ),
+ 'depends-on' => array(
+ self::$type . '_address_country_input' => 'pick',
+ self::$type . '_address_country' => true,
+ self::$type . '_type' => 'address'
+ ),
+ 'default' => 'long',
+ 'type' => 'pick',
+ 'data' => array(
+ 'long' => __( 'Full name', 'pods' ),
+ 'short' => __( 'Country code', 'pods' )
+ )
+ ),
+ self::$type . '_display_type' => array(
+ 'label' => __( 'Display Type', 'pods' ),
+ 'default' => 'default',
+ 'type' => 'pick',
+ 'data' => array(
+ 'default' => __( 'Default', 'pods' ),
+ 'custom' => __( 'Custom', 'pods' )
+ ),
+ 'depends-on' => array( self::$type . '_type' => 'address' ),
+ 'dependency' => true
+ ),
+ self::$type . '_display_type_custom' => array(
+ 'label' => __( 'Custom display', 'pods' ),
+ 'help' => __( 'You can use the following tags for address fields', 'pods' ) . ': {{line_1}}
, {{line_2}}
, {{postal_code}}
, {{city}}
, {{region}}
, {{country}}
',
+ 'default' => self::default_display_format(),
+ 'type' => 'paragraph',
+ 'depends-on' => array( self::$type . '_display_type' => 'custom', self::$type . '_type' => 'address' )
+ ),
+ self::$type . '_microdata' => array(
+ 'label' => __( 'Format with microdata?', 'pods' ) . ' (schema.org)',
+ 'default' => 0,
+ 'type' => 'boolean',
+ 'depends-on' => array( self::$type . '_type' => 'address' )
+ )
+ );
+
+ return $options;
+
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @since 1.0
+ */
+ public function schema( $options = null ) {
+
+ /**
+ * @todo Storage types
+ *
+ * 1: Single meta value (default)
+ * 2: Separate meta values
+ * 3: Multiple columns (ACT)
+ *
+ * This field does not handle lat/lng & other maps related data so
+ * also allow the Maps component (and perhaps others) to modify/append to this with actions
+ */
+
+ $schema = 'LONGTEXT';
+
+ return $schema;
+
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @since 1.0
+ */
+ public function display( $value = null, $name = null, $options = null, $pod = null, $id = null ) {
+
+ $value_raw = $value;
+ $display_type = pods_v( self::$type . '_display_type', $options );
+
+ $view = PODS_DIR . 'ui/front/address.php';
+ $view = apply_filters( 'pods_ui_field_address_display_view', $view, $display_type, $value, $name, $options, $pod, $id );
+
+ $output = pods_view( $view, compact( array_keys( get_defined_vars() ) ), false, 'cache', true );
+ $output = apply_filters( 'pods_ui_field_address_display_value', $output, $value, $view, $display_type, $name, $options, $pod, $id );
+
+ return $output;
+
+ }
+
+ /**
+ * Change the way the a list of values of the field are displayed with Pods::field
+ *
+ * @param mixed|null $value
+ * @param string|null $name
+ * @param array|null $options
+ * @param array|null $pod
+ * @param int|null $id
+ *
+ * @return mixed|null|string
+ *
+ * @since 2.7
+ */
+ public function display_list( $value = null, $name = null, $options = null, $pod = null, $id = null ) {
+
+ return call_user_func_array( array( $this, 'display' ), func_get_args() );
+
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @since 1.0
+ */
+ public function input( $name, $value = null, $options = null, $pod = null, $id = null ) {
+
+ $form_field_type = PodsForm::$field_type;
+
+ $type = pods_v( self::$type . '_type', $options, 'address' );
+
+ // Text type is handled within the address field view
+ $view = PODS_DIR . 'ui/fields/address.php';
+ $view = apply_filters( 'pods_ui_field_address_input_view', $view, $type, $name, $value, $options, $pod, $id );
+
+ if ( ! empty( $view ) ) {
+ pods_view( $view, compact( array_keys( get_defined_vars() ) ) );
+ }
+
+ do_action( 'pods_ui_field_address_input_view_extra', $view, $type, $name, $value, $options, $pod, $id );
+
+ }
+
+ /**
+ * {@inheritDoc}
+ * @since 1.0
+ */
+ public function validate( $value, $name = null, $options = null, $fields = null, $pod = null, $id = null, $params = null ) {
+
+ // @todo: Validate each returned value for variable type and content (sanitizing)
+ $errors = array();
+
+ $type = pods_v( self::$type . '_type', $options );
+
+ /**
+ * Add extra validation checks
+ *
+ * @param array $errors
+ * @param mixed $value
+ * @param string $type Field address type
+ * @param string $name
+ * @param array $options
+ * @param array $fields
+ * @param array $pod
+ * @param int $id
+ * @param array $params
+ */
+ $errors = apply_filters( 'pods_ui_field_address_validate', $errors, $value, $type, $name, $options, $fields, $pod, $id, $params );
+
+ if ( 1 == pods_v( 'required', $options ) ) {
+ $errors[] = __( 'This field is required.', 'pods' );
+ }
+
+ if ( ! empty( $errors ) ) {
+ return $errors;
+ }
+
+ return true;
+
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @since 1.0
+ */
+ public function pre_save( $value, $id = null, $name = null, $options = null, $fields = null, $pod = null, $params = null ) {
+
+ $type = pods_v( self::$type . '_type', $options );
+
+ /**
+ * Add extra value sanitation
+ *
+ * @param mixed $value
+ * @param string $type Field address type
+ * @param int $id
+ * @param string $name
+ * @param array $options
+ * @param array $fields
+ * @param array $pod
+ * @param array $params
+ */
+ $value = apply_filters( 'pods_ui_field_address_pre_save', $value, $type, $id, $name, $options, $fields, $pod, $params );
+
+ return $value;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @since 1.0
+ */
+ public function ui( $id, $value, $name = null, $options = null, $fields = null, $pod = null ) {
+
+ return $value;
+
+ }
+
+ /**
+ * Convert the value for output display based on the field options
+ *
+ * @param array $value
+ * @param array $options
+ *
+ * @return array
+ */
+ public static function format_value_for_output( $value, $options ) {
+
+ if ( ! empty( $value['address'] ) ) {
+ foreach ( $value['address'] as $key => $val ) {
+ if ( 'region' === $key &&
+ 'pick' === pods_v( self::$type . '_address_region_input', $options ) &&
+ 'long' === pods_v( self::$type . '_address_region_output', $options )
+ ) {
+ // Display full region names if enabled
+ $regions = PodsForm::field_method( 'pick', 'data_us_states' );
+
+ if ( array_key_exists( $val, $regions ) ) {
+ $value['address'][ $key ] = $regions[ $val ];
+ }
+ } elseif ( 'country' === $key &&
+ 'pick' === pods_v( self::$type . '_address_country_input', $options ) &&
+ 'long' === pods_v( self::$type . '_address_country_output', $options )
+ ) {
+ // Display full country names if enabled
+ $countries = PodsForm::field_method( 'pick', 'data_countries' );
+
+ if ( array_key_exists( $val, $countries ) ) {
+ $value['address'][ $key ] = $countries[ $val ];
+ }
+ }
+ }
+ }
+
+ return $value;
+
+ }
+
+ /**
+ * Convert the field format into HTML for display
+ *
+ * @since 2.7
+ *
+ * @param string $format The format to be used (default or custom)
+ * @param array $value The field value
+ * @param array $options The field options
+ *
+ * @return string
+ */
+ public static function format_to_html( $format, $value, $options ) {
+
+ $output = '';
+
+ $value = self::format_value_for_output( $value, $options );
+
+ if ( ! empty ( $value['address'] ) ) {
+ $address = $value['address'];
+ }
+
+ if ( ! empty( $address ) ) {
+ // Format in microdata?
+ $microdata = ( ! empty( $options[ self::$type . '_microdata' ] ) ) ? true : false;
+
+ // @todo check pregreplace, maybe this can be done better (nl2br not working)
+ // Convert actual line breaks into an array
+ $lines = explode( '\r\n', preg_replace( "/\n/m", '\r\n', $format ) );
+
+ foreach ( $lines as $key => $line ) {
+ // preg_match to all tags
+ preg_match_all( '#{{(.*?)}}#', $line, $tags );
+
+ if ( ! empty( $tags[1] ) ) {
+ foreach ( $tags[1] as $tag ) {
+ // Default value is empty. Only known tags are allowed, remove all unknown tags
+ $value = '';
+
+ if ( ! empty( $address[ $tag ] ) ) {
+ // Format the value for HTML
+ $value = self::wrap_html_format( $address[ $tag ], $tag, 'span', $microdata );
+ }
+
+ $lines[ $key ] = str_replace( '{{' . $tag . '}}', $value, $lines[ $key ] );
+ }
+ }
+
+ $lines[ $key ] = trim( $lines[ $key ] );
+
+ if ( empty( $lines[ $key ] ) ) {
+ unset( $lines[ $key ] );
+ }
+ }
+
+ // Lines to HTML line breaks
+ $output = implode( '
', $lines );
+
+ $output = self::wrap_html_format( $output, 'address', 'div', $microdata );
+ }
+
+ return $output;
+
+ }
+
+ /**
+ * Wrap values in the correct HTML format with optional schema.org microdata based on the address tag
+ *
+ * @since 2.7
+ *
+ * @param string $value
+ * @param string $tag The address tag
+ *
+ * @return string
+ */
+ public static function wrap_html_format( $value, $tag, $element, $microdata = false ) {
+
+ $atts = array(
+ 'class' => 'pods-address' . $tag,
+ );
+
+ switch ( $tag ) {
+ case 'address':
+ $atts['class'] = 'pods-address';
+
+ if ( $microdata ) {
+ $atts['itemprop'] = 'address';
+ $atts['itemscope'] = '';
+ $atts['itemtype'] = 'http://schema.org/PostalAddress';
+ }
+
+ break;
+
+ case 'line_1':
+ case 'line_2':
+ if ( $microdata ) {
+ $atts['itemprop'] = 'streetAddress';
+ }
+
+ break;
+
+ case 'postal_code':
+ if ( $microdata ) {
+ $atts['itemprop'] = 'postalCode';
+ }
+
+ break;
+
+ case 'city':
+ if ( $microdata ) {
+ $atts['itemprop'] = 'addressLocality';
+ }
+
+ break;
+
+ case 'region':
+ if ( $microdata ) {
+ $atts['itemprop'] = 'addressRegion';
+ }
+
+ break;
+
+ case 'country':
+ if ( $microdata ) {
+ $atts['itemprop'] = 'addressCountry';
+ }
+
+ break;
+
+ default:
+ $atts = false;
+
+ break;
+ }
+
+ if ( $atts ) {
+ $attributes = '';
+
+ foreach ( $atts as $key => $val ) {
+ $attributes .= ' ' . esc_html( $key ) . '="' . esc_attr( $val ) . '"';
+ }
+
+ $value = '<' . esc_html( $element ) . $attributes . '>' . wp_kses_post( $value ) . '' . esc_html( $element ) . '>';
+ }
+
+ return $value;
+
+ }
+
+ /**
+ * The default display format
+ *
+ * @since 2.7
+ *
+ * @return string
+ */
+ public static function default_display_format() {
+
+ return '{{line_1}}
+{{line_2}}
+{{postal_code}} {{city}}
+{{region}}
+{{country}}';
+ }
+
+}
\ No newline at end of file
diff --git a/components/AddressMaps.php b/components/AddressMaps.php
new file mode 100644
index 0000000000..e5e23b8e32
--- /dev/null
+++ b/components/AddressMaps.php
@@ -0,0 +1,152 @@
+ realpath( self::$component_file ) );
+
+ return $components;
+
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @since 1.0
+ */
+ public function options( $settings ) {
+
+ $options = array(
+ 'provider' => array(
+ 'label' => __( 'Maps Provider', 'pods' ),
+ 'help' => __( 'help', 'pods' ),
+ 'default' => 'google',
+ 'type' => 'pick',
+ 'data' => apply_filters( 'pods_component_maps_providers', array(
+ 'google' => __( 'Google Maps', 'pods' ),
+ //'bing' => __( 'Bing Maps', 'pods' )
+ ) ),
+ 'dependency' => true
+ ),
+ 'api_key' => array(
+ 'label' => __( 'Maps API Key', 'pods' ),
+ 'help' => __( 'help', 'pods' ),
+ 'default' => '',
+ 'type' => 'text'
+ ),
+ 'google_client_id' => array(
+ 'label' => __( 'Google Maps Client ID', 'pods' ),
+ 'help' => __( 'For use with Google Maps API for Business and Geocoding; A Client ID does not come with the Free edition.', 'pods' ),
+ 'includes-on' => array( 'provider' => 'google' ),
+ 'default' => '',
+ 'type' => 'text'
+ ),
+ 'address_map_style' => array(
+ 'label' => __( 'Default Map Output Type', 'pods' ),
+ 'default' => 'static',
+ 'type' => 'pick',
+ 'data' => array(
+ 'static' => __( 'Static (Image)', 'pods' ),
+ 'js' => __( 'Javascript (Interactive)', 'pods' )
+ )
+ ),
+ 'address_map_type_of_map' => array(
+ 'label' => __( 'Default Map Type', 'pods' ),
+ 'default' => 'roadmap',
+ 'type' => 'pick',
+ 'data' => array(
+ 'roadmap' => __( 'Roadmap', 'pods' ),
+ 'satellite' => __( 'Satellite', 'pods' ),
+ 'terrain' => __( 'Terrain', 'pods' ),
+ 'hybrid' => __( 'Hybrid', 'pods' )
+ )
+ ),
+ 'address_map_zoom' => array(
+ 'label' => __( 'Default Map Zoom Level', 'pods' ),
+ 'help' => array(
+ __( 'Google Maps has documentation on the different zoom levels you can use.', 'pods' ),
+ 'https://developers.google.com/maps/documentation/staticmaps/#Zoomlevels'
+ ),
+ 'default' => 12,
+ 'type' => 'number',
+ 'options' => array(
+ 'number_decimals' => 0,
+ 'number_max_length' => 2
+ )
+ ),
+ 'address_map_marker' => array(
+ 'label' => __( 'Default Map Custom Marker', 'pods' ),
+ 'type' => 'file',
+ 'options' => array(
+ 'file_uploader' => 'plupload',
+ 'file_edit_title' => 0,
+ 'file_restrict_filesize' => '1MB',
+ 'file_type' => 'images',
+ 'file_add_button' => 'Upload Marker Icon'
+ )
+ )
+ );
+
+ return $options;
+
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @since 1.0
+ */
+ public function handler( $options ) {
+
+ self::$options = $options;
+
+ }
+}
\ No newline at end of file
diff --git a/components/Maps/Maps-Google.php b/components/Maps/Maps-Google.php
new file mode 100644
index 0000000000..7926d5c2de
--- /dev/null
+++ b/components/Maps/Maps-Google.php
@@ -0,0 +1,493 @@
+ __( 'Maps API Key or Client ID', 'pods' ),
+ 'help' => __( 'help', 'pods' ),
+ 'default' => '',
+ 'type' => 'text',
+ );
+
+ /*$options['google_client_id'] = array(
+ 'label' => __( 'Google Maps Client ID', 'pods' ),
+ 'help' => __( 'For use with Google Maps API for Business and Geocoding; A Client ID does not come with the Free edition.', 'pods' ),
+ 'includes-on' => array( 'provider' => 'google' ),
+ 'default' => '',
+ 'type' => 'text',
+ );*/
+
+ $options['maps_style'] = array(
+ 'label' => __( 'Default Map Output Type', 'pods' ),
+ 'default' => 'static',
+ 'type' => 'pick',
+ 'data' => array(
+ 'static' => __( 'Static (Image)', 'pods' ),
+ 'js' => __( 'Javascript (Interactive)', 'pods' ),
+ ),
+ );
+
+ $options['maps_type'] = array(
+ 'label' => __( 'Default Map Type', 'pods' ),
+ 'default' => 'roadmap',
+ 'type' => 'pick',
+ 'data' => array(
+ 'roadmap' => __( 'Roadmap', 'pods' ),
+ 'satellite' => __( 'Satellite', 'pods' ),
+ 'terrain' => __( 'Terrain', 'pods' ),
+ 'hybrid' => __( 'Hybrid', 'pods' ),
+ ),
+ );
+
+ $options['maps_zoom'] = array(
+ 'label' => __( 'Default Map Zoom Level', 'pods' ),
+ 'help' => array(
+ __( 'Google Maps has documentation on the different zoom levels you can use.', 'pods' ),
+ 'https://developers.google.com/maps/documentation/javascript/tutorial#zoom-levels',
+ //'https://developers.google.com/maps/documentation/staticmaps/#Zoomlevels'
+ ),
+ 'default' => 12,
+ 'type' => 'number',
+ 'options' => array(
+ 'number_decimals' => 0, // 2
+ 'number_max_length' => 2,
+ 'number_min' => 1,
+ 'number_max' => 21,
+ 'number_format' => '9999.99',
+ //'number_format_type' => 'slider',
+ ),
+ );
+
+ $options['maps_scrollwheel'] = array(
+ 'label' => __( 'Enable scrollwheel?', 'pods' ),
+ 'default' => 1,
+ 'type' => 'boolean',
+ );
+
+ $options['maps_marker'] = array(
+ 'label' => __( 'Default Map Custom Marker', 'pods' ),
+ 'type' => 'file',
+ 'options' => array(
+ 'file_uploader' => 'plupload',
+ 'file_edit_title' => 0,
+ 'file_restrict_filesize' => '1MB',
+ 'file_type' => 'images',
+ 'file_add_button' => __( 'Upload Marker Icon', 'pods' ),
+ ),
+ );
+
+ return $options;
+ }
+
+ /**
+ * Add options to the maps fields.
+ * @inheritdoc
+ */
+ public function field_options( $options = array(), $type = '' ) {
+
+ $options['maps_style'] = array(
+ 'label' => __( 'Map Output Type', 'pods' ),
+ 'depends-on' => array( 'maps' => true ),
+ 'default' => pods_v( 'maps_style', Pods_Component_Maps::$options, 'static', true ),
+ 'type' => 'pick',
+ 'data' => array(
+ 'static' => __( 'Static (Image)', 'pods' ),
+ 'js' => __( 'Javascript (Interactive)', 'pods' ),
+ ),
+ );
+
+ $options['maps_type'] = array(
+ 'label' => __( 'Map Type', 'pods' ),
+ 'depends-on' => array( 'maps' => true ),
+ 'default' => pods_v( 'maps_type', Pods_Component_Maps::$options, 'roadmap', true ),
+ 'type' => 'pick',
+ 'data' => array(
+ 'roadmap' => __( 'Roadmap', 'pods' ),
+ 'satellite' => __( 'Satellite', 'pods' ),
+ 'terrain' => __( 'Terrain', 'pods' ),
+ 'hybrid' => __( 'Hybrid', 'pods' ),
+ ),
+ );
+
+ $options['maps_zoom'] = array(
+ 'label' => __( 'Map Zoom Level', 'pods' ),
+ 'depends-on' => array( 'maps' => true ),
+ 'help' => array(
+ __( 'Google Maps has documentation on the different zoom levels you can use.', 'pods' ),
+ 'https://developers.google.com/maps/documentation/javascript/tutorial#zoom-levels',
+ //'https://developers.google.com/maps/documentation/staticmaps/#Zoomlevels'
+ ),
+ 'default' => pods_v( 'maps_zoom', Pods_Component_Maps::$options, 12, true ),
+ 'type' => 'number',
+ 'options' => array(
+ 'number_decimals' => 0, // 2
+ 'number_max_length' => 2,
+ 'number_min' => 1,
+ 'number_max' => 21,
+ 'number_format' => '9999.99',
+ //'number_format_type' => 'slider',
+ ),
+ );
+
+ $options['maps_scrollwheel'] = array(
+ 'label' => __( 'Enable scroll wheel?', 'pods' ),
+ 'default' => 1,
+ 'type' => 'boolean',
+ );
+
+ $options['maps_info_window'] = array(
+ 'label' => __( 'Display an Info Window', 'pods' ),
+ 'default' => 0,
+ 'type' => 'boolean',
+ 'depends-on' => array( 'maps' => true ),
+ 'dependency' => true,
+ );
+
+ $options['maps_info_window_content'] = array(
+ 'label' => __( 'Info Window content', 'pods' ),
+ 'depends-on' => array(
+ 'maps' => true,
+ 'maps_info_window' => true,
+ ),
+ 'default' => 'paragraph',
+ 'type' => 'pick',
+ 'data' => array(
+ 'paragraph' => __( 'Custom', 'pods' ),
+ 'wysiwyg' => __( 'Custom (WYSIWYG)', 'pods' ),
+ // @todo 'display_type' is only available for field type 'address'
+ 'display_type' => __( 'Display Type', 'pods' ),
+ ),
+ );
+
+ if ( pods_components()->is_component_active( 'templates' ) ) {
+ //$titles = (array) $this->get_template_titles();
+ //if ( ! empty( $title ) ) {
+ $options['maps_info_window_content']['data']['template'] = __( 'Template', 'pods' );
+ $options['maps_info_window_template'] = array(
+ 'label' => __( 'Info Window template', 'pods' ),
+ 'depends-on' => array(
+ 'maps' => true,
+ 'maps_info_window' => true,
+ 'maps_info_window_content' => 'template',
+ ),
+ 'default' => 'true',
+ 'type' => 'pick',
+ 'data' => (array) Pods_Component_Maps::get_template_titles(),//array_combine( $titles, $titles ),
+ 'pick_format_type' => 'single',
+ 'pick_format_single' => 'dropdown',
+ );
+ //}
+ }
+
+ $options['maps_marker'] = array(
+ 'label' => __( 'Map Custom Marker', 'pods' ),
+ 'depends-on' => array( 'maps' => true ),
+ 'default' => pods_v( 'maps_marker', Pods_Component_Maps::$options ),
+ 'type' => 'file',
+ 'options' => array(
+ 'file_uploader' => 'plupload',
+ 'file_edit_title' => 0,
+ 'file_restrict_filesize' => '1MB',
+ 'file_type' => 'images',
+ 'file_add_button' => 'Upload Marker Icon',
+ ),
+ );
+
+ return $options;
+ }
+
+ /**
+ * The input field view file. Used by pods_view();
+ * @inheritdoc
+ */
+ public function field_input_view() {
+
+ $view = false;
+ if ( ! empty( Pods_Component_Maps::$api_key ) ) {
+ $view = plugin_dir_path( __FILE__ ) . 'ui/fields/map-google.php';
+ }
+
+ return $view;
+ }
+
+ /**
+ * The display field view file. Used by pods_view();
+ * @inheritdoc
+ */
+ public function field_display_view() {
+
+ $view = false;
+ if ( ! empty( Pods_Component_Maps::$api_key ) ) {
+ $view = plugin_dir_path( __FILE__ ) . 'ui/front/map-google.php';
+ }
+
+ return $view;
+ }
+
+ /**
+ * Geocode an address with given data
+ *
+ * @param string|array $data Any type of address data
+ * @param string $api_key
+ *
+ * @return array {
+ * @type array $address See get_address()
+ * @type array $geo See get_latlng()
+ * }
+ *
+ * @public
+ * @static
+ * @since 2.x
+ */
+ public static function geocode_address( $data, $api_key = '' ) {
+
+ $data = self::geocode( $data, $api_key );
+
+ $address = self::get_address( $data );
+ $latlng = self::get_latlng( $data );
+
+ return array( 'address' => $address, 'geo' => $latlng );
+ }
+
+ /**
+ * Geocode an address into Latitude and Longitude values
+ *
+ * @param string|array $address Address
+ * @param string $api_key
+ *
+ * @return array Latitude, Longitude (format: array( 'lat' => value, 'lng' => value ) )
+ *
+ * @public
+ * @static
+ * @since 2.x
+ */
+ public static function geocode_address_to_latlng( $address, $api_key = '' ) {
+
+ if ( is_array( $address ) ) {
+ foreach ( $address as $key => $val ) {
+ if ( is_array( $val ) ) {
+ $address[ $key ] = implode( ', ', $val );
+ }
+ }
+ $address = implode( ', ', $address );
+ }
+
+ $data = self::geocode( $address, $api_key );
+
+ return self::get_latlng( $data );
+ }
+
+ /**
+ * Get address data from Latitude and Longitude values
+ *
+ * @param string|array $lat_lng Lat / long numbers
+ * @param string $api_key
+ *
+ * @return array Address information
+ *
+ * @public
+ * @static
+ * @since 2.x
+ */
+ public static function geocode_latlng_to_address( $lat_lng, $api_key = '' ) {
+
+ if ( is_array( $lat_lng ) ) {
+ $lat_lng = implode( ',', array_map( 'floatval', $lat_lng ) );
+ }
+
+ $data = self::geocode( $lat_lng, $api_key, 'latlng' );
+
+ return self::get_address( $data );
+ }
+
+ /**
+ * Return address data from returned Google data
+ *
+ * @param array $data The data from Google
+ *
+ * @return array {
+ * @type string $line_1 Line 1 address parts, space separated.
+ * @type string $line_2 Line 2 address parts, space separated.
+ * @type string $postal_code Postal/ZIP code.
+ * @type string $city City.
+ * @type string $region Region parts, space separated.
+ * @type string $country Country.
+ * }
+ *
+ * @public
+ * @static
+ * @since 2.x
+ */
+ public static function get_address( $data ) {
+
+ if ( ! empty( $data['results'][0] ) ) {
+ $data = $data['results'][0];
+ }
+
+ if ( empty( $data['address_components'] ) ) {
+ return array();
+ }
+
+ $address = array(
+ 'line_1' => array(),
+ 'line_2' => array(),
+ 'postal_code' => '',
+ 'city' => '',
+ 'region' => array(),
+ 'country' => '',
+ );
+
+ foreach ( $data['address_components'] as $component ) {
+
+ $value = $component['long_name'];
+
+ // https://developers.google.com/maps/documentation/javascript/geocoding#GeocodingAddressTypes
+ switch ( $component['types'][0] ) {
+ case 'street_number':
+ $address['line_1'][1] = $value;
+ break;
+ case 'route':
+ $address['line_1'][0] = $value;
+ break;
+ case 'locality':
+ $address['city'] = $value;
+ break;
+ case 'country':
+ $address['country'] = $value;
+ break;
+ case 'postal_code':
+ $address['postal_code'] = $value;
+ break;
+ case 'administrative_area_level_1':
+ case 'administrative_area_level_2':
+ case 'administrative_area_level_3':
+ case 'administrative_area_level_4':
+ case 'administrative_area_level_5':
+ $address['region'][ $component['types'][0] ] = $value;
+ break;
+ }
+ }
+
+ /**
+ * Change the values and format passed by Google Maps.
+ * @param array $address The parsed value.
+ * @param array $address_components The address parts from Google Maps API.
+ */
+ $address = apply_filters( 'pods_component_maps_google_get_address', $address, $data['address_components'] );
+
+ foreach ( $address as $key => $parts ) {
+ if ( is_array( $parts ) ) {
+ ksort( $address[ $key ] );
+ }
+ }
+
+ foreach ( $address as $key => $value ) {
+ if ( is_array( $value ) ) {
+ $address[ $key ] = implode( ' ', $value );
+ }
+ }
+
+ return $address;
+ }
+
+ /**
+ * Return lat/lng data from returned Google data
+ *
+ * @param array $data The data from Google
+ *
+ * @return array {
+ * @type float|string $lat Latitude.
+ * @type float|string $lng Longitude.
+ * }
+ *
+ * @public
+ * @static
+ * @since 2.x
+ */
+ public static function get_latlng( $data ) {
+
+ if ( ! empty( $data['results'][0] ) ) {
+ $data = $data['results'][0];
+ }
+
+ if ( empty( $data['geometry']['location'] ) ) {
+ return array();
+ }
+
+ return array_map( 'floatval', $data['geometry']['location'] );
+ }
+
+ /**
+ * Call to Google Maps API
+ *
+ * @param string|array $data
+ * @param string $api_key Optional
+ * @param string $type ( address | latlng )
+ *
+ * @return array
+ *
+ * @public
+ * @static
+ * @since 2.x
+ */
+ public static function geocode( $data, $api_key = '', $type = 'address' ) {
+
+ if ( is_array( $data ) ) {
+ $data = implode( ',', $data );
+ }
+
+ $url = self::$geocode_url . '?' . $type . '=' . $data;
+
+ /*if ( ! empty( $api_key ) ) {
+ $url .= '&key=' . $api_key;
+ }*/
+
+ $post = wp_remote_post( $url );
+
+ if ( ! empty( $post['body'] ) ) {
+ $data = json_decode( $post['body'], true );
+ if ( ! empty( $data['results'][0] ) ) {
+ return $data['results'][0];
+ }
+ }
+
+ // Try again once.
+ $post = wp_remote_post( $url );
+
+ if ( ! empty( $post['body'] ) ) {
+ $data = json_decode( $post['body'], true );
+ if ( ! empty( $data['results'][0] ) ) {
+ return $data['results'][0];
+ }
+ }
+
+ return array();
+ }
+
+}
\ No newline at end of file
diff --git a/components/Maps/Maps-Provider.php b/components/Maps/Maps-Provider.php
new file mode 100644
index 0000000000..b48e7bd3d0
--- /dev/null
+++ b/components/Maps/Maps-Provider.php
@@ -0,0 +1,98 @@
+ value, 'lng' => value ) )
+ *
+ * @public
+ * @static
+ * @since 2.x
+ */
+ public static function geocode_address( $data, $api_key = '' );
+
+ /**
+ * Geocode an address into Latitude and Longitude values
+ *
+ * @param string|array $address Address
+ * @param string $api_key
+ *
+ * @return array Latitude, Longitude (format: array( 'lat' => value, 'lng' => value ) )
+ *
+ * @public
+ * @static
+ * @since 2.x
+ */
+ public static function geocode_address_to_latlng( $address, $api_key = '' );
+
+ /**
+ * Get address data from Latitude and Longitude values
+ *
+ * @param string|array $lat_lng Lat / long numbers
+ * @param string $api_key
+ *
+ * @return string Address information
+ *
+ * @public
+ * @static
+ * @since 2.x
+ */
+ public static function geocode_latlng_to_address( $lat_lng, $api_key = '' );
+
+}
diff --git a/components/Maps/Maps.php b/components/Maps/Maps.php
new file mode 100644
index 0000000000..bef41d4354
--- /dev/null
+++ b/components/Maps/Maps.php
@@ -0,0 +1,588 @@
+ admin_url( 'admin-ajax.php' ),
+ '_nonce' => wp_create_nonce( self::$nonce )
+ ) );
+
+ // @todo Allways load required front end assets (Maybe as an option?)
+ // Enqueue doesn't work in the display function anymore (hook is already fires before that)
+ self::$provider->assets();
+ }
+
+ /**
+ * Register the component
+ *
+ * @param $components
+ *
+ * @return array
+ * @since 1.0
+ */
+ public static function component_register( $components ) {
+
+ $components[] = array( 'File' => realpath( self::$component_file ) );
+
+ return $components;
+
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @since 1.0
+ */
+ public function handler( $options ) {
+
+ self::$options = $options;
+
+ if ( ! empty( $options['api_key'] ) ) {
+ self::$api_key = $options['api_key'];
+ }
+
+ $this->load_provider();
+
+ }
+
+ /**
+ * Load the selected provider
+ *
+ * @since 2.x
+ */
+ private function load_provider() {
+
+ /**
+ * Let Pods use a custom provider.
+ * Return string should match the instance you return in `pods_component_maps_provider_{provider}`
+ *
+ * @param string $provider Provider name slug.
+ * @return string Custom provider name slug.
+ */
+ $provider = (string) apply_filters( 'pods_component_maps_provider', self::$options['provider'] );
+
+ switch ( $provider ) {
+ case 'google':
+ if ( file_exists( plugin_dir_path( __FILE__ ) . 'Maps-Google.php' ) ) {
+ include_once( plugin_dir_path( __FILE__ ) . 'Maps-Google.php' );
+ self::$provider = new Pods_Component_Maps_Google();
+ }
+ break;
+ default:
+ /**
+ * Add your own maps API provider instance
+ *
+ * @param string $provider
+ * @return object Custom provider class instance.
+ */
+ self::$provider = apply_filters( 'pods_component_maps_provider_' . $provider, self::$options['provider'] );
+ break;
+ }
+
+ }
+
+ /**
+ * Ajax handler for geocode calls
+ *
+ * AJAX call data setup:
+ * action => pods_maps
+ * _pods_maps_nonce => PodsMaps._nonce
+ * pods_maps_action => 'string' (the maps action)
+ * pods_maps_data => 'string|array' (the provided data)
+ */
+ public function ajax_handler() {
+
+ if ( ! defined( 'DOING_AJAX' ) || ! DOING_AJAX || ! isset( $_POST['_pods_maps_nonce'] ) || ! wp_verify_nonce( $_POST['_pods_maps_nonce'], self::$nonce ) ) {
+ wp_send_json_error( __( 'Cheatin uh?', 'pods' ) );
+ die();
+ }
+
+ if ( isset( $_POST['pods_maps_action'] ) ) {
+ $return = false;
+ $data = '';
+ if ( ! empty( $_POST['pods_maps_data'] ) ) {
+ if ( is_array( $_POST['pods_maps_data'] ) ) {
+ $data = array_map( 'pods_sanitize', $_POST['pods_maps_data'] );
+ } else {
+ $data = pods_sanitize( $_POST['pods_maps_data'] );
+ }
+ }
+ if ( ! empty( $data ) ) {
+ switch ( pods_sanitize( $_POST['pods_maps_action'] ) ) {
+ case 'geocode':
+ case 'geocode_address':
+ $return = self::geocode_address( $data );
+ break;
+ case 'geocode_address_to_latlng':
+ $return = self::geocode_address_to_latlng( $data );
+ break;
+ case 'geocode_latlng_to_address':
+ $return = self::geocode_latlng_to_address( $data );
+ break;
+ }
+ }
+ if ( ! empty( $return ) ) {
+ wp_send_json_success( $return );
+ } else {
+ wp_send_json_error( __( 'Geocode error, please try again or type different address data.', 'pods' ) );
+ }
+ }
+ die();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @since 1.0
+ */
+ public function options( $settings ) {
+
+ $options = array(
+ 'provider' => array(
+ 'label' => __( 'Maps Provider', 'pods' ),
+ 'help' => __( 'help', 'pods' ),
+ 'default' => 'google',
+ 'type' => 'pick',
+ 'data' => apply_filters( 'pods_component_maps_providers', array(
+ 'google' => __( 'Google Maps', 'pods' ),
+ //'bing' => __( 'Bing Maps', 'pods' ),
+ //'openstreetmap' => __( 'OpenStreetMap', 'pods' ),
+ ) ),
+ 'dependency' => true
+ ),
+ );
+
+ if ( is_callable( array( self::$provider, 'options' ) ) ) {
+ $options = self::$provider->options( $options );
+ }
+
+ return $options;
+
+ }
+
+ /**
+ * Add map field options
+ *
+ * @param array $options
+ * @param string $type The field type
+ *
+ * @return array
+ *
+ * @since 2.x
+ */
+ public function field_options( $options, $type ) {
+
+ // Add lat/lng input type
+ $options[ $type . '_type' ]['data']['lat-lng'] = __( 'Latitude / Longitude', 'pods' );
+
+ // Add Map display types
+ //$options[ $type . '_display_type' ]['data']['map'] = __( 'Map', 'pods' );
+ //$options[ $type . '_display_type' ]['data']['default-map'] = __( 'Default and map', 'pods' );
+ //$options[ $type . '_display_type' ]['data']['custom-map'] = __( 'Custom and map', 'pods' );
+
+ // Add extra options
+
+ $options['maps'] = array(
+ 'label' => __( 'Display a map', 'pods' ),
+ 'default' => 0,
+ 'type' => 'boolean',
+ 'dependency' => true
+ );
+ $options['maps_autocorrect'] = array(
+ 'label' => __( 'Autocorrect Address during save', 'pods' ),
+ 'depends-on' => array(
+ 'maps' => true,
+ $type . '_type' => array( 'address', 'text' )
+ ),
+ 'default' => 0,
+ 'type' => 'boolean'
+ );
+ $options['maps_display'] = array(
+ 'label' => __( 'Map Display', 'pods' ),
+ 'depends-on' => array( 'maps' => true ),
+ 'default' => 'replace',
+ 'type' => 'pick',
+ 'data' => array(
+ 'replace' => __( 'Replace default display', 'pods' ),
+ 'before' => __( 'Before default display', 'pods' ),
+ 'after' => __( 'After default display', 'pods' ),
+ 'admin' => __( 'Admin only', 'pods' ),
+ )
+ );
+
+ if ( is_callable( array( self::$provider, 'field_options' ) ) ) {
+ $options = self::$provider->field_options( $options, $type );
+ }
+
+ // Add option dependencies
+ /*if ( empty( $options[ $type . '_display_type_custom' ]['depends-on'][ $type . '_display_type' ] ) ) {
+ $options[ $type . '_display_type_custom' ]['depends-on'][ $type . '_display_type' ] = array( 'custom-map' );
+ } else {
+ $options[ $type . '_display_type_custom' ]['depends-on'][ $type . '_display_type' ] = $this->append_dependency(
+ $options[ $type . '_display_type_custom' ]['depends-on'][ $type . '_display_type' ],
+ 'custom-map'
+ );
+ }*/
+
+ //$options['maps_microdata']['excludes-on']['maps'] = true;
+
+ return $options;
+ }
+
+ /**
+ * Get titles of all Pods Templates
+ *
+ * @return string[] Array of template names
+ *
+ * @since 2.x
+ */
+ public static function get_template_titles() {
+
+ static $template_titles;
+
+ if ( empty( $template_titles ) ) {
+ $all_templates = (array) pods_api()->load_templates( array() );
+
+ $template_titles = array();
+ foreach ( $all_templates as $template ) {
+ $template_titles[ $template['id'] ] = $template['name'];
+ }
+ }
+
+ return $template_titles;
+
+ }
+
+ /**
+ * Add/Change the display value
+ *
+ * @param $value
+ * @param $view
+ * @param $display_type
+ * @param $value
+ * @param $name
+ * @param $options
+ * @param $pod
+ * @param $id
+ *
+ * @return string
+ */
+ public function pods_ui_field_address_display_value( $output, $value, $view, $display_type, $name, $options, $pod, $id ) {
+
+ if ( pods_v( 'maps', $options ) && 'admin' !== pods_v( 'maps_display', $options ) ) {
+ $view = '';
+ $provider = get_class( self::$provider );
+
+ if ( is_callable( array( $provider, 'field_display_view' ) ) ) {
+ $view = self::$provider->field_display_view();
+ }
+
+ if ( $view && file_exists( $view ) ) {
+ // Add hidden lat/lng fields for non latlng view types
+ $maps_value = pods_view( $view, compact( array_keys( get_defined_vars() ) ), false, 'cache', true );
+
+ $maps_display = pods_v( 'maps_display', $options, 'replace', true );
+
+ if ( 'before' === $maps_display ) {
+ $output = $maps_value . $output;
+ } elseif ( 'after' === $maps_display ) {
+ $output .= $maps_value;
+ } else {
+ $output = $maps_value;
+ }
+ }
+ }
+
+ return $output;
+
+ }
+
+ /**
+ * Allow Map providers to add a map to the field input field
+ *
+ * @param $view
+ * @param $type
+ * @param $name
+ * @param $value
+ * @param $options
+ * @param $pod
+ * @param $id
+ */
+ public function pods_ui_field_address_input_view_extra( $view, $type, $name, $value, $options, $pod, $id ) {
+
+ if ( pods_v( 'maps', $options ) ) {
+ $provider = get_class( self::$provider );
+ if ( is_callable( array( $provider, 'field_input_view' ) ) ) {
+ $view = self::$provider->field_input_view();
+ }
+
+ if ( $view && file_exists( $view ) ) {
+ // Add hidden lat/lng fields for non latlng view types
+ pods_view( $view, compact( array_keys( get_defined_vars() ) ) );
+ if ( $type != 'lat-lng' ) {
+ echo '
{{line_1}}
, {{line_2}}
, {{postal_code}}
, {{city}}
, {{region}}
, {{country}}
' );
+ }
+ echo PodsForm::field( $name . '[info_window]', pods_v( 'info_window', $value ), $options['maps_info_window_content'], array(
+ 'settings' => array(
+ 'wpautop' => false,
+ 'editor_height' => 150
+ )
+ ) );
+}
+
+echo PodsForm::label( 'map-google', __( 'Google Maps', 'pod' ) );
+?>
+
+
+
+
diff --git a/components/Maps/ui/front/map-google.php b/components/Maps/ui/front/map-google.php
new file mode 100644
index 0000000000..bd4296f97b
--- /dev/null
+++ b/components/Maps/ui/front/map-google.php
@@ -0,0 +1,273 @@
+ $val ) {
+
+ $val = wp_parse_args( $val, array(
+ 'address' => array(),
+ 'geo' => array(),
+ 'address_html' => '',
+ 'info_window' => '', // Format.
+ 'marker_icon' => null,
+ ) );
+
+ // Allow custom overwrites.
+ if ( 'custom' === pods_v( 'maps_info_window_content', $options, true ) ) {
+ $address_html = '';
+ if ( ! empty( $val['address_html'] ) ) {
+ $address_html = $val['address_html'];
+ } elseif ( ! empty( $val['info_window'] ) ) {
+ $address_html = $val['info_window'];
+ }
+ }
+
+ // Parse format.
+ elseif ( ! isset( $address_html ) || $multiple ) {
+ // @todo Check field type
+ if ( ! empty( $val['info_window'] ) ) {
+ $format = $val['info_window'];
+
+ } elseif ( pods_components()->is_component_active( 'templates' ) &&
+ 'template' === pods_v( 'maps_info_window_content', $options ) &&
+ isset( $val['pod'] ) && $val['pod'] instanceof Pods
+ ) {
+ $template = get_post( pods_v( 'maps_info_window_template', $options ) );
+ if ( $template instanceof WP_Post ) {
+ $format = $val['pod']->template( $template->post_title );
+ echo $format;
+ }
+
+ } else {
+ $format = PodsForm::field_method( 'address', 'default_display_format' );
+ if ( 'custom' === pods_v( 'address_display_type', $options ) ) {
+ $format = pods_v( 'address_display_type_custom', $options );
+ }
+ }
+ $address_html = PodsForm::field_method( 'address', 'format_to_html', $format, $val, $options );
+ }
+
+ unset( $value[ $key ]['info_window'] );
+ $value[ $key ]['address_html'] = $address_html;
+
+ if ( is_numeric( $val['marker_icon'] ) ) {
+ $value[ $key ]['marker_icon'] = wp_get_attachment_image_url( $val['marker_icon'], 'full' );
+ }
+
+ if ( is_array( $val['geo'] ) ) {
+ $value[ $key ]['geo'] = array_map( 'floatval', $val['geo'] );
+ }
+
+ unset( $value[ $key ]['pod'] );
+}
+
+if ( ! empty( $options['maps_combine_equal_geo'] ) ) {
+
+ // User array keys to match locations.
+ $combined_values = array();
+ foreach ( $value as $key => $val ) {
+ $geo_key = implode( ',', $val['geo'] );
+ if ( array_key_exists( $geo_key, $combined_values ) ) {
+ $combined_values[ $geo_key ]['address_html'] .= $val['address_html'];
+ continue;
+ }
+ $combined_values[ $geo_key ] = $val;
+ }
+
+ // Reset array keys.
+ $value = array();
+ foreach ( $combined_values as $val ) {
+ $value[] = $val;
+ }
+}
+?>
+
+
+
diff --git a/components/Maps/ui/js/pods-maps-google.js b/components/Maps/ui/js/pods-maps-google.js
new file mode 100644
index 0000000000..560811273b
--- /dev/null
+++ b/components/Maps/ui/js/pods-maps-google.js
@@ -0,0 +1,11 @@
+
+
+if ( typeof PodsMapsGoogle == 'undefined' ) {
+ var PodsMapsGoogle = {};
+}
+
+(function ( $ ) {
+
+
+
+})( jQuery );
\ No newline at end of file
diff --git a/components/Maps/ui/js/pods-maps.js b/components/Maps/ui/js/pods-maps.js
new file mode 100644
index 0000000000..ba17b885a6
--- /dev/null
+++ b/components/Maps/ui/js/pods-maps.js
@@ -0,0 +1,77 @@
+
+if ( typeof PodsMaps == 'undefined' ) {
+ var PodsMaps = {};
+}
+
+(function ( $ ) {
+
+ // @todo PodsMaps is probably not needed anymore
+
+ PodsMaps.ajaxData = {};
+ PodsMaps.doingAjax = false;
+ PodsMaps.ajaxResults = false;
+
+ PodsMaps.mergeAddressFromInputs = function( fields ) {
+ var address = [];
+ if ( fields.line_1.length ) { address.push( fields.line_1.val() ); }
+ if ( fields.line_2.length ) { address.push( fields.line_2.val() ); }
+ if ( fields.city.length ) { address.push( fields.city.val() ); }
+ if ( fields.postal_code.length ) { address.push( fields.postal_code.val() ); }
+ if ( fields.region.length ) { address.push( fields.region.val() ); }
+ if ( fields.country.length ) { address.push( fields.country.val() ); }
+ return address.join(', ');
+ };
+
+ PodsMaps.geocode = function( data ) {
+ PodsMaps.ajaxData.pods_maps_action = 'geocode';
+ PodsMaps.ajaxData.pods_maps_data = data;
+ return PodsMaps.doAjaxPost();
+ };
+
+ PodsMaps.geocodeAddressToLatLng = function( data ) {
+ PodsMaps.ajaxData.pods_maps_action = 'geocode_address_to_latlng';
+ PodsMaps.ajaxData.pods_maps_data = data;
+ return PodsMaps.doAjaxPost();
+ };
+
+ PodsMaps.geocodeLatLngToAddress = function( data ) {
+ PodsMaps.ajaxData.pods_maps_action = 'geocode_latlng_to_address';
+ PodsMaps.ajaxData.pods_maps_data = data;
+ return PodsMaps.doAjaxPost();
+ };
+
+ PodsMaps.doAjaxPost = function() {
+ PodsMaps.ajaxData.action = 'pods_maps';
+ PodsMaps.ajaxData._pods_maps_nonce = PodsMaps._nonce;
+ PodsMaps.doingAjax = true;
+ PodsMaps.ajaxResults = false;
+ $.post(
+ PodsMaps.ajaxurl,
+ PodsMaps.ajaxData,
+ function( response ) {
+ PodsMaps.ajaxData = {};
+ PodsMaps.doingAjax = false;
+ if ( typeof response.data != 'undefined' ) {
+ PodsMaps.ajaxResults = response.data;
+ $(document).trigger('PodsMapsAjaxDone');
+ return response.data;
+ }
+ return false;
+ }
+ );
+ };
+
+ var methods = {};
+
+ $.fn.PodsMap = function ( method ) {
+
+ if ( methods [method] ) {
+ return methods[method].apply( this, Array.prototype.slice.call( arguments, 1 ) );
+ }
+ else {
+ $.error( 'Method ' + method );
+ }
+
+ };
+
+})( jQuery );
\ No newline at end of file
diff --git a/ui/css/pods-address-maps.css b/ui/css/pods-address-maps.css
new file mode 100644
index 0000000000..bb38c9d26d
--- /dev/null
+++ b/ui/css/pods-address-maps.css
@@ -0,0 +1,5 @@
+.pods-address-maps-map-canvas {
+ margin-top: 10px;
+ height: 300px;
+ width: 95%;
+}
\ No newline at end of file
diff --git a/ui/fields/address.php b/ui/fields/address.php
new file mode 100644
index 0000000000..6a942d2bec
--- /dev/null
+++ b/ui/fields/address.php
@@ -0,0 +1,63 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 'us_state' ) ) ?>
+
+
+
+
+
+
+
+
+
+ 'country' ) ) ?>
+
+
+
+
+
+
+
+
+
+
+