Completed
Push — master ( 4713b5...48986a )
by David
05:28 queued 15s
created

WL_Metabox::html()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 16
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 5
nc 2
nop 1
dl 0
loc 16
rs 9.4285
c 0
b 0
f 0
1
<?php
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 15 and the first side effect is on line 3.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
2
3
require_once( 'WL_Metabox_Field.php' );
4
require_once( 'WL_Metabox_Field_date.php' );
5
require_once( 'WL_Metabox_Field_uri.php' );
6
require_once( 'WL_Metabox_Field_coordinates.php' );
7
require_once( 'WL_Metabox_Field_sameas.php' );
8
require_once( 'WL_Metabox_Field_address.php' );
9
10
/**
11
 * Class WL_Metabox
12
 *
13
 * @since 3.1.0
14
 */
15
class WL_Metabox {
16
17
	public $fields;
18
19
	/**
20
	 * WL_Metabox constructor.
21
	 *
22
	 * @since 3.1.0
23
	 */
24
	public function __construct() {
25
26
		// Add hooks to print metaboxes and save submitted data.
27
		add_action( 'add_meta_boxes', array( &$this, 'add_main_metabox' ) );
28
		add_action( 'wl_linked_data_save_post', array(
29
			&$this,
30
			'save_form_data',
31
		) );
32
33
		// Enqueue js and css.
34
		$this->enqueue_scripts_and_styles();
35
36
	}
37
38
	/**
39
	 * Add a callback to print the metabox in page.
40
	 * Wordpress will fire the $this->html() callback at the right time.
41
	 */
42
	public function add_main_metabox() {
43
44
		// Add main metabox (will print also the inner fields).
45
		$id    = uniqid( 'wl-metabox-' );
46
		$title = get_the_title() . ' ' . __( 'properties', 'wordlift' );
47
		add_meta_box( $id, $title, array(
48
			$this,
49
			'html',
50
		), Wordlift_Entity_Service::TYPE_NAME, 'normal', 'high' );
51
52
		// Add filter to change the metabox CSS class.
53
		add_filter( "postbox_classes_entity_$id", 'wl_admin_metaboxes_add_css_class' );
54
	}
55
56
	/**
57
	 * Called from WP to print the metabox content in page.
58
	 *
59
	 * @since 3.1.0
60
	 *
61
	 * @param WP_Post $post The post.
62
	 */
63
	public function html( $post ) {
64
65
		// Build the fields we need to print.
66
		$this->instantiate_fields( $post->ID );
67
68
		// Loop over the fields.
69
		foreach ( $this->fields as $field ) {
70
71
			// load data from DB (values will be available in $field->data).
72
			$field->get_data();
73
74
			// print field HTML (nonce included).
75
			echo $field->html();
76
		}
77
78
	}
79
80
	/**
81
	 * Read the WL <-> Schema mapping and build the Fields for the entity being edited.
82
	 *
83
	 * Note: the first function that calls this method will instantiate the fields.
84
	 * Why it isn't called from the constructor? Because we need to hook this process as late as possible.
85
	 *
86
	 * @since 3.1.0
87
	 *
88
	 * @param int $post_id The post id.
89
	 */
90
	public function instantiate_fields( $post_id ) {
91
92
		// This function must be called only once. Not called from the constructor because WP hooks have a rococo ordering.
93
		if ( isset( $this->fields ) ) {
94
			return;
95
		}
96
97
		$entity_type = wl_entity_taxonomy_get_custom_fields( $post_id );
98
99
		if ( isset( $entity_type ) ) {
100
101
			/**
102
			 * In some special case, properties must be grouped in one field (e.g. coordinates) or dealed with custom methods.
103
			 * We must divide fields in two groups:
104
			 * - simple: accept values for one property
105
			 * - grouped: accept values for more properties, or for one property that needs a specific metabox.
106
			 */
107
			$metaboxes         = $this->group_properties_by_input_field( $entity_type );
108
			$simple_metaboxes  = $metaboxes[0];
109
			$grouped_metaboxes = $metaboxes[1];
110
111
			// Loop over simple entity properties.
112
			foreach ( $simple_metaboxes as $key => $property ) {
113
114
				// Info passed to the metabox.
115
				$info         = array();
116
				$info[ $key ] = $property;
117
118
				// Build the requested field as WL_Metabox_Field_ object.
119
				$this->add_field( $info );
120
			}
121
122
			// Loop over grouped properties.
123
			foreach ( $grouped_metaboxes as $key => $property ) {
124
125
				// Info passed to the metabox.
126
				$info         = array();
127
				$info[ $key ] = $property;
128
129
				// Build the requested field group as WL_Metabox_Field_ object.
130
				$this->add_field( $info, true );
131
			}
132
133
		}
134
	}
135
136
	/**
137
	 * Separes metaboxes in simple and grouped.
138
	 *
139
	 * @param array $custom_fields Information on the entity type.
140
	 */
141
	public function group_properties_by_input_field( $custom_fields ) {
142
143
		$simple_properties  = array();
144
		$grouped_properties = array();
145
146
		// Loop over possible entity properties.
147
		foreach ( $custom_fields as $key => $property ) {
148
149
			// Check presence of predicate and type.
150
			if ( isset( $property['predicate'] ) && isset( $property['type'] ) ) {
151
152
				// Check if input_field is defined.
153
				if ( isset( $property['input_field'] ) && $property['input_field'] !== '' ) {
154
155
					$grouped_key = $property['input_field'];
156
157
					// Update list of grouped properties.
158
					$grouped_properties[ $grouped_key ][ $key ] = $property;
159
160
				} else {
161
162
					// input_field not defined, add simple metabox.
163
					$simple_properties[ $key ] = $property;
164
				}
165
			}
166
		}
167
168
		return array( $simple_properties, $grouped_properties );
169
	}
170
171
	/**
172
	 * Add a Field to the current Metabox, based on the description of the Field.
173
	 * This method is a rude factory for Field objects.
174
	 *
175
	 * @param array $args
176
	 * @param bool  $grouped Flag to distinguish between simple and grouped Fields
177
	 */
178
	public function add_field( $args, $grouped = false ) {
179
180
		if ( $grouped ) {
181
			// Special fields (sameas, coordinates, etc.).
182
183
			// Build Field with a custom class (e.g. WL_Metabox_Field_date).
184
			$field_class = 'WL_Metabox_Field_' . key( $args );
185
186
		} else {
187
			// Simple fields (string, uri, boolean, etc.).
188
189
			// Which field? We want to use the class that is specific for the field.
190
			$meta      = key( $args );
191
			$this_meta = $args[ $meta ];
192
193
			// If the field declares what metabox it wants, use that one.
194
			if ( isset( $this_meta['metabox']['class'] ) ) {
195
196
				$field_class = $this_meta['metabox']['class'];
197
198
			} elseif ( ! isset( $this_meta['type'] ) || ( $this_meta['type'] == Wordlift_Schema_Service::DATA_TYPE_STRING ) ) {
199
200
				// TODO: all fields should explicitly declare the required WL_Metabox.
201
				// When they will remove this.
202
203
				// Use default WL_Metabox_Field (manages strings).
204
				$field_class = 'WL_Metabox_Field';
205
206
			} else {
207
208
				// TODO: all fields should explicitly declare the required WL_Metabox.
209
				// When they will remove this.
210
211
				// Build Field with a custom class (e.g. WL_Metabox_Field_date).
212
				$field_class = 'WL_Metabox_Field_' . $this_meta['type'];
213
214
			}
215
		}
216
217
		// Call apropriate constructor (e.g. WL_Metabox_Field_... ).
218
		$this->fields[] = new $field_class( $args );
219
	}
220
221
	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...
222
223
		// Build Field objects.
224
		$this->instantiate_fields( $entity_id );
225
226
		// Check if WL metabox form was posted.
227
		if ( ! isset( $_POST['wl_metaboxes'] ) ) {
228
			return;
229
		}
230
231
		foreach ( $this->fields as $field ) {
232
233
			// Verify nonce.
234
			$valid_nonce = $field->verify_nonce();
235
			if ( $valid_nonce ) {
236
237
				$posted_data = $_POST['wl_metaboxes'];
238
				$field_name  = $field->meta_name;
239
240
				// Each Filed only deals with its values.
241
				if ( isset( $posted_data[ $field_name ] ) ) {
242
243
					$values = $posted_data[ $field_name ];
244
					if ( ! is_array( $values ) ) {
245
						$values = array( $values );
246
					}
247
248
					// Save data permanently
249
					$field->save_data( $values );
250
				}
251
			}
252
		}
253
254
		wl_linked_data_push_to_redlink( $entity_id );
255
	}
256
257
	/**
258
	 * Enqueue scripts and styles.
259
	 *
260
	 * @since 3.0.0
261
	 */
262
	public function enqueue_scripts_and_styles() {
263
264
		// Load the jquery-ui-timepicker-addon library.
265
		wp_enqueue_style( 'jquery-ui-timepicker-addon', dirname( plugin_dir_url( __FILE__ ) ) . '/js/jquery-ui-timepicker-addon/jquery-ui-timepicker-addon.min.css' );
266
		wp_enqueue_script( 'jquery-ui-timepicker-addon', dirname( plugin_dir_url( __FILE__ ) ) . '/js/jquery-ui-timepicker-addon/jquery-ui-timepicker-addon.min.js', array( 'jquery-ui-datepicker' ), '1.6.3', true );
267
268
		wp_enqueue_script( 'jquery-ui-timepicker-no-conflict', dirname( plugin_dir_url( __FILE__ ) ) . '/js/jquery.datetimepicker.no-conflict.js', array(
269
			'jquery-ui-datepicker',
270
			'jquery-ui-timepicker-addon',
271
		) );
272
273
		// Leaflet.
274
		wp_enqueue_style( 'leaflet', dirname( dirname( plugin_dir_url( __FILE__ ) ) ) . '/bower_components/leaflet/dist/leaflet.css' );
275
		wp_enqueue_script( 'leaflet', dirname( dirname( plugin_dir_url( __FILE__ ) ) ) . '/bower_components/leaflet/dist/leaflet.js', __FILE__ );
276
277
		// Add AJAX autocomplete to facilitate metabox editing.
278
		wp_enqueue_script( 'wl-entity-metabox-utility', dirname( plugin_dir_url( __FILE__ ) ) . '/js/wl_entity_metabox_utilities.js' );
279
		wp_localize_script( 'wl-entity-metabox-utility', 'wlEntityMetaboxParams', array(
280
				'ajax_url' => admin_url( 'admin-ajax.php' ),
281
				'action'   => 'entity_by_title',
282
			)
283
		);
284
285
	}
286
287
}
288