Completed
Push — master ( 5db201...585add )
by David
08:20
created

WL_Metabox::add_field()   B

Complexity

Conditions 5
Paths 4

Size

Total Lines 46
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 13
nc 4
nop 2
dl 0
loc 46
rs 8.4751
c 0
b 0
f 0
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( 'class-wl-metabox-field.php' );
11
require_once( 'WL_Metabox_Field_date.php' );
12
require_once( 'class-wl-metabox-field-uri.php' );
13
require_once( 'WL_Metabox_Field_coordinates.php' );
14
require_once( 'class-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
		// Build the fields we need to print.
63
		$this->instantiate_fields( get_the_ID() );
64
65
		// Bailout if there are no actual fields, we do not need a metabox in that case.
66
		if ( empty( $this->fields ) ) {
67
			return;
68
		}
69
70
		// Add main metabox (will print also the inner fields).
71
		$id    = uniqid( 'wl-metabox-' );
72
		$title = get_the_title() . ' ' . __( 'properties', 'wordlift' );
73
74
		// WordPress 4.2 do not accept an array of screens as parameter, have to do be explicit.
75
		foreach ( Wordlift_Entity_Service::valid_entity_post_types() as $screen ) {
76
			add_meta_box( $id, $title, array(
77
				$this,
78
				'html',
79
			), $screen, 'normal', 'high' );
80
		}
81
82
		// Add filter to change the metabox CSS class.
83
		add_filter( "postbox_classes_entity_$id", 'wl_admin_metaboxes_add_css_class' );
84
	}
85
86
	/**
87
	 * Called from WP to print the metabox content in page.
88
	 *
89
	 * @since 3.1.0
90
	 *
91
	 * @param WP_Post $post The post.
92
	 */
93
	public function html( $post ) {
0 ignored issues
show
Unused Code introduced by
The parameter $post is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
94
95
		// Loop over the fields.
96
		foreach ( $this->fields as $field ) {
97
98
			// load data from DB (values will be available in $field->data).
99
			$field->get_data();
100
101
			// print field HTML (nonce included).
102
			echo $field->html();
103
		}
104
105
	}
106
107
	/**
108
	 * Read the WL <-> Schema mapping and build the Fields for the entity being edited.
109
	 *
110
	 * Note: the first function that calls this method will instantiate the fields.
111
	 * Why it isn't called from the constructor? Because we need to hook this process as late as possible.
112
	 *
113
	 * @since 3.1.0
114
	 *
115
	 * @param int $post_id The post id.
116
	 */
117
	public function instantiate_fields( $post_id ) {
118
119
		// This function must be called only once. Not called from the constructor because WP hooks have a rococo ordering.
120
		if ( isset( $this->fields ) ) {
121
			return;
122
		}
123
124
		$entity_type = wl_entity_taxonomy_get_custom_fields( $post_id );
125
126
		if ( isset( $entity_type ) ) {
127
128
			/*
129
			 * Might not have any relevant meta box field, for example for articles,
130
			 * therefor make sure fields are at least an empty array to help the considered
131
			 * in other functions using it.
132
			 */
133
			$this->fields = array();
134
135
			/**
136
			 * In some special case, properties must be grouped in one field (e.g. coordinates) or dealed with custom methods.
137
			 * We must divide fields in two groups:
138
			 * - simple: accept values for one property
139
			 * - grouped: accept values for more properties, or for one property that needs a specific metabox.
140
			 */
141
			$metaboxes         = $this->group_properties_by_input_field( $entity_type );
142
			$simple_metaboxes  = $metaboxes[0];
143
			$grouped_metaboxes = $metaboxes[1];
144
145
			// Loop over simple entity properties.
146
			foreach ( $simple_metaboxes as $key => $property ) {
147
148
				// Info passed to the metabox.
149
				$info         = array();
150
				$info[ $key ] = $property;
151
152
				// Build the requested field as WL_Metabox_Field_ object.
153
				$this->add_field( $info );
154
155
			}
156
157
			// Loop over grouped properties.
158
			foreach ( $grouped_metaboxes as $key => $property ) {
159
160
				// Info passed to the metabox.
161
				$info         = array();
162
				$info[ $key ] = $property;
163
164
				// Build the requested field group as WL_Metabox_Field_ object.
165
				$this->add_field( $info, true );
166
167
			}
168
		}
169
170
	}
171
172
	/**
173
	 * Separates metaboxes in simple and grouped.
174
	 *
175
	 * @param array $custom_fields Information on the entity type.
176
	 *
177
	 * @return array
178
	 */
179
	public function group_properties_by_input_field( $custom_fields ) {
180
181
		$simple_properties  = array();
182
		$grouped_properties = array();
183
184
		// Loop over possible entity properties.
185
		foreach ( $custom_fields as $key => $property ) {
186
187
			// Check presence of predicate and type.
188
			if ( isset( $property['predicate'] ) && isset( $property['type'] ) ) {
189
190
				// Check if input_field is defined.
191
				if ( isset( $property['input_field'] ) && '' !== $property['input_field'] ) {
192
193
					$grouped_key = $property['input_field'];
194
195
					// Update list of grouped properties.
196
					$grouped_properties[ $grouped_key ][ $key ] = $property;
197
198
				} else {
199
200
					// input_field not defined, add simple metabox.
201
					$simple_properties[ $key ] = $property;
202
				}
203
			}
204
		}
205
206
		return array( $simple_properties, $grouped_properties );
207
	}
208
209
	/**
210
	 * Add a Field to the current Metabox, based on the description of the Field.
211
	 * This method is a rude factory for Field objects.
212
	 *
213
	 * @param array $args    The field's information.
214
	 * @param bool  $grouped Flag to distinguish between simple and grouped fields.
215
	 */
216
	public function add_field( $args, $grouped = false ) {
217
218
		if ( $grouped ) {
219
220
			// Special fields (sameas, coordinates, etc.).
221
			//
222
			// Build Field with a custom class (e.g. WL_Metabox_Field_date).
223
			$field_class = 'WL_Metabox_Field_' . key( $args );
224
225
		} else {
226
227
			// Simple fields (string, uri, boolean, etc.).
228
			//
229
			// Which field? We want to use the class that is specific for the field.
230
			$meta      = key( $args );
231
			$this_meta = $args[ $meta ];
232
233
			// If the field declares what metabox it wants, use that one.
234
			if ( isset( $this_meta['metabox']['class'] ) ) {
235
236
				$field_class = $this_meta['metabox']['class'];
237
238
			} elseif ( ! isset( $this_meta['type'] ) || Wordlift_Schema_Service::DATA_TYPE_STRING === $this_meta['type'] ) {
239
240
				// TODO: all fields should explicitly declare the required WL_Metabox.
241
				// When they will remove this.
242
				//
243
				// Use default WL_Metabox_Field (manages strings).
244
				$field_class = 'WL_Metabox_Field';
245
246
			} else {
247
248
				// TODO: all fields should explicitly declare the required WL_Metabox.
249
				// When they will remove this.
250
				//
251
				// Build Field with a custom class (e.g. WL_Metabox_Field_date).
252
				$field_class = 'WL_Metabox_Field_' . $this_meta['type'];
253
254
			}
255
256
		}
257
		// 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...
258
259
		// Call apropriate constructor (e.g. WL_Metabox_Field_... ).
260
		$this->fields[] = new $field_class( $args );
261
	}
262
263
	/**
264
	 * Save the form data for the specified entity {@link WP_Post}'s id.
265
	 *
266
	 * @since 3.5.4
267
	 *
268
	 * @param int $entity_id The entity's {@link WP_Post}'s id.
269
	 */
270
	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...
271
272
		// Build Field objects.
273
		$this->instantiate_fields( $entity_id );
274
275
		// Check if WL metabox form was posted.
276
		if ( ! isset( $_POST['wl_metaboxes'] ) ) {
277
			return;
278
		}
279
280
		foreach ( $this->fields as $field ) {
281
282
			// Verify nonce.
283
			$valid_nonce = $field->verify_nonce();
284
			if ( $valid_nonce ) {
285
286
				$posted_data = $_POST['wl_metaboxes'];
287
				$field_name  = $field->meta_name;
288
289
				// Each Filed only deals with its values.
290
				if ( isset( $posted_data[ $field_name ] ) ) {
291
292
					$values = $posted_data[ $field_name ];
293
					if ( ! is_array( $values ) ) {
294
						$values = array( $values );
295
					}
296
297
					// Save data permanently
298
					$field->save_data( $values );
299
				}
300
			}
301
		}
302
303
		Wordlift_Linked_Data_Service::get_instance()->push( $entity_id );
304
305
	}
306
307
	/**
308
	 * Enqueue scripts and styles.
309
	 *
310
	 * @since 3.0.0
311
	 */
312
	public function enqueue_scripts_and_styles() {
313
314
		// Use the minified version if PW_DEBUG isn't set.
315
		$min = ! defined( 'WP_DEBUG' ) || ! WP_DEBUG ? '.min' : '';
316
317
		// Load the jquery-ui-timepicker-addon library.
318
		wp_enqueue_style( 'wl-flatpickr', dirname( plugin_dir_url( __FILE__ ) ) . "/js/flatpickr/flatpickr$min.css", array(), '3.0.6' );
319
		wp_enqueue_script( 'wl-flatpickr', dirname( plugin_dir_url( __FILE__ ) ) . "/js/flatpickr/flatpickr$min.js", array( 'jquery' ), '3.0.6', true );
320
321
		// Leaflet.
322
		wp_enqueue_style( 'leaflet', dirname( dirname( plugin_dir_url( __FILE__ ) ) ) . '/bower_components/leaflet/dist/leaflet.css' );
323
		wp_enqueue_script( 'leaflet', dirname( dirname( plugin_dir_url( __FILE__ ) ) ) . '/bower_components/leaflet/dist/leaflet.js', __FILE__ );
324
325
		// Add AJAX autocomplete to facilitate metabox editing.
326
		wp_enqueue_script( 'wl-entity-metabox-utility', dirname( plugin_dir_url( __FILE__ ) ) . '/js/wl_entity_metabox_utilities.js' );
327
		wp_localize_script( 'wl-entity-metabox-utility', 'wlEntityMetaboxParams', array(
328
				'ajax_url' => admin_url( 'admin-ajax.php' ),
329
				'action'   => 'entity_by_title',
330
			)
331
		);
332
333
	}
334
335
}
336