PluginProbe ʕ •ᴥ•ʔ
Nested Pages / 3.2.15
Nested Pages v3.2.15
3.2.15 3.2.14 3.1.8 3.1.9 3.2.0 3.2.1 3.2.10 3.2.11 3.2.12 3.2.13 3.2.2 3.2.3 3.2.4 3.2.5 3.2.6 3.2.7 3.2.8 3.2.9 trunk 1.0 1.1 1.1.1 1.1.2 1.1.3 1.1.4 1.1.5 1.1.6 1.1.7 1.1.8 1.1.9 1.2.0 1.2.1 1.3.0 1.3.1 1.3.10 1.3.11 1.3.12 1.3.13 1.3.14 1.3.15 1.3.2 1.3.4 1.3.5 1.3.6 1.3.7 1.3.8 1.3.9 1.4.0 1.4.1 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.6.0 1.6.1 1.6.2 1.6.3 1.6.3.1 1.6.3.2 1.6.4 1.6.5 1.6.5.1 1.6.5.2 1.6.6 1.6.7 1.6.8 1.7.0 1.7.1 2.0.1 2.0.2 2.0.3 2.0.4 3.0.1 3.0.10 3.0.11 3.0.2 3.0.3 3.0.4 3.0.5 3.0.6 3.0.7 3.0.8 3.0.9 3.1.0 3.1.1 3.1.10 3.1.11 3.1.12 3.1.13 3.1.14 3.1.15 3.1.16 3.1.17 3.1.18 3.1.19 3.1.2 3.1.20 3.1.21 3.1.22 3.1.3 3.1.4 3.1.5 3.1.6 3.1.7
wp-nested-pages / app / Entities / Listing / Listing.php
wp-nested-pages / app / Entities / Listing Last commit date
Listing.php 2 years ago ListingActions.php 8 years ago ListingQuery.php 3 years ago ListingRepository.php 2 days ago
Listing.php
489 lines
1 <?php
2 namespace NestedPages\Entities\Listing;
3
4 use NestedPages\Helpers;
5 use NestedPages\Entities\Confirmation\ConfirmationFactory;
6 use NestedPages\Entities\Post\PostDataFactory;
7 use NestedPages\Entities\Post\PostRepository;
8 use NestedPages\Entities\User\UserRepository;
9 use NestedPages\Entities\PostType\PostTypeRepository;
10 use NestedPages\Entities\Listing\ListingRepository;
11 use NestedPages\Entities\Listing\ListingQuery;
12 use NestedPages\Config\SettingsRepository;
13 use NestedPages\Entities\PluginIntegration\IntegrationFactory;
14 use NestedPages\Entities\PostType\PostTypeCustomFields;
15
16 /**
17 * Primary Post Listing
18 */
19 class Listing
20 {
21 /**
22 * Post Type
23 * @var object WP Post Type Object
24 */
25 private $post_type;
26
27 /**
28 * Query Results
29 * @var array of post objects (WP Query)
30 */
31 private $all_posts;
32
33 /**
34 * Hierarchical Taxonomies
35 * @var array
36 */
37 private $h_taxonomies;
38
39 /**
40 * Flat Taxonomies
41 * @var array
42 */
43 private $f_taxonomies;
44
45 /**
46 * Post Data Factory
47 */
48 private $post_data_factory;
49
50 /**
51 * Post Data
52 * @var object
53 */
54 private $post;
55
56 /**
57 * Post Repository
58 */
59 private $post_repo;
60
61 /**
62 * Post Type Repository
63 */
64 private $post_type_repo;
65
66 /**
67 * Listing Repository
68 */
69 private $listing_repo;
70
71 /**
72 * Listing Query
73 */
74 private $listing_query;
75
76 /**
77 * Confirmation Factory
78 */
79 private $confirmation;
80
81 /**
82 * User Repository
83 */
84 private $user;
85
86 /**
87 * Settings Repository
88 */
89 private $settings;
90
91 /**
92 * Custom Field Repository
93 */
94 private $custom_fields_repo;
95
96 /**
97 * Post Type Settings
98 * @var object from post type repo
99 */
100 private $post_type_settings;
101
102 /**
103 * Assigned Pages for post types
104 * @var array from post type repo
105 */
106 private $assigned_pt_pages;
107
108 /**
109 * Plugin Integrations
110 */
111 private $integrations;
112
113 /**
114 * Disabled Standard Fields
115 */
116 private $disabled_standard_fields;
117
118 /**
119 * Sticky Posts
120 * @var array
121 */
122 private $sticky_posts;
123
124 /**
125 * User status preference
126 * @var array
127 */
128 private $status_preference;
129
130 /**
131 * User can perform bulk actions
132 */
133 private $can_user_perform_bulk_actions;
134
135 /**
136 * Enabled Custom Fields
137 */
138 private $enabled_custom_fields;
139
140 public function __construct($post_type)
141 {
142 $this->setPostType($post_type);
143 $this->setStickyPosts();
144 $this->integrations = new IntegrationFactory;
145 $this->post_repo = new PostRepository;
146 $this->user = new UserRepository;
147 $this->confirmation = new ConfirmationFactory;
148 $this->post_type_repo = new PostTypeRepository;
149 $this->listing_repo = new ListingRepository;
150 $this->listing_query = new ListingQuery;
151 $this->post_data_factory = new PostDataFactory;
152 $this->settings = new SettingsRepository;
153 $this->custom_fields_repo = new PostTypeCustomFields;
154 $this->setTaxonomies();
155 $this->setPostTypeSettings();
156 $this->setStandardFields();
157 $this->setStatusPreference();
158 $this->setCanUserPerformBulkActions();
159 }
160
161 /**
162 * Called by Menu Class
163 * Instantiates Listing Class
164 * @since 1.2.0
165 */
166 public static function admin_menu($post_type)
167 {
168 $classinstance = new \NestedPages\Entities\Listing\Listing($post_type);
169 return [&$classinstance, "listPosts"];
170 }
171
172 /**
173 * Get the Current Page URL
174 */
175 private function pageURL()
176 {
177 $base = ( $this->post_type->name == 'post' ) ? admin_url('edit.php') : admin_url('admin.php');
178 return $base . '?page=' . sanitize_text_field($_GET['page']);
179 }
180
181 /**
182 * Set the Post Type
183 * @since 1.1.16
184 */
185 private function setPostType($post_type)
186 {
187 $this->post_type = get_post_type_object($post_type);
188 }
189
190 /**
191 * Set the Sticky Posts
192 * @since 2.0.1
193 */
194 private function setStickyPosts()
195 {
196 $this->sticky_posts = get_option('sticky_posts');
197 if ( !$this->sticky_posts ) $this->sticky_posts = [];
198 }
199
200 /**
201 * Set the Post Type Settings
202 * @since 1.6.9
203 */
204 private function setPostTypeSettings()
205 {
206 $this->post_type_settings = $this->post_type_repo->getSinglePostType($this->post_type->name);
207 $this->assigned_pt_pages = $this->post_type_repo->getAssignedPages();
208 }
209
210 /**
211 * Set the Quick Edit Field Options
212 */
213 private function setStandardFields()
214 {
215 // The standard fields checkbox is explicitly not set
216 if ( isset($this->post_type_settings->standard_fields_enabled) && !$this->post_type_settings->standard_fields_enabled ){
217 $this->disabled_standard_fields = [];
218 return;
219 }
220
221 if ( isset($this->post_type_settings->standard_fields) && is_array($this->post_type_settings->standard_fields) ){
222 $this->disabled_standard_fields = $this->post_type_settings->standard_fields;
223 foreach ( $this->post_type_settings->standard_fields as $key => $fields ){
224 if ( $key == 'standard' ) $this->disabled_standard_fields = $fields;
225 }
226 return;
227 }
228 $this->disabled_standard_fields = [];
229 return;
230 }
231
232 /**
233 * Get the Post States
234 */
235 private function postStates($assigned_pt)
236 {
237 $out = '';
238 $post_states = [];
239 if ( !$assigned_pt ) {
240 if ( $this->post->id == get_option('page_on_front') ) $post_states['page_on_front'] = '&ndash; ' . __('Front Page', 'wp-nested-pages');
241 if ( $this->post->id == get_option('page_for_posts') ) $post_states['page_for_posts'] = '&ndash; ' . __('Posts Page', 'wp-nested-pages');
242 }
243 $post_states = apply_filters('display_post_states', $post_states, $this->post);
244 if ( empty($post_states) ) return $out;
245 $state_count = count($post_states);
246 $i = 0;
247 foreach ( $post_states as $state ) {
248 ++$i;
249 ( $i == $state_count ) ? $sep = '' : $sep = ',';
250 $out .= " <em class='np-page-type'><strong>$state</strong>$sep</em>";
251 }
252 return $out;
253 }
254
255 /**
256 * Row Actions
257 * Adds assigned pt actions as well as any custom actions registered through page_row_actions filter
258 */
259 private function rowActions($assigned_pt)
260 {
261 $actions = [];
262 if ( $assigned_pt ) {
263 if ( current_user_can('publish_posts') ) $actions['add_new'] = '<a href="' . $this->post_type_repo->addNewPostLink($assigned_pt->name) . '">' . $assigned_pt->labels->add_new . '</a>';
264 $actions['view_all'] = '<a href="' . $this->post_type_repo->allPostsLink($assigned_pt->name) . '">' . $assigned_pt->labels->all_items . ' (' . $this->listing_repo->postCount($assigned_pt->name) . ')</a>';
265 }
266 $actions = apply_filters('post_row_actions', $actions, $this->post);
267 if ( $this->post_type->name == 'page' ) $actions = apply_filters('page_row_actions', $actions, $this->post);
268 if ( empty($actions) ) return null;
269 $out = '<ul class="np-assigned-pt-actions">';
270 foreach ( $actions as $key => $action ){
271 $out .= '<li class="' . $key;
272 if ( $key == 'add_new' || $key == 'view_all' ) $out .= ' visible';
273 $out .= '">' . $action . '</li>';
274 }
275 $out .= '</ul>';
276 return $out;
277 }
278
279 /**
280 * The Main View
281 * Replaces Default Post Listing
282 */
283 public function listPosts()
284 {
285 include( Helpers::view('listing') );
286 }
287
288 /**
289 * Set the Taxonomies for Post Type
290 */
291 private function setTaxonomies()
292 {
293 $this->h_taxonomies = $this->post_type_repo->getTaxonomies($this->post_type->name, true);
294 $this->f_taxonomies = $this->post_type_repo->getTaxonomies($this->post_type->name, false);
295 }
296
297 /**
298 * Set if the user can perform bulk actions
299 */
300 private function setCanUserPerformBulkActions()
301 {
302 $this->can_user_perform_bulk_actions = $this->user->canPerformBulkActions($this->post_type_settings);
303 }
304
305 /**
306 * Set the user status preference
307 */
308 private function setStatusPreference()
309 {
310 $this->status_preference = $this->user->getStatusPreference($this->post_type->name);
311 }
312
313 /**
314 * Opening list tag <ol>
315 * @param array $pages - array of page objects from current query
316 * @param int $count - current count in loop
317 */
318 private function listOpening($pages, $count, $sortable = true)
319 {
320 if ( $this->listing_repo->isSearch() ) $sortable = false;
321 if ( $this->post_type_settings->disable_sorting ) $sortable = false;
322
323 // Get array of child pages
324 $children = [];
325 $all_children = $pages;
326 foreach($all_children as $child){
327 array_push($children, $child->ID);
328 }
329 // Compare child pages with user's toggled pages
330 $compared = array_intersect($this->listing_repo->visiblePages($this->post_type->name), $children);
331
332 $list_classes = 'sortable visible nplist';
333 if ( !$this->user->canSortPosts($this->post_type->name) || !$sortable || $this->listing_repo->isSearch() ) $list_classes .= ' no-sort';
334 if ( $this->listing_repo->isOrdered($this->post_type->name) ) $list_classes .= ' no-sort';
335 if ( $this->integrations->plugins->wpml->installed && $this->integrations->plugins->wpml->getCurrentLanguage() == 'all' ) $list_classes .= ' no-sort';
336 if ( $this->integrations->plugins->yoast->installed ) $list_classes .= ' has-yoast';
337 if ( $this->listing_repo->isSearch() ) $list_classes .= ' np-search-results';
338 if ( $this->settings->nonIndentEnabled() ) $list_classes .= ' non-indent';
339
340 // Primary List
341 if ( $count == 0 ) {
342 if ( $this->can_user_perform_bulk_actions ) {
343 include( Helpers::view('partials/list-header') ); // List Header
344 include( Helpers::view('partials/bulk-edit') ); // Bulk Edit
345 }
346 echo '<ol class="' . $list_classes . '" id="np-' . $this->post_type->name . '">';
347 return;
348 }
349
350 echo '<ol class="nplist';
351 if ( count($compared) > 0 ) echo ' visible" style="display:block;';
352 echo '" id="np-' . $this->post_type->name . '">';
353 }
354
355 /**
356 * Set Post Data
357 * @param object post object
358 */
359 private function setPost($post)
360 {
361 $this->post = $this->post_data_factory->build($post, $this->h_taxonomies, $this->f_taxonomies);
362 }
363
364 /**
365 * Get count of published child posts
366 * @param object $post
367 */
368 private function publishedChildrenCount($post)
369 {
370 $publish_count = 0;
371 foreach ( $this->all_posts as $p ){
372 if ( $p->post_parent == $post->id && $p->post_status !== 'trash' ) $publish_count++;
373 }
374 return $publish_count;
375 }
376
377 /**
378 * Loop through all the pages and create the nested / sortable list
379 * Called in listing.php view
380 */
381 private function getPosts()
382 {
383 $this->all_posts = $this->listing_query->getPosts($this->post_type, $this->h_taxonomies, $this->f_taxonomies);
384 $this->listPostLevel();
385 return;
386 }
387
388 /**
389 * List a single tree node of posts
390 */
391 private function listPostLevel($parent = 0, $count = 0, $level = 1)
392 {
393 $wpml = $this->integrations->plugins->wpml->installed;
394 $wpml_current_language = null;
395 if ( $wpml ) $wpml_current_language = $this->integrations->plugins->wpml->getCurrentLanguage();
396
397 if ( $this->listing_repo->isFiltered() ){
398 $parent_status = null;
399 $pages = $this->all_posts;
400 $level++;
401 echo '<ol class="sortable nplist visible filtered">';
402 } elseif ( !$this->listing_repo->isSearch() ) {
403 $pages = get_page_children($parent, $this->all_posts);
404 if ( !$pages ) return;
405 $parent_status = get_post_status($parent);
406 $level++;
407 if ( $parent_status !== 'trash' ) $this->listOpening($pages, $count);
408 } else {
409 $parent_status = null;
410 $pages = $this->all_posts;
411 echo '<ol class="sortable no-sort nplist visible">';
412 }
413 if ( !$pages ) return;
414
415 foreach($pages as $page) :
416
417 if ( $page->post_parent !== $parent && !$this->listing_repo->isSearch() && !$this->listing_repo->isFiltered() ) continue;
418 $count++;
419
420 global $post;
421 $post = $page;
422 $this->setPost($post);
423
424 if ( $this->post->status !== 'trash' ) :
425
426 $row_parent_classes = 'page-row';
427 // Post Type
428 $row_parent_classes .= ' post-type-' . esc_attr($this->post->post_type);
429
430 // Managed Post Type page?
431 if ( $this->listing_repo->isAssignedPostType($this->post->id, $this->assigned_pt_pages) ) $row_parent_classes .= ' is-page-assignment';
432
433 // Published?
434 if ( $this->post->status == 'publish' ) $row_parent_classes .= ' published';
435 if ( $this->post->status == 'draft' ) $row_parent_classes .= ' draft';
436
437 // Hidden in Nested Pages?
438 if ( $this->post->np_status == 'hide' ) $row_parent_classes .= ' np-hide';
439
440 // User Status Preference
441 if ( $this->status_preference == 'published' && $this->post->status == 'draft' ) $row_parent_classes .= ' np-hide';
442 if ( $this->status_preference == 'draft' && $this->post->status !== 'draft' ) $row_parent_classes .= ' np-hide';
443
444 // Taxonomies
445 $row_parent_classes .= ' ' . $this->post_repo->getTaxonomyCSS($this->post, $this->h_taxonomies, $this->f_taxonomies);
446
447 echo '<li id="menuItem_' . esc_attr($this->post->id) . '" class="' . apply_filters('nestedpages_row_parent_css_classes', $row_parent_classes, $this->post, $this->post_type) . '">';
448
449 $count++;
450
451 $row_view = ( $this->post->type !== 'np-redirect' ) ? 'partials/row' : 'partials/row-link';
452
453 // CSS Classes for the <li> row element
454 $template = ( $this->post->template )
455 ? ' tpl-' . sanitize_html_class( str_replace('.php', '', $this->post->template ) )
456 : '';
457
458 $row_classes = '';
459 if ( !$this->post_type->hierarchical ) $row_classes .= ' non-hierarchical';
460 if ( !$this->user->canSortPosts($this->post_type->name) ) $row_classes .= ' no-sort';
461 if ( $wpml_current_language == 'all' ) $row_classes .= ' no-sort';
462 if ( $this->listing_repo->isSearch() || $this->listing_repo->isOrdered($this->post_type->name) ) $row_classes .= ' search';
463 if ( $this->post->template ) $row_classes .= $template;
464
465 // Filter sortable per post
466 $filtered_sortable = apply_filters('nestedpages_post_sortable', true, $this->post, $this->post_type);
467 if ( !$filtered_sortable && $this->user->canSortPosts($this->post_type->name) && $this->post_type->hierarchical && !$wpml_current_language ) $row_classes .= ' no-sort-filtered';
468
469 // Page Assignment for Post Type
470 $assigned_pt = ( $this->listing_repo->isAssignedPostType($this->post->id, $this->assigned_pt_pages) )
471 ? $this->listing_repo->assignedPostType($this->post->id, $this->assigned_pt_pages)
472 : false;
473
474 include( Helpers::view($row_view) );
475
476 endif; // trash status
477
478 if ( !$this->listing_repo->isSearch() && !$this->listing_repo->isFiltered() ) $this->listPostLevel($page->ID, $count, $level);
479
480 if ( $this->post->status !== 'trash' ) echo '</li>';
481
482 if ( $this->publishedChildrenCount($this->post) > 0 && !$this->listing_repo->isSearch() && !$this->listing_repo->isFiltered() ) echo '</ol>';
483
484 endforeach; // Loop
485
486 if ( $parent_status !== 'trash' ) echo '</ol><!-- list close -->';
487 }
488 }
489