Completed
Branch GDPR/consent (53a229)
by
unknown
75:36 queued 61:02
created

CptQueryModifier::setRequest()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace EventEspresso\core\CPTs;
4
5
use EE_Config;
6
use EE_Error;
7
use EE_Request_Handler;
8
use EE_Secondary_Table;
9
use EE_Table_Base;
10
use EEM_Base;
11
use EEM_CPT_Base;
12
use EventEspresso\core\exceptions\InvalidDataTypeException;
13
use EventEspresso\core\exceptions\InvalidInterfaceException;
14
use EventEspresso\core\services\loaders\LoaderInterface;
15
use EventEspresso\core\services\request\RequestInterface;
16
use InvalidArgumentException;
17
use WP_Post;
18
use WP_Query;
19
20
/**
21
 * Class CptQueryModifier
22
 * Description
23
 *
24
 * @package       Event Espresso
25
 * @subpackage    core
26
 * @author        Brent Christensen
27
 */
28
class CptQueryModifier
29
{
30
31
    /**
32
     * @var string $post_type
33
     */
34
    protected $post_type = '';
35
36
    /**
37
     * CPT details from CustomPostTypeDefinitions for specific post type
38
     *
39
     * @var array $cpt_details
40
     */
41
    protected $cpt_details = array();
42
43
    /**
44
     * @var EE_Table_Base[] $model_tables
45
     */
46
    protected $model_tables = array();
47
48
    /**
49
     * @var array $taxonomies
50
     */
51
    protected $taxonomies = array();
52
53
    /**
54
     * meta table for the related CPT
55
     *
56
     * @var EE_Secondary_Table $meta_table
57
     */
58
    protected $meta_table;
59
60
    /**
61
     * EEM_CPT_Base model for the related CPT
62
     *
63
     * @var EEM_CPT_Base $model
64
     */
65
    protected $model;
66
67
    /**
68
     * @var EE_Request_Handler $request_handler
69
     */
70
    protected $request_handler;
71
72
    /**
73
     * @var WP_Query $wp_query
74
     */
75
    protected $wp_query;
76
77
    /**
78
     * @var LoaderInterface $loader
79
     */
80
    protected $loader;
81
82
    /**
83
     * @var RequestInterface $request
84
     */
85
    protected $request;
86
87
88
    /**
89
     * CptQueryModifier constructor
90
     *
91
     * @param string             $post_type
92
     * @param array              $cpt_details
93
     * @param WP_Query           $WP_Query
94
     * @param EE_Request_Handler $request_handler
95
     * @param RequestInterface   $request
96
     * @param LoaderInterface    $loader
97
     * @throws EE_Error
98
     */
99
    public function __construct(
100
        $post_type,
101
        array $cpt_details,
102
        WP_Query $WP_Query,
103
        EE_Request_Handler $request_handler,
104
        RequestInterface $request,
105
        LoaderInterface $loader
106
    ) {
107
        $this->loader = $loader;
108
        $this->request = $request;
109
        $this->request_handler = $request_handler;
110
        $this->setWpQuery($WP_Query);
111
        $this->setPostType($post_type);
112
        $this->setCptDetails($cpt_details);
113
        $this->init();
114
    }
115
116
117
    /**
118
     * @return string
119
     */
120
    public function postType()
121
    {
122
        return $this->post_type;
123
    }
124
125
126
    /**
127
     * @param string $post_type
128
     */
129
    protected function setPostType($post_type)
130
    {
131
        $this->post_type = $post_type;
132
    }
133
134
135
    /**
136
     * @return array
137
     */
138
    public function cptDetails()
139
    {
140
        return $this->cpt_details;
141
    }
142
143
144
    /**
145
     * @param array $cpt_details
146
     */
147
    protected function setCptDetails($cpt_details)
148
    {
149
        $this->cpt_details = $cpt_details;
150
    }
151
152
153
    /**
154
     * @return EE_Table_Base[]
155
     */
156
    public function modelTables()
157
    {
158
        return $this->model_tables;
159
    }
160
161
162
    /**
163
     * @param EE_Table_Base[] $model_tables
164
     */
165
    protected function setModelTables($model_tables)
166
    {
167
        $this->model_tables = $model_tables;
168
    }
169
170
171
    /**
172
     * @return array
173
     * @throws InvalidArgumentException
174
     * @throws InvalidDataTypeException
175
     * @throws InvalidInterfaceException
176
     */
177
    public function taxonomies()
178
    {
179
        if (empty($this->taxonomies)) {
180
            $this->initializeTaxonomies();
181
        }
182
        return $this->taxonomies;
183
    }
184
185
186
    /**
187
     * @param array $taxonomies
188
     */
189
    protected function setTaxonomies(array $taxonomies)
190
    {
191
        $this->taxonomies = $taxonomies;
192
    }
193
194
195
    /**
196
     * @return EE_Secondary_Table
197
     */
198
    public function metaTable()
199
    {
200
        return $this->meta_table;
201
    }
202
203
204
    /**
205
     * @param EE_Secondary_Table $meta_table
206
     */
207
    public function setMetaTable(EE_Secondary_Table $meta_table)
208
    {
209
        $this->meta_table = $meta_table;
210
    }
211
212
213
    /**
214
     * @return EEM_Base
215
     */
216
    public function model()
217
    {
218
        return $this->model;
219
    }
220
221
222
    /**
223
     * @param EEM_Base $CPT_model
224
     */
225
    protected function setModel(EEM_Base $CPT_model)
226
    {
227
        $this->model = $CPT_model;
0 ignored issues
show
Documentation Bug introduced by
$CPT_model is of type object<EEM_Base>, but the property $model was declared to be of type object<EEM_CPT_Base>. Are you sure that you always receive this specific sub-class here, or does it make sense to add an instanceof check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a given class or a super-class is assigned to a property that is type hinted more strictly.

Either this assignment is in error or an instanceof check should be added for that assignment.

class Alien {}

class Dalek extends Alien {}

class Plot
{
    /** @var  Dalek */
    public $villain;
}

$alien = new Alien();
$plot = new Plot();
if ($alien instanceof Dalek) {
    $plot->villain = $alien;
}
Loading history...
228
    }
229
230
231
    /**
232
     * @deprecated $VID:$
233
     * @return EE_Request_Handler
234
     */
235
    public function request()
236
    {
237
        return $this->request_handler;
238
    }
239
240
241
242
    // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
243
244
245
    /**
246
     * @return WP_Query
247
     */
248
    public function WpQuery()
249
    {
250
        return $this->wp_query;
251
    }
252
    // phpcs:enable
253
254
255
    /**
256
     * @param WP_Query $wp_query
257
     */
258
    public function setWpQuery(WP_Query $wp_query)
259
    {
260
        $this->wp_query = $wp_query;
261
    }
262
263
264
    /**
265
     * @return void
266
     * @throws InvalidDataTypeException
267
     * @throws InvalidInterfaceException
268
     * @throws InvalidArgumentException
269
     */
270
    protected function initializeTaxonomies()
271
    {
272
        // check if taxonomies have already been set and that this CPT has taxonomies registered for it
273
        if (empty($this->taxonomies)
274
            && isset($this->cpt_details['args']['taxonomies'])
275
        ) {
276
            // if so then grab them, but we want the taxonomy name as the key
277
            $taxonomies = array_flip($this->cpt_details['args']['taxonomies']);
278
            // then grab the list of ALL taxonomies
279
            /** @var \EventEspresso\core\domain\entities\custom_post_types\CustomTaxonomyDefinitions
280
             * $taxonomy_definitions
281
             */
282
            $taxonomy_definitions = $this->loader->getShared(
283
                'EventEspresso\core\domain\entities\custom_post_types\CustomTaxonomyDefinitions'
284
            );
285
            $all_taxonomies = $taxonomy_definitions->getCustomTaxonomyDefinitions();
286
            foreach ($taxonomies as $taxonomy => &$details) {
287
                // add details to our taxonomies if they exist
288
                $details = isset($all_taxonomies[ $taxonomy ])
289
                    ? $all_taxonomies[ $taxonomy ]
290
                    : array();
291
            }
292
            // ALWAYS unset() variables that were passed by reference
293
            unset($details);
294
            $this->setTaxonomies($taxonomies);
295
        }
296
    }
297
298
299
    /**
300
     * @since $VID:$
301
     * @throws EE_Error
302
     */
303
    protected function init()
304
    {
305
        $this->setAdditionalCptDetails();
306
        $this->setRequestVarsIfCpt();
307
        // convert post_type to model name
308
        $model_name = str_replace('EE_', '', $this->cpt_details['class_name']);
309
        // load all tables related to CPT
310
        $this->setupModelsAndTables($model_name);
311
        // load and instantiate CPT_*_Strategy
312
        $CPT_Strategy = $this->cptStrategyClass($model_name);
313
        // !!!!!!!!!!  IMPORTANT !!!!!!!!!!!!
314
        // here's the list of available filters in the WP_Query object
315
        // 'posts_where_paged'
316
        // 'posts_groupby'
317
        // 'posts_join_paged'
318
        // 'posts_orderby'
319
        // 'posts_distinct'
320
        // 'post_limits'
321
        // 'posts_fields'
322
        // 'posts_join'
323
        add_filter('posts_fields', array($this, 'postsFields'));
324
        add_filter('posts_join', array($this, 'postsJoin'));
325
        add_filter(
326
            'get_' . $this->post_type . '_metadata',
327
            array($CPT_Strategy, 'get_EE_post_type_metadata'),
328
            1,
329
            4
330
        );
331
        add_filter('the_posts', array($this, 'thePosts'), 1, 1);
332
        if ($this->wp_query->is_main_query()) {
333
            add_filter('get_edit_post_link', array($this, 'getEditPostLink'), 10, 2);
334
            $this->addTemplateFilters();
335
        }
336
    }
337
338
339
    /**
340
     * sets some basic query vars that pertain to the CPT
341
     *
342
     * @access protected
343
     * @return void
344
     */
345
    protected function setAdditionalCptDetails()
346
    {
347
        // the post or category or term that is triggering EE
348
        $this->cpt_details['espresso_page'] = $this->request_handler->is_espresso_page();
349
        // requested post name
350
        $this->cpt_details['post_name'] = $this->request->getRequestParam('post_name');
351
        // add support for viewing 'private', 'draft', or 'pending' posts
352
        if (isset($this->wp_query->query_vars['p'])
353
            && $this->wp_query->query_vars['p'] !== 0
354
            && is_user_logged_in()
355
            && current_user_can('edit_post', $this->wp_query->query_vars['p'])
356
        ) {
357
            // we can just inject directly into the WP_Query object
358
            $this->wp_query->query['post_status'] = array('publish', 'private', 'draft', 'pending');
359
            // now set the main 'ee' request var so that the appropriate module can load the appropriate template(s)
360
            $this->request->setRequestParam('ee', $this->cpt_details['singular_slug']);
361
        }
362
    }
363
364
365
    /**
366
     * Checks if we're on a EE-CPT archive-or-single page, and if we've never set the EE request var.
367
     * If so, sets the 'ee' request variable
368
     * so other parts of EE can know what CPT is getting queried.
369
     * To Mike's knowledge, this must be called from during or after the pre_get_posts hook
370
     * in order for is_archive() and is_single() methods to work properly.
371
     *
372
     * @return void
373
     */
374
    public function setRequestVarsIfCpt()
375
    {
376
        // check if ee action var has been set
377
        if (! $this->request->requestParamIsSet('ee')) {
378
            // check that route exists for CPT archive slug
379
            if (is_archive() && EE_Config::get_route($this->cpt_details['plural_slug'])) {
380
                // ie: set "ee" to "events"
381
                $this->request->setRequestParam('ee', $this->cpt_details['plural_slug']);
382
                // or does it match a single page CPT like /event/
383
            } elseif (is_single() && EE_Config::get_route($this->cpt_details['singular_slug'])) {
384
                // ie: set "ee" to "event"
385
                $this->request->setRequestParam('ee', $this->cpt_details['singular_slug']);
386
            }
387
        }
388
    }
389
390
391
    /**
392
     * setupModelsAndTables
393
     *
394
     * @access protected
395
     * @param string $model_name
396
     * @throws EE_Error
397
     */
398
    protected function setupModelsAndTables($model_name)
399
    {
400
        // get CPT table data via CPT Model
401
        $full_model_name = strpos($model_name, 'EEM_') !== 0
402
            ? 'EEM_' . $model_name
403
            : $model_name;
404
        $model = $this->loader->getShared($full_model_name);
405
        if (! $model instanceof EEM_Base) {
406
            throw new EE_Error(
407
                sprintf(
408
                    __(
409
                        'The "%1$s" model could not be loaded.',
410
                        'event_espresso'
411
                    ),
412
                    $full_model_name
413
                )
414
            );
415
        }
416
        $this->setModel($model);
417
        $this->setModelTables($this->model->get_tables());
418
        $meta_model = $model_name . '_Meta';
419
        // is there a Meta Table for this CPT?
420
        if (isset($this->cpt_details['tables'][ $meta_model ])
421
            && $this->cpt_details['tables'][ $meta_model ] instanceof EE_Secondary_Table
422
        ) {
423
            $this->setMetaTable($this->cpt_details['tables'][ $meta_model ]);
424
        }
425
    }
426
427
428
    /**
429
     * cptStrategyClass
430
     *
431
     * @access protected
432
     * @param  string $model_name
433
     * @return string
434
     */
435
    protected function cptStrategyClass($model_name)
436
    {
437
        // creates classname like:  CPT_Event_Strategy
438
        $CPT_Strategy_class_name = 'EE_CPT_' . $model_name . '_Strategy';
439
        // load and instantiate
440
        $CPT_Strategy = $this->loader->getShared(
441
            $CPT_Strategy_class_name,
442
            array('WP_Query' => $this->wp_query, 'CPT' => $this->cpt_details)
443
        );
444
        if ($CPT_Strategy === null) {
445
            $CPT_Strategy = $this->loader->getShared(
446
                'EE_CPT_Default_Strategy',
447
                array('WP_Query' => $this->wp_query, 'CPT' => $this->cpt_details)
448
            );
449
        }
450
        return $CPT_Strategy;
451
    }
452
453
454
    /**
455
     * postsFields
456
     *
457
     * @access public
458
     * @param  $SQL
459
     * @return string
460
     */
461
    public function postsFields($SQL)
462
    {
463
        // does this CPT have a meta table ?
464
        if ($this->meta_table instanceof EE_Secondary_Table) {
465
            // adds something like ", wp_esp_event_meta.* " to WP Query SELECT statement
466
            $SQL .= ', ' . $this->meta_table->get_table_name() . '.* ';
467
        }
468
        remove_filter('posts_fields', array($this, 'postsFields'));
469
        return $SQL;
470
    }
471
472
473
    /**
474
     * postsJoin
475
     *
476
     * @access public
477
     * @param  $SQL
478
     * @return string
479
     */
480
    public function postsJoin($SQL)
481
    {
482
        // does this CPT have a meta table ?
483
        if ($this->meta_table instanceof EE_Secondary_Table) {
484
            global $wpdb;
485
            // adds something like " LEFT JOIN wp_esp_event_meta ON ( wp_esp_event_meta.EVT_ID = wp_posts.ID ) " to WP Query JOIN statement
486
            $SQL .= ' LEFT JOIN '
487
                    . $this->meta_table->get_table_name()
488
                    . ' ON ( '
489
                    . $this->meta_table->get_table_name()
490
                    . '.'
491
                    . $this->meta_table->get_fk_on_table()
492
                    . ' = '
493
                    . $wpdb->posts
494
                    . '.ID ) ';
495
        }
496
        remove_filter('posts_join', array($this, 'postsJoin'));
497
        return $SQL;
498
    }
499
500
501
    /**
502
     * thePosts
503
     *
504
     * @access public
505
     * @param  WP_Post[] $posts
506
     * @return WP_Post[]
507
     */
508
    public function thePosts($posts)
509
    {
510
        $CPT_class = $this->cpt_details['class_name'];
511
        // loop thru posts
512
        if (is_array($posts) && $this->model instanceof EEM_CPT_Base) {
513
            foreach ($posts as $key => $post) {
514
                if ($post->post_type === $this->post_type) {
515
                    $post->{$CPT_class} = $this->model->instantiate_class_from_post_object($post);
516
                }
517
            }
518
        }
519
        remove_filter('the_posts', array($this, 'thePosts'), 1);
520
        return $posts;
521
    }
522
523
524
    /**
525
     * @param $url
526
     * @param $ID
527
     * @return string
528
     */
529
    public function getEditPostLink($url, $ID)
530
    {
531
        // need to make sure we only edit links if our cpt
532
        global $post;
533
        // notice if the cpt is registered with `show_ee_ui` set to false, we take that to mean that the WordPress core ui
534
        // for interacting with the CPT is desired and there is no EE UI for interacting with the CPT in the admin.
535
        if (! $post instanceof WP_Post
0 ignored issues
show
Bug introduced by
The class WP_Post does not exist. Is this class maybe located in a folder that is not analyzed, or in a newer version of your dependencies than listed in your composer.lock/composer.json?
Loading history...
536
            || $post->post_type !== $this->post_type
537
            || (
538
                isset($this->cpt_details['args']['show_ee_ui'])
539
                && ! $this->cpt_details['args']['show_ee_ui']
540
            )
541
        ) {
542
            return $url;
543
        }
544
        // k made it here so all is good.
545
        return wp_nonce_url(
546
            add_query_arg(
547
                array('page' => $this->post_type, 'post' => $ID, 'action' => 'edit'),
548
                admin_url('admin.php')
549
            ),
550
            'edit',
551
            'edit_nonce'
552
        );
553
    }
554
555
556
    /**
557
     * Execute any template filters.
558
     * This method is only called if in main query.
559
     *
560
     * @return void
561
     */
562
    public function addTemplateFilters()
563
    {
564
        // if requested cpt supports page_templates and it's the main query
565
        if (! empty($this->cpt_details['args']['page_templates']) && $this->wp_query->is_main_query()) {
566
            // then let's hook into the appropriate query_template hook
567
            add_filter('single_template', array($this, 'singleCptTemplate'));
568
        }
569
    }
570
571
572
    /**
573
     * Callback for single_template wp filter.
574
     * This is used to load the set page_template for a single ee cpt if its set.  If "default" then we load the normal
575
     * hierarchy.
576
     *
577
     * @access public
578
     * @param string $current_template Existing default template path derived for this page call.
579
     * @return string the path to the full template file.
580
     */
581
    public function singleCptTemplate($current_template)
582
    {
583
        $object = get_queried_object();
584
        // does this called object HAVE a page template set that is something other than the default.
585
        $template = get_post_meta($object->ID, '_wp_page_template', true);
586
        // exit early if default or not set or invalid path (accounts for theme changes)
587
        if ($template === 'default'
588
            || empty($template)
589
            || ! is_readable(get_stylesheet_directory() . '/' . $template)
590
        ) {
591
            return $current_template;
592
        }
593
        // made it here so we SHOULD be able to just locate the template and then return it.
594
        return locate_template(array($template));
595
    }
596
}
597