1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace lloc\Msls\ContentImport; |
4
|
|
|
|
5
|
|
|
use lloc\Msls\ContentImport\Importers\Importer; |
6
|
|
|
use lloc\Msls\ContentImport\Importers\Map; |
7
|
|
|
use lloc\Msls\ContentImport\Importers\WithRequestPostAttributes; |
8
|
|
|
use lloc\Msls\MslsBlogCollection; |
9
|
|
|
use lloc\Msls\MslsMain; |
10
|
|
|
use lloc\Msls\MslsOptionsPost; |
11
|
|
|
use lloc\Msls\MslsRegistryInstance; |
12
|
|
|
|
13
|
|
|
/** |
14
|
|
|
* Class ContentImporter |
15
|
|
|
* |
16
|
|
|
* Handles the request for a content import. |
17
|
|
|
* |
18
|
|
|
* @package lloc\Msls\ContentImport |
19
|
|
|
*/ |
20
|
|
|
class ContentImporter extends MslsRegistryInstance { |
21
|
|
|
use WithRequestPostAttributes; |
22
|
|
|
|
23
|
|
|
/** |
24
|
|
|
* @var MslsMain |
25
|
|
|
*/ |
26
|
|
|
protected $main; |
27
|
|
|
|
28
|
|
|
/** |
29
|
|
|
* @var ImportLogger |
30
|
|
|
*/ |
31
|
|
|
protected $logger; |
32
|
|
|
/** |
33
|
|
|
* @var Relations |
34
|
|
|
*/ |
35
|
|
|
protected $relations; |
36
|
|
|
|
37
|
|
|
/** |
38
|
|
|
* @var bool Whether the class should handle requests or not. |
39
|
|
|
*/ |
40
|
|
|
protected $handle = true; |
41
|
|
|
|
42
|
|
|
/** |
43
|
|
|
* @var int The ID of the post the class created while handling the request, if any. |
44
|
|
|
*/ |
45
|
|
|
protected $has_created_post = 0; |
46
|
|
|
|
47
|
|
|
/** |
48
|
|
|
* ContentImporter constructor. |
49
|
|
|
* |
50
|
|
|
* @param \lloc\Msls\MslsMain|null $main |
51
|
|
|
*/ |
52
|
|
|
public function __construct( MslsMain $main = null ) { |
53
|
|
|
$this->main = $main ?: MslsMain::init(); |
54
|
|
|
} |
55
|
|
|
|
56
|
|
|
/** |
57
|
|
|
* @return \lloc\Msls\ContentImport\ImportLogger |
58
|
|
|
*/ |
59
|
|
|
public function get_logger() { |
60
|
|
|
return $this->logger; |
61
|
|
|
} |
62
|
|
|
|
63
|
|
|
/** |
64
|
|
|
* @param \lloc\Msls\ContentImport\ImportLogger $logger |
65
|
|
|
*/ |
66
|
|
|
public function set_logger( $logger ) { |
67
|
|
|
$this->logger = $logger; |
68
|
|
|
} |
69
|
|
|
|
70
|
|
|
/** |
71
|
|
|
* @return \lloc\Msls\ContentImport\Relations |
72
|
|
|
*/ |
73
|
|
|
public function get_relations() { |
74
|
|
|
return $this->relations; |
75
|
|
|
} |
76
|
|
|
|
77
|
|
|
/** |
78
|
|
|
* @param \lloc\Msls\ContentImport\Relations $relations |
79
|
|
|
*/ |
80
|
|
|
public function set_relations( $relations ) { |
81
|
|
|
$this->relations = $relations; |
82
|
|
|
} |
83
|
|
|
|
84
|
|
|
/** |
85
|
|
|
* Handles an import request happening during a post save or a template redirect. |
86
|
|
|
* |
87
|
|
|
* @param array|null $data |
88
|
|
|
* |
89
|
|
|
* @return array The updated, if needed, data array. |
90
|
|
|
*/ |
91
|
|
|
public function handle_import( array $data = [] ) { |
92
|
|
|
if ( ! $this->pre_flight_check() || false === $sources = $this->parse_sources() ) { |
93
|
|
|
return $data; |
94
|
|
|
} |
95
|
|
|
|
96
|
|
|
list( $source_blog_id, $source_post_id ) = $sources; |
97
|
|
|
|
98
|
|
|
if ( $source_blog_id === get_current_blog_id() ) { |
99
|
|
|
return $data; |
100
|
|
|
} |
101
|
|
|
|
102
|
|
|
$source_lang = MslsBlogCollection::get_blog_language( $source_blog_id ); |
103
|
|
|
$dest_blog_id = get_current_blog_id(); |
104
|
|
|
$dest_lang = MslsBlogCollection::get_blog_language( get_current_blog_id() ); |
105
|
|
|
|
106
|
|
|
$dest_post_id = $this->get_the_blog_post_ID( $dest_blog_id ); |
107
|
|
|
|
108
|
|
|
if ( empty( $dest_post_id ) ) { |
109
|
|
|
return $data; |
110
|
|
|
} |
111
|
|
|
|
112
|
|
|
switch_to_blog( $source_blog_id ); |
113
|
|
|
$source_post = get_post( $source_post_id ); |
114
|
|
|
restore_current_blog(); |
115
|
|
|
|
116
|
|
|
if ( ! $source_post instanceof \WP_Post ) { |
|
|
|
|
117
|
|
|
return $data; |
118
|
|
|
} |
119
|
|
|
|
120
|
|
|
$import_coordinates = new ImportCoordinates(); |
121
|
|
|
|
122
|
|
|
$import_coordinates->source_blog_id = $source_blog_id; |
123
|
|
|
$import_coordinates->source_post_id = $source_post_id; |
124
|
|
|
$import_coordinates->dest_blog_id = $dest_blog_id; |
125
|
|
|
$import_coordinates->dest_post_id = $dest_post_id; |
126
|
|
|
$import_coordinates->source_post = $source_post; |
127
|
|
|
$import_coordinates->source_lang = $source_lang; |
128
|
|
|
$import_coordinates->dest_lang = $dest_lang; |
129
|
|
|
|
130
|
|
|
$import_coordinates->parse_importers_from_request(); |
131
|
|
|
|
132
|
|
|
$data = $this->import_content( $import_coordinates, $data ); |
133
|
|
|
|
134
|
|
|
if ( $this->has_created_post ) { |
135
|
|
|
$this->update_inserted_blog_post_data($dest_blog_id, $dest_post_id, $data ); |
136
|
|
|
$this->redirect_to_blog_post( $dest_blog_id, $dest_post_id ); |
137
|
|
|
} |
138
|
|
|
|
139
|
|
|
return $data; |
140
|
|
|
} |
141
|
|
|
|
142
|
|
|
/** |
143
|
|
|
* Whether the importer should run or not. |
144
|
|
|
* |
145
|
|
|
* @return bool |
146
|
|
|
*/ |
147
|
|
|
protected function pre_flight_check( array $data = [] ) { |
|
|
|
|
148
|
|
|
if ( ! $this->handle ) { |
149
|
|
|
return false; |
150
|
|
|
} |
151
|
|
|
|
152
|
|
|
if ( ! $this->main->verify_nonce() ) { |
153
|
|
|
return false; |
154
|
|
|
} |
155
|
|
|
|
156
|
|
|
if ( ! isset( $_POST['msls_import'] ) ) { |
157
|
|
|
return false; |
158
|
|
|
} |
159
|
|
|
|
160
|
|
|
return true; |
161
|
|
|
} |
162
|
|
|
|
163
|
|
|
/** |
164
|
|
|
* Parses the source blog and post IDs from the $_POST array validating them. |
165
|
|
|
* |
166
|
|
|
* @return array|bool |
167
|
|
|
*/ |
168
|
|
|
public function parse_sources() { |
169
|
|
|
if ( ! isset( $_POST['msls_import'] ) ) { |
170
|
|
|
return false; |
171
|
|
|
} |
172
|
|
|
|
173
|
|
|
$import_data = array_filter( explode( '|', trim( $_POST['msls_import'] ) ), 'is_numeric' ); |
174
|
|
|
|
175
|
|
|
if ( count( $import_data ) !== 2 ) { |
176
|
|
|
return false; |
177
|
|
|
} |
178
|
|
|
|
179
|
|
|
return array_map( 'intval', $import_data ); |
180
|
|
|
} |
181
|
|
|
|
182
|
|
|
protected function get_the_blog_post_ID( $blog_id ) { |
183
|
|
|
switch_to_blog( $blog_id ); |
184
|
|
|
|
185
|
|
|
$id = get_the_ID(); |
186
|
|
|
|
187
|
|
|
if ( ! empty( $id ) ) { |
188
|
|
|
restore_current_blog(); |
189
|
|
|
|
190
|
|
|
return $id; |
191
|
|
|
} |
192
|
|
|
|
193
|
|
|
if ( isset( $_REQUEST['post'] ) && filter_var( $_REQUEST['post'], FILTER_VALIDATE_INT ) ) { |
194
|
|
|
return (int) $_REQUEST['post']; |
195
|
|
|
} |
196
|
|
|
|
197
|
|
|
$data = [ |
198
|
|
|
'post_type' => $this->read_post_type_from_request( 'post' ), |
199
|
|
|
'post_title' => 'MSLS Content Import Draft - ' . date( 'Y-m-d H:i:s' ) |
200
|
|
|
]; |
201
|
|
|
|
202
|
|
|
return $this->insert_blog_post( $blog_id, $data ); |
203
|
|
|
} |
204
|
|
|
|
205
|
|
|
protected function insert_blog_post( $blog_id, array $data = [] ) { |
206
|
|
|
if ( empty( $data ) ) { |
207
|
|
|
return false; |
208
|
|
|
} |
209
|
|
|
|
210
|
|
|
switch_to_blog( $blog_id ); |
211
|
|
|
|
212
|
|
|
$this->handle( false ); |
213
|
|
|
if ( isset( $data['ID'] ) ) { |
214
|
|
|
$post_id = wp_update_post( $data ); |
215
|
|
|
} else { |
216
|
|
|
$post_id = wp_insert_post( $data ); |
217
|
|
|
} |
218
|
|
|
$this->handle( true ); |
219
|
|
|
|
220
|
|
|
$this->has_created_post = $post_id ?: false; |
221
|
|
|
|
222
|
|
|
restore_current_blog(); |
223
|
|
|
|
224
|
|
|
return $this->has_created_post; |
225
|
|
|
} |
226
|
|
|
|
227
|
|
|
public function handle( $handle ) { |
228
|
|
|
$this->handle = $handle; |
229
|
|
|
|
230
|
|
|
// also prevent MSLS from saving |
231
|
|
|
if ( false === $handle ) { |
232
|
|
|
add_action( 'msls_main_save', '__return_false' ); |
233
|
|
|
} else { |
234
|
|
|
remove_action( 'msls_main_save', '__return_false' ); |
235
|
|
|
} |
236
|
|
|
} |
237
|
|
|
|
238
|
|
|
/** |
239
|
|
|
* Imports content according to the provided coordinates. |
240
|
|
|
* |
241
|
|
|
* @param ImportCoordinates $import_coordinates |
242
|
|
|
* @param array $post_fields An optional array of post fields; this can be |
243
|
|
|
* left empty if the method is not called as a consequence |
244
|
|
|
* of filtering the `wp_insert_post_data` filter. |
245
|
|
|
* |
246
|
|
|
* @return array An array of modified post fields. |
247
|
|
|
*/ |
248
|
|
|
public function import_content( ImportCoordinates $import_coordinates, array $post_fields = [] ) { |
249
|
|
|
if ( ! $import_coordinates->validate() ) { |
250
|
|
|
return $post_fields; |
251
|
|
|
} |
252
|
|
|
|
253
|
|
|
/** |
254
|
|
|
* Fires before the import runs. |
255
|
|
|
* |
256
|
|
|
* @param ImportCoordinates $import_coordinates |
257
|
|
|
*/ |
258
|
|
|
do_action( 'msls_content_import_before_import', $import_coordinates ); |
259
|
|
|
|
260
|
|
|
/** |
261
|
|
|
* Filters the data before the import runs. |
262
|
|
|
* |
263
|
|
|
* @since TBD |
264
|
|
|
* |
265
|
|
|
* @param array $post_fields |
266
|
|
|
* @param ImportCoordinates $import_coordinates |
267
|
|
|
*/ |
268
|
|
|
$post_fields = apply_filters( 'msls_content_import_data_before_import', $post_fields, $import_coordinates ); |
269
|
|
|
|
270
|
|
|
/** |
271
|
|
|
* Filters the importers map before it's populated. |
272
|
|
|
* |
273
|
|
|
* Returning a non `null` value here will override the creation of the importers map completely |
274
|
|
|
* and use the one returned in the filter. |
275
|
|
|
* |
276
|
|
|
* @param null $importers |
277
|
|
|
* @param ImportCoordinates $import_coordinates |
278
|
|
|
*/ |
279
|
|
|
$importers = apply_filters( 'msls_content_import_importers', null, $import_coordinates ); |
280
|
|
|
|
281
|
|
|
if ( null === $importers ) { |
282
|
|
|
$importers = Map::instance()->make( $import_coordinates ); |
283
|
|
|
} |
284
|
|
|
|
285
|
|
|
$this->logger = $this->logger ?: new ImportLogger( $import_coordinates ); |
286
|
|
|
$this->relations = $this->relations ?: new Relations( $import_coordinates ); |
287
|
|
|
|
288
|
|
|
if ( ! empty( $importers ) && is_array( $importers ) ) { |
289
|
|
|
$source_post_id = $import_coordinates->source_post_id; |
290
|
|
|
$dest_lang = $import_coordinates->dest_lang; |
291
|
|
|
$dest_post_id = $import_coordinates->dest_post_id; |
292
|
|
|
$this->relations->should_create( MslsOptionsPost::create( $source_post_id ), $dest_lang, $dest_post_id ); |
|
|
|
|
293
|
|
|
|
294
|
|
|
foreach ( $importers as $key => $importer ) { |
295
|
|
|
/** @var Importer $importer */ |
296
|
|
|
$post_fields = $importer->import( $post_fields ); |
297
|
|
|
$this->logger->merge( $importer->get_logger() ); |
298
|
|
|
$this->relations->merge( $importer->get_relations() ); |
299
|
|
|
} |
300
|
|
|
|
301
|
|
|
$this->relations->create(); |
302
|
|
|
$this->logger->save(); |
303
|
|
|
} |
304
|
|
|
|
305
|
|
|
/** |
306
|
|
|
* Fires after the import ran. |
307
|
|
|
* |
308
|
|
|
* @since TBD |
309
|
|
|
* |
310
|
|
|
* @param ImportCoordinates $import_coordinates |
311
|
|
|
* @param ImportLogger $logger |
312
|
|
|
* @param Relations $relations |
313
|
|
|
*/ |
314
|
|
|
do_action( 'msls_content_import_after_import', $import_coordinates, $this->logger, $this->relations ); |
315
|
|
|
|
316
|
|
|
/** |
317
|
|
|
* Filters the data after the import ran. |
318
|
|
|
* |
319
|
|
|
* @param array $post_fields |
320
|
|
|
* @param ImportCoordinates $import_coordinates |
321
|
|
|
* @param ImportLogger $logger |
322
|
|
|
* @param Relations $relations |
323
|
|
|
*/ |
324
|
|
|
return apply_filters( 'msls_content_import_data_after_import', $post_fields, $import_coordinates, $this->logger, $this->relations ); |
325
|
|
|
} |
326
|
|
|
|
327
|
|
|
/** |
328
|
|
|
* @param array $data |
329
|
|
|
* @param int $post_id |
330
|
|
|
* |
331
|
|
|
* @return array |
332
|
|
|
*/ |
333
|
|
|
protected function update_inserted_blog_post_data($blog_id, $post_id, array $data ) { |
334
|
|
|
$data['ID'] = $post_id; |
335
|
|
|
$data['post_status'] = empty( $data['post_status'] ) || $data['post_status'] === 'auto-draft' |
|
|
|
|
336
|
|
|
? 'draft' |
337
|
|
|
: $data['post_status']; |
338
|
|
|
$this->insert_blog_post( $blog_id, $data ); |
339
|
|
|
|
340
|
|
|
return $data; |
341
|
|
|
} |
342
|
|
|
|
343
|
|
|
protected function redirect_to_blog_post( $dest_blog_id, $post_id ) { |
344
|
|
|
switch_to_blog( $dest_blog_id ); |
345
|
|
|
$edit_post_link = html_entity_decode( get_edit_post_link( $post_id ) ); |
346
|
|
|
wp_redirect( $edit_post_link ); |
347
|
|
|
die(); |
348
|
|
|
} |
349
|
|
|
|
350
|
|
|
/** |
351
|
|
|
* Filters whether the post should be considered empty or not. |
352
|
|
|
* |
353
|
|
|
* Empty posts would not be saved to database but it's fine if in |
354
|
|
|
* the context of a content import as it will be populated. |
355
|
|
|
* |
356
|
|
|
* @param bool $empty |
357
|
|
|
* |
358
|
|
|
* @return bool |
359
|
|
|
*/ |
360
|
|
|
public function filter_empty( $empty ) { |
361
|
|
|
if ( ! $this->main->verify_nonce() ) { |
362
|
|
|
return $empty; |
363
|
|
|
} |
364
|
|
|
|
365
|
|
|
if ( ! isset( $_POST['msls_import'] ) ) { |
366
|
|
|
return $empty; |
367
|
|
|
} |
368
|
|
|
|
369
|
|
|
return false; |
370
|
|
|
} |
371
|
|
|
} |
372
|
|
|
|
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 thecomposer.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
orrequire-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 you have not tested against this specific condition, such errors might go unnoticed.