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 ) . ''; + } + + 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 '
'; + pods_view( plugin_dir_path( __FILE__ ) . 'ui/fields/lat-lng.php', compact( array_keys( get_defined_vars() ) ) ); + echo '
'; + } + } + + } + + } + + /** + * Validate current value + * + * @param $errors + * @param $value + * @param $type + * @param $name + * @param $options + * @param $fields + * @param $pod + * @param $id + * @param $params + * + * @return array + */ + public function pods_ui_field_address_validate( $errors, $value, $type, $name, $options, $fields, $pod, $id, $params ) { + + // @todo: Validate based on address type ( lat / lon, address fields) + + if ( ! $value ) { + return $errors; + } + + // Get geocode from address fields + if ( isset( $value['address'] ) ) { + // @todo: What to do if Google doesn't respond? + $geocode = self::geocode_address_to_latlng( $value['address'] ); + if ( empty( $geocode['lat'] ) && empty( $geocode['lng'] ) ) { + $errors[] = __( 'Could not find geodata for this address', 'pods' ); + } + } + + return $errors; + + } + + /** + * Save Additional geo data dependent on the field type + * + * @param $value + * @param $type + * @param $id + * @param $name + * @param $options + * @param $fields + * @param $pod + * @param $params + * + * @return mixed + */ + public function pods_ui_field_address_pre_save( $value, $type, $id, $name, $options, $fields, $pod, $params ) { + + $org_value = $value; + + // Get geocode from address fields + if ( isset( $value['address'] ) ) { + $geocode = array(); + if ( pods_v( 'maps_autocorrect', $options, 0 ) ) { + $address = self::geocode_address( $value['address'] ); + if ( ! empty( $address['address'] ) ) { + $value['address'] = $address['address']; + } + if ( ! empty( $address['geo'] ) ) { + $geocode = $address['geo']; + } + } else { + $geocode = self::geocode_address_to_latlng( $value['address'] ); + } + if ( isset( $geocode['lat'] ) && isset( $geocode['lng'] ) ) { + $value['geo'] = $geocode; + } + } + + $value = apply_filters( 'pods_ui_field_address_maps_pre_save', $value, $org_value, $type, $id, $name, $options, $fields, $pod, $params ); + + return $value; + + } + + /** + * @param string|array $data + * + * @return mixed + */ + public static function geocode_address( $data ) { + + if ( is_object( self::$provider ) ) { + $provider = get_class( self::$provider ); + if ( method_exists( $provider, 'geocode_address' ) ) { + return $provider::geocode_address( $data, self::$api_key ); + } + } + + return false; + } + + /** + * @param string|array $data + * + * @return mixed + */ + public static function geocode_address_to_latlng( $data ) { + + if ( is_object( self::$provider ) ) { + $provider = get_class( self::$provider ); + if ( method_exists( $provider, 'geocode_address_to_latlng' ) ) { + return $provider::geocode_address_to_latlng( $data, self::$api_key ); + } + } + + return false; + } + + /** + * @param string|array $data + * + * @return mixed + */ + public static function geocode_latlng_to_address( $data ) { + + if ( is_object( self::$provider ) ) { + $provider = get_class( self::$provider ); + if ( method_exists( $provider, 'geocode_latlng_to_address' ) ) { + return $provider::geocode_latlng_to_address( $data, self::$api_key ); + } + } + + return false; + } + + /** + * Append new dependency to existing data + * + * @param $value + * @param $new + * + * @return array + */ + public function append_dependency( $value, $new ) { + + if ( ! is_array( $value ) ) { + $value = array( + (string) $value, + $new + ); + } else { + $value[] = $new; + } + + return $value; + } + +} \ No newline at end of file diff --git a/components/Maps/ui/css/pods-maps.css b/components/Maps/ui/css/pods-maps.css new file mode 100644 index 0000000000..5ff299537f --- /dev/null +++ b/components/Maps/ui/css/pods-maps.css @@ -0,0 +1,21 @@ + +.pods-form-ui-row-type-address .pods-submittable-fields * + label { padding-top: 6px; } + +.pods-form-ui-row-type-address label + p.description { margin-bottom: 8px; } + +/*.pods-form-ui-row-type-address .pods-form-ui-field-type-wysiwyg { + width: 95%; +}*/ + +/* Admin */ +.pods-maps-map-canvas { + margin-top: 10px; + height: 300px; + /*width: 95%;*/ +} + +/* Front */ +.pods-address-maps-map-canvas { + min-height: 250px; + width: 100%; +} \ No newline at end of file diff --git a/components/Maps/ui/fields/lat-lng.php b/components/Maps/ui/fields/lat-lng.php new file mode 100644 index 0000000000..916e68d3e9 --- /dev/null +++ b/components/Maps/ui/fields/lat-lng.php @@ -0,0 +1,17 @@ + + + 10, 'number_format' => '9999.99' ) ) ?> + + + 10, 'number_format' => '9999.99' ) ) ?> +{{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' ) ) ?> + + + + + + + + + + +