Meta Box - Version 4.15.0

Version Description

Download this release

Release Info

Developer rilwis
Plugin Icon 128x128 Meta Box
Version 4.15.0
Comparing to
See all releases

Code changes from version 4.14.11 to 4.15.0

css/osm.css ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
1
+ .rwmb-osm-canvas {
2
+ width: 100%;
3
+ height: 400px;
4
+ margin-bottom: 10px;
5
+ }
inc/about/about.php CHANGED
@@ -165,7 +165,7 @@ class RWMB_About {
165
  * or just the current site. Multisite only. Default is false.
166
  */
167
  public function redirect( $plugin, $network_wide ) {
168
- if ( ! $network_wide && 'meta-box/meta-box.php' === $plugin && ! $this->is_bundled() ) {
169
  wp_safe_redirect( $this->get_menu_link() );
170
  die;
171
  }
165
  * or just the current site. Multisite only. Default is false.
166
  */
167
  public function redirect( $plugin, $network_wide ) {
168
+ if ( 'cli' !== php_sapi_name() && ! $network_wide && 'meta-box/meta-box.php' === $plugin && ! $this->is_bundled() ) {
169
  wp_safe_redirect( $this->get_menu_link() );
170
  die;
171
  }
inc/field.php CHANGED
@@ -290,7 +290,7 @@ abstract class RWMB_Field {
290
  * @param array $field The field parameters.
291
  */
292
  public static function save( $new, $old, $post_id, $field ) {
293
- if ( empty( $field['id'] ) ) {
294
  return;
295
  }
296
  $name = $field['id'];
@@ -388,6 +388,7 @@ abstract class RWMB_Field {
388
  'after' => '',
389
  'field_name' => isset( $field['id'] ) ? $field['id'] : '',
390
  'placeholder' => '',
 
391
 
392
  'clone' => false,
393
  'max_clone' => 0,
290
  * @param array $field The field parameters.
291
  */
292
  public static function save( $new, $old, $post_id, $field ) {
293
+ if ( empty( $field['id'] ) || ! $field['save_field'] ) {
294
  return;
295
  }
296
  $name = $field['id'];
388
  'after' => '',
389
  'field_name' => isset( $field['id'] ) ? $field['id'] : '',
390
  'placeholder' => '',
391
+ 'save_field' => true,
392
 
393
  'clone' => false,
394
  'max_clone' => 0,
inc/fields/button-group.php CHANGED
@@ -18,22 +18,20 @@ class RWMB_Button_Group_Field extends RWMB_Choice_Field {
18
  }
19
 
20
  /**
21
- * Walk options.
22
- *
23
- * @param array $field Field parameters.
24
- * @param mixed $options Select options.
25
- * @param mixed $db_fields Database fields to use in the output.
26
- * @param mixed $meta Meta value.
27
  *
 
 
28
  * @return string
29
  */
30
- public static function walk( $field, $options, $db_fields, $meta ) {
31
- $walker = new RWMB_Walker_Input_List( $db_fields, $field, $meta );
 
32
 
33
  $output = sprintf( '<ul class="rwmb-button-input-list %s">',
34
  $field['inline'] ? 'inline' : ''
35
  );
36
- $output .= $walker->walk( $options, - 1 );
37
  $output .= '</ul>';
38
 
39
  return $output;
18
  }
19
 
20
  /**
21
+ * Get field HTML.
 
 
 
 
 
22
  *
23
+ * @param mixed $meta Meta value.
24
+ * @param array $field Field parameters.
25
  * @return string
26
  */
27
+ public static function html( $meta, $field ) {
28
+ $options = self::transform_options( $field['options'] );
29
+ $walker = new RWMB_Walker_Input_List( $field, $meta );
30
 
31
  $output = sprintf( '<ul class="rwmb-button-input-list %s">',
32
  $field['inline'] ? 'inline' : ''
33
  );
34
+ $output .= $walker->walk( $options, -1 );
35
  $output .= '</ul>';
36
 
37
  return $output;
inc/fields/choice.php CHANGED
@@ -9,19 +9,6 @@
9
  * Abstract class for any kind of choice field.
10
  */
11
  abstract class RWMB_Choice_Field extends RWMB_Field {
12
- /**
13
- * Walk options.
14
- *
15
- * @param array $field Field parameters.
16
- * @param mixed $options Select options.
17
- * @param mixed $db_fields Database fields to use in the output.
18
- * @param mixed $meta Meta value.
19
- * @return string
20
- */
21
- public static function walk( $field, $options, $db_fields, $meta ) {
22
- return '';
23
- }
24
-
25
  /**
26
  * Get field HTML.
27
  *
@@ -30,11 +17,7 @@ abstract class RWMB_Choice_Field extends RWMB_Field {
30
  * @return string
31
  */
32
  public static function html( $meta, $field ) {
33
- $meta = (array) $meta;
34
- $options = self::call( 'get_options', $field );
35
- $options = self::call( 'filter_options', $field, $options );
36
- $db_fields = self::call( 'get_db_fields', $field );
37
- return ! empty( $options ) ? self::call( 'walk', $field, $options, $db_fields, $meta ) : null;
38
  }
39
 
40
  /**
@@ -54,55 +37,25 @@ abstract class RWMB_Choice_Field extends RWMB_Field {
54
  }
55
 
56
  /**
57
- * Get field names of object to be used by walker.
58
  *
59
- * @return array
60
- */
61
- public static function get_db_fields() {
62
- return array(
63
- 'parent' => 'parent',
64
- 'id' => 'value',
65
- 'label' => 'label',
66
- );
67
- }
68
-
69
- /**
70
- * Get options for walker.
71
- *
72
- * @param array $field Field parameters.
73
  *
74
  * @return array
75
  */
76
- public static function get_options( $field ) {
77
- $options = array();
78
- foreach ( (array) $field['options'] as $value => $label ) {
 
79
  $option = is_array( $label ) ? $label : array(
80
  'label' => (string) $label,
81
  'value' => (string) $value,
82
  );
83
  if ( isset( $option['label'] ) && isset( $option['value'] ) ) {
84
- $options[ $option['value'] ] = (object) $option;
85
  }
86
  }
87
- return $options;
88
- }
89
-
90
- /**
91
- * Filter options for walker.
92
- *
93
- * @param array $field Field parameters.
94
- * @param array $options Array of choice options.
95
- *
96
- * @return array
97
- */
98
- public static function filter_options( $field, $options ) {
99
- $db_fields = self::call( 'get_db_fields', $field );
100
- $label = $db_fields['label'];
101
- foreach ( $options as &$option ) {
102
- $option = apply_filters( 'rwmb_option', $option, $field );
103
- $option->$label = apply_filters( 'rwmb_option_label', $option->$label, $option, $field );
104
- }
105
- return $options;
106
  }
107
 
108
  /**
@@ -116,19 +69,7 @@ abstract class RWMB_Choice_Field extends RWMB_Field {
116
  * @return string
117
  */
118
  public static function format_single_value( $field, $value, $args, $post_id ) {
119
- return self::call( 'get_option_label', $field, $value );
120
- }
121
-
122
- /**
123
- * Get option label.
124
- *
125
- * @param array $field Field parameters.
126
- * @param string $value Option value.
127
- *
128
- * @return string
129
- */
130
- public static function get_option_label( $field, $value ) {
131
- $options = self::call( 'get_options', $field );
132
  return isset( $options[ $value ] ) ? $options[ $value ]->label : '';
133
  }
134
  }
9
  * Abstract class for any kind of choice field.
10
  */
11
  abstract class RWMB_Choice_Field extends RWMB_Field {
 
 
 
 
 
 
 
 
 
 
 
 
 
12
  /**
13
  * Get field HTML.
14
  *
17
  * @return string
18
  */
19
  public static function html( $meta, $field ) {
20
+ return '';
 
 
 
 
21
  }
22
 
23
  /**
37
  }
38
 
39
  /**
40
+ * Transform field options into the verbose format.
41
  *
42
+ * @param array $options Field options.
 
 
 
 
 
 
 
 
 
 
 
 
 
43
  *
44
  * @return array
45
  */
46
+ public static function transform_options( $options ) {
47
+ $transformed = array();
48
+ $options = (array) $options;
49
+ foreach ( $options as $value => $label ) {
50
  $option = is_array( $label ) ? $label : array(
51
  'label' => (string) $label,
52
  'value' => (string) $value,
53
  );
54
  if ( isset( $option['label'] ) && isset( $option['value'] ) ) {
55
+ $transformed[ $option['value'] ] = (object) $option;
56
  }
57
  }
58
+ return $transformed;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
59
  }
60
 
61
  /**
69
  * @return string
70
  */
71
  public static function format_single_value( $field, $value, $args, $post_id ) {
72
+ $options = self::transform_options( $field['options'] );
 
 
 
 
 
 
 
 
 
 
 
 
73
  return isset( $options[ $value ] ) ? $options[ $value ]->label : '';
74
  }
75
  }
inc/fields/datetime.php CHANGED
@@ -252,7 +252,7 @@ class RWMB_Datetime_Field extends RWMB_Text_Field {
252
  * @return string
253
  */
254
  public static function format_single_value( $field, $value, $args, $post_id ) {
255
- if ( ! isset( $args['format'] ) ) {
256
  return $value;
257
  }
258
  if ( ! $field['timestamp'] ) {
252
  * @return string
253
  */
254
  public static function format_single_value( $field, $value, $args, $post_id ) {
255
+ if ( empty( $args['format'] ) ) {
256
  return $value;
257
  }
258
  if ( ! $field['timestamp'] ) {
inc/fields/input-list.php CHANGED
@@ -18,23 +18,21 @@ class RWMB_Input_List_Field extends RWMB_Choice_Field {
18
  }
19
 
20
  /**
21
- * Walk options.
22
- *
23
- * @param array $field Field parameters.
24
- * @param mixed $options Select options.
25
- * @param mixed $db_fields Database fields to use in the output.
26
- * @param mixed $meta Meta value.
27
  *
 
 
28
  * @return string
29
  */
30
- public static function walk( $field, $options, $db_fields, $meta ) {
31
- $walker = new RWMB_Walker_Input_List( $db_fields, $field, $meta );
 
32
  $output = self::get_select_all_html( $field );
33
  $output .= sprintf( '<ul class="rwmb-input-list %s %s">',
34
  $field['collapse'] ? 'collapse' : '',
35
  $field['inline'] ? 'inline' : ''
36
  );
37
- $output .= $walker->walk( $options, $field['flatten'] ? - 1 : 0 );
38
  $output .= '</ul>';
39
 
40
  return $output;
18
  }
19
 
20
  /**
21
+ * Get field HTML.
 
 
 
 
 
22
  *
23
+ * @param mixed $meta Meta value.
24
+ * @param array $field Field parameters.
25
  * @return string
26
  */
27
+ public static function html( $meta, $field ) {
28
+ $options = self::transform_options( $field['options'] );
29
+ $walker = new RWMB_Walker_Input_List( $field, $meta );
30
  $output = self::get_select_all_html( $field );
31
  $output .= sprintf( '<ul class="rwmb-input-list %s %s">',
32
  $field['collapse'] ? 'collapse' : '',
33
  $field['inline'] ? 'inline' : ''
34
  );
35
+ $output .= $walker->walk( $options, $field['flatten'] ? -1 : 0 );
36
  $output .= '</ul>';
37
 
38
  return $output;
inc/fields/map.php CHANGED
@@ -42,6 +42,9 @@ class RWMB_Map_Field extends RWMB_Field {
42
  'jquery-ui-autocomplete',
43
  'google-maps',
44
  ), RWMB_VER, true );
 
 
 
45
  }
46
 
47
  /**
42
  'jquery-ui-autocomplete',
43
  'google-maps',
44
  ), RWMB_VER, true );
45
+ self::localize_script( 'rwmb-map', 'RWMB_Map', array(
46
+ 'no_results_string' => __( 'No results found', 'meta-box' ),
47
+ ) );
48
  }
49
 
50
  /**
inc/fields/media.php CHANGED
@@ -163,6 +163,9 @@ class RWMB_Media_Field extends RWMB_File_Field {
163
  * @param array $field The field parameters.
164
  */
165
  public static function save( $new, $old, $post_id, $field ) {
 
 
 
166
  $storage = $field['storage'];
167
  $storage->delete( $post_id, $field['id'] );
168
  parent::save( $new, array(), $post_id, $field );
163
  * @param array $field The field parameters.
164
  */
165
  public static function save( $new, $old, $post_id, $field ) {
166
+ if ( empty( $field['id'] ) || ! $field['save_field'] ) {
167
+ return;
168
+ }
169
  $storage = $field['storage'];
170
  $storage->delete( $post_id, $field['id'] );
171
  parent::save( $new, array(), $post_id, $field );
inc/fields/object-choice.php CHANGED
@@ -10,16 +10,26 @@
10
  */
11
  abstract class RWMB_Object_Choice_Field extends RWMB_Choice_Field {
12
  /**
13
- * Get field HTML
14
  *
15
- * @param array $field Field parameters.
16
- * @param mixed $options Select options.
17
- * @param mixed $db_fields Database fields to use in the output.
18
- * @param mixed $meta Meta value.
 
 
 
 
 
 
 
 
 
 
19
  * @return string
20
  */
21
- public static function walk( $field, $options, $db_fields, $meta ) {
22
- return call_user_func( array( self::get_type_class( $field ), 'walk' ), $field, $options, $db_fields, $meta );
23
  }
24
 
25
  /**
@@ -68,19 +78,6 @@ abstract class RWMB_Object_Choice_Field extends RWMB_Choice_Field {
68
  return $attributes;
69
  }
70
 
71
- /**
72
- * Get field names of object to be used by walker.
73
- *
74
- * @return array
75
- */
76
- public static function get_db_fields() {
77
- return array(
78
- 'parent' => '',
79
- 'id' => '',
80
- 'label' => '',
81
- );
82
- }
83
-
84
  /**
85
  * Enqueue scripts and styles.
86
  */
10
  */
11
  abstract class RWMB_Object_Choice_Field extends RWMB_Choice_Field {
12
  /**
13
+ * Get field HTML.
14
  *
15
+ * @param mixed $meta Meta value.
16
+ * @param array $field Field parameters.
17
+ * @return string
18
+ */
19
+ public static function html( $meta, $field ) {
20
+ $html = call_user_func( array( self::get_type_class( $field ), 'html' ), $meta, $field );
21
+ $html .= self::call( 'add_new_form', $field );
22
+ return $html;
23
+ }
24
+
25
+ /**
26
+ * Render "Add New" form
27
+ *
28
+ * @param array $field Field settings.
29
  * @return string
30
  */
31
+ public static function add_new_form( $field ) {
32
+ return '';
33
  }
34
 
35
  /**
78
  return $attributes;
79
  }
80
 
 
 
 
 
 
 
 
 
 
 
 
 
 
81
  /**
82
  * Enqueue scripts and styles.
83
  */
inc/fields/oembed.php CHANGED
@@ -9,6 +9,25 @@
9
  * OEmbed field class.
10
  */
11
  class RWMB_OEmbed_Field extends RWMB_Text_Field {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
  /**
13
  * Enqueue scripts and styles.
14
  */
@@ -29,16 +48,18 @@ class RWMB_OEmbed_Field extends RWMB_Text_Field {
29
  */
30
  public static function wp_ajax_get_embed() {
31
  $url = (string) filter_input( INPUT_POST, 'url', FILTER_SANITIZE_URL );
32
- wp_send_json_success( self::get_embed( $url ) );
 
33
  }
34
 
35
  /**
36
  * Get embed html from url.
37
  *
38
- * @param string $url URL.
 
39
  * @return string
40
  */
41
- public static function get_embed( $url ) {
42
  /**
43
  * Set arguments for getting embeded HTML.
44
  * Without arguments, default width will be taken from global $content_width, which can break UI in the admin.
@@ -58,10 +79,19 @@ class RWMB_OEmbed_Field extends RWMB_Text_Field {
58
 
59
  // If no oembed provides found, try WordPress auto embed.
60
  if ( ! $embed ) {
61
- $embed = $GLOBALS['wp_embed']->shortcode( $args, $url );
 
 
 
 
 
 
 
 
62
  }
 
63
 
64
- return $embed ? $embed : __( 'Embed HTML not available.', 'meta-box' );
65
  }
66
 
67
  /**
@@ -75,7 +105,7 @@ class RWMB_OEmbed_Field extends RWMB_Text_Field {
75
  return parent::html( $meta, $field ) . sprintf(
76
  '<span class="spinner"></span>
77
  <div class="rwmb-embed-media">%s</div>',
78
- $meta ? self::get_embed( $meta ) : ''
79
  );
80
  }
81
 
@@ -104,6 +134,6 @@ class RWMB_OEmbed_Field extends RWMB_Text_Field {
104
  * @return string
105
  */
106
  public static function format_single_value( $field, $value, $args, $post_id ) {
107
- return self::get_embed( $value );
108
  }
109
  }
9
  * OEmbed field class.
10
  */
11
  class RWMB_OEmbed_Field extends RWMB_Text_Field {
12
+ /**
13
+ * Normalize parameters for field.
14
+ *
15
+ * @param array $field Field parameters.
16
+ * @return array
17
+ */
18
+ public static function normalize( $field ) {
19
+ $field = parent::normalize( $field );
20
+
21
+ $field = wp_parse_args( $field, array(
22
+ 'not_available_string' => __( 'Embed HTML not available.', 'meta-box' ),
23
+ ) );
24
+ $field['attributes'] = wp_parse_args( $field['attributes'], array(
25
+ 'data-not-available' => $field['not_available_string'],
26
+ ) );
27
+
28
+ return $field;
29
+ }
30
+
31
  /**
32
  * Enqueue scripts and styles.
33
  */
48
  */
49
  public static function wp_ajax_get_embed() {
50
  $url = (string) filter_input( INPUT_POST, 'url', FILTER_SANITIZE_URL );
51
+ $not_available = (string) filter_input( INPUT_POST, 'not_available' );
52
+ wp_send_json_success( self::get_embed( $url, $not_available ) );
53
  }
54
 
55
  /**
56
  * Get embed html from url.
57
  *
58
+ * @param string $url URL.
59
+ * @param string $not_available Not available string displayed to users.
60
  * @return string
61
  */
62
+ public static function get_embed( $url, $not_available = '' ) {
63
  /**
64
  * Set arguments for getting embeded HTML.
65
  * Without arguments, default width will be taken from global $content_width, which can break UI in the admin.
79
 
80
  // If no oembed provides found, try WordPress auto embed.
81
  if ( ! $embed ) {
82
+ global $wp_embed;
83
+ $temp = $wp_embed->return_false_on_fail;
84
+ $wp_embed->return_false_on_fail = true; // Do not fallback to make a link.
85
+ $embed = $wp_embed->shortcode( $args, $url );
86
+ $wp_embed->return_false_on_fail = $temp;
87
+ }
88
+
89
+ if ( $not_available ) {
90
+ $not_available = '<div class="rwmb-oembed-not-available">' . wp_kses_post( $not_available ) . '</div>';
91
  }
92
+ $not_available = apply_filters( 'rwmb_oembed_not_available_string', $not_available );
93
 
94
+ return $embed ?: $not_available;
95
  }
96
 
97
  /**
105
  return parent::html( $meta, $field ) . sprintf(
106
  '<span class="spinner"></span>
107
  <div class="rwmb-embed-media">%s</div>',
108
+ $meta ? self::get_embed( $meta, $field['not_available_string'] ) : ''
109
  );
110
  }
111
 
134
  * @return string
135
  */
136
  public static function format_single_value( $field, $value, $args, $post_id ) {
137
+ return self::get_embed( $value, $field['not_available_string'] );
138
  }
139
  }
inc/fields/osm.php ADDED
@@ -0,0 +1,162 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * The Open Street Map field.
4
+ *
5
+ * @package Meta Box
6
+ * @since 4.15.0
7
+ */
8
+
9
+ /**
10
+ * Open Street Map field class.
11
+ */
12
+ class RWMB_OSM_Field extends RWMB_Field {
13
+ /**
14
+ * Enqueue scripts and styles.
15
+ */
16
+ public static function admin_enqueue_scripts() {
17
+ // Because map is a hosted service, it's ok to use hosted Leaflet scripts.
18
+ wp_enqueue_style( 'leaflet', 'https://unpkg.com/leaflet@1.3.1/dist/leaflet.css', array(), '1.3.1' );
19
+ wp_enqueue_script( 'leaflet', 'https://unpkg.com/leaflet@1.3.1/dist/leaflet.js', array(), '1.3.1', true );
20
+
21
+ wp_enqueue_style( 'rwmb-osm', RWMB_CSS_URL . 'osm.css', array( 'leaflet' ), RWMB_VER );
22
+ wp_enqueue_script( 'rwmb-osm', RWMB_JS_URL . 'osm.js', array( 'jquery', 'leaflet' ), RWMB_VER, true );
23
+ self::localize_script( 'rwmb-osm', 'RWMB_Osm', array(
24
+ 'no_results_string' => __( 'No results found', 'meta-box' ),
25
+ ) );
26
+ }
27
+
28
+ /**
29
+ * Get field HTML.
30
+ *
31
+ * @param mixed $meta Meta value.
32
+ * @param array $field Field parameters.
33
+ *
34
+ * @return string
35
+ */
36
+ public static function html( $meta, $field ) {
37
+ $address = is_array( $field['address_field'] ) ? implode( ',', $field['address_field'] ) : $field['address_field'];
38
+ $html = sprintf(
39
+ '<div class="rwmb-osm-field" data-address-field="%s">',
40
+ esc_attr( $address )
41
+ );
42
+
43
+ $html .= sprintf(
44
+ '<div class="rwmb-osm-canvas" data-default-loc="%s" data-region="%s" data-language="%s"></div>
45
+ <input type="hidden" name="%s" class="rwmb-osm-coordinate" value="%s">',
46
+ esc_attr( $field['std'] ),
47
+ esc_attr( $field['region'] ),
48
+ esc_attr( $field['language'] ),
49
+ esc_attr( $field['field_name'] ),
50
+ esc_attr( $meta )
51
+ );
52
+
53
+ if ( $field['address_field'] ) {
54
+ $html .= sprintf(
55
+ '<button class="button rwmb-osm-goto-address-button">%s</button>',
56
+ esc_html__( 'Find Address', 'meta-box' )
57
+ );
58
+ }
59
+
60
+ $html .= '</div>';
61
+
62
+ return $html;
63
+ }
64
+
65
+ /**
66
+ * Normalize parameters for field.
67
+ *
68
+ * @param array $field Field parameters.
69
+ *
70
+ * @return array
71
+ */
72
+ public static function normalize( $field ) {
73
+ $field = parent::normalize( $field );
74
+ $field = wp_parse_args( $field, array(
75
+ 'std' => '',
76
+ 'address_field' => '',
77
+ 'language' => '',
78
+ 'region' => '',
79
+ ) );
80
+
81
+ return $field;
82
+ }
83
+
84
+ /**
85
+ * Get the field value.
86
+ * The difference between this function and 'meta' function is 'meta' function always returns the escaped value
87
+ * of the field saved in the database, while this function returns more meaningful value of the field.
88
+ *
89
+ * @param array $field Field parameters.
90
+ * @param array $args Not used for this field.
91
+ * @param int|null $post_id Post ID. null for current post. Optional.
92
+ *
93
+ * @return mixed Array(latitude, longitude, zoom)
94
+ */
95
+ public static function get_value( $field, $args = array(), $post_id = null ) {
96
+ $value = parent::get_value( $field, $args, $post_id );
97
+ list( $latitude, $longitude, $zoom ) = explode( ',', $value . ',,' );
98
+ return compact( 'latitude', 'longitude', 'zoom' );
99
+ }
100
+
101
+ /**
102
+ * Output the field value.
103
+ * Display Google maps.
104
+ *
105
+ * @param array $field Field parameters.
106
+ * @param array $args Additional arguments for the map.
107
+ * @param int|null $post_id Post ID. null for current post. Optional.
108
+ *
109
+ * @return string HTML output of the field
110
+ */
111
+ public static function the_value( $field, $args = array(), $post_id = null ) {
112
+ $value = parent::get_value( $field, $args, $post_id );
113
+ return self::render_map( $value, $args );
114
+ }
115
+
116
+ /**
117
+ * Render a map in the frontend.
118
+ *
119
+ * @param array $location The [latitude, longitude[, zoom]] location.
120
+ * @param array $args Additional arguments for the map.
121
+ *
122
+ * @return string
123
+ */
124
+ public static function render_map( $location, $args = array() ) {
125
+ list( $latitude, $longitude, $zoom ) = explode( ',', $location . ',,' );
126
+ if ( ! $latitude || ! $longitude ) {
127
+ return '';
128
+ }
129
+
130
+ $args = wp_parse_args( $args, array(
131
+ 'latitude' => $latitude,
132
+ 'longitude' => $longitude,
133
+ 'width' => '100%',
134
+ 'height' => '480px',
135
+ 'marker' => true, // Display marker?
136
+ 'marker_title' => '', // Marker title, when hover.
137
+ 'info_window' => '', // Content of info window (when click on marker). HTML allowed.
138
+ 'js_options' => array(),
139
+ ) );
140
+
141
+ wp_enqueue_style( 'leaflet', 'https://unpkg.com/leaflet@1.3.1/dist/leaflet.css', array(), '1.3.1' );
142
+ wp_enqueue_script( 'leaflet', 'https://unpkg.com/leaflet@1.3.1/dist/leaflet.js', array(), '1.3.1', true );
143
+ wp_enqueue_script( 'rwmb-osm-frontend', RWMB_JS_URL . 'osm-frontend.js', array( 'jquery', 'leaflet' ), RWMB_VER, true );
144
+
145
+ /*
146
+ * More Open Street Map options
147
+ * @link https://leafletjs.com/reference-1.3.0.html#map-option
148
+ */
149
+ $args['js_options'] = wp_parse_args( $args['js_options'], array(
150
+ // Default to 'zoom' level set in admin, but can be overwritten.
151
+ 'zoom' => $zoom,
152
+ ) );
153
+
154
+ $output = sprintf(
155
+ '<div class="rwmb-osm-canvas" data-osm_options="%s" style="width:%s;height:%s"></div>',
156
+ esc_attr( wp_json_encode( $args ) ),
157
+ esc_attr( $args['width'] ),
158
+ esc_attr( $args['height'] )
159
+ );
160
+ return $output;
161
+ }
162
+ }
inc/fields/post.php CHANGED
@@ -16,10 +16,10 @@ class RWMB_Post_Field extends RWMB_Object_Choice_Field {
16
  * @return array
17
  */
18
  public static function normalize( $field ) {
19
- // Set default field args.
20
  $field = wp_parse_args( $field, array(
21
- 'post_type' => 'post',
22
- 'parent' => false,
 
23
  ) );
24
 
25
  $field['post_type'] = (array) $field['post_type'];
@@ -41,11 +41,9 @@ class RWMB_Post_Field extends RWMB_Object_Choice_Field {
41
  $field = wp_parse_args( $field, array(
42
  'placeholder' => $placeholder,
43
  ) );
44
- $field = parent::normalize( $field );
45
 
46
- if ( ! isset( $field['query_args']['post_type'] ) ) {
47
- $field['query_args']['post_type'] = $field['post_type'];
48
- }
49
 
50
  // Set parent option, which will change field name to `parent_id` to save as post parent.
51
  if ( $field['parent'] ) {
@@ -53,26 +51,36 @@ class RWMB_Post_Field extends RWMB_Object_Choice_Field {
53
  $field['field_name'] = 'parent_id';
54
  }
55
 
56
- // Set default query args.
57
- $field['query_args'] = wp_parse_args( $field['query_args'], array(
58
- 'post_status' => 'publish',
59
- 'posts_per_page' => - 1,
60
- ) );
61
 
62
  return $field;
63
  }
64
 
65
  /**
66
- * Get field names of object to be used by walker.
67
  *
68
- * @return array
 
69
  */
70
- public static function get_db_fields() {
71
- return array(
72
- 'parent' => 'post_parent',
73
- 'id' => 'ID',
74
- 'label' => 'post_title',
75
- );
 
 
 
 
 
 
 
 
 
 
 
 
 
76
  }
77
 
78
  /**
@@ -93,26 +101,17 @@ class RWMB_Post_Field extends RWMB_Object_Choice_Field {
93
  }
94
 
95
  /**
96
- * Get options for walker.
97
- *
98
- * @param array $field Field parameters.
99
- * @return array
100
- */
101
- public static function get_options( $field ) {
102
- $query = new WP_Query( $field['query_args'] );
103
- return $query->have_posts() ? $query->posts : array();
104
- }
105
-
106
- /**
107
- * Get option label.
108
  *
109
- * @param array $field Field parameters.
110
- * @param string $value Option value.
 
 
111
  *
112
  * @return string
113
  */
114
- public static function get_option_label( $field, $value ) {
115
- return sprintf(
116
  '<a href="%s" title="%s">%s</a>',
117
  esc_url( get_permalink( $value ) ),
118
  the_title_attribute( array(
16
  * @return array
17
  */
18
  public static function normalize( $field ) {
 
19
  $field = wp_parse_args( $field, array(
20
+ 'post_type' => 'post',
21
+ 'parent' => false,
22
+ 'query_args' => array(),
23
  ) );
24
 
25
  $field['post_type'] = (array) $field['post_type'];
41
  $field = wp_parse_args( $field, array(
42
  'placeholder' => $placeholder,
43
  ) );
 
44
 
45
+ // Query posts for field options.
46
+ $field['options'] = self::query( $field );
 
47
 
48
  // Set parent option, which will change field name to `parent_id` to save as post parent.
49
  if ( $field['parent'] ) {
51
  $field['field_name'] = 'parent_id';
52
  }
53
 
54
+ $field = parent::normalize( $field );
 
 
 
 
55
 
56
  return $field;
57
  }
58
 
59
  /**
60
+ * Query posts for field options.
61
  *
62
+ * @param array $field Field settings.
63
+ * @return array Field options array.
64
  */
65
+ public static function query( $field ) {
66
+ $args = wp_parse_args( $field['query_args'], array(
67
+ 'post_type' => $field['post_type'],
68
+ 'post_status' => 'publish',
69
+ 'posts_per_page' => -1,
70
+ 'no_found_rows' => true,
71
+ 'update_post_meta_cache' => false,
72
+ 'update_post_term_cache' => false,
73
+ ) );
74
+ $query = new WP_Query( $args );
75
+ $options = array();
76
+ foreach ( $query->posts as $post ) {
77
+ $options[ $post->ID ] = array(
78
+ 'value' => $post->ID,
79
+ 'label' => $post->post_title,
80
+ 'parent' => $post->post_parent,
81
+ );
82
+ }
83
+ return $options;
84
  }
85
 
86
  /**
101
  }
102
 
103
  /**
104
+ * Format a single value for the helper functions. Sub-fields should overwrite this method if necessary.
 
 
 
 
 
 
 
 
 
 
 
105
  *
106
+ * @param array $field Field parameters.
107
+ * @param string $value The value.
108
+ * @param array $args Additional arguments. Rarely used. See specific fields for details.
109
+ * @param int|null $post_id Post ID. null for current post. Optional.
110
  *
111
  * @return string
112
  */
113
+ public static function format_single_value( $field, $value, $args, $post_id ) {
114
+ return ! $value ? '' : sprintf(
115
  '<a href="%s" title="%s">%s</a>',
116
  esc_url( get_permalink( $value ) ),
117
  the_title_attribute( array(
inc/fields/select-tree.php CHANGED
@@ -12,15 +12,14 @@ class RWMB_Select_Tree_Field extends RWMB_Select_Field {
12
  /**
13
  * Walk options.
14
  *
15
- * @param array $field Field parameters.
16
- * @param mixed $options Select options.
17
- * @param mixed $db_fields Database fields to use in the output.
18
- * @param mixed $meta Meta value.
19
  *
20
  * @return string
21
  */
22
- public static function walk( $field, $options, $db_fields, $meta ) {
23
- $walker = new RWMB_Walker_Select_Tree( $db_fields, $field, $meta );
24
  return $walker->walk( $options );
25
  }
26
 
12
  /**
13
  * Walk options.
14
  *
15
+ * @param array $field Field parameters.
16
+ * @param mixed $options Field options.
17
+ * @param mixed $meta Meta value.
 
18
  *
19
  * @return string
20
  */
21
+ public static function walk( $field, $options, $meta ) {
22
+ $walker = new RWMB_Walker_Select_Tree( $field, $meta );
23
  return $walker->walk( $options );
24
  }
25
 
inc/fields/select.php CHANGED
@@ -18,27 +18,25 @@ class RWMB_Select_Field extends RWMB_Choice_Field {
18
  }
19
 
20
  /**
21
- * Walk options.
22
- *
23
- * @param array $field Field parameters.
24
- * @param mixed $options Select options.
25
- * @param mixed $db_fields Database fields to use in the output.
26
- * @param mixed $meta Meta value.
27
  *
 
 
28
  * @return string
29
  */
30
- public static function walk( $field, $options, $db_fields, $meta ) {
 
31
  $attributes = self::call( 'get_attributes', $field, $meta );
32
  $attributes['data-selected'] = $meta;
33
- $walker = new RWMB_Walker_Select( $db_fields, $field, $meta );
34
  $output = sprintf(
35
  '<select %s>',
36
  self::render_attributes( $attributes )
37
  );
38
- if ( false === $field['multiple'] ) {
39
- $output .= $field['placeholder'] ? '<option value="">' . esc_html( $field['placeholder'] ) . '</option>' : '';
40
  }
41
- $output .= $walker->walk( $options, $field['flatten'] ? - 1 : 0 );
42
  $output .= '</select>';
43
  $output .= self::get_select_all_html( $field );
44
  return $output;
18
  }
19
 
20
  /**
21
+ * Get field HTML.
 
 
 
 
 
22
  *
23
+ * @param mixed $meta Meta value.
24
+ * @param array $field Field parameters.
25
  * @return string
26
  */
27
+ public static function html( $meta, $field ) {
28
+ $options = self::transform_options( $field['options'] );
29
  $attributes = self::call( 'get_attributes', $field, $meta );
30
  $attributes['data-selected'] = $meta;
31
+ $walker = new RWMB_Walker_Select( $field, $meta );
32
  $output = sprintf(
33
  '<select %s>',
34
  self::render_attributes( $attributes )
35
  );
36
+ if ( ! $field['multiple'] && $field['placeholder'] ) {
37
+ $output .= '<option value="">' . esc_html( $field['placeholder'] ) . '</option>';
38
  }
39
+ $output .= $walker->walk( $options, $field['flatten'] ? -1 : 0 );
40
  $output .= '</select>';
41
  $output .= self::get_select_all_html( $field );
42
  return $output;
inc/fields/sidebar.php CHANGED
@@ -17,59 +17,47 @@ class RWMB_Sidebar_Field extends RWMB_Object_Choice_Field {
17
  * @return array
18
  */
19
  public static function normalize( $field ) {
20
- // Set default field args.
21
- $field = parent::normalize( $field );
22
-
23
- // Prevent select tree for user since it's not hierarchical.
24
- $field['field_type'] = 'select_tree' === $field['field_type'] ? 'select' : $field['field_type'];
25
 
26
- // Set to always flat.
27
- $field['flatten'] = true;
28
 
29
- // Set default placeholder.
30
- $field['placeholder'] = empty( $field['placeholder'] ) ? __( 'Select a sidebar', 'meta-box' ) : $field['placeholder'];
31
 
32
  return $field;
33
  }
34
 
35
  /**
36
- * Get users.
37
  *
38
- * @param array $field Field parameters.
39
- *
40
- * @return array
41
  */
42
- public static function get_options( $field ) {
43
  global $wp_registered_sidebars;
44
  $options = array();
45
  foreach ( $wp_registered_sidebars as $sidebar ) {
46
- $options[] = (object) $sidebar;
 
 
 
47
  }
48
  return $options;
49
  }
50
 
51
  /**
52
- * Get field names of object to be used by walker.
53
- *
54
- * @return array
55
- */
56
- public static function get_db_fields() {
57
- return array(
58
- 'parent' => 'parent',
59
- 'id' => 'id',
60
- 'label' => 'name',
61
- );
62
- }
63
-
64
- /**
65
- * Get option label.
66
  *
67
- * @param array $field Field parameters.
68
- * @param string $value Option value.
 
 
69
  *
70
  * @return string
71
  */
72
- public static function get_option_label( $field, $value ) {
73
  if ( ! is_active_sidebar( $value ) ) {
74
  return '';
75
  }
17
  * @return array
18
  */
19
  public static function normalize( $field ) {
20
+ $field = wp_parse_args( $field, array(
21
+ 'placeholder' => __( 'Select a sidebar', 'meta-box' ),
22
+ ) );
 
 
23
 
24
+ // Get sidebars for field options.
25
+ $field['options'] = self::query( $field );
26
 
27
+ $field = parent::normalize( $field );
 
28
 
29
  return $field;
30
  }
31
 
32
  /**
33
+ * Get sidebars for field options.
34
  *
35
+ * @param array $field Field settings.
36
+ * @return array Field options array.
 
37
  */
38
+ public static function query( $field ) {
39
  global $wp_registered_sidebars;
40
  $options = array();
41
  foreach ( $wp_registered_sidebars as $sidebar ) {
42
+ $options[ $sidebar['id'] ] = array(
43
+ 'value' => $sidebar['id'],
44
+ 'label' => $sidebar['name'],
45
+ );
46
  }
47
  return $options;
48
  }
49
 
50
  /**
51
+ * Format a single value for the helper functions. Sub-fields should overwrite this method if necessary.
 
 
 
 
 
 
 
 
 
 
 
 
 
52
  *
53
+ * @param array $field Field parameters.
54
+ * @param string $value The value.
55
+ * @param array $args Additional arguments. Rarely used. See specific fields for details.
56
+ * @param int|null $post_id Post ID. null for current post. Optional.
57
  *
58
  * @return string
59
  */
60
+ public static function format_single_value( $field, $value, $args, $post_id ) {
61
  if ( ! is_active_sidebar( $value ) ) {
62
  return '';
63
  }
inc/fields/taxonomy-advanced.php CHANGED
@@ -52,6 +52,9 @@ class RWMB_Taxonomy_Advanced_Field extends RWMB_Taxonomy_Field {
52
  * @param array $field The field parameters.
53
  */
54
  public static function save( $new, $old, $post_id, $field ) {
 
 
 
55
  $storage = $field['storage'];
56
 
57
  if ( $new ) {
52
  * @param array $field The field parameters.
53
  */
54
  public static function save( $new, $old, $post_id, $field ) {
55
+ if ( empty( $field['id'] ) || ! $field['save_field'] ) {
56
+ return;
57
+ }
58
  $storage = $field['storage'];
59
 
60
  if ( $new ) {
inc/fields/taxonomy.php CHANGED
@@ -29,7 +29,8 @@ class RWMB_Taxonomy_Field extends RWMB_Object_Choice_Field {
29
 
30
  // Set default field args.
31
  $field = wp_parse_args( $field, array(
32
- 'taxonomy' => 'category',
 
33
  ) );
34
 
35
  // Force taxonomy to be an array.
@@ -52,41 +53,47 @@ class RWMB_Taxonomy_Field extends RWMB_Object_Choice_Field {
52
  $field = wp_parse_args( $field, array(
53
  'placeholder' => $placeholder,
54
  ) );
55
- $field = parent::normalize( $field );
56
 
57
  // Set default query args.
58
  $field['query_args'] = wp_parse_args( $field['query_args'], array(
59
  'hide_empty' => false,
60
  ) );
 
 
61
 
62
  // Prevent cloning for taxonomy field.
63
  $field['clone'] = false;
64
 
65
- return $field;
66
- }
67
 
68
- /**
69
- * Get field names of object to be used by walker.
70
- *
71
- * @return array
72
- */
73
- public static function get_db_fields() {
74
- return array(
75
- 'parent' => 'parent',
76
- 'id' => 'term_id',
77
- 'label' => 'name',
78
- );
79
  }
80
 
81
  /**
82
- * Get options for selects, checkbox list, etc via the terms.
83
- *
84
- * @param array $field Field parameters.
85
  *
86
- * @return array
 
87
  */
88
- public static function get_options( $field ) {
89
- $options = get_terms( $field['taxonomy'], $field['query_args'] );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
90
  return $options;
91
  }
92
 
@@ -99,6 +106,9 @@ class RWMB_Taxonomy_Field extends RWMB_Object_Choice_Field {
99
  * @param array $field The field parameters.
100
  */
101
  public static function save( $new, $old, $post_id, $field ) {
 
 
 
102
  $new = array_unique( array_map( 'intval', (array) $new ) );
103
  $new = empty( $new ) ? null : $new;
104
 
@@ -155,20 +165,22 @@ class RWMB_Taxonomy_Field extends RWMB_Object_Choice_Field {
155
  }
156
 
157
  /**
158
- * Get option label.
159
  *
160
- * @param array $field Field parameters.
161
- * @param object $value The term object.
 
 
162
  *
163
  * @return string
164
  */
165
- public static function get_option_label( $field, $value ) {
166
  return sprintf(
167
  '<a href="%s" title="%s">%s</a>',
168
  // @codingStandardsIgnoreLine
169
  esc_url( get_term_link( $value ) ),
170
  esc_attr( $value->name ),
171
- $value->name
172
  );
173
  }
174
  }
29
 
30
  // Set default field args.
31
  $field = wp_parse_args( $field, array(
32
+ 'taxonomy' => 'category',
33
+ 'query_args' => array(),
34
  ) );
35
 
36
  // Force taxonomy to be an array.
53
  $field = wp_parse_args( $field, array(
54
  'placeholder' => $placeholder,
55
  ) );
 
56
 
57
  // Set default query args.
58
  $field['query_args'] = wp_parse_args( $field['query_args'], array(
59
  'hide_empty' => false,
60
  ) );
61
+ // Query terms for field options.
62
+ $field['options'] = self::query( $field );
63
 
64
  // Prevent cloning for taxonomy field.
65
  $field['clone'] = false;
66
 
67
+ $field = parent::normalize( $field );
 
68
 
69
+ return $field;
 
 
 
 
 
 
 
 
 
 
70
  }
71
 
72
  /**
73
+ * Query terms for field options.
 
 
74
  *
75
+ * @param array $field Field settings.
76
+ * @return array Field options array.
77
  */
78
+ public static function query( $field ) {
79
+ $args = wp_parse_args( $field['query_args'], array(
80
+ 'taxonomy' => $field['taxonomy'],
81
+ 'hide_empty' => false,
82
+ 'count' => false,
83
+ 'update_term_meta_cache' => false,
84
+ ) );
85
+ $terms = get_terms( $args );
86
+ if ( ! is_array( $terms ) ) {
87
+ return array();
88
+ }
89
+ $options = array();
90
+ foreach ( $terms as $term ) {
91
+ $options[ $term->term_id ] = array(
92
+ 'value' => $term->term_id,
93
+ 'label' => $term->name,
94
+ 'parent' => $term->parent,
95
+ );
96
+ }
97
  return $options;
98
  }
99
 
106
  * @param array $field The field parameters.
107
  */
108
  public static function save( $new, $old, $post_id, $field ) {
109
+ if ( empty( $field['id'] ) || ! $field['save_field'] ) {
110
+ return;
111
+ }
112
  $new = array_unique( array_map( 'intval', (array) $new ) );
113
  $new = empty( $new ) ? null : $new;
114
 
165
  }
166
 
167
  /**
168
+ * Format a single value for the helper functions. Sub-fields should overwrite this method if necessary.
169
  *
170
+ * @param array $field Field parameters.
171
+ * @param string $value The value.
172
+ * @param array $args Additional arguments. Rarely used. See specific fields for details.
173
+ * @param int|null $post_id Post ID. null for current post. Optional.
174
  *
175
  * @return string
176
  */
177
+ public static function format_single_value( $field, $value, $args, $post_id ) {
178
  return sprintf(
179
  '<a href="%s" title="%s">%s</a>',
180
  // @codingStandardsIgnoreLine
181
  esc_url( get_term_link( $value ) ),
182
  esc_attr( $value->name ),
183
+ esc_html( $value->name )
184
  );
185
  }
186
  }
inc/fields/text-list.php CHANGED
@@ -117,6 +117,9 @@ class RWMB_Text_List_Field extends RWMB_Multiple_Values_Field {
117
  * @param array $field The field parameters.
118
  */
119
  public static function save( $new, $old, $post_id, $field ) {
 
 
 
120
  $storage = $field['storage'];
121
  $storage->delete( $post_id, $field['id'] );
122
  parent::save( $new, array(), $post_id, $field );
117
  * @param array $field The field parameters.
118
  */
119
  public static function save( $new, $old, $post_id, $field ) {
120
+ if ( empty( $field['id'] ) || ! $field['save_field'] ) {
121
+ return;
122
+ }
123
  $storage = $field['storage'];
124
  $storage->delete( $post_id, $field['id'] );
125
  parent::save( $new, array(), $post_id, $field );
inc/fields/user.php CHANGED
@@ -19,62 +19,55 @@ class RWMB_User_Field extends RWMB_Object_Choice_Field {
19
  public static function normalize( $field ) {
20
  // Set default field args.
21
  $field = wp_parse_args( $field, array(
22
- 'placeholder' => __( 'Select an user', 'meta-box' ),
 
 
23
  ) );
24
- $field = parent::normalize( $field );
25
-
26
- // Prevent select tree for user since it's not hierarchical.
27
- $field['field_type'] = 'select_tree' === $field['field_type'] ? 'select' : $field['field_type'];
28
 
29
- // Set to always flat.
30
- $field['flatten'] = true;
31
 
32
- // Set default query args.
33
- $field['query_args'] = wp_parse_args( $field['query_args'], array(
34
- 'orderby' => 'display_name',
35
- 'order' => 'asc',
36
- 'role' => '',
37
- 'fields' => 'all',
38
- ) );
39
 
40
  return $field;
41
  }
42
 
43
  /**
44
- * Get users.
45
- *
46
- * @param array $field Field parameters.
47
- *
48
- * @return array
49
- */
50
- public static function get_options( $field ) {
51
- $query = new WP_User_Query( $field['query_args'] );
52
- return $query->get_results();
53
- }
54
-
55
- /**
56
- * Get field names of object to be used by walker.
57
  *
58
- * @return array
 
59
  */
60
- public static function get_db_fields() {
61
- return array(
62
- 'parent' => 'parent',
63
- 'id' => 'ID',
64
- 'label' => 'display_name',
65
- );
 
 
 
 
 
 
 
 
 
66
  }
67
 
68
  /**
69
- * Get option label.
70
  *
71
- * @param array $field Field parameters.
72
- * @param string $value Option value.
 
 
73
  *
74
  * @return string
75
  */
76
- public static function get_option_label( $field, $value ) {
77
- $user = get_userdata( $value );
78
- return '<a href="' . get_author_posts_url( $value ) . '">' . $user->display_name . '</a>';
 
79
  }
80
  }
19
  public static function normalize( $field ) {
20
  // Set default field args.
21
  $field = wp_parse_args( $field, array(
22
+ 'placeholder' => __( 'Select an user', 'meta-box' ),
23
+ 'query_args' => array(),
24
+ 'display_field' => 'display_name',
25
  ) );
 
 
 
 
26
 
27
+ // Query posts for field options.
28
+ $field['options'] = self::query( $field );
29
 
30
+ $field = parent::normalize( $field );
 
 
 
 
 
 
31
 
32
  return $field;
33
  }
34
 
35
  /**
36
+ * Query users for field options.
 
 
 
 
 
 
 
 
 
 
 
 
37
  *
38
+ * @param array $field Field settings.
39
+ * @return array Field options array.
40
  */
41
+ public static function query( $field ) {
42
+ $display_field = $field['display_field'];
43
+ $args = wp_parse_args( $field['query_args'], array(
44
+ 'orderby' => $display_field,
45
+ 'order' => 'asc',
46
+ ) );
47
+ $users = get_users( $args );
48
+ $options = array();
49
+ foreach ( $users as $user ) {
50
+ $options[ $user->ID ] = array(
51
+ 'value' => $user->ID,
52
+ 'label' => $user->$display_field,
53
+ );
54
+ }
55
+ return $options;
56
  }
57
 
58
  /**
59
+ * Format a single value for the helper functions. Sub-fields should overwrite this method if necessary.
60
  *
61
+ * @param array $field Field parameters.
62
+ * @param string $value The value.
63
+ * @param array $args Additional arguments. Rarely used. See specific fields for details.
64
+ * @param int|null $post_id Post ID. null for current post. Optional.
65
  *
66
  * @return string
67
  */
68
+ public static function format_single_value( $field, $value, $args, $post_id ) {
69
+ $display_field = $field['display_field'];
70
+ $user = get_userdata( $value );
71
+ return '<a href="' . esc_url( get_author_posts_url( $value ) ) . '">' . esc_html( $user->$display_field ) . '</a>';
72
  }
73
  }
inc/functions.php CHANGED
@@ -26,7 +26,7 @@ if ( ! function_exists( 'rwmb_meta' ) ) {
26
  if ( false === $field ) {
27
  return apply_filters( 'rwmb_meta', rwmb_meta_legacy( $key, $args, $post_id ) );
28
  }
29
- $meta = in_array( $field['type'], array( 'oembed', 'map' ), true ) ?
30
  rwmb_the_value( $key, $args, $post_id, false ) :
31
  rwmb_get_value( $key, $args, $post_id );
32
  return apply_filters( 'rwmb_meta', $meta, $key, $args, $post_id );
@@ -92,6 +92,7 @@ if ( ! function_exists( 'rwmb_meta_legacy' ) ) {
92
  $field['taxonomy'] = $args['taxonomy'];
93
  break;
94
  case 'map':
 
95
  case 'oembed':
96
  $method = 'the_value';
97
  break;
26
  if ( false === $field ) {
27
  return apply_filters( 'rwmb_meta', rwmb_meta_legacy( $key, $args, $post_id ) );
28
  }
29
+ $meta = in_array( $field['type'], array( 'oembed', 'map', 'osm' ), true ) ?
30
  rwmb_the_value( $key, $args, $post_id, false ) :
31
  rwmb_get_value( $key, $args, $post_id );
32
  return apply_filters( 'rwmb_meta', $meta, $key, $args, $post_id );
92
  $field['taxonomy'] = $args['taxonomy'];
93
  break;
94
  case 'map':
95
+ case 'osm':
96
  case 'oembed':
97
  $method = 'the_value';
98
  break;
inc/loader.php CHANGED
@@ -18,7 +18,7 @@ class RWMB_Loader {
18
  */
19
  protected function constants() {
20
  // Script version, used to add version for scripts and styles.
21
- define( 'RWMB_VER', '4.14.11' );
22
 
23
  list( $path, $url ) = self::get_path( dirname( dirname( __FILE__ ) ) );
24
 
18
  */
19
  protected function constants() {
20
  // Script version, used to add version for scripts and styles.
21
+ define( 'RWMB_VER', '4.15.0' );
22
 
23
  list( $path, $url ) = self::get_path( dirname( dirname( __FILE__ ) ) );
24
 
inc/meta-box.php CHANGED
@@ -88,7 +88,7 @@ class RW_Meta_Box {
88
  *
89
  * @return bool
90
  */
91
- protected function is_shown() {
92
  $show = apply_filters( 'rwmb_show', true, $this->meta_box );
93
 
94
  return apply_filters( "rwmb_show_{$this->id}", $show, $this->meta_box );
@@ -144,10 +144,6 @@ class RW_Meta_Box {
144
  wp_enqueue_style( 'rwmb-rtl', RWMB_CSS_URL . 'style-rtl.css', array(), RWMB_VER );
145
  }
146
 
147
- if ( 'seamless' === $this->style ) {
148
- wp_enqueue_script( 'rwmb', RWMB_JS_URL . 'script.js', array( 'jquery' ), RWMB_VER, true );
149
- }
150
-
151
  // Load clone script conditionally.
152
  foreach ( $this->fields as $field ) {
153
  if ( $field['clone'] ) {
@@ -178,6 +174,9 @@ class RW_Meta_Box {
178
  * Add meta box for multiple post types
179
  */
180
  public function add_meta_boxes() {
 
 
 
181
  foreach ( $this->post_types as $post_type ) {
182
  add_meta_box(
183
  $this->id,
@@ -190,6 +189,23 @@ class RW_Meta_Box {
190
  }
191
  }
192
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
193
  /**
194
  * Hide meta box if it's set 'default_hidden'
195
  *
@@ -217,8 +233,7 @@ class RW_Meta_Box {
217
 
218
  // Container.
219
  printf(
220
- '<div class="rwmb-meta-box%s" data-autosave="%s" data-object-type="%s">',
221
- esc_attr( 'seamless' === $this->style ? ' rwmb-meta-box--seamless' : '' ),
222
  esc_attr( $this->autosave ? 'true' : 'false' ),
223
  esc_attr( $this->object_type )
224
  );
88
  *
89
  * @return bool
90
  */
91
+ public function is_shown() {
92
  $show = apply_filters( 'rwmb_show', true, $this->meta_box );
93
 
94
  return apply_filters( "rwmb_show_{$this->id}", $show, $this->meta_box );
144
  wp_enqueue_style( 'rwmb-rtl', RWMB_CSS_URL . 'style-rtl.css', array(), RWMB_VER );
145
  }
146
 
 
 
 
 
147
  // Load clone script conditionally.
148
  foreach ( $this->fields as $field ) {
149
  if ( $field['clone'] ) {
174
  * Add meta box for multiple post types
175
  */
176
  public function add_meta_boxes() {
177
+ $screen = get_current_screen();
178
+ add_filter( "postbox_classes_{$screen->id}_{$this->id}", array( $this, 'postbox_classes' ) );
179
+
180
  foreach ( $this->post_types as $post_type ) {
181
  add_meta_box(
182
  $this->id,
189
  }
190
  }
191
 
192
+ /**
193
+ * Modify meta box postbox classes.
194
+ *
195
+ * @param array $classes Array of classes.
196
+ * @return array
197
+ */
198
+ public function postbox_classes( $classes ) {
199
+ if ( $this->closed && ! in_array( 'closed', $classes ) ) {
200
+ $classes[] = 'closed';
201
+ }
202
+ if ( 'seamless' === $this->style ) {
203
+ $classes[] = 'rwmb-seamless';
204
+ }
205
+
206
+ return $classes;
207
+ }
208
+
209
  /**
210
  * Hide meta box if it's set 'default_hidden'
211
  *
233
 
234
  // Container.
235
  printf(
236
+ '<div class="rwmb-meta-box" data-autosave="%s" data-object-type="%s">',
 
237
  esc_attr( $this->autosave ? 'true' : 'false' ),
238
  esc_attr( $this->object_type )
239
  );
inc/walkers/base.php CHANGED
@@ -11,35 +11,32 @@
11
  */
12
  abstract class RWMB_Walker_Base extends Walker {
13
  /**
14
- * Field data.
15
  *
16
- * @access public
17
  * @var array
18
  */
19
  public $field;
20
 
21
  /**
22
- * Meta data.
23
  *
24
- * @access public
25
  * @var array
26
  */
27
- public $meta = array();
28
 
29
  /**
30
  * Constructor.
31
  *
32
- * @param array $db_fields Database fields.
33
- * @param array $field Field parameters.
34
- * @param mixed $meta Meta value.
35
  */
36
- public function __construct( $db_fields, $field, $meta ) {
37
- $this->db_fields = wp_parse_args( (array) $db_fields, array(
38
- 'parent' => '',
39
- 'id' => '',
40
- 'label' => '',
41
- ) );
42
- $this->field = $field;
43
- $this->meta = (array) $meta;
44
  }
45
  }
11
  */
12
  abstract class RWMB_Walker_Base extends Walker {
13
  /**
14
+ * Field settings.
15
  *
 
16
  * @var array
17
  */
18
  public $field;
19
 
20
  /**
21
+ * Field meta data.
22
  *
 
23
  * @var array
24
  */
25
+ public $meta;
26
 
27
  /**
28
  * Constructor.
29
  *
30
+ * @param array $field Field parameters.
31
+ * @param mixed $meta Meta value.
 
32
  */
33
+ public function __construct( $field, $meta ) {
34
+ $this->db_fields = array(
35
+ 'id' => 'value',
36
+ 'parent' => 'parent',
37
+ );
38
+
39
+ $this->field = $field;
40
+ $this->meta = (array) $meta;
41
  }
42
  }
inc/walkers/input-list.php CHANGED
@@ -41,15 +41,13 @@ class RWMB_Walker_Input_List extends RWMB_Walker_Base {
41
  * @param int $current_object_id ID of the current item.
42
  */
43
  public function start_el( &$output, $object, $depth = 0, $args = array(), $current_object_id = 0 ) {
44
- $label = $this->db_fields['label'];
45
- $id = $this->db_fields['id'];
46
- $attributes = RWMB_Field::call( 'get_attributes', $this->field, $object->$id );
47
 
48
  $output .= sprintf(
49
  '<li><label><input %s %s>%s</label>',
50
  RWMB_Field::render_attributes( $attributes ),
51
- checked( in_array( $object->$id, $this->meta ), 1, false ),
52
- RWMB_Field::filter( 'choice_label', $object->$label, $this->field, $object )
53
  );
54
  }
55
 
41
  * @param int $current_object_id ID of the current item.
42
  */
43
  public function start_el( &$output, $object, $depth = 0, $args = array(), $current_object_id = 0 ) {
44
+ $attributes = RWMB_Field::call( 'get_attributes', $this->field, $object->value );
 
 
45
 
46
  $output .= sprintf(
47
  '<li><label><input %s %s>%s</label>',
48
  RWMB_Field::render_attributes( $attributes ),
49
+ checked( in_array( $object->value, $this->meta ), true, false ),
50
+ esc_html( $object->label )
51
  );
52
  }
53
 
inc/walkers/select-tree.php CHANGED
@@ -10,7 +10,7 @@
10
  */
11
  class RWMB_Walker_Select_Tree {
12
  /**
13
- * Field data.
14
  *
15
  * @var string
16
  */
@@ -21,23 +21,17 @@ class RWMB_Walker_Select_Tree {
21
  *
22
  * @var array
23
  */
24
- public $meta = array();
25
 
26
  /**
27
  * Constructor.
28
  *
29
- * @param array $db_fields Database fields.
30
- * @param array $field Field parameters.
31
- * @param mixed $meta Meta value.
32
  */
33
- public function __construct( $db_fields, $field, $meta ) {
34
- $this->db_fields = wp_parse_args( (array) $db_fields, array(
35
- 'parent' => '',
36
- 'id' => '',
37
- 'label' => '',
38
- ) );
39
- $this->field = $field;
40
- $this->meta = (array) $meta;
41
  }
42
 
43
  /**
@@ -48,15 +42,14 @@ class RWMB_Walker_Select_Tree {
48
  * @return string
49
  */
50
  public function walk( $options ) {
51
- $parent = $this->db_fields['parent'];
52
  $children = array();
53
 
54
  foreach ( $options as $option ) {
55
- $index = isset( $option->$parent ) ? $option->$parent : 0;
56
- $children[ $index ][] = $option;
57
  }
58
 
59
- $top_level = isset( $children[0] ) ? 0 : $options[0]->$parent;
60
  return $this->display_level( $children, $top_level, true );
61
  }
62
 
@@ -70,25 +63,24 @@ class RWMB_Walker_Select_Tree {
70
  * @return string
71
  */
72
  public function display_level( $options, $parent_id = 0, $active = false ) {
73
- $id = $this->db_fields['id'];
74
  $field = $this->field;
75
- $walker = new RWMB_Walker_Select( $this->db_fields, $field, $this->meta );
76
  $attributes = RWMB_Field::call( 'get_attributes', $field, $this->meta );
77
 
78
  $children = $options[ $parent_id ];
79
  $output = sprintf(
80
  '<div class="rwmb-select-tree %s" data-parent-id="%s"><select %s>',
81
  $active ? '' : 'hidden',
82
- $parent_id,
83
  RWMB_Field::render_attributes( $attributes )
84
  );
85
- $output .= isset( $field['placeholder'] ) ? "<option value=''>{$field['placeholder']}</option>" : '<option></option>';
86
  $output .= $walker->walk( $children, - 1 );
87
  $output .= '</select>';
88
 
89
- foreach ( $children as $c ) {
90
- if ( isset( $options[ $c->$id ] ) ) {
91
- $output .= $this->display_level( $options, $c->$id, in_array( $c->$id, $this->meta ) && $active );
92
  }
93
  }
94
 
10
  */
11
  class RWMB_Walker_Select_Tree {
12
  /**
13
+ * Field settings.
14
  *
15
  * @var string
16
  */
21
  *
22
  * @var array
23
  */
24
+ public $meta;
25
 
26
  /**
27
  * Constructor.
28
  *
29
+ * @param array $field Field parameters.
30
+ * @param mixed $meta Meta value.
 
31
  */
32
+ public function __construct( $field, $meta ) {
33
+ $this->field = $field;
34
+ $this->meta = (array) $meta;
 
 
 
 
 
35
  }
36
 
37
  /**
42
  * @return string
43
  */
44
  public function walk( $options ) {
 
45
  $children = array();
46
 
47
  foreach ( $options as $option ) {
48
+ $parent = isset( $option->parent ) ? $option->parent : 0;
49
+ $children[ $parent ][] = $option;
50
  }
51
 
52
+ $top_level = isset( $children[0] ) ? 0 : $options[0]->parent;
53
  return $this->display_level( $children, $top_level, true );
54
  }
55
 
63
  * @return string
64
  */
65
  public function display_level( $options, $parent_id = 0, $active = false ) {
 
66
  $field = $this->field;
67
+ $walker = new RWMB_Walker_Select( $field, $this->meta );
68
  $attributes = RWMB_Field::call( 'get_attributes', $field, $this->meta );
69
 
70
  $children = $options[ $parent_id ];
71
  $output = sprintf(
72
  '<div class="rwmb-select-tree %s" data-parent-id="%s"><select %s>',
73
  $active ? '' : 'hidden',
74
+ esc_attr( $parent_id ),
75
  RWMB_Field::render_attributes( $attributes )
76
  );
77
+ $output .= $field['placeholder'] ? "<option value=''>{$field['placeholder']}</option>" : '<option></option>';
78
  $output .= $walker->walk( $children, - 1 );
79
  $output .= '</select>';
80
 
81
+ foreach ( $children as $child ) {
82
+ if ( isset( $options[ $child->value ] ) ) {
83
+ $output .= $this->display_level( $options, $child->value, in_array( $child->value, $this->meta ) && $active );
84
  }
85
  }
86
 
inc/walkers/select.php CHANGED
@@ -21,17 +21,15 @@ class RWMB_Walker_Select extends RWMB_Walker_Base {
21
  * @param int $current_object_id ID of the current item.
22
  */
23
  public function start_el( &$output, $object, $depth = 0, $args = array(), $current_object_id = 0 ) {
24
- $label = $this->db_fields['label'];
25
- $id = $this->db_fields['id'];
26
  $meta = $this->meta;
27
  $indent = str_repeat( '&nbsp;', $depth * 4 );
28
 
29
  $output .= sprintf(
30
  '<option value="%s" %s>%s%s</option>',
31
- esc_attr( $object->$id ),
32
- selected( in_array( $object->$id, $meta ), true, false ),
33
  $indent,
34
- esc_html( RWMB_Field::filter( 'choice_label', $object->$label, $this->field, $object ) )
35
  );
36
  }
37
  }
21
  * @param int $current_object_id ID of the current item.
22
  */
23
  public function start_el( &$output, $object, $depth = 0, $args = array(), $current_object_id = 0 ) {
 
 
24
  $meta = $this->meta;
25
  $indent = str_repeat( '&nbsp;', $depth * 4 );
26
 
27
  $output .= sprintf(
28
  '<option value="%s" %s>%s%s</option>',
29
+ esc_attr( $object->value ),
30
+ selected( in_array( $object->value, $meta ), true, false ),
31
  $indent,
32
+ esc_html( $object->label )
33
  );
34
  }
35
  }
js/map.js CHANGED
@@ -63,8 +63,7 @@
63
 
64
  this.map.setCenter( this.marker.position );
65
  this.map.setZoom( zoom );
66
- }
67
- else if ( this.addressField ) {
68
  this.geocodeAddress();
69
  }
70
  },
@@ -92,7 +91,7 @@
92
 
93
  /**
94
  * Add a custom event that allows other scripts to refresh the maps when needed
95
- * For example: when maps is in tabs or hidden div (this is known issue of Google Maps)
96
  *
97
  * @see https://developers.google.com/maps/documentation/javascript/reference ('resize' Event)
98
  */
@@ -115,28 +114,20 @@
115
  center = this.map.getCenter();
116
 
117
  if ( this.map ) {
118
- google.maps.event.trigger( this.map, 'resize' );
119
  this.map.setZoom( zoom );
120
- this.map.setCenter( center );
121
  }
122
  },
123
 
124
  // Autocomplete address
125
  autocomplete: function () {
126
- var that = this;
 
127
 
128
- // No address field or more than 1 address fields, ignore
129
- if ( ! this.addressField || this.addressField.split( ',' ).length > 1 ) {
130
  return;
131
  }
132
 
133
- var $address = $( 'input[name="' + this.addressField + '"]');
134
-
135
- // If map and address is inside a group, the input name of address field is changed.
136
- if ( 0 === $address.length ) {
137
- $address = this.$container.closest( '.rwmb-group-wrapper' ).find( 'input[name*="[' + this.addressField + ']"]' );
138
- }
139
-
140
  // If Meta Box Geo Location installed. Do not run auto complete.
141
  if ( $( '.rwmb-geo-binding' ).length ) {
142
  $address.on( 'selected_address', function () {
@@ -153,7 +144,14 @@
153
  'region': that.$canvas.data( 'region' )
154
  };
155
  geocoder.geocode( options, function ( results ) {
156
- response( $.map( results, function ( item ) {
 
 
 
 
 
 
 
157
  return {
158
  label: item.formatted_address,
159
  value: item.formatted_address,
@@ -165,7 +163,6 @@
165
  },
166
  select: function ( event, ui ) {
167
  var latLng = new google.maps.LatLng( ui.item.latitude, ui.item.longitude );
168
-
169
  that.map.setCenter( latLng );
170
  that.marker.setPosition( latLng );
171
  that.updateCoordinate( latLng );
@@ -181,18 +178,8 @@
181
 
182
  // Find coordinates by address
183
  geocodeAddress: function () {
184
- var address,
185
- addressList = [],
186
- fieldList = this.addressField.split( ',' ),
187
- loop,
188
  that = this;
189
-
190
- for ( loop = 0; loop < fieldList.length; loop ++ ) {
191
- addressList[loop] = $( '#' + fieldList[loop] ).val();
192
- }
193
-
194
- address = addressList.join( ',' ).replace( /\n/g, ',' ).replace( /,,/g, ',' );
195
-
196
  if ( ! address ) {
197
  return;
198
  }
@@ -205,6 +192,50 @@
205
  that.marker.setPosition( results[0].geometry.location );
206
  that.updateCoordinate( results[0].geometry.location );
207
  } );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
208
  }
209
  };
210
 
@@ -216,7 +247,7 @@
216
  return;
217
  }
218
 
219
- controller = new MapField( $( this ) );
220
  controller.init();
221
  $this.data( 'mapController', controller );
222
  } );
63
 
64
  this.map.setCenter( this.marker.position );
65
  this.map.setZoom( zoom );
66
+ } else if ( this.addressField ) {
 
67
  this.geocodeAddress();
68
  }
69
  },
91
 
92
  /**
93
  * Add a custom event that allows other scripts to refresh the maps when needed
94
+ * For example: when maps is in tabs or hidden div.
95
  *
96
  * @see https://developers.google.com/maps/documentation/javascript/reference ('resize' Event)
97
  */
114
  center = this.map.getCenter();
115
 
116
  if ( this.map ) {
 
117
  this.map.setZoom( zoom );
118
+ this.map.panTo( center );
119
  }
120
  },
121
 
122
  // Autocomplete address
123
  autocomplete: function () {
124
+ var that = this,
125
+ $address = this.getAddressField();
126
 
127
+ if ( null === $address ) {
 
128
  return;
129
  }
130
 
 
 
 
 
 
 
 
131
  // If Meta Box Geo Location installed. Do not run auto complete.
132
  if ( $( '.rwmb-geo-binding' ).length ) {
133
  $address.on( 'selected_address', function () {
144
  'region': that.$canvas.data( 'region' )
145
  };
146
  geocoder.geocode( options, function ( results ) {
147
+ if ( ! results.length ) {
148
+ response( [ {
149
+ value: '',
150
+ label: RWMB_Map.no_results_string
151
+ } ] );
152
+ return;
153
+ }
154
+ response( results.map( function ( item ) {
155
  return {
156
  label: item.formatted_address,
157
  value: item.formatted_address,
163
  },
164
  select: function ( event, ui ) {
165
  var latLng = new google.maps.LatLng( ui.item.latitude, ui.item.longitude );
 
166
  that.map.setCenter( latLng );
167
  that.marker.setPosition( latLng );
168
  that.updateCoordinate( latLng );
178
 
179
  // Find coordinates by address
180
  geocodeAddress: function () {
181
+ var address = this.getAddress(),
 
 
 
182
  that = this;
 
 
 
 
 
 
 
183
  if ( ! address ) {
184
  return;
185
  }
192
  that.marker.setPosition( results[0].geometry.location );
193
  that.updateCoordinate( results[0].geometry.location );
194
  } );
195
+ },
196
+
197
+ // Get the address field.
198
+ getAddressField: function() {
199
+ // No address field or more than 1 address fields, ignore
200
+ if ( ! this.addressField || this.addressField.split( ',' ).length > 1 ) {
201
+ return null;
202
+ }
203
+ return this.findAddressField( this.addressField );
204
+ },
205
+
206
+ // Get the address value for geocoding.
207
+ getAddress: function() {
208
+ var that = this;
209
+
210
+ return this.addressField.split( ',' )
211
+ .map( function( part ) {
212
+ part = that.findAddressField( part );
213
+ return null === part ? '' : part.val();
214
+ } )
215
+ .join( ',' ).replace( /\n/g, ',' ).replace( /,,/g, ',' );
216
+ },
217
+
218
+ // Find address field based on its name attribute. Auto search inside groups when needed.
219
+ findAddressField: function( fieldName ) {
220
+ // Not in a group.
221
+ var $address = $( 'input[name="' + fieldName + '"]');
222
+ if ( $address.length ) {
223
+ return $address;
224
+ }
225
+
226
+ // If map and address is inside a cloneable group.
227
+ $address = this.$container.closest( '.rwmb-group-clone' ).find( 'input[name*="[' + fieldName + ']"]' );
228
+ if ( $address.length ) {
229
+ return $address;
230
+ }
231
+
232
+ // If map and address is inside a non-cloneable group.
233
+ $address = this.$container.closest( '.rwmb-group-wrapper' ).find( 'input[name*="[' + fieldName + ']"]' );
234
+ if ( $address.length ) {
235
+ return $address;
236
+ }
237
+
238
+ return null;
239
  }
240
  };
241
 
247
  return;
248
  }
249
 
250
+ controller = new MapField( $this );
251
  controller.init();
252
  $this.data( 'mapController', controller );
253
  } );
js/oembed.js CHANGED
@@ -11,7 +11,8 @@ jQuery( function ( $ ) {
11
  $spinner = $this.siblings( '.spinner' ),
12
  data = {
13
  action: 'rwmb_get_embed',
14
- url: $this.val()
 
15
  };
16
 
17
  $spinner.css( 'visibility', 'visible' );
11
  $spinner = $this.siblings( '.spinner' ),
12
  data = {
13
  action: 'rwmb_get_embed',
14
+ url: this.value,
15
+ not_available: $this.data( 'not-available' ),
16
  };
17
 
18
  $spinner.css( 'visibility', 'visible' );
js/osm-frontend.js ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ jQuery( function( $ ) {
2
+ 'use strict';
3
+
4
+ var osmTileLayer = L.tileLayer( 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
5
+ attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
6
+ } );
7
+
8
+ /**
9
+ * Display Open Street Map
10
+ */
11
+ function displayMap() {
12
+ var options = $( this ).data( 'osm_options' ),
13
+ mapOptions = options.js_options,
14
+ center = L.latLng( options.latitude, options.longitude ),
15
+ map;
16
+
17
+ mapOptions.center = center;
18
+
19
+ // Typcast zoom to a number
20
+ mapOptions.zoom *= 1;
21
+
22
+ map = L.map( this, mapOptions );
23
+ map.addLayer( osmTileLayer );
24
+
25
+ // Set marker
26
+ if ( options.marker ) {
27
+ var markerOptions = {};
28
+
29
+ // Set marker title
30
+ if ( options.marker_title ) {
31
+ markerOptions.title = options.marker_title;
32
+ }
33
+
34
+ // Set marker icon
35
+ if ( options.marker_icon ) {
36
+ markerOptions.icon = L.icon( options.marker_icon );
37
+ }
38
+
39
+ var marker = L.marker( center, markerOptions ).addTo( map )
40
+ }
41
+
42
+ // Set info window
43
+ if ( options.info_window ) {
44
+ marker.bindPopup( options.info_window ).openPopup();
45
+ }
46
+ }
47
+
48
+ // Loop through all map instances and display them
49
+ $( '.rwmb-osm-canvas' ).each( displayMap );
50
+ } );
js/osm.js ADDED
@@ -0,0 +1,264 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ( function( $, L ) {
2
+ 'use strict';
3
+
4
+ var osmTileLayer = L.tileLayer( 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
5
+ attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
6
+ } );
7
+
8
+ // Use function construction to store map & DOM elements separately for each instance
9
+ var OsmField = function ( $container ) {
10
+ this.$container = $container;
11
+ };
12
+
13
+ // Use prototype for better performance
14
+ OsmField.prototype = {
15
+ // Initialize everything
16
+ init: function () {
17
+ this.initDomElements();
18
+ this.initMapElements();
19
+
20
+ this.initMarkerPosition();
21
+ this.addListeners();
22
+ this.autocomplete();
23
+ },
24
+
25
+ // Initialize DOM elements
26
+ initDomElements: function () {
27
+ this.$canvas = this.$container.find( '.rwmb-osm-canvas' );
28
+ this.canvas = this.$canvas[0];
29
+ this.$coordinate = this.$container.find( '.rwmb-osm-coordinate' );
30
+ this.$findButton = this.$container.find( '.rwmb-osm-goto-address-button' );
31
+ this.addressField = this.$container.data( 'address-field' );
32
+ },
33
+
34
+ // Initialize map elements
35
+ initMapElements: function () {
36
+ var defaultLoc = this.$canvas.data( 'default-loc' ),
37
+ latLng;
38
+
39
+ defaultLoc = defaultLoc ? defaultLoc.split( ',' ) : [53.346881, -6.258860];
40
+ latLng = L.latLng( defaultLoc[0], defaultLoc[1] ); // Initial position for map.
41
+
42
+ this.map = L.map( this.canvas, {
43
+ center: latLng,
44
+ zoom: 14
45
+ } );
46
+ this.map.addLayer( osmTileLayer );
47
+ this.marker = L.marker( latLng, {
48
+ draggable: true
49
+ } ).addTo( this.map );
50
+ },
51
+
52
+ // Initialize marker position
53
+ initMarkerPosition: function () {
54
+ var coordinate = this.$coordinate.val(),
55
+ location,
56
+ zoom;
57
+
58
+ if ( coordinate ) {
59
+ location = coordinate.split( ',' );
60
+ var latLng = L.latLng( location[0], location[1] );
61
+ this.marker.setLatLng( latLng );
62
+
63
+ zoom = location.length > 2 ? parseInt( location[2], 10 ) : 14;
64
+
65
+ this.map.panTo( latLng );
66
+ this.map.setZoom( zoom );
67
+ } else if ( this.addressField ) {
68
+ this.geocodeAddress();
69
+ }
70
+ },
71
+
72
+ // Add event listeners for 'click' & 'drag'
73
+ addListeners: function () {
74
+ var that = this;
75
+ this.map.on( 'click', function ( event ) {
76
+ that.marker.setLatLng( event.latlng );
77
+ that.updateCoordinate( event.latlng );
78
+ } );
79
+
80
+ this.map.on( 'zoom', function () {
81
+ that.updateCoordinate( that.marker.getLatLng() );
82
+ } );
83
+
84
+ this.marker.on( 'drag', function () {
85
+ that.updateCoordinate( that.marker.getLatLng() );
86
+ } );
87
+
88
+ this.$findButton.on( 'click', function ( e ) {
89
+ e.preventDefault();
90
+ that.geocodeAddress();
91
+ } );
92
+
93
+ /**
94
+ * Add a custom event that allows other scripts to refresh the maps when needed
95
+ * For example: when maps is in tabs or hidden div (this is known issue of Google Maps)
96
+ *
97
+ * @see https://developers.google.com/maps/documentation/javascript/reference ('resize' Event)
98
+ */
99
+ $( window ).on( 'rwmb_map_refresh', function () {
100
+ that.refresh();
101
+ } );
102
+
103
+ // Refresh on meta box hide and show
104
+ $( document ).on( 'postbox-toggled', function () {
105
+ that.refresh();
106
+ } );
107
+ // Refresh on sorting meta boxes
108
+ $( '.meta-box-sortables' ).on( 'sortstop', function () {
109
+ that.refresh();
110
+ } );
111
+ },
112
+
113
+ refresh: function () {
114
+ if ( this.map ) {
115
+ this.map.panTo( this.map.getCenter() );
116
+ }
117
+ },
118
+
119
+ // Autocomplete address
120
+ autocomplete: function () {
121
+ var that = this,
122
+ $address = this.getAddressField();
123
+
124
+ if ( null === $address ) {
125
+ return;
126
+ }
127
+
128
+ // If Meta Box Geo Location installed. Do not run auto complete.
129
+ if ( $( '.rwmb-geo-binding' ).length ) {
130
+ $address.on( 'selected_address', that.geocodeAddress );
131
+ return;
132
+ }
133
+
134
+ $address.autocomplete( {
135
+ source: function ( request, response ) {
136
+ $.get( 'https://nominatim.openstreetmap.org/search', {
137
+ format: 'json',
138
+ q: request.term,
139
+ countrycodes: that.$canvas.data( 'region' ),
140
+ "accept-language": that.$canvas.data( 'language' )
141
+ }, function( results ) {
142
+ if ( ! results.length ) {
143
+ response( [ {
144
+ value: '',
145
+ label: RWMB_Osm.no_results_string
146
+ } ] );
147
+ return;
148
+ }
149
+ response( results.map( function ( item ) {
150
+ return {
151
+ label: item.display_name,
152
+ value: item.display_name,
153
+ latitude: item.lat,
154
+ longitude: item.lon
155
+ };
156
+ } ) );
157
+ }, 'json' );
158
+ },
159
+ select: function ( event, ui ) {
160
+ var latLng = L.latLng( ui.item.latitude, ui.item.longitude );
161
+
162
+ that.map.panTo( latLng );
163
+ that.marker.setLatLng( latLng );
164
+ that.updateCoordinate( latLng );
165
+ }
166
+ } );
167
+ },
168
+
169
+ // Update coordinate to input field
170
+ updateCoordinate: function ( latLng ) {
171
+ var zoom = this.map.getZoom();
172
+ this.$coordinate.val( latLng.lat + ',' + latLng.lng + ',' + zoom );
173
+ },
174
+
175
+ // Find coordinates by address
176
+ geocodeAddress: function () {
177
+ var address = this.getAddress(),
178
+ that = this;
179
+ if ( ! address ) {
180
+ return;
181
+ }
182
+
183
+ $.get( 'https://nominatim.openstreetmap.org/search', {
184
+ format: 'json',
185
+ q: address,
186
+ limit: 1,
187
+ countrycodes: that.$canvas.data( 'region' ),
188
+ "accept-language": that.$canvas.data( 'language' )
189
+ }, function( result ) {
190
+ if ( result.length !== 1 ) {
191
+ return;
192
+ }
193
+ var latLng = L.latLng( result[0].lat, result[0].lon );
194
+ that.map.panTo( latLng );
195
+ that.marker.setLatLng( latLng );
196
+ that.updateCoordinate( latLng );
197
+ }, 'json' );
198
+ },
199
+
200
+ // Get the address field.
201
+ getAddressField: function() {
202
+ // No address field or more than 1 address fields, ignore
203
+ if ( ! this.addressField || this.addressField.split( ',' ).length > 1 ) {
204
+ return null;
205
+ }
206
+ return this.findAddressField( this.addressField );
207
+ },
208
+
209
+ // Get the address value for geocoding.
210
+ getAddress: function() {
211
+ var that = this;
212
+
213
+ return this.addressField.split( ',' )
214
+ .map( function( part ) {
215
+ part = that.findAddressField( part );
216
+ return null === part ? '' : part.val();
217
+ } )
218
+ .join( ',' ).replace( /\n/g, ',' ).replace( /,,/g, ',' );
219
+ },
220
+
221
+ // Find address field based on its name attribute. Auto search inside groups when needed.
222
+ findAddressField: function( fieldName ) {
223
+ // Not in a group.
224
+ var $address = $( 'input[name="' + fieldName + '"]');
225
+ if ( $address.length ) {
226
+ return $address;
227
+ }
228
+
229
+ // If map and address is inside a cloneable group.
230
+ $address = this.$container.closest( '.rwmb-group-clone' ).find( 'input[name*="[' + fieldName + ']"]' );
231
+ if ( $address.length ) {
232
+ return $address;
233
+ }
234
+
235
+ // If map and address is inside a non-cloneable group.
236
+ $address = this.$container.closest( '.rwmb-group-wrapper' ).find( 'input[name*="[' + fieldName + ']"]' );
237
+ if ( $address.length ) {
238
+ return $address;
239
+ }
240
+
241
+ return null;
242
+ }
243
+ };
244
+
245
+ function update() {
246
+ $( '.rwmb-osm-field' ).each( function () {
247
+ var $this = $( this ),
248
+ controller = $this.data( 'osmController' );
249
+ if ( controller ) {
250
+ return;
251
+ }
252
+
253
+ controller = new OsmField( $this );
254
+ controller.init();
255
+ $this.data( 'osmController', controller );
256
+ } );
257
+ }
258
+
259
+ $( function () {
260
+ update();
261
+ $( '.rwmb-input' ).on( 'clone', update );
262
+ } );
263
+
264
+ } )( jQuery, L );
js/script.js DELETED
@@ -1,4 +0,0 @@
1
- jQuery( function ( $ ) {
2
- // Add class for seamless meta boxes.
3
- $( '.rwmb-meta-box--seamless' ).closest( '.postbox' ).addClass( 'rwmb-seamless' );
4
- } );
 
 
 
 
meta-box.php CHANGED
@@ -3,7 +3,7 @@
3
  * Plugin Name: Meta Box
4
  * Plugin URI: https://metabox.io
5
  * Description: Create custom meta boxes and custom fields in WordPress.
6
- * Version: 4.14.11
7
  * Author: MetaBox.io
8
  * Author URI: https://metabox.io
9
  * License: GPL2+
3
  * Plugin Name: Meta Box
4
  * Plugin URI: https://metabox.io
5
  * Description: Create custom meta boxes and custom fields in WordPress.
6
+ * Version: 4.15.0
7
  * Author: MetaBox.io
8
  * Author URI: https://metabox.io
9
  * License: GPL2+
readme.txt CHANGED
@@ -3,8 +3,8 @@ Contributors: metabox, rilwis, fitwp, f-j-kaiser, funkatronic, PerWiklander, rua
3
  Donate link: https://metabox.io/pricing/
4
  Tags: meta-box, custom fields, custom field, meta, meta-boxes, admin, advanced, custom, edit, field, file, image, magic fields, matrix, more fields, Post, repeater, simple fields, text, textarea, type, cms, fields post
5
  Requires at least: 4.3
6
- Tested up to: 4.9.6
7
- Stable tag: 4.14.11
8
  License: GPLv2 or later
9
 
10
  Meta Box plugin is a powerful, professional developer toolkit to create custom meta boxes and custom fields for WordPress.
3
  Donate link: https://metabox.io/pricing/
4
  Tags: meta-box, custom fields, custom field, meta, meta-boxes, admin, advanced, custom, edit, field, file, image, magic fields, matrix, more fields, Post, repeater, simple fields, text, textarea, type, cms, fields post
5
  Requires at least: 4.3
6
+ Tested up to: 4.9.7
7
+ Stable tag: 4.15.0
8
  License: GPLv2 or later
9
 
10
  Meta Box plugin is a powerful, professional developer toolkit to create custom meta boxes and custom fields for WordPress.