Completed
Pull Request — master (#111)
by Luca
02:07
created

MslsMetaBox::add()   B

Complexity

Conditions 4
Paths 3

Size

Total Lines 33
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 4
eloc 22
nc 3
nop 0
dl 0
loc 33
rs 8.5806
c 1
b 0
f 0
1
<?php
2
/**
3
 * MslsMetaBox
4
 * @author Dennis Ploetner <[email protected]>
5
 * @since 0.9.8
6
 */
7
8
namespace lloc\Msls;
9
10
use lloc\Msls\ContentImport\MetaBox as ContentImportMetaBox;
11
12
/**
13
 * Meta box for the edit mode of the (custom) post types
14
 * @package Msls
15
 */
16
class MslsMetaBox extends MslsMain {
17
18
	/**
19
	 * Suggest
20
	 *
21
	 * Echo a JSON-ified array of posts of the given post-type and
22
	 * the requested search-term and then die silently
23
	 */
24
	public static function suggest() {
25
		$json = new MslsJson;
26
27
		if ( filter_has_var( INPUT_POST, 'blog_id' ) ) {
28
			switch_to_blog(
0 ignored issues
show
introduced by
switch_to_blog is not something you should ever need to do in a VIP theme context. Instead use an API (XML-RPC, REST) to interact with other sites if needed.
Loading history...
29
				filter_input( INPUT_POST, 'blog_id', FILTER_SANITIZE_NUMBER_INT )
30
			);
31
32
			$args = array(
33
				'post_status'    => get_post_stati( [ 'internal' => '' ] ),
34
				'posts_per_page' => 10,
35
			);
36
37
			if ( filter_has_var( INPUT_POST, 'post_type' ) ) {
38
				$args['post_type'] = sanitize_text_field(
39
					filter_input( INPUT_POST, 'post_type' )
40
				);
41
			}
42
43
			if ( filter_has_var( INPUT_POST, 's' ) ) {
44
				$args['s'] = sanitize_text_field(
45
					filter_input( INPUT_POST, 's' )
46
				);
47
			}
48
49
			/**
50
			 * Overrides the query-args for the suggest fields in the MetaBox
51
			 * @since 0.9.9
52
			 *
53
			 * @param array $args
54
			 */
55
			$args = (array) apply_filters( 'msls_meta_box_suggest_args', $args );
56
57
			$my_query = new \WP_Query( $args );
58
			while ( $my_query->have_posts() ) {
59
				$my_query->the_post();
60
61
				/**
62
				 * Manipulates the WP_Post object before using it
63
				 * @since 0.9.9
64
				 *
65
				 * @param \WP_Post $post
66
				 */
67
				$my_query->post = apply_filters( 'msls_meta_box_suggest_post', $my_query->post );
68
69
				if ( is_object( $my_query->post ) ) {
70
					$json->add( get_the_ID(), get_the_title() );
71
				}
72
			}
73
			wp_reset_postdata();
74
			restore_current_blog();
75
		}
76
		wp_die( $json->encode() );
77
	}
78
79
	/**
80
	 * Init
81
	 *
82
	 * @codeCoverageIgnore
83
	 *
84
	 * @return MslsMetaBox
85
	 */
86
	public static function init() {
87
		$options    = MslsOptions::instance();
88
		$collection = MslsBlogCollection::instance();
89
		$obj        = new static( $options, $collection );
90
91
		if ( ! $options->is_excluded() ) {
92
			add_action( 'add_meta_boxes', [ $obj, 'add' ] );
93
			add_action( 'save_post', [ $obj, 'set' ] );
94
			add_action( 'trashed_post', [ $obj, 'delete' ] );
95
		}
96
97
		return $obj;
98
	}
99
100
	/**
101
	 * Add
102
	 */
103
	public function add() {
104
		foreach ( MslsPostType::instance()->get() as $post_type ) {
105
			add_meta_box(
106
				'msls',
107
				__( 'Multisite Language Switcher', 'multisite-language-switcher' ),
108
				[
109
					$this,
110
					(
111
					MslsOptions::instance()->activate_autocomplete ?
112
						'render_input' :
113
						'render_select'
114
					),
115
				],
116
				$post_type,
117
				'side',
118
				'high'
119
			);
120
121
			if ( MslsOptions::instance()->activate_content_import ) {
122
				add_meta_box(
123
					'msls-content-import',
124
					__( 'Multisite Language Switcher - Import content', 'multisite-language-switcher' ),
125
					[
126
						ContentImportMetaBox::instance(),
127
						'render',
128
					],
129
					$post_type,
130
					'side',
131
					'high' );
0 ignored issues
show
Coding Style introduced by
This line of the multi-line function call does not seem to be indented correctly. Expected 16 spaces, but found 20.
Loading history...
132
				add_action( 'admin_footer', [ ContentImportMetaBox::instance(), 'print_modal_html' ] );
133
			}
134
		}
135
	}
136
137
	/**
138
	 * Render the classic select-box
139
	 * @uses selected
140
	 */
141
	public function render_select() {
142
		$blogs = $this->collection->get();
143
		if ( $blogs ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $blogs of type lloc\Msls\MslsBlog[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
144
			global $post;
145
146
			$type   = get_post_type( $post->ID );
147
			$mydata = new MslsOptionsPost( $post->ID );
148
149
			$this->maybe_set_linked_post( $mydata );
150
151
			$temp   = $post;
152
153
			wp_nonce_field( MSLS_PLUGIN_PATH, 'msls_noncename' );
154
155
			$lis = '';
156
157
			foreach ( $blogs as $blog ) {
158
				switch_to_blog( $blog->userblog_id );
0 ignored issues
show
introduced by
switch_to_blog is not something you should ever need to do in a VIP theme context. Instead use an API (XML-RPC, REST) to interact with other sites if needed.
Loading history...
159
160
				$language = $blog->get_language();
161
162
				$icon = MslsAdminIcon::create()
163
				                     ->set_language( $language )
164
				                     ->set_src( MslsOptions::instance()->get_flag_url( $language ) );
165
				if ( $mydata->has_value( $language ) ) {
166
					$icon->set_href( $mydata->$language );
167
				}
168
169
				$selects = '';
170
				$pto     = get_post_type_object( $type );
171
172
				if ( $pto->hierarchical ) {
173
					$args = array(
174
						'post_type'         => $type,
175
						'selected'          => $mydata->$language,
176
						'name'              => 'msls_input_' . $language,
177
						'show_option_none'  => ' ',
178
						'option_none_value' => 0,
179
						'sort_column'       => 'menu_order, post_title',
180
						'echo'              => 0,
181
					);
182
					/**
183
					 * Overrides the args for wp_dropdown_pages when using the HTML select in the MetaBox
184
					 * @since 1.0.5
185
					 *
186
					 * @param array $args
187
					 */
188
					$args = (array) apply_filters( 'msls_meta_box_render_select_hierarchical', $args );
189
190
					$selects .= wp_dropdown_pages( $args );
191
				} else {
192
					$options = '';
193
194
					$my_query = new \WP_Query(
195
						array(
196
							'post_type'      => $type,
197
							'post_status'    => get_post_stati( [ 'internal' => '' ] ),
198
							'orderby'        => 'title',
199
							'order'          => 'ASC',
200
							'posts_per_page' => - 1,
201
							'fields'         => 'ids',
202
						)
203
					);
204
205
					if ( $my_query->have_posts() ) {
206
						foreach ( $my_query->posts as $my_id ) {
207
							$options .= sprintf(
208
								'<option value="%s" %s>%s</option>',
209
								$my_id,
210
								selected( $my_id, $mydata->$language, false ),
211
								get_the_title( $my_id )
212
							);
213
						}
214
					}
215
					$selects .= sprintf(
216
						'<select name="msls_input_%s"><option value="0"></option>%s</select>',
217
						$language,
218
						$options
219
					);
220
				}
221
222
				$lis .= sprintf(
223
					'<li><label for="msls_input_%s">%s</label>%s</li>',
224
					$language,
225
					$icon,
226
					$selects
227
				);
228
229
				restore_current_blog();
230
			}
231
			printf(
232
				'<ul>%s</ul><input type="submit" class="button-secondary" value="%s"/>',
233
				$lis,
234
				__( 'Update', 'multisite-language-switcher' )
235
			);
236
			$post = $temp;
0 ignored issues
show
introduced by
Overridding WordPress globals is prohibited
Loading history...
237
		} else {
238
			printf(
239
				'<p>%s</p>',
240
				__( 'You should define at least another blog in a different language in order to have some benefit from this plugin!', 'multisite-language-switcher' )
241
			);
242
		}
243
	}
244
245
	/**
246
	 * Render the suggest input-field
247
	 *
248
	 * @param bool $echo Whether the metabox markup should be echoed to the page or not.
249
	 */
250
	public function render_input( $echo = true ) {
0 ignored issues
show
Unused Code introduced by
The parameter $echo 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...
251
		$blogs = $this->collection->get();
252
253
		if ( $blogs ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $blogs of type lloc\Msls\MslsBlog[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
254
			global $post;
255
256
			$post_type = get_post_type( $post->ID );
257
			$my_data   = new MslsOptionsPost( $post->ID );
258
259
			$this->maybe_set_linked_post( $my_data );
260
261
			$temp      = $post;
262
			$items     = '';
263
264
			wp_nonce_field( MSLS_PLUGIN_PATH, 'msls_noncename' );
265
266
			foreach ( $blogs as $blog ) {
267
				switch_to_blog( $blog->userblog_id );
0 ignored issues
show
introduced by
switch_to_blog is not something you should ever need to do in a VIP theme context. Instead use an API (XML-RPC, REST) to interact with other sites if needed.
Loading history...
268
269
				$language = $blog->get_language();
270
				$flag_url = MslsOptions::instance()->get_flag_url( $language );
271
				$icon     = MslsAdminIcon::create()->set_language( $language )->set_src( $flag_url );
272
273
				$value = $title = '';
274
275
				if ( $my_data->has_value( $language ) ) {
276
					$icon->set_href( $my_data->$language );
277
					$value = $my_data->$language;
278
					$title = get_the_title( $value );
279
				}
280
281
				$items .= sprintf(
282
					'<li>
283
					<label for="msls_title_%1$s">%2$s</label>
284
					<input type="hidden" id="msls_id_%1$s" name="msls_input_%3$s" value="%4$s"/>
285
					<input class="msls_title" id="msls_title_%1$s" name="msls_title_%1$s" type="text" value="%5$s"/>
286
					</li>',
287
					$blog->userblog_id,
288
					$icon,
289
					$language,
290
					$value,
291
					$title
292
				);
293
294
				restore_current_blog();
295
			}
296
297
			$input_button = sprintf(
298
				'<input type="submit" class="button-secondary clear" value="%s"/>',
299
				__( 'Update', 'multisite-language-switcher' )
300
			);
301
302
			/**
303
			 * Returns the input button, return an empty string if you'ld like to hide the button
304
			 * @since 1.0.2
305
			 *
306
			 * @param string $input_button
307
			 */
308
			$input_button = ( string ) apply_filters( 'msls_meta_box_render_input_button', $input_button );
0 ignored issues
show
introduced by
Cast statements must not contain whitespace; expected "(string)" but found "( string )"
Loading history...
309
310
			printf(
311
				'<ul>%s</ul>
312
				<input type="hidden" name="msls_post_type" id="msls_post_type" value="%s"/>
313
				<input type="hidden" name="msls_action" id="msls_action" value="suggest_posts"/>
314
				%s',
315
				$items,
316
				$post_type,
317
				$input_button
318
			);
319
320
			$post = $temp;
0 ignored issues
show
introduced by
Overridding WordPress globals is prohibited
Loading history...
321
		} else {
322
			printf(
323
				'<p>%s</p>',
324
				__( 'You should define at least another blog in a different language in order to have some benefit from this plugin!', 'multisite-language-switcher' )
325
			);
326
		}
327
	}
328
329
	/**
330
	 * Set
331
	 *
332
	 * @param int $post_id
333
	 */
334
	public function set( $post_id ) {
335
		if ( $this->is_autosave( $post_id ) || ! $this->verify_nonce() ) {
336
			return;
337
		}
338
339
		$capability = (
340
		'page' == filter_input( INPUT_POST, 'post_type', FILTER_SANITIZE_STRING ) ?
341
			'edit_page' :
342
			'edit_post'
343
		);
344
345
		if ( ! current_user_can( $capability, $post_id ) ) {
346
			return;
347
		}
348
349
		$this->save( $post_id, MslsOptionsPost::class );
350
	}
351
352
	/**
353
	 * Sets the selected element in the data from the `$_GET` superglobal, if any.
354
	 * @param MslsOptionsPost $mydata
355
	 * @return MslsOptionsPost
356
	 */
357
	public function maybe_set_linked_post( MslsOptionsPost $mydata ) {
0 ignored issues
show
Coding Style introduced by
maybe_set_linked_post uses the super-global variable $_GET 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...
358
		if ( ! isset( $_GET['msls_id'], $_GET['msls_lang'] ) ) {
0 ignored issues
show
introduced by
Detected access of super global var $_GET, probably need manual inspection.
Loading history...
359
			return $mydata;
360
		}
361
362
		$origin_lang = trim( $_GET['msls_lang'] );
0 ignored issues
show
introduced by
Detected access of super global var $_GET, probably need manual inspection.
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_GET
Loading history...
363
364
		if ( isset( $mydata->{$origin_lang} ) ) {
365
			return $mydata;
366
		}
367
368
		$origin_post_id = (int) $_GET['msls_id'];
0 ignored issues
show
introduced by
Detected access of super global var $_GET, probably need manual inspection.
Loading history...
369
370
		$origin_blog_id = $this->collection->get_blog_id( $origin_lang );
371
372
		if ( null === $origin_blog_id ) {
373
			return $mydata;
374
		}
375
376
		switch_to_blog( $origin_blog_id );
0 ignored issues
show
introduced by
switch_to_blog is not something you should ever need to do in a VIP theme context. Instead use an API (XML-RPC, REST) to interact with other sites if needed.
Loading history...
377
		$origin_post = get_post( $origin_post_id );
378
		restore_current_blog();
379
380
		if ( ! $origin_post instanceof \WP_Post ) {
0 ignored issues
show
Bug introduced by
The class WP_Post does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
381
			return $mydata;
382
		}
383
384
		$mydata->{$origin_lang} = $origin_post_id;
385
386
		return $mydata;
387
	}
388
}
389