Completed
Push — develop ( bf654c...059c7c )
by David
02:47
created

WL_Metabox   A

Complexity

Total Complexity 29

Size/Duplication

Total Lines 294
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 0

Importance

Changes 0
Metric Value
dl 0
loc 294
rs 10
c 0
b 0
f 0
wmc 29
lcom 1
cbo 0

8 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 13 1
A add_main_metabox() 0 13 1
A html() 0 16 2
B instantiate_fields() 0 48 5
B group_properties_by_input_field() 0 29 6
B add_field() 0 46 5
B save_form_data() 0 35 6
A enqueue_scripts_and_styles() 0 22 3
1
<?php
2
/**
3
 * Metaboxes.
4
 *
5
 * @since      3.1.0
6
 * @package    Wordlift
7
 * @subpackage Wordlift/admin/WL_Metabox
8
 */
9
10
require_once( 'WL_Metabox_Field.php' );
11
require_once( 'WL_Metabox_Field_date.php' );
12
require_once( 'WL_Metabox_Field_uri.php' );
13
require_once( 'WL_Metabox_Field_coordinates.php' );
14
require_once( 'WL_Metabox_Field_sameas.php' );
15
require_once( 'WL_Metabox_Field_address.php' );
16
require_once( 'class-wordlift-metabox-field-duration.php' );
17
require_once( 'class-wordlift-metabox-field-multiline.php' );
18
19
/**
20
 * Define the {@link WL_Metabox} class.
21
 *
22
 * @since      3.1.0
23
 * @package    Wordlift
24
 * @subpackage Wordlift/admin/WL_Metabox
25
 */
26
class WL_Metabox {
27
28
	/**
29
	 * The metabox custom fields for the current {@link WP_Post}.
30
	 *
31
	 * @since  3.1.0
32
	 * @access public
33
	 * @var array $fields The metabox custom fields.
34
	 */
35
	public $fields;
36
37
	/**
38
	 * WL_Metabox constructor.
39
	 *
40
	 * @since 3.1.0
41
	 */
42
	public function __construct() {
43
44
		// Add hooks to print metaboxes and save submitted data.
45
		add_action( 'add_meta_boxes', array( &$this, 'add_main_metabox' ) );
46
		add_action( 'wl_linked_data_save_post', array(
47
			&$this,
48
			'save_form_data',
49
		) );
50
51
		// Enqueue js and css.
52
		$this->enqueue_scripts_and_styles();
53
54
	}
55
56
	/**
57
	 * Add a callback to print the metabox in page.
58
	 * Wordpress will fire the $this->html() callback at the right time.
59
	 */
60
	public function add_main_metabox() {
61
62
		// Add main metabox (will print also the inner fields).
63
		$id    = uniqid( 'wl-metabox-' );
64
		$title = get_the_title() . ' ' . __( 'properties', 'wordlift' );
65
		add_meta_box( $id, $title, array(
66
			$this,
67
			'html',
68
		), Wordlift_Entity_Service::TYPE_NAME, 'normal', 'high' );
69
70
		// Add filter to change the metabox CSS class.
71
		add_filter( "postbox_classes_entity_$id", 'wl_admin_metaboxes_add_css_class' );
72
	}
73
74
	/**
75
	 * Called from WP to print the metabox content in page.
76
	 *
77
	 * @since 3.1.0
78
	 *
79
	 * @param WP_Post $post The post.
80
	 */
81
	public function html( $post ) {
82
83
		// Build the fields we need to print.
84
		$this->instantiate_fields( $post->ID );
85
86
		// Loop over the fields.
87
		foreach ( $this->fields as $field ) {
88
89
			// load data from DB (values will be available in $field->data).
90
			$field->get_data();
91
92
			// print field HTML (nonce included).
93
			echo $field->html();
94
		}
95
96
	}
97
98
	/**
99
	 * Read the WL <-> Schema mapping and build the Fields for the entity being edited.
100
	 *
101
	 * Note: the first function that calls this method will instantiate the fields.
102
	 * Why it isn't called from the constructor? Because we need to hook this process as late as possible.
103
	 *
104
	 * @since 3.1.0
105
	 *
106
	 * @param int $post_id The post id.
107
	 */
108
	public function instantiate_fields( $post_id ) {
109
110
		// This function must be called only once. Not called from the constructor because WP hooks have a rococo ordering.
111
		if ( isset( $this->fields ) ) {
112
			return;
113
		}
114
115
		$entity_type = wl_entity_taxonomy_get_custom_fields( $post_id );
116
117
		if ( isset( $entity_type ) ) {
118
119
			/**
120
			 * In some special case, properties must be grouped in one field (e.g. coordinates) or dealed with custom methods.
121
			 * We must divide fields in two groups:
122
			 * - simple: accept values for one property
123
			 * - grouped: accept values for more properties, or for one property that needs a specific metabox.
124
			 */
125
			$metaboxes         = $this->group_properties_by_input_field( $entity_type );
126
			$simple_metaboxes  = $metaboxes[0];
127
			$grouped_metaboxes = $metaboxes[1];
128
129
			// Loop over simple entity properties.
130
			foreach ( $simple_metaboxes as $key => $property ) {
131
132
				// Info passed to the metabox.
133
				$info         = array();
134
				$info[ $key ] = $property;
135
136
				// Build the requested field as WL_Metabox_Field_ object.
137
				$this->add_field( $info );
138
139
			}
140
141
			// Loop over grouped properties.
142
			foreach ( $grouped_metaboxes as $key => $property ) {
143
144
				// Info passed to the metabox.
145
				$info         = array();
146
				$info[ $key ] = $property;
147
148
				// Build the requested field group as WL_Metabox_Field_ object.
149
				$this->add_field( $info, true );
150
151
			}
152
153
		}
154
155
	}
156
157
	/**
158
	 * Separates metaboxes in simple and grouped.
159
	 *
160
	 * @param array $custom_fields Information on the entity type.
161
	 *
162
	 * @return array
163
	 */
164
	public function group_properties_by_input_field( $custom_fields ) {
165
166
		$simple_properties  = array();
167
		$grouped_properties = array();
168
169
		// Loop over possible entity properties.
170
		foreach ( $custom_fields as $key => $property ) {
171
172
			// Check presence of predicate and type.
173
			if ( isset( $property['predicate'] ) && isset( $property['type'] ) ) {
174
175
				// Check if input_field is defined.
176
				if ( isset( $property['input_field'] ) && '' !== $property['input_field'] ) {
177
178
					$grouped_key = $property['input_field'];
179
180
					// Update list of grouped properties.
181
					$grouped_properties[ $grouped_key ][ $key ] = $property;
182
183
				} else {
184
185
					// input_field not defined, add simple metabox.
186
					$simple_properties[ $key ] = $property;
187
				}
188
			}
189
		}
190
191
		return array( $simple_properties, $grouped_properties );
192
	}
193
194
	/**
195
	 * Add a Field to the current Metabox, based on the description of the Field.
196
	 * This method is a rude factory for Field objects.
197
	 *
198
	 * @param array $args    The field's information.
199
	 * @param bool  $grouped Flag to distinguish between simple and grouped fields.
200
	 */
201
	public function add_field( $args, $grouped = false ) {
202
203
		if ( $grouped ) {
204
205
			// Special fields (sameas, coordinates, etc.).
206
			//
207
			// Build Field with a custom class (e.g. WL_Metabox_Field_date).
208
			$field_class = 'WL_Metabox_Field_' . key( $args );
209
210
		} else {
211
212
			// Simple fields (string, uri, boolean, etc.).
213
			//
214
			// Which field? We want to use the class that is specific for the field.
215
			$meta      = key( $args );
216
			$this_meta = $args[ $meta ];
217
218
			// If the field declares what metabox it wants, use that one.
219
			if ( isset( $this_meta['metabox']['class'] ) ) {
220
221
				$field_class = $this_meta['metabox']['class'];
222
223
			} elseif ( ! isset( $this_meta['type'] ) || Wordlift_Schema_Service::DATA_TYPE_STRING === $this_meta['type'] ) {
224
225
				// TODO: all fields should explicitly declare the required WL_Metabox.
226
				// When they will remove this.
227
				//
228
				// Use default WL_Metabox_Field (manages strings).
229
				$field_class = 'WL_Metabox_Field';
230
231
			} else {
232
233
				// TODO: all fields should explicitly declare the required WL_Metabox.
234
				// When they will remove this.
235
				//
236
				// Build Field with a custom class (e.g. WL_Metabox_Field_date).
237
				$field_class = 'WL_Metabox_Field_' . $this_meta['type'];
238
239
			}
240
241
		}
242
		// End if().
0 ignored issues
show
Unused Code Comprehensibility introduced by
43% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
243
244
		// Call apropriate constructor (e.g. WL_Metabox_Field_... ).
245
		$this->fields[] = new $field_class( $args );
246
	}
247
248
	/**
249
	 * Save the form data for the specified entity {@link WP_Post}'s id.
250
	 *
251
	 * @since 3.5.4
252
	 *
253
	 * @param int $entity_id The entity's {@link WP_Post}'s id.
254
	 */
255
	public function save_form_data( $entity_id ) {
0 ignored issues
show
Coding Style introduced by
save_form_data uses the super-global variable $_POST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
256
257
		// Build Field objects.
258
		$this->instantiate_fields( $entity_id );
259
260
		// Check if WL metabox form was posted.
261
		if ( ! isset( $_POST['wl_metaboxes'] ) ) {
262
			return;
263
		}
264
265
		foreach ( $this->fields as $field ) {
266
267
			// Verify nonce.
268
			$valid_nonce = $field->verify_nonce();
269
			if ( $valid_nonce ) {
270
271
				$posted_data = $_POST['wl_metaboxes'];
272
				$field_name  = $field->meta_name;
273
274
				// Each Filed only deals with its values.
275
				if ( isset( $posted_data[ $field_name ] ) ) {
276
277
					$values = $posted_data[ $field_name ];
278
					if ( ! is_array( $values ) ) {
279
						$values = array( $values );
280
					}
281
282
					// Save data permanently
283
					$field->save_data( $values );
284
				}
285
			}
286
		}
287
288
		wl_linked_data_push_to_redlink( $entity_id );
289
	}
290
291
	/**
292
	 * Enqueue scripts and styles.
293
	 *
294
	 * @since 3.0.0
295
	 */
296
	public function enqueue_scripts_and_styles() {
297
298
		// Use the minified version if PW_DEBUG isn't set.
299
		$min = ! defined( 'WP_DEBUG' ) || ! WP_DEBUG ? '.min' : '';
300
301
		// Load the jquery-ui-timepicker-addon library.
302
		wp_enqueue_style( 'wl-flatpickr', dirname( plugin_dir_url( __FILE__ ) ) . "/js/flatpickr/flatpickr$min.css", array(), '3.0.6' );
303
		wp_enqueue_script( 'wl-flatpickr', dirname( plugin_dir_url( __FILE__ ) ) . "/js/flatpickr/flatpickr$min.js", array( 'jquery' ), '3.0.6', true );
304
305
		// Leaflet.
306
		wp_enqueue_style( 'leaflet', dirname( dirname( plugin_dir_url( __FILE__ ) ) ) . '/bower_components/leaflet/dist/leaflet.css' );
307
		wp_enqueue_script( 'leaflet', dirname( dirname( plugin_dir_url( __FILE__ ) ) ) . '/bower_components/leaflet/dist/leaflet.js', __FILE__ );
308
309
		// Add AJAX autocomplete to facilitate metabox editing.
310
		wp_enqueue_script( 'wl-entity-metabox-utility', dirname( plugin_dir_url( __FILE__ ) ) . '/js/wl_entity_metabox_utilities.js' );
311
		wp_localize_script( 'wl-entity-metabox-utility', 'wlEntityMetaboxParams', array(
312
				'ajax_url' => admin_url( 'admin-ajax.php' ),
313
				'action'   => 'entity_by_title',
314
			)
315
		);
316
317
	}
318
319
}
320