PluginProbe
Adminify – White Label, Admin Menu Editor, Login Customizer / 4.0.5.4
Adminify – White Label, Admin Menu Editor, Login Customizer v4.0.5.4
4.3.2 4.3.1 4.3.0 4.2.26 4.2.25 4.2.24 4.2.23 4.2.22 4.2.21 4.2.20 4.2.19 4.2.18 4.2.17 4.2.16 4.2.15 4.2.14 4.2.13 4.2.12 4.2.11 4.2.10 4.2.9 4.2.8 4.2.7 4.2.6 4.2.5 All 165 releases
← All changes | Inc/Modules/Folders/Folders.php +782 -1005 4.3.24.0.5.4 View file →
@@ -1,358 +1,246 @@
1 1 <?php
2 2
3 -namespace PXLBSAdminify\Inc\Modules\Folders;
3 +namespace WPAdminify\Inc\Modules\Folders;
4 4
5 -use PXLBSAdminify\Inc\Utils;
6 -use PXLBSAdminify\Inc\Admin\AdminSettings;
7 -
8 -if ( ! defined( 'ABSPATH' ) ) {
9 - exit;
5 +use WPAdminify\Inc\Utils;
6 +use WPAdminify\Inc\Admin\AdminSettings;
7 +if ( !defined( 'ABSPATH' ) ) {
8 + exit;
10 9 }
11 -
12 10 class Folders {
13 - private static $postIds;
14 - public $options;
11 + private static $postIds;
15 12
16 - public function __construct() {
17 - $this->options = (array) AdminSettings::get_instance()->get('folders');
13 + public $options;
18 14
19 - add_action( 'init', [ $this, 'register_folders_terms' ], 999 );
15 + public function __construct() {
16 + $this->options = (array) AdminSettings::get_instance()->get( 'folders' );
17 + $needed_keys = ['user_roles', 'enable_for', 'media'];
18 + add_action( 'init', [$this, 'register_folders_terms'], 999 );
19 + add_action( 'admin_footer', [$this, 'add_footer_markup'] );
20 + add_action( 'admin_enqueue_scripts', [$this, 'enqueue_scripts'], PHP_INT_MAX );
21 + add_action( 'wp_ajax_adminify_folder', [$this, 'handle_adminify_folder'] );
22 + add_action( 'ajax_query_attachments_args', [$this, 'filter_grid'] );
23 + add_filter( 'pre_get_posts', [$this, 'filter_list'] );
24 + add_action( 'admin_init', [$this, 'modify_columns_actions'] );
25 + add_action( 'print_media_templates', [$this, 'modify_media_templates'] );
26 + add_filter( 'wp_prepare_attachment_for_js', [$this, 'modify_attachment_for_js'] );
27 + add_action( 'pre-upload-ui', [$this, 'wp_adminify_select_folder_when_upload'] );
28 + add_filter(
29 + 'attachment_fields_to_edit',
30 + [$this, 'wp_adminify_edit_attachment_fields'],
31 + 25,
32 + 2
33 + );
34 + add_action( 'wp_ajax_wp_adminify_assign_media_folder', array($this, 'wp_adminify_handle_folder_assignment') );
35 + add_action( 'restrict_manage_posts', [$this, 'wp_adminify_show_folders_in_list_filter'] );
36 + add_action( 'add_attachment', [$this, 'wp_adminify_assign_media_folder_to_new_attachment'] );
37 + add_action( 'enqueue_block_editor_assets', [$this, 'enqueue_scripts_for_media_uploads'], PHP_INT_MAX );
38 + }
20 39
21 - add_action( 'admin_footer', [ $this, 'add_footer_markup' ] );
40 + public function modify_attachment_for_js( $response ) {
41 + if ( !(bool) $this->options['media'] ) {
42 + return $response;
43 + }
44 + $folders = wp_get_post_terms( $response['id'], 'media_folder' );
45 + $folder_ids = wp_list_pluck( $folders, 'term_id' );
46 + $response['media_folder'] = implode( ',', $folder_ids );
47 + return $response;
48 + }
22 49
23 - add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_scripts' ], PHP_INT_MAX );
50 + public function get_post_types() {
51 + $post_types = get_post_types( [
52 + 'public' => true,
53 + ] );
54 + // @todo add more configurations here
55 + return $post_types;
56 + }
24 57
25 - add_action( 'wp_ajax_pxlbsadminify_folder', [ $this, 'handle_adminify_folder' ] );
58 + public function filter_list( $query ) {
59 + global $typenow;
60 + global $pagenow;
61 + $post_type = $typenow;
62 + if ( empty( $post_type ) ) {
63 + if ( $pagenow == 'edit.php' ) {
64 + $post_type = 'post';
65 + } elseif ( $pagenow == 'upload.php' ) {
66 + $post_type = 'attachment';
67 + }
68 + }
69 + if ( !isset( $query->query['post_type'] ) ) {
70 + return $query;
71 + }
72 + $taxonomy = self::get_post_type_taxonomy( $post_type );
73 + if ( !isset( $_REQUEST[$taxonomy] ) ) {
74 + return $query;
75 + }
76 + $term = sanitize_text_field( wp_unslash( $_REQUEST[$taxonomy] ) );
77 + if ( $term != '-1' ) {
78 + return $query;
79 + }
80 + unset($query->query_vars[$taxonomy]);
81 + $tax_query = [
82 + 'taxonomy' => $taxonomy,
83 + 'operator' => __( 'NOT EXISTS', 'adminify' ),
84 + ];
85 + $query->set( 'tax_query', [$tax_query] );
86 + $query->tax_query = new \WP_Tax_Query([$tax_query]);
87 + return $query;
88 + }
26 89
27 - add_action( 'ajax_query_attachments_args', [ $this, 'filter_grid' ] );
90 + public function filter_grid( $args ) {
91 + $taxonomy = self::get_post_type_taxonomy( 'attachment' );
92 + if ( !isset( $args[$taxonomy] ) ) {
93 + return $args;
94 + }
95 + $term = sanitize_text_field( $args[$taxonomy] );
96 + if ( $term != '-1' ) {
97 + return $args;
98 + }
99 + unset($args[$taxonomy]);
100 + $args['tax_query'] = [[
101 + 'taxonomy' => $taxonomy,
102 + 'operator' => __( 'NOT EXISTS', 'adminify' ),
103 + ]];
104 + return $args;
105 + }
28 106
29 - add_filter( 'pre_get_posts', [ $this, 'filter_list' ] );
107 + public function is_module_active( $post_type = null ) {
108 + $current_screen = get_current_screen();
109 + if ( empty( $current_screen->base ) || !in_array( $current_screen->base, ['upload', 'edit', 'media'] ) ) {
110 + return false;
111 + }
112 + if ( $current_screen->base === 'media' && $current_screen->action === 'add' ) {
113 + $post_type = 'attachment';
114 + }
115 + if ( empty( $post_type ) ) {
116 + if ( empty( $post_type = $current_screen->post_type ) ) {
117 + return false;
118 + }
119 + }
120 + if ( $post_type == 'attachment' ) {
121 + return (bool) $this->options['media'];
122 + }
123 + $default_post_types = ['post', 'page'];
124 + $folders_enable_for = (array) $this->options['enable_for'];
125 + $folders_enable_for = array_intersect( $folders_enable_for, $default_post_types );
126 + if ( in_array( $post_type, $folders_enable_for ) ) {
127 + return true;
128 + }
129 + return false;
130 + }
30 131
31 - add_action( 'admin_init', [ $this, 'modify_columns_actions' ] );
132 + public function add_footer_markup() {
133 + if ( $this->is_module_active() ) {
134 + echo '</div><div id="wp-adminify--folder-app"></div>';
135 + }
136 + }
32 137
33 - add_action( 'print_media_templates', [ $this, 'modify_media_templates' ] );
138 + public function get_uncategorized_posts( $post_type ) {
139 + global $wpdb;
140 + $post_table = $wpdb->prefix . 'posts';
141 + $term_table = $wpdb->prefix . 'term_relationships';
142 + $term_taxonomy_table = $wpdb->prefix . 'term_taxonomy';
143 + $post_type_tax = self::get_post_type_taxonomy( $post_type );
144 + if ( $post_type != 'attachment' ) {
145 + $query = "SELECT COUNT(DISTINCT({$post_table}.ID)) AS total_records FROM {$post_table} WHERE 1=1 AND (\n NOT EXISTS (\n SELECT 1\n FROM {$term_table}\n INNER JOIN {$term_taxonomy_table}\n ON {$term_taxonomy_table}.term_taxonomy_id = {$term_table}.term_taxonomy_id\n WHERE {$term_taxonomy_table}.taxonomy = '%s'\n AND {$term_table}.object_id = {$post_table}.ID\n )\n ) AND {$post_table}.post_type = '%s' AND (({$post_table}.post_status = 'publish' OR {$post_table}.post_status = 'future' OR {$post_table}.post_status = 'draft' OR {$post_table}.post_status = 'private'))";
146 + } else {
147 + $query = "SELECT COUNT(DISTINCT({$post_table}.ID)) AS total_records FROM {$post_table} WHERE 1=1 AND (\n NOT EXISTS (\n SELECT 1\n FROM {$term_table}\n INNER JOIN {$term_taxonomy_table}\n ON {$term_taxonomy_table}.term_taxonomy_id = {$term_table}.term_taxonomy_id\n WHERE {$term_taxonomy_table}.taxonomy = '%s'\n AND {$term_table}.object_id = {$post_table}.ID\n )\n ) AND {$post_table}.post_type = '%s' AND {$post_table}.post_status = 'inherit'";
148 + }
149 + $query = $wpdb->prepare( $query, $post_type_tax, $post_type );
150 + $total = $wpdb->get_var( $query );
151 + return ( empty( $total ) ? 0 : $total );
152 + }
34 153
35 - add_filter( 'wp_prepare_attachment_for_js', [ $this, 'modify_attachment_for_js' ] );
36 -
37 - add_action( 'pre-upload-ui', [ $this, 'select_folder_when_upload' ] );
154 + public function get_folders( $post_type, $post_type_tax ) {
155 + $folders = get_terms( $post_type_tax, [
156 + 'hide_empty' => false,
157 + 'pad_counts' => true,
158 + ] );
159 + if ( is_wp_error( $folders ) ) {
160 + return [];
161 + }
162 + foreach ( $folders as $folder ) {
163 + $posts = $this->get_posts_by_folder( $folder->term_id, $post_type, $post_type_tax );
164 + $color = get_term_meta( $folder->term_id, '_wp_adminify_fodler_color', true );
165 + if ( empty( $color ) ) {
166 + $color = '';
167 + }
168 + $folder->color = $color;
169 + $folder->count = count( $posts );
170 + $folder->posts = $posts;
171 + }
172 + return $folders;
173 + }
38 174
39 - add_action('wp_ajax_pxlbsadminify_assign_media_folder', array($this, 'handle_folder_assignment'));
40 -
41 - add_action( 'restrict_manage_posts', [$this, 'show_folders_in_list_filter'] );
42 -
43 - add_action( 'add_attachment', [$this ,'assign_media_folder_to_new_attachment'] );
44 -
45 - if ( ! empty( $this->options['media'] )) {
46 - add_filter( 'attachment_fields_to_edit', [$this, 'edit_attachment_fields'], 25, 2 );
47 -
48 - add_action( 'enqueue_block_editor_assets', [ $this, 'enqueue_scripts_for_media_uploads' ], PHP_INT_MAX );
49 - add_action( 'customize_controls_print_footer_scripts', [ $this, 'add_adminify_body_class' ] );
50 - add_action( 'customize_controls_enqueue_scripts', [ $this, 'enqueue_scripts_for_media_uploads' ], PHP_INT_MAX );
51 -
52 - // Elementor editor support
53 - add_action( 'elementor/editor/footer', [ $this, 'add_adminify_body_class' ] );
54 - add_action( 'elementor/editor/before_enqueue_scripts', [ $this, 'enqueue_scripts_for_media_uploads' ], PHP_INT_MAX );
55 -
56 - // Classic editor support (post/page/CPT edit screens without Gutenberg)
57 - add_action( 'admin_enqueue_scripts', [ $this, 'maybe_enqueue_for_classic_editor' ], PHP_INT_MAX );
58 - }
59 - }
60 -
61 - /**
62 - * Enqueue folder scripts for classic editor (non-Gutenberg) post edit screens
63 - */
64 - public function maybe_enqueue_for_classic_editor( $hook ) {
65 - // Only on post edit screens
66 - if ( ! in_array( $hook, [ 'post.php', 'post-new.php' ], true ) ) {
67 - return;
68 - }
69 -
70 - // Skip if Gutenberg/block editor is active for this post type
71 - $current_screen = get_current_screen();
72 - if ( $current_screen && method_exists( $current_screen, 'is_block_editor' ) && $current_screen->is_block_editor() ) {
73 - return;
74 - }
75 -
76 - $this->enqueue_scripts_for_media_uploads();
77 -
78 - // Add classic editor body class for CSS scoping
79 - add_action( 'admin_footer', function() {
80 - echo '<script>document.body.classList.add("wp-adminify-classic-editor");</script>';
81 - });
82 - }
83 -
84 - /**
85 - * Add wp-adminify class to body
86 - * Required for folder widget CSS to work in media modal (Elementor, Customizer, etc.)
87 - */
88 - public function add_adminify_body_class() {
89 - ?>
90 - <script>
91 - document.body.classList.add('wp-adminify');
92 - </script>
93 - <?php
94 - }
95 -
96 - public function modify_attachment_for_js( $response ) {
97 - if ( ! (bool) $this->options['media'] ) return $response;
98 -
99 - $folders = wp_get_post_terms( $response['id'], 'media_folder' );
100 - $folder_ids = wp_list_pluck( $folders, 'term_id' );
101 - $response['media_folder'] = implode(',', $folder_ids);
102 -
103 - return $response;
104 - }
105 -
106 - public function get_post_types() {
107 - $post_types = get_post_types(
108 - [
109 - 'public' => true,
110 - ]
111 - );
112 -
113 - return $post_types;
114 - }
115 -
116 - public function filter_list( $query ) {
117 - global $typenow, $pagenow;
118 -
119 - $post_type = $typenow;
120 - if ( empty( $post_type ) ) {
121 - if ( $pagenow == 'edit.php' ) {
122 - $post_type = 'post';
123 - } elseif ( $pagenow == 'upload.php' ) {
124 - $post_type = 'attachment';
125 - }
126 - }
127 -
128 - if ( ! isset( $query->query['post_type'] ) ) {
129 - return $query;
130 - }
131 -
132 - $taxonomy = self::get_post_type_taxonomy( $post_type );
133 -
134 - // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only check, no state change.
135 - if ( ! isset( $_REQUEST[ $taxonomy ] ) ) {
136 - return $query;
137 - }
138 -
139 - // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only check, no state change.
140 - $term = sanitize_text_field( wp_unslash( $_REQUEST[ $taxonomy ] ) );
141 -
142 - if ( $term != '-1' ) {
143 - return $query;
144 - }
145 -
146 - unset( $query->query_vars[ $taxonomy ] );
147 -
148 - $tax_query = [
149 - 'taxonomy' => $taxonomy,
150 - 'operator' => __( 'NOT EXISTS', 'adminify' ),
151 - ];
152 -
153 - $query->set( 'tax_query', [ $tax_query ] );
154 - $query->tax_query = new \WP_Tax_Query( [ $tax_query ] );
155 -
156 - return $query;
157 - }
158 -
159 - public function filter_grid( $args ) {
160 - $taxonomy = self::get_post_type_taxonomy( 'attachment' );
161 -
162 - if ( ! isset( $args[ $taxonomy ] ) ) {
163 - return $args;
164 - }
165 -
166 - $term = sanitize_text_field( $args[ $taxonomy ] );
167 -
168 - if ( $term != '-1' ) {
169 - return $args;
170 - }
171 -
172 - unset( $args[ $taxonomy ] );
173 -
174 - $args['tax_query'] = [ // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query -- intentional taxonomy filter on an admin-side query.
175 - [
176 - 'taxonomy' => $taxonomy,
177 - 'operator' => __( 'NOT EXISTS', 'adminify' ),
178 - ],
179 - ];
180 -
181 - return $args;
182 - }
183 -
184 - public function is_module_active( $post_type = null ) {
185 - $current_screen = get_current_screen();
186 - if ( empty( $current_screen->base ) || ! in_array( $current_screen->base, [ 'upload', 'edit', 'media' ] ) ) {
187 - return false;
188 - }
189 - if($current_screen->base === 'media' && $current_screen->action === 'add'){
190 - $post_type = 'attachment';
191 - }
192 -
193 - if ( empty( $post_type ) ) {
194 - if ( empty( $post_type = $current_screen->post_type ) ) {
195 - return false;
196 - }
197 - }
198 -
199 -
200 - if ( $post_type == 'attachment' ) {
201 - return (bool) $this->options['media'];
202 - }
203 -
204 - $default_post_types = [ 'post', 'page' ];
205 - $folders_enable_for = (array) $this->options['enable_for'];
206 -
207 - if ( ! jltwp_adminify()->can_use_premium_code() ) {
208 - $folders_enable_for = array_intersect( $folders_enable_for, $default_post_types );
209 - }
210 -
211 - if ( in_array( $post_type, $folders_enable_for ) ) {
212 - return true;
213 - }
214 -
215 - return false;
216 - }
217 -
218 - // Add folder app markup in footer but move it to wpbody
219 - public function add_footer_markup() {
220 - if ( $this->is_module_active() ) {
221 - ?>
222 - <div id="wp-adminify--folder-app"></div>
223 - <script>
224 - (function() {
225 - var folderApp = document.getElementById('wp-adminify--folder-app');
226 - var wpbody = document.getElementById('wpbody');
227 - var wpbodyContent = document.getElementById('wpbody-content');
228 - if (folderApp && wpbody && wpbodyContent) {
229 - wpbody.insertBefore(folderApp, wpbodyContent);
230 - }
231 - })();
232 - </script>
233 - <?php
234 - }
235 - }
236 -
237 - public function get_uncategorized_posts( $post_type ) {
238 - global $wpdb;
239 -
240 - $post_table = $wpdb->prefix . 'posts';
241 - $term_table = $wpdb->prefix . 'term_relationships';
242 - $term_taxonomy_table = $wpdb->prefix . 'term_taxonomy';
243 - $post_type_tax = self::get_post_type_taxonomy( $post_type );
244 -
245 - if ( $post_type != 'attachment' ) {
246 - $query = "SELECT COUNT(DISTINCT({$post_table}.ID)) AS total_records FROM {$post_table} WHERE 1=1 AND (
247 - NOT EXISTS (
248 - SELECT 1
249 - FROM {$term_table}
250 - INNER JOIN {$term_taxonomy_table}
251 - ON {$term_taxonomy_table}.term_taxonomy_id = {$term_table}.term_taxonomy_id
252 - WHERE {$term_taxonomy_table}.taxonomy = '%s'
253 - AND {$term_table}.object_id = {$post_table}.ID
254 - )
255 - ) AND {$post_table}.post_type = '%s' AND (({$post_table}.post_status = 'publish' OR {$post_table}.post_status = 'future' OR {$post_table}.post_status = 'draft' OR {$post_table}.post_status = 'private'))";
256 - } else {
257 - $query = "SELECT COUNT(DISTINCT({$post_table}.ID)) AS total_records FROM {$post_table} WHERE 1=1 AND (
258 - NOT EXISTS (
259 - SELECT 1
260 - FROM {$term_table}
261 - INNER JOIN {$term_taxonomy_table}
262 - ON {$term_taxonomy_table}.term_taxonomy_id = {$term_table}.term_taxonomy_id
263 - WHERE {$term_taxonomy_table}.taxonomy = '%s'
264 - AND {$term_table}.object_id = {$post_table}.ID
265 - )
266 - ) AND {$post_table}.post_type = '%s' AND {$post_table}.post_status = 'inherit'";
267 - }
268 -
269 - // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- $query is composed only of trusted internal $wpdb->prefix table names; user values are bound here as %s placeholders.
270 - $query = $wpdb->prepare( $query, $post_type_tax, $post_type );
271 -
272 - // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.NotPrepared,PluginCheck.Security.DirectDB.UnescapedDBParameter -- direct query required for uncategorized post count; not cached intentionally; $query already prepared above.
273 - $total = $wpdb->get_var( $query );
274 -
275 - return empty( $total ) ? 0 : $total;
276 - }
277 -
278 - public function get_folders( $post_type, $post_type_tax ) {
279 - $args = [
280 - 'taxonomy' => $post_type_tax,
281 - 'hide_empty' => false,
282 - 'pad_counts' => true,
283 - ];
284 -
285 - $folders = get_terms( $args );
286 -
287 - if ( is_wp_error( $folders ) ) {
288 - return [];
289 - }
290 -
291 - foreach ( $folders as $folder ) {
292 - $posts = $this->get_posts_by_folder( $folder->term_id, $post_type, $post_type_tax );
293 -
294 - $color = get_term_meta( $folder->term_id, 'pxlbsadminify_fodler_color', true );
295 - if ( empty( $color ) ) {
296 - $color = '';
297 - }
298 -
299 - $folder->color = $color;
300 - $folder->count = count( $posts );
301 - $folder->posts = $posts;
302 - }
303 -
304 - return $folders;
305 - }
306 -
307 - public function enqueue_scripts() {
308 - if ( ! $this->is_module_active() ) {
309 - return;
310 - }
311 -
312 - $current_screen = get_current_screen();
313 - wp_enqueue_style( 'wp-adminify--folder', PXLBSADMINIFY_URL . 'assets/admin/css/wp-adminify--folder' . Utils::assets_ext( '.css' ), [], PXLBSADMINIFY_VER );
314 - wp_enqueue_style('adminify-simple-line-icons', PXLBSADMINIFY_ASSETS . '/vendors/font-icons/simple-line-icons/css/simple-line-icons' . Utils::assets_ext('.css'), false, PXLBSADMINIFY_VER);
315 -
316 - $post_type = $current_screen->post_type;
317 - $post_type_tax = self::get_post_type_taxonomy( $post_type );
318 - if($current_screen->base === 'media' && $current_screen->action === 'add'){
319 - $post_type = 'attachment';
320 - $post_type_tax = 'media_folder';
321 - }
322 - $media_folders = get_terms([
323 - 'taxonomy' => 'media_folder',
324 - 'hide_empty' => false,
325 - ]);
326 -
327 - $media_folders_data = [];
328 - foreach ($media_folders as $media_folder) {
329 - $media_folders_data[$media_folder->term_id] = [
330 - 'name' => $media_folder->name,
331 - 'slug' => $media_folder->slug,
332 - 'term_id' => $media_folder->term_id
333 - ];
334 - }
335 -
336 - $data = [
337 - 'adminurl' => admin_url(),
338 - 'ajaxurl' => admin_url( 'admin-ajax.php' ),
339 - 'post_type' => $post_type,
340 - 'nonce' => wp_create_nonce( 'pxlbsadminify_folder_nonce' ),
341 - 'post_type_tax' => $post_type_tax,
342 - 'media_folders_data' => $media_folders_data,
343 - 'is_pro' => wp_validate_boolean( jltwp_adminify()->can_use_premium_code() ),
344 - 'pro_notice' => Utils::upgrade_pro_notice(),
345 - ];
346 -
347 - $data = array_merge( $data, $this->refreshed_folder_data( $post_type, $post_type_tax ) );
348 -
349 - // Enqueue Scripts
350 - wp_enqueue_script('wp-adminify--folder', PXLBSADMINIFY_ASSETS . 'admin/js/wp-adminify--folder' . Utils::assets_ext('.js'), array('jquery', 'jquery-ui-droppable', 'jquery-ui-draggable'), PXLBSADMINIFY_VER, true);
351 -
352 - wp_localize_script( 'wp-adminify--folder', 'PXLBSADMINIFY_FOLDER_DATA', $data );
353 -
354 - $inline_script_content = '
175 + public function enqueue_scripts() {
176 + if ( !$this->is_module_active() ) {
177 + return;
178 + }
179 + $current_screen = get_current_screen();
180 + wp_enqueue_style(
181 + 'wp-adminify--folder',
182 + WP_ADMINIFY_URL . 'assets/admin/css/wp-adminify--folder' . Utils::assets_ext( '.css' ),
183 + [],
184 + WP_ADMINIFY_VER
185 + );
186 + wp_enqueue_style(
187 + 'wp-adminify-simple-line-icons',
188 + WP_ADMINIFY_ASSETS . '/vendors/font-icons/simple-line-icons/css/simple-line-icons' . Utils::assets_ext( '.css' ),
189 + false,
190 + WP_ADMINIFY_VER
191 + );
192 + $post_type = $current_screen->post_type;
193 + $post_type_tax = self::get_post_type_taxonomy( $post_type );
194 + if ( $current_screen->base === 'media' && $current_screen->action === 'add' ) {
195 + $post_type = 'attachment';
196 + $post_type_tax = 'media_folder';
197 + }
198 + $media_folders = get_terms( [
199 + 'taxonomy' => 'media_folder',
200 + 'hide_empty' => false,
201 + ] );
202 + $media_folders_data = [];
203 + foreach ( $media_folders as $media_folder ) {
204 + $media_folders_data[$media_folder->term_id] = [
205 + 'name' => $media_folder->name,
206 + 'slug' => $media_folder->slug,
207 + 'term_id' => $media_folder->term_id,
208 + ];
209 + }
210 + $data = [
211 + 'adminurl' => admin_url(),
212 + 'ajaxurl' => admin_url( 'admin-ajax.php' ),
213 + 'post_type' => $post_type,
214 + 'nonce' => wp_create_nonce( '__adminify-folder-secirity__' ),
215 + 'post_type_tax' => $post_type_tax,
216 + 'media_folders_data' => $media_folders_data,
217 + 'is_pro' => wp_validate_boolean( jltwp_adminify()->can_use_premium_code__premium_only() ),
218 + 'pro_notice' => Utils::adminify_upgrade_pro(),
219 + ];
220 + $data = array_merge( $data, $this->refreshed_folder_data( $post_type, $post_type_tax ) );
221 + // Adminify Folder
222 + wp_enqueue_script(
223 + 'wp-adminify-vue-vendors',
224 + WP_ADMINIFY_ASSETS . 'admin/js/vendor' . Utils::assets_ext( '.js' ),
225 + [],
226 + WP_ADMINIFY_VER,
227 + true
228 + );
229 + wp_enqueue_script(
230 + 'wp-adminify--folder',
231 + WP_ADMINIFY_ASSETS . 'admin/js/wp-adminify--folder' . Utils::assets_ext( '.js' ),
232 + array(
233 + 'jquery',
234 + 'jquery-ui-droppable',
235 + 'jquery-ui-draggable',
236 + 'wp-adminify-vue-vendors'
237 + ),
238 + WP_ADMINIFY_VER,
239 + true
240 + );
241 + wp_localize_script( 'wp-adminify--folder', 'wp_adminify__folder_data', $data );
242 + $inline_script_content = '
355 243 (function($) {
356 244 $(document).ready(function() {
357 245
358 246 let selectedFolder = null;
@@ -370,9 +258,9 @@
370 258 text: "All folders",
371 259 props: { folders: "" },
372 260 priority: 10
373 261 };
374 - _.each(window.PXLBSADMINIFY_FOLDER_DATA?.media_folders_data || {}, function(value) {
262 + _.each(window.wp_adminify__folder_data?.media_folders_data || {}, function(value) {
375 263 filters[value.slug] = {
376 264 text: value.name,
377 265 props: { folders: value.slug },
378 266 priority: 20
@@ -437,71 +325,33 @@
437 325
438 326 });
439 327 })(jQuery);
440 328 ';
329 + wp_add_inline_script( 'media-views', $inline_script_content, 'after' );
330 + }
441 331
442 - wp_add_inline_script('media-views', $inline_script_content, 'after');
443 - }
444 -
445 - function enqueue_scripts_for_media_uploads(){
446 - wp_enqueue_media();
447 - wp_enqueue_script('media-views');
448 - wp_enqueue_script('wp-dom-ready');
449 -
450 - // Enqueue folder styles for modal
451 - wp_enqueue_style( 'wp-adminify--folder', PXLBSADMINIFY_URL . 'assets/admin/css/wp-adminify--folder' . Utils::assets_ext( '.css' ), [], PXLBSADMINIFY_VER );
452 - wp_enqueue_style('adminify-simple-line-icons', PXLBSADMINIFY_ASSETS . '/vendors/font-icons/simple-line-icons/css/simple-line-icons' . Utils::assets_ext('.css'), false, PXLBSADMINIFY_VER);
453 -
454 - // Enqueue folder script for modal sidebar
455 - wp_enqueue_script('wp-adminify--popup-folder', PXLBSADMINIFY_ASSETS . 'admin/js/wp-adminify--popup-folder' . Utils::assets_ext('.js'), array('jquery', 'jquery-ui-droppable', 'jquery-ui-draggable', 'wp-element', 'wp-dom-ready'), PXLBSADMINIFY_VER, true);
456 -
457 - wp_enqueue_script('wp-adminify--folder', PXLBSADMINIFY_ASSETS . 'admin/js/wp-adminify--folder' . Utils::assets_ext('.js'), array('jquery', 'jquery-ui-droppable', 'jquery-ui-draggable', 'wp-element', 'wp-dom-ready'), PXLBSADMINIFY_VER, true);
458 -
459 - $post_type = 'attachment';
460 - $post_type_tax = 'media_folder';
461 -
462 - // Get simplified folder data for dropdown filter
463 - $media_folders = get_terms([
464 - 'taxonomy' => 'media_folder',
465 - 'hide_empty' => false,
466 - ]);
467 -
468 - $media_folders_data = [];
469 - foreach ($media_folders as $folder) {
470 - $media_folders_data[$folder->term_id] = [
471 - 'name' => $folder->name,
472 - 'slug' => $folder->slug,
473 - 'term_id' => $folder->term_id
474 - ];
475 - }
476 -
477 - // Build full folder data for React sidebar
478 - $data = apply_filters(
479 - 'pxlbsadminify_folder_data',
480 - [
481 - 'adminurl' => admin_url(),
482 - 'ajaxurl' => admin_url( 'admin-ajax.php' ),
483 - 'post_type' => $post_type,
484 - 'nonce' => wp_create_nonce( 'pxlbsadminify_folder_nonce' ),
485 - 'post_type_tax' => $post_type_tax,
486 - 'media_folders_data' => $media_folders_data,
487 - 'is_pro' => wp_validate_boolean( jltwp_adminify()->can_use_premium_code() ),
488 - 'pro_notice' => Utils::upgrade_pro_notice(),
489 - 'is_rtl' => is_rtl(),
490 - ]
491 - );
492 -
493 - // Add full folder data (folders, hierarchy, counts)
494 - $data = array_merge( $data, $this->refreshed_folder_data( $post_type, $post_type_tax ) );
495 -
496 - // Localize the data to multiple script handles
497 - // This ensures data is available in different contexts
498 - wp_localize_script( 'wp-adminify--folder', 'PXLBSADMINIFY_FOLDER_DATA', $data );
499 - wp_localize_script( 'wp-dom-ready', 'PXLBSADMINIFY_FOLDER_DATA', $data );
500 - wp_localize_script( 'media-views', 'PXLBSADMINIFY_FOLDER_DATA', $data );
501 -
502 -
503 - $inline_script_content = '
332 + function enqueue_scripts_for_media_uploads() {
333 + wp_enqueue_media();
334 + wp_enqueue_script( 'media-views' );
335 + $post_type = 'attachment';
336 + $post_type_tax = 'media_folder';
337 + $media_folders = get_terms( [
338 + 'taxonomy' => 'media_folder',
339 + 'hide_empty' => false,
340 + ] );
341 + $media_folders_data = [];
342 + foreach ( $media_folders as $folder ) {
343 + $media_folders_data[$folder->term_id] = [
344 + 'name' => $folder->name,
345 + 'slug' => $folder->slug,
346 + 'term_id' => $folder->term_id,
347 + ];
348 + }
349 + // Localize the data
350 + wp_localize_script( 'media-views', 'wp_adminify__folder_data', [
351 + 'media_folders_data' => $media_folders_data,
352 + ] );
353 + $inline_script_content = '
504 354 (function($) {
505 355 $(document).ready(function() {
506 356
507 357 let selectedFolder = null;
@@ -519,9 +369,9 @@
519 369 text: "All folders",
520 370 props: { folders: "" },
521 371 priority: 10
522 372 };
523 - _.each(window.PXLBSADMINIFY_FOLDER_DATA?.media_folders_data || {}, function(value) {
373 + _.each(window.wp_adminify__folder_data?.media_folders_data || {}, function(value) {
524 374 filters[value.slug] = {
525 375 text: value.name,
526 376 props: { folders: value.slug },
527 377 priority: 20
@@ -539,9 +389,19 @@
539 389 }
540 390 }
541 391 });
542 392
543 - // Note: AttachmentsBrowser extension for folder sidebar is handled in wp-adminify--folder.js
393 + const AttachmentsBrowser = wp.media.view.AttachmentsBrowser;
394 + wp.media.view.AttachmentsBrowser = AttachmentsBrowser.extend({
395 + createToolbar: function() {
396 + AttachmentsBrowser.prototype.createToolbar.call(this);
397 + this.toolbar.set("MediaLibraryTaxonomyFilter", new MediaLibraryTaxonomyFilter({
398 + controller: this.controller,
399 + model: this.collection.props,
400 + priority: -75
401 + }).render());
402 + }
403 + });
544 404 }
545 405
546 406 if (typeof wp.Uploader === "function") {
547 407 $.extend(wp.Uploader.prototype, {
@@ -576,12 +436,14 @@
576 436
577 437 });
578 438 })(jQuery);
579 439 ';
440 + wp_add_inline_script( 'media-views', $inline_script_content, 'after' );
441 + }
580 442
581 - wp_add_inline_script('media-views', $inline_script_content, 'after');
582 - }
583 - public function modify_media_templates() { ?>
443 + public function modify_media_templates() {
444 + ?>
445 +
584 446 <script>
585 447 var attachment_template = jQuery('#tmpl-attachment');
586 448 if ( attachment_template.length ) {
587 449 var template = attachment_template.html().replace( 'data.orientation }}">', 'data.orientation }}" data-folders="{{ data.media_folder }}">' );
@@ -586,586 +448,512 @@
586 448 if ( attachment_template.length ) {
587 449 var template = attachment_template.html().replace( 'data.orientation }}">', 'data.orientation }}" data-folders="{{ data.media_folder }}">' );
588 450 attachment_template.html( template );
589 451 }
590 - </script>
591 - <?php
592 - }
452 + </script>
593 453
594 - public function handle_adminify_folder() {
595 - check_ajax_referer( 'pxlbsadminify_folder_nonce' );
454 + <?php
455 + }
596 456
597 - if ( ! current_user_can( 'edit_posts' ) ) {
598 - wp_send_json_error( array( 'message' => __( 'You do not have permission to perform this action.', 'adminify' ) ) );
599 - }
457 + public function handle_adminify_folder() {
458 + check_ajax_referer( '__adminify-folder-secirity__' );
459 + if ( !empty( $_POST['route'] ) ) {
460 + $route_handler = 'handle_' . sanitize_text_field( wp_unslash( $_POST['route'] ) );
461 + if ( is_callable( get_class( $this ), $route_handler ) ) {
462 + $this->{$route_handler}( $_POST );
463 + }
464 + }
465 + wp_send_json_error( [
466 + 'message' => __( 'Something is wrong, no route found' ),
467 + ], 400 );
468 + }
600 469
601 - $allowed_routes = array(
602 - 'delete_folders',
603 - 'rename_folder',
604 - 'move_to_folder',
605 - 'refresh_folders',
606 - 'create_new_folder',
607 - );
470 + public function handle_delete_folders( $data ) {
471 + if ( empty( $data['term_ids'] ) || empty( $data['post_type'] ) || empty( $data['post_type_tax'] ) ) {
472 + wp_send_json_error( [
473 + 'message' => __( 'Something is wrong, few args are missing' ),
474 + ], 400 );
475 + }
476 + $term_ids = $data['term_ids'];
477 + $post_type = $data['post_type'];
478 + $post_type_tax = $data['post_type_tax'];
479 + foreach ( $term_ids as $term_id ) {
480 + wp_delete_term( $term_id, $post_type_tax );
481 + }
482 + $data = $this->refreshed_folder_data( $post_type, $post_type_tax );
483 + wp_send_json_success( $data );
484 + }
608 485
609 - if ( ! empty( $_POST['route'] ) ) {
610 - $route = sanitize_key( wp_unslash( $_POST['route'] ) );
486 + public function handle_rename_folder( $data ) {
487 + if ( empty( $data['term_id'] ) || empty( $data['post_type'] ) || empty( $data['post_type_tax'] ) || empty( $data['folder_name'] ) || empty( $data['folder_color_tag'] ) ) {
488 + wp_send_json_error( [
489 + 'message' => __( 'Something is wrong, few args are missing' ),
490 + ], 400 );
491 + }
492 + $term_id = $data['term_id'];
493 + $folder_name = $data['folder_name'];
494 + $post_type = $data['post_type'];
495 + $post_type_tax = $data['post_type_tax'];
496 + $folder_color_tag = $data['folder_color_tag'];
497 + $update = wp_update_term( $term_id, $post_type_tax, [
498 + 'name' => $folder_name,
499 + ] );
500 + if ( is_wp_error( $update ) ) {
501 + wp_send_json_success( [
502 + 'message' => $update->get_error_message(),
503 + ], 202 );
504 + }
505 + update_term_meta( $term_id, '_wp_adminify_fodler_color', $folder_color_tag );
506 + $data = $this->refreshed_folder_data( $post_type, $post_type_tax );
507 + wp_send_json_success( $data );
508 + }
611 509
612 - if ( in_array( $route, $allowed_routes, true ) ) {
613 - $route_handler = 'handle_' . $route;
614 - if ( method_exists( $this, $route_handler ) ) {
615 - $this->$route_handler( wp_unslash( $_POST ) );
616 - }
617 - }
618 - }
510 + public function handle_move_to_folder( $data ) {
511 + if ( empty( $data['post_ids'] ) || empty( $data['folder_id'] ) || empty( $data['post_type'] ) || empty( $data['post_type_tax'] ) ) {
512 + wp_send_json_error( [
513 + 'message' => __( 'Something is wrong, few args are missing' ),
514 + ], 400 );
515 + }
516 + $post_ids = (array) $data['post_ids'];
517 + $folder_id = sanitize_text_field( $data['folder_id'] );
518 + $post_type = sanitize_text_field( $data['post_type'] );
519 + $post_type_tax = sanitize_text_field( $data['post_type_tax'] );
520 + global $mode;
521 + $mode = ( empty( $data['mode'] ) ? 'list' : sanitize_text_field( $data['mode'] ) );
522 + $move_to_folder = wp_validate_boolean( $data['move_to_folder'] );
523 + foreach ( $post_ids as $post_id ) {
524 + if ( $folder_id == 'uncategorized' ) {
525 + wp_set_object_terms(
526 + $post_id,
527 + '',
528 + $post_type_tax,
529 + false
530 + );
531 + continue;
532 + }
533 + $term = get_term( $folder_id );
534 + if ( !empty( $term ) && isset( $term->slug ) ) {
535 + wp_set_object_terms(
536 + $post_id,
537 + $term->slug,
538 + $post_type_tax,
539 + !$move_to_folder
540 + );
541 + }
542 + }
543 + $updated_rows = '';
544 + if ( $post_type == 'attachment' ) {
545 + global $wp_query;
546 + $args = [
547 + 'posts_per_page' => count( $post_ids ),
548 + 'orderby' => 'title',
549 + 'order' => 'ASC',
550 + 'post_type' => $post_type,
551 + 'post_status' => 'any',
552 + 'post__in' => $post_ids,
553 + ];
554 + $wp_query = new \WP_Query($args);
555 + $wp_list_table = \_get_list_table( 'WP_Media_List_Table', [
556 + 'screen' => sanitize_text_field( wp_unslash( $_POST['screen'] ) ),
557 + ] );
558 + foreach ( $post_ids as $post_id ) {
559 + ob_start();
560 + $wp_list_table->display_rows();
561 + $updated_rows = ob_get_clean();
562 + }
563 + } else {
564 + $wp_list_table = \_get_list_table( 'WP_Posts_List_Table', [
565 + 'screen' => sanitize_text_field( wp_unslash( $_POST['screen'] ) ),
566 + ] );
567 + foreach ( $post_ids as $post_id ) {
568 + $level = 0;
569 + if ( is_post_type_hierarchical( $wp_list_table->screen->post_type ) ) {
570 + $request_post = [get_post( $post_id )];
571 + $parent = $request_post[0]->post_parent;
572 + while ( $parent > 0 ) {
573 + $parent_post = get_post( $parent );
574 + $parent = $parent_post->post_parent;
575 + $level++;
576 + }
577 + }
578 + ob_start();
579 + $wp_list_table->display_rows( [get_post( $post_id )], $level );
580 + $updated_rows .= ob_get_clean();
581 + }
582 + }
583 + $data = [
584 + 'updated_rows' => $updated_rows,
585 + ];
586 + $data = array_merge( $data, $this->refreshed_folder_data( $post_type, $post_type_tax ) );
587 + wp_send_json_success( $data );
588 + }
619 589
620 - wp_send_json_error( [ 'message' => __( 'Something is wrong, no route found', 'adminify' ) ], 400 );
621 - }
590 + public function handle_refresh_folders( $data ) {
591 + if ( empty( $data['post_type'] ) || empty( $data['post_type_tax'] ) ) {
592 + wp_send_json_error( [
593 + 'message' => __( 'Something is wrong, few args are missing' ),
594 + ], 400 );
595 + }
596 + $post_type = $data['post_type'];
597 + $post_type_tax = $data['post_type_tax'];
598 + wp_send_json_success( $this->refreshed_folder_data( $post_type, $post_type_tax ) );
599 + }
622 600
623 - public function handle_delete_folders( $data ) {
624 - check_ajax_referer( 'pxlbsadminify_folder_nonce' );
601 + public function handle_create_new_folder( $data ) {
602 + if ( empty( $data['post_type'] ) || empty( $data['post_type_tax'] ) ) {
603 + wp_send_json_error( [
604 + 'message' => __( 'Something is wrong, few args are missing' ),
605 + ], 400 );
606 + }
607 + if ( empty( $data['new_folder_name'] ) || empty( $data['folder_color_tag'] ) ) {
608 + wp_send_json_error( [
609 + 'message' => __( 'Something is wrong, few args are missing' ),
610 + ], 400 );
611 + }
612 + $post_type = $data['post_type'];
613 + $post_type_tax = $data['post_type_tax'];
614 + $new_folder_name = $data['new_folder_name'];
615 + $folder_color_tag = $data['folder_color_tag'];
616 + $parent_term_id = 0;
617 + if ( jltwp_adminify()->can_use_premium_code__premium_only() && !empty( $data['parent_folder'] ) ) {
618 + $parent_term_id = $data['parent_folder'];
619 + }
620 + $insert_data = wp_insert_term( $new_folder_name, $post_type_tax, [
621 + 'parent' => $parent_term_id,
622 + ] );
623 + if ( !is_wp_error( $insert_data ) ) {
624 + update_term_meta( $insert_data['term_id'], '_wp_adminify_fodler_color', $folder_color_tag );
625 + wp_send_json_success( $this->refreshed_folder_data( $post_type, $post_type_tax ) );
626 + } else {
627 + wp_send_json_success( [
628 + 'message' => $insert_data->get_error_message(),
629 + ], 202 );
630 + }
631 + }
625 632
626 - if ( ! current_user_can( 'edit_posts' ) ) {
627 - wp_send_json_error( [ 'message' => __( 'You do not have permission to perform this action.', 'adminify' ) ], 403 );
628 - }
633 + function refreshed_folder_data( $post_type, $post_type_tax ) {
634 + remove_filter( 'pre_get_posts', [$this, 'filter_list'] );
635 + return [
636 + 'folders' => $this->get_folders( $post_type, $post_type_tax ),
637 + 'folder_hierarchy' => _get_term_hierarchy( $post_type_tax ),
638 + 'total_posts' => wp_count_posts( $post_type ),
639 + 'total_uncat_posts' => $this->get_uncategorized_posts( $post_type ),
640 + ];
641 + }
629 642
630 - if ( empty( $data['term_ids'] ) || empty( $data['post_type'] ) || empty( $data['post_type_tax'] ) ) {
631 - wp_send_json_error( [ 'message' => __( 'Something is wrong, few args are missing', 'adminify' ) ], 400 );
632 - }
643 + function wp_set_post_categories( $post_ID = 0, $post_categories = [], $append = false ) {
644 + $post_ID = (int) $post_ID;
645 + $post_type = get_post_type( $post_ID );
646 + $post_status = get_post_status( $post_ID );
647 + // If $post_categories isn't already an array, make it one.
648 + $post_categories = (array) $post_categories;
649 + if ( empty( $post_categories ) ) {
650 + /**
651 + * Filters post types (in addition to 'post') that require a default category.
652 + *
653 + * @since 5.5.0
654 + *
655 + * @param string[] $post_types An array of post type names. Default empty array.
656 + */
657 + $default_category_post_types = apply_filters( 'default_category_post_types', [] );
658 + // Regular posts always require a default category.
659 + $default_category_post_types = array_merge( $default_category_post_types, ['post'] );
660 + if ( in_array( $post_type, $default_category_post_types, true ) && is_object_in_taxonomy( $post_type, 'category' ) && 'auto-draft' !== $post_status ) {
661 + $post_categories = [get_option( 'default_category' )];
662 + $append = false;
663 + } else {
664 + $post_categories = [];
665 + }
666 + } elseif ( 1 === count( $post_categories ) && '' === reset( $post_categories ) ) {
667 + return true;
668 + }
669 + return wp_set_post_terms(
670 + $post_ID,
671 + $post_categories,
672 + 'category',
673 + $append
674 + );
675 + }
633 676
634 - $term_ids = array_map( 'absint', (array) $data['term_ids'] );
635 - $post_type = sanitize_key( $data['post_type'] );
636 - $post_type_tax = sanitize_key( $data['post_type_tax'] );
677 + public function get_posts_by_folder( $term_id, $post_type, $taxonomy ) {
678 + $posts = get_posts( [
679 + 'numberposts' => -1,
680 + 'post_status' => 'any',
681 + 'post_type' => $post_type,
682 + 'fields' => 'ids',
683 + 'tax_query' => [[
684 + 'operator' => 'IN',
685 + 'taxonomy' => $taxonomy,
686 + 'field' => 'term_id',
687 + 'terms' => $term_id,
688 + ]],
689 + ] );
690 + return $posts;
691 + }
637 692
638 - foreach ( $term_ids as $term_id ) {
639 - wp_delete_term( $term_id, $post_type_tax );
640 - }
693 + public static function get_post_type_taxonomy( $post_type ) {
694 + if ( $post_type == 'page' ) {
695 + return 'folder';
696 + }
697 + if ( $post_type == 'attachment' ) {
698 + $post_type = 'media';
699 + }
700 + return $post_type . '_folder';
701 + }
641 702
642 - $data = $this->refreshed_folder_data( $post_type, $post_type_tax );
703 + public function register_folders_terms() {
704 + $post_types = $this->get_post_types();
705 + foreach ( $post_types as $post_type ) {
706 + $labels = [
707 + 'name' => esc_html__( 'Folders', 'adminify' ),
708 + 'singular_name' => esc_html__( 'Folder', 'adminify' ),
709 + 'all_items' => esc_html__( 'All Folders', 'adminify' ),
710 + 'edit_item' => esc_html__( 'Edit Folder', 'adminify' ),
711 + 'update_item' => esc_html__( 'Update Folder', 'adminify' ),
712 + 'add_new_item' => esc_html__( 'Add New Folder', 'adminify' ),
713 + 'new_item_name' => esc_html__( 'Add folder name', 'adminify' ),
714 + 'menu_name' => esc_html__( 'Folders', 'adminify' ),
715 + 'search_items' => esc_html__( 'Search Folders', 'adminify' ),
716 + 'parent_item' => esc_html__( 'Parent Folder', 'adminify' ),
717 + ];
718 + $args = [
719 + 'label' => esc_html__( 'Folder', 'adminify' ),
720 + 'labels' => $labels,
721 + 'show_tagcloud' => false,
722 + 'hierarchical' => true,
723 + 'public' => false,
724 + 'show_ui' => false,
725 + 'show_in_menu' => false,
726 + 'show_in_rest' => true,
727 + 'show_admin_column' => true,
728 + 'query_var' => true,
729 + 'rewrite' => false,
730 + 'capabilities' => [
731 + 'manage_terms' => 'manage_categories',
732 + 'edit_terms' => 'manage_categories',
733 + 'delete_terms' => 'manage_categories',
734 + 'assign_terms' => 'manage_categories',
735 + ],
736 + ];
737 + $taxonomy = self::get_post_type_taxonomy( $post_type );
738 + register_taxonomy( $taxonomy, $post_type, $args );
739 + }
740 + }
643 741
644 - wp_send_json_success( $data );
645 - }
742 + public function modify_columns_actions() {
743 + $post_types = $this->get_post_types();
744 + foreach ( $post_types as $post_type ) {
745 + if ( $post_type == 'post' ) {
746 + add_filter( 'manage_edit-post_columns', [$this, 'manage_columns_head'] );
747 + add_filter( 'manage_posts_columns', [$this, 'manage_columns_head'] );
748 + add_action(
749 + 'manage_posts_custom_column',
750 + [$this, 'manage_columns_content'],
751 + 10,
752 + 2
753 + );
754 + add_filter( 'bulk_actions-edit-post', [$this, 'custom_bulk_action'] );
755 + } elseif ( $post_type == 'page' ) {
756 + add_filter( 'manage_edit-page_columns', [$this, 'manage_columns_head'] );
757 + add_filter( 'manage_page_posts_columns', [$this, 'manage_columns_head'] );
758 + add_action(
759 + 'manage_page_posts_custom_column',
760 + [$this, 'manage_columns_content'],
761 + 10,
762 + 2
763 + );
764 + add_filter( 'bulk_actions-edit-page', [$this, 'custom_bulk_action'] );
765 + } elseif ( $post_type == 'attachment' ) {
766 + add_filter( 'manage_media_columns', [$this, 'manage_columns_head'] );
767 + add_action(
768 + 'manage_media_custom_column',
769 + [$this, 'manage_columns_content'],
770 + 10,
771 + 2
772 + );
773 + } else {
774 + add_filter( 'manage_edit-' . $post_type . '_columns', [$this, 'manage_columns_head'], 99999 );
775 + add_action(
776 + 'manage_' . $post_type . '_posts_custom_column',
777 + [$this, 'manage_columns_content'],
778 + 2,
779 + 2
780 + );
781 + add_filter( 'bulk_actions-edit-' . $post_type, [$this, 'custom_bulk_action'] );
782 + }
783 + }
784 + }
646 785
647 - public function handle_rename_folder( $data ) {
648 - check_ajax_referer( 'pxlbsadminify_folder_nonce' );
786 + function manage_columns_head( $posts_columns ) {
787 + $post_type = null;
788 + if ( isset( $_REQUEST['post_type'] ) ) {
789 + $post_type = sanitize_text_field( wp_unslash( $_REQUEST['post_type'] ) );
790 + }
791 + if ( $this->is_module_active( $post_type ) ) {
792 + $title = sprintf( __( 'Moving selected items', 'adminify' ), '<span class="adminify-folder-items--count"></span>' );
793 + return [
794 + 'adminify_move' => '<div class="adminify-move-multiple adminify-col" title="' . esc_attr__( 'Move selected items', 'adminify' ) . '"><span class="dashicons dashicons-move"></span><span class="adminify-move-file--title">' . wp_kses_post( $title ) . '</span><div class="adminify-items"></div></div>',
795 + ] + $posts_columns;
796 + }
797 + return $posts_columns;
798 + }
649 799
650 - if ( ! current_user_can( 'edit_posts' ) ) {
651 - wp_send_json_error( [ 'message' => __( 'You do not have permission to perform this action.', 'adminify' ) ], 403 );
652 - }
800 + function manage_columns_content( $column_name, $post_ID ) {
801 + $post_type = null;
802 + if ( isset( $_REQUEST['post_type'] ) ) {
803 + $post_type = sanitize_text_field( wp_unslash( $_REQUEST['post_type'] ) );
804 + }
805 + $postIDs = self::$postIds;
806 + $folder_ids = $this->get_folders_by_post( $post_ID );
807 + $folder_ids = implode( ',', $folder_ids );
808 + if ( !is_array( $postIDs ) ) {
809 + $postIDs = [];
810 + }
811 + if ( !in_array( $post_ID, $postIDs ) ) {
812 + $postIDs[] = $post_ID;
813 + self::$postIds = $postIDs;
814 + if ( $this->is_module_active( $post_type ) ) {
815 + if ( $column_name == 'adminify_move' ) {
816 + $title = get_the_title();
817 + if ( strlen( $title ) > 20 ) {
818 + $title = substr( $title, 0, 20 ) . '...';
819 + }
820 + echo Utils::wp_kses_custom( '<div class="adminify-move-file" data-id="' . esc_attr( $post_ID ) . '" data-folders="' . esc_attr( $folder_ids ) . '"><span class="adminify-move dashicons dashicons-move"></span><span class="adminify-move-file--title">' . esc_html( $title ) . '</span></div>' );
821 + }
822 + }
823 + }
824 + }
653 825
654 - if ( empty( $data['term_id'] ) || empty( $data['post_type'] ) || empty( $data['post_type_tax'] ) || empty( $data['folder_name'] ) || empty( $data['folder_color_tag'] ) ) {
655 - wp_send_json_error( [ 'message' => __( 'Something is wrong, few args are missing', 'adminify' ) ], 400 );
656 - }
826 + public function get_folders_by_post( $post_ID, $return_type = 'ids' ) {
827 + $folder_tax = self::get_post_type_taxonomy( get_post_type( $post_ID ) );
828 + $folders = wp_get_post_terms( $post_ID, $folder_tax );
829 + if ( $return_type == 'ids' ) {
830 + return wp_list_pluck( $folders, 'term_id' );
831 + }
832 + return $folders;
833 + }
657 834
658 - $term_id = absint( $data['term_id'] );
659 - $folder_name = sanitize_text_field( $data['folder_name'] );
660 - $post_type = sanitize_key( $data['post_type'] );
661 - $post_type_tax = sanitize_key( $data['post_type_tax'] );
662 - $folder_color_tag = sanitize_text_field( $data['folder_color_tag'] );
835 + public function custom_bulk_action( $bulk_actions ) {
836 + $bulk_actions['move_to_folder'] = __( 'Move to Folder', 'adminify' );
837 + return $bulk_actions;
838 + }
663 839
664 - $update = wp_update_term( $term_id, $post_type_tax, [ 'name' => $folder_name ] );
840 + public function wp_adminify_select_folder_when_upload() {
841 + if ( !$this->options['media'] ) {
842 + return;
843 + }
844 + $selected = ( isset( $_GET['media_folder'] ) ? $_GET['media_folder'] : '' );
845 + wp_dropdown_categories( array(
846 + 'show_option_none' => 'Choose folder',
847 + 'taxonomy' => 'media_folder',
848 + 'name' => 'folder_id',
849 + 'id' => 'folders',
850 + 'orderby' => 'name',
851 + 'selected' => $selected,
852 + 'hierarchical' => true,
853 + 'value_field' => 'slug',
854 + 'hide_empty' => 0,
855 + ) );
856 + }
665 857
666 - if ( is_wp_error( $update ) ) {
667 - wp_send_json_success( [ 'message' => $update->get_error_message() ], 202 );
668 - }
858 + public function wp_adminify_assign_media_folder_to_new_attachment( $post_ID ) {
859 + if ( isset( $_POST['folder_id'] ) && !empty( $_POST['folder_id'] ) && $_POST['folder_id'] !== '-1' ) {
860 + $term = get_term_by( 'slug', $_POST['folder_id'], 'media_folder' );
861 + if ( !$term && is_numeric( $_POST['folder_id'] ) ) {
862 + $term = get_term_by( 'id', (int) $_POST['folder_id'], 'media_folder' );
863 + }
864 + if ( $term && !is_wp_error( $term ) ) {
865 + wp_set_object_terms( $post_ID, (int) $term->term_id, 'media_folder' );
866 + $post_type = 'attachment';
867 + $post_type_tax = $_POST['folder_id'];
868 + } else {
869 + error_log( 'Media Folder: Could not find term for value "' . $_POST['folder_id'] . '" for attachment ID ' . $post_ID );
870 + }
871 + $this->refreshed_folder_data( $post_type, $post_type_tax );
872 + }
873 + }
669 874
670 - update_term_meta( $term_id, 'pxlbsadminify_fodler_color', $folder_color_tag );
671 - $data = $this->refreshed_folder_data( $post_type, $post_type_tax );
875 + public function wp_adminify_edit_attachment_fields( $form_fields, $post ) {
876 + if ( !$this->options['media'] ) {
877 + return;
878 + }
879 + $folder_fields = array(
880 + 'label' => 'Folders',
881 + 'show_in_edit' => false,
882 + 'input' => 'html',
883 + 'value' => '',
884 + );
885 + $taxonomy_name = 'media_folder';
886 + // get the assigned media library folders from the cache
887 + $terms = get_the_terms( $post->ID, $taxonomy_name );
888 + if ( $terms ) {
889 + $folder_fields['value'] = join( ', ', wp_list_pluck( $terms, 'slug' ) );
890 + }
891 + ob_start();
892 + $this->wp_adminify_render_terms_dropdown( $post->ID, $taxonomy_name );
893 + $html = ob_get_contents();
894 + ob_end_clean();
895 + $folder_fields['html'] = $html;
896 + $form_fields[$taxonomy_name] = $folder_fields;
897 + return $form_fields;
898 + }
672 899
673 - wp_send_json_success( $data );
674 - }
675 -
676 - public function handle_move_to_folder( $data ) {
677 - check_ajax_referer( 'pxlbsadminify_folder_nonce' );
678 -
679 - if ( ! current_user_can( 'edit_posts' ) ) {
680 - wp_send_json_error( [ 'message' => __( 'You do not have permission to perform this action.', 'adminify' ) ], 403 );
681 - }
682 -
683 - if ( empty( $data['post_ids'] ) || empty( $data['folder_id'] ) || empty( $data['post_type'] ) || empty( $data['post_type_tax'] ) ) {
684 - wp_send_json_error( [ 'message' => __( 'Something is wrong, few args are missing', 'adminify' ) ], 400 );
685 - }
686 -
687 - $post_ids = array_map( 'absint', (array) $data['post_ids'] );
688 - $folder_id = sanitize_text_field( $data['folder_id'] );
689 - $post_type = sanitize_text_field( $data['post_type'] );
690 - $post_type_tax = sanitize_text_field( $data['post_type_tax'] );
691 - $screen = isset( $data['screen'] ) ? sanitize_text_field( $data['screen'] ) : '';
692 -
693 - global $mode;
694 -
695 - $mode = empty( $data['mode'] ) ? 'list' : sanitize_text_field( $data['mode'] );
696 - $move_to_folder = wp_validate_boolean( $data['move_to_folder'] );
697 -
698 - foreach ( $post_ids as $post_id ) {
699 - if ( $folder_id == 'uncategorized' ) {
700 - wp_set_object_terms( $post_id, '', $post_type_tax, false );
701 - continue;
702 - }
703 -
704 - $term = get_term( $folder_id );
705 -
706 - if ( ! empty( $term ) && isset( $term->slug ) ) {
707 - wp_set_object_terms( $post_id, $term->slug, $post_type_tax, ! $move_to_folder );
708 - }
709 - }
710 -
711 - $updated_rows = '';
712 -
713 - if ( $post_type == 'attachment' ) {
714 - global $wp_query;
715 -
716 - $args = [
717 - 'posts_per_page' => count( $post_ids ),
718 - 'orderby' => 'title',
719 - 'order' => 'ASC',
720 - 'post_type' => $post_type,
721 - 'post_status' => 'any',
722 - 'post__in' => $post_ids,
723 - ];
724 -
725 - $wp_query = new \WP_Query( $args );
726 -
727 - $wp_list_table = \_get_list_table( 'WP_Media_List_Table', [ 'screen' => $screen ] );
728 -
729 - foreach ( $post_ids as $post_id ) {
730 - ob_start();
731 - $wp_list_table->display_rows();
732 - $updated_rows = ob_get_clean();
733 - }
734 - } else {
735 - $wp_list_table = \_get_list_table( 'WP_Posts_List_Table', [ 'screen' => $screen ] );
736 -
737 - foreach ( $post_ids as $post_id ) {
738 - $level = 0;
739 -
740 - if ( is_post_type_hierarchical( $wp_list_table->screen->post_type ) ) {
741 - $request_post = [ get_post( $post_id ) ];
742 - $parent = $request_post[0]->post_parent;
743 - while ( $parent > 0 ) {
744 - $parent_post = get_post( $parent );
745 - $parent = $parent_post->post_parent;
746 - $level++;
747 - }
748 - }
749 -
750 - ob_start();
751 - $wp_list_table->display_rows( [ get_post( $post_id ) ], $level );
752 - $updated_rows .= ob_get_clean();
753 - }
754 - }
755 -
756 - $data = [
757 - 'updated_rows' => $updated_rows,
758 - ];
759 -
760 - $data = array_merge( $data, $this->refreshed_folder_data( $post_type, $post_type_tax ) );
761 -
762 - wp_send_json_success( $data );
763 - }
764 -
765 - public function handle_refresh_folders( $data ) {
766 - check_ajax_referer( 'pxlbsadminify_folder_nonce' );
767 -
768 - if ( ! current_user_can( 'edit_posts' ) ) {
769 - wp_send_json_error( [ 'message' => __( 'You do not have permission to perform this action.', 'adminify' ) ], 403 );
770 - }
771 -
772 - if ( empty( $data['post_type'] ) || empty( $data['post_type_tax'] ) ) {
773 - wp_send_json_error( [ 'message' => __( 'Something is wrong, few args are missing', 'adminify' ) ], 400 );
774 - }
775 -
776 - $post_type = sanitize_key( $data['post_type'] );
777 - $post_type_tax = sanitize_key( $data['post_type_tax'] );
778 -
779 - wp_send_json_success( $this->refreshed_folder_data( $post_type, $post_type_tax ) );
780 - }
781 -
782 - public function handle_create_new_folder( $data ) {
783 - check_ajax_referer( 'pxlbsadminify_folder_nonce' );
784 -
785 - if ( ! current_user_can( 'edit_posts' ) ) {
786 - wp_send_json_error( [ 'message' => __( 'You do not have permission to perform this action.', 'adminify' ) ], 403 );
787 - }
788 -
789 - if ( empty( $data['post_type'] ) || empty( $data['post_type_tax'] ) ) {
790 - wp_send_json_error( [ 'message' => __( 'Something is wrong, few args are missing', 'adminify' ) ], 400 );
791 - }
792 - if ( empty( $data['new_folder_name'] ) || empty( $data['folder_color_tag'] ) ) {
793 - wp_send_json_error( [ 'message' => __( 'Something is wrong, few args are missing', 'adminify' ) ], 400 );
794 - }
795 -
796 - $post_type = sanitize_key( $data['post_type'] );
797 - $post_type_tax = sanitize_key( $data['post_type_tax'] );
798 - $new_folder_name = sanitize_text_field( $data['new_folder_name'] );
799 - $folder_color_tag = sanitize_text_field( $data['folder_color_tag'] );
800 - $parent_term_id = 0;
801 -
802 - if ( jltwp_adminify()->can_use_premium_code() && ! empty( $data['parent_folder'] ) ) {
803 - $parent_term_id = absint( $data['parent_folder'] );
804 - }
805 -
806 - $insert_data = wp_insert_term( $new_folder_name, $post_type_tax, [ 'parent' => $parent_term_id ] );
807 -
808 - if ( ! is_wp_error( $insert_data ) ) {
809 - update_term_meta( $insert_data['term_id'], 'pxlbsadminify_fodler_color', $folder_color_tag );
810 - wp_send_json_success( $this->refreshed_folder_data( $post_type, $post_type_tax ) );
811 - } else {
812 - wp_send_json_success( [ 'message' => $insert_data->get_error_message() ], 202 );
813 - }
814 - }
815 -
816 - function refreshed_folder_data( $post_type, $post_type_tax ) {
817 - remove_filter( 'pre_get_posts', [ $this, 'filter_list' ] );
818 -
819 - return [
820 - 'folders' => $this->get_folders( $post_type, $post_type_tax ),
821 - 'folder_hierarchy' => _get_term_hierarchy( $post_type_tax ),
822 - 'total_posts' => wp_count_posts( $post_type ),
823 - 'total_uncat_posts' => $this->get_uncategorized_posts( $post_type ),
824 - ];
825 - }
826 -
827 - function set_post_categories( $post_ID = 0, $post_categories = [], $append = false ) {
828 - $post_ID = (int) $post_ID;
829 - $post_type = get_post_type( $post_ID );
830 - $post_status = get_post_status( $post_ID );
831 -
832 - // If $post_categories isn't already an array, make it one.
833 - $post_categories = (array) $post_categories;
834 -
835 - if ( empty( $post_categories ) ) {
836 - /**
837 - * Filters post types (in addition to 'post') that require a default category.
838 - *
839 - * @since 5.5.0
840 - *
841 - * @param string[] $post_types An array of post type names. Default empty array.
842 - */
843 - $default_category_post_types = apply_filters( 'pxlbsadminify_default_category_post_types', [] );
844 -
845 - // Regular posts always require a default category.
846 - $default_category_post_types = array_merge( $default_category_post_types, [ 'post' ] );
847 -
848 - if ( in_array( $post_type, $default_category_post_types, true ) && is_object_in_taxonomy( $post_type, 'category' ) && 'auto-draft' !== $post_status ) {
849 - $post_categories = [ get_option( 'default_category' ) ];
850 - $append = false;
851 - } else {
852 - $post_categories = [];
853 - }
854 - } elseif ( 1 === count( $post_categories ) && '' === reset( $post_categories ) ) {
855 - return true;
856 - }
857 -
858 - return wp_set_post_terms( $post_ID, $post_categories, 'category', $append );
859 - }
860 -
861 - public function get_posts_by_folder( $term_id, $post_type, $taxonomy ) {
862 - $posts = get_posts(
863 - [
864 - 'numberposts' => -1,
865 - 'post_status' => 'any',
866 - 'post_type' => $post_type,
867 - 'fields' => 'ids',
868 - 'tax_query' => [ // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query -- intentional taxonomy filter on an admin-side query.
869 - [
870 - 'operator' => 'IN',
871 - 'taxonomy' => $taxonomy,
872 - 'field' => 'term_id',
873 - 'terms' => $term_id,
874 - ],
875 - ],
876 - ]
877 - );
878 -
879 - return $posts;
880 - }
881 -
882 - public static function get_post_type_taxonomy( $post_type ) {
883 - if ( $post_type == 'page' ) {
884 - return 'folder';
885 - }
886 -
887 - if ( $post_type == 'attachment' ) {
888 - $post_type = 'media';
889 - }
890 -
891 - return $post_type . '_folder';
892 - }
893 -
894 - public function register_folders_terms() {
895 - $post_types = $this->get_post_types();
896 -
897 - foreach ( $post_types as $post_type ) {
898 - $labels = [
899 - 'name' => esc_html__( 'Folders', 'adminify' ),
900 - 'singular_name' => esc_html__( 'Folder', 'adminify' ),
901 - 'all_items' => esc_html__( 'All Folders', 'adminify' ),
902 - 'edit_item' => esc_html__( 'Edit Folder', 'adminify' ),
903 - 'update_item' => esc_html__( 'Update Folder', 'adminify' ),
904 - 'add_new_item' => esc_html__( 'Add New Folder', 'adminify' ),
905 - 'new_item_name' => esc_html__( 'Add folder name', 'adminify' ),
906 - 'menu_name' => esc_html__( 'Folders', 'adminify' ),
907 - 'search_items' => esc_html__( 'Search Folders', 'adminify' ),
908 - 'parent_item' => esc_html__( 'Parent Folder', 'adminify' ),
909 - ];
910 -
911 - $args = [
912 - 'label' => esc_html__( 'Folder', 'adminify' ),
913 - 'labels' => $labels,
914 - 'show_tagcloud' => false,
915 - 'hierarchical' => true,
916 - 'public' => false,
917 - 'show_ui' => false,
918 - 'show_in_menu' => false,
919 - 'show_in_rest' => true,
920 - 'show_admin_column' => true,
921 - 'query_var' => true,
922 - 'rewrite' => false,
923 - 'capabilities' => [
924 - 'manage_terms' => 'manage_categories',
925 - 'edit_terms' => 'manage_categories',
926 - 'delete_terms' => 'manage_categories',
927 - 'assign_terms' => 'manage_categories',
928 - ],
929 - ];
930 -
931 - $taxonomy = self::get_post_type_taxonomy( $post_type );
932 -
933 - register_taxonomy( $taxonomy, $post_type, $args );
934 - }
935 - }
936 -
937 - public function modify_columns_actions() {
938 - $post_types = $this->get_post_types();
939 -
940 - foreach ( $post_types as $post_type ) {
941 - if ( $post_type == 'post' ) {
942 - add_filter( 'manage_edit-post_columns', [ $this, 'manage_columns_head' ] );
943 - add_filter( 'manage_posts_columns', [ $this, 'manage_columns_head' ] );
944 - add_action( 'manage_posts_custom_column', [ $this, 'manage_columns_content' ], 10, 2 );
945 - add_filter( 'bulk_actions-edit-post', [ $this, 'custom_bulk_action' ] );
946 - } elseif ( $post_type == 'page' ) {
947 - add_filter( 'manage_edit-page_columns', [ $this, 'manage_columns_head' ] );
948 - add_filter( 'manage_page_posts_columns', [ $this, 'manage_columns_head' ] );
949 - add_action( 'manage_page_posts_custom_column', [ $this, 'manage_columns_content' ], 10, 2 );
950 - add_filter( 'bulk_actions-edit-page', [ $this, 'custom_bulk_action' ] );
951 - } elseif ( $post_type == 'attachment' ) {
952 - add_filter( 'manage_media_columns', [ $this, 'manage_columns_head' ] );
953 - add_action( 'manage_media_custom_column', [ $this, 'manage_columns_content' ], 10, 2 );
954 - } else {
955 - add_filter( 'manage_edit-' . $post_type . '_columns', [ $this, 'manage_columns_head' ], 99999 );
956 - add_action( 'manage_' . $post_type . '_posts_custom_column', [ $this, 'manage_columns_content' ], 2, 2 );
957 - add_filter( 'bulk_actions-edit-' . $post_type, [ $this, 'custom_bulk_action' ] );
958 - }
959 - }
960 - }
961 -
962 - function manage_columns_head( $posts_columns ) {
963 - $post_type = null;
964 -
965 - // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only check, no state change.
966 - if ( isset( $_REQUEST['post_type'] ) ) {
967 - // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only check, no state change.
968 - $post_type = sanitize_text_field( wp_unslash( $_REQUEST['post_type'] ) );
969 - }
970 -
971 - if ( $this->is_module_active( $post_type ) ) {
972 - $title = sprintf( __( 'Moving selected items', 'adminify' ), '<span class="adminify-folder-items--count"></span>' );
973 - return [
974 - 'adminify_move' => '<div class="adminify-move-multiple adminify-col" title="' . esc_attr__( 'Move selected items', 'adminify' ) . '"><span class="dashicons dashicons-move"></span><span class="adminify-move-file--title">' . wp_kses_post( $title ) . '</span><div class="adminify-items"></div></div>',
975 - ] + $posts_columns;
976 - }
977 -
978 - return $posts_columns;
979 - }
980 -
981 - function manage_columns_content( $column_name, $post_ID ) {
982 - $post_type = null;
983 -
984 - // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only check, no state change.
985 - if ( isset( $_REQUEST['post_type'] ) ) {
986 - // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only check, no state change.
987 - $post_type = sanitize_text_field( wp_unslash( $_REQUEST['post_type'] ) );
988 - }
989 -
990 - $postIDs = self::$postIds;
991 -
992 - $folder_ids = $this->get_folders_by_post( $post_ID );
993 - $folder_ids = implode( ',', $folder_ids );
994 -
995 - if ( ! is_array( $postIDs ) ) {
996 - $postIDs = [];
997 - }
998 -
999 - if ( ! in_array( $post_ID, $postIDs ) ) {
1000 - $postIDs[] = $post_ID;
1001 - self::$postIds = $postIDs;
1002 -
1003 - if ( $this->is_module_active( $post_type ) ) {
1004 - if ( $column_name == 'adminify_move' ) {
1005 - $title = get_the_title();
1006 - if ( strlen( $title ) > 20 ) {
1007 - $title = substr( $title, 0, 20 ) . '...';
1008 - }
1009 - // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- kses_custom() is a wp_kses() wrapper; output already escaped.
1010 - echo Utils::kses_custom( '<div class="adminify-move-file" data-id="' . esc_attr( $post_ID ) . '" data-folders="' . esc_attr( $folder_ids ) . '"><span class="adminify-move dashicons dashicons-move"></span><span class="adminify-move-file--title">' . esc_html( $title ) . '</span></div>' );
1011 - }
1012 - }
1013 - }
1014 - }
1015 -
1016 - public function get_folders_by_post( $post_ID, $return_type = 'ids' ) {
1017 - $folder_tax = self::get_post_type_taxonomy( get_post_type( $post_ID ) );
1018 - $folders = wp_get_post_terms( $post_ID, $folder_tax );
1019 - if ( $return_type == 'ids' ) {
1020 - return wp_list_pluck( $folders, 'term_id' );
1021 - }
1022 - return $folders;
1023 - }
1024 -
1025 - public function custom_bulk_action( $bulk_actions ) {
1026 - $bulk_actions['move_to_folder'] = __( 'Move to Folder', 'adminify' );
1027 - return $bulk_actions;
1028 - }
1029 -
1030 - public function select_folder_when_upload() {
1031 - if ( ! $this->options['media'] ) {
1032 - return;
1033 - }
1034 - // Only show the folder selector to users who can upload media.
1035 - if ( ! current_user_can( 'upload_files' ) ) {
1036 - return;
1037 - }
1038 - // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only check, no state change.
1039 - $selected = isset($_GET['media_folder']) ? sanitize_text_field( wp_unslash( $_GET['media_folder'] ) ) : '';
1040 - wp_dropdown_categories( array(
1041 - 'show_option_none' => 'Choose folder',
1042 - 'taxonomy' => 'media_folder',
1043 - 'name' => 'folder_id',
1044 - 'id' => 'folders',
1045 - 'orderby' => 'name',
1046 - 'selected' => $selected,
1047 - 'hierarchical' => true,
1048 - 'value_field' => 'slug',
1049 - 'hide_empty' => 0,
1050 - ) );
1051 -
1052 - }
1053 -
1054 - public function assign_media_folder_to_new_attachment( $post_ID ) {
1055 -
1056 - // Authorization: only users who can edit this attachment may change its folder.
1057 - if ( ! current_user_can( 'upload_files' ) || ! current_user_can( 'edit_post', $post_ID ) ) {
1058 - return;
1059 - }
1060 -
1061 - // CSRF: the media upload request is signed with core's media-form nonce.
1062 - $nonce = isset( $_POST['_wpnonce'] ) ? sanitize_text_field( wp_unslash( $_POST['_wpnonce'] ) ) : '';
1063 - if ( ! $nonce || ! wp_verify_nonce( $nonce, 'media-form' ) ) {
1064 - return;
1065 - }
1066 -
1067 - $folder_id = isset( $_POST['folder_id'] ) ? sanitize_text_field( wp_unslash( $_POST['folder_id'] ) ) : '';
1068 -
1069 - if ( '' !== $folder_id && '-1' !== $folder_id ) {
1070 - $term = get_term_by( 'slug', $folder_id, 'media_folder' );
1071 - if ( ! $term && is_numeric( $folder_id ) ) {
1072 - $term = get_term_by( 'id', (int) $folder_id, 'media_folder' );
1073 - }
1074 -
1075 - $post_type = 'attachment';
1076 - $post_type_tax = $folder_id;
1077 -
1078 - if ( $term && ! is_wp_error( $term ) ) {
1079 - wp_set_object_terms( $post_ID, (int) $term->term_id, 'media_folder' );
1080 - } else {
1081 - // if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
1082 - // error_log( 'Media Folder: Could not find term for value "' . $folder_id . '" for attachment ID ' . $post_ID );
1083 - // }
1084 - }
1085 - $this->refreshed_folder_data( $post_type, $post_type_tax );
1086 - }
1087 - }
1088 -
1089 -
1090 - public function edit_attachment_fields($form_fields, $post) {
1091 - $folder_fields = array(
1092 - 'label' => 'Folders',
1093 - 'show_in_edit' => false,
1094 - 'input' => 'html',
1095 - 'value' => '',
1096 - );
1097 -
1098 - $taxonomy_name = 'media_folder';
1099 -
1100 - // get the assigned media library folders from the cache
1101 - $terms = get_the_terms($post->ID, $taxonomy_name);
1102 - if ($terms) {
1103 - $folder_fields['value'] = join(', ', wp_list_pluck($terms, 'slug'));
900 + public function wp_adminify_render_terms_dropdown( $post_id, $taxonomy ) {
901 + $selected_terms = wp_get_object_terms( $post_id, $taxonomy, array(
902 + 'fields' => 'ids',
903 + ) );
904 + $selected_term = ( !empty( $selected_terms ) ? $selected_terms[0] : 0 );
905 + $terms = get_terms( array(
906 + 'taxonomy' => $taxonomy,
907 + 'hide_empty' => false,
908 + 'parent' => 0,
909 + ) );
910 + echo '<select name="media_folder_select" class="media-folder-select" data-attachment-id="' . $post_id . '">';
911 + echo '<option value="">— Select Folder —</option>';
912 + if ( !empty( $terms ) && !is_wp_error( $terms ) ) {
913 + foreach ( $terms as $term ) {
914 + $this->wp_adminify_render_term_option( $term, $selected_term, $taxonomy );
915 + }
916 + }
917 + echo '</select>';
918 + $this->wp_adminify_add_folder_script();
1104 919 }
1105 920
1106 - ob_start();
1107 - $this->render_terms_dropdown($post->ID, $taxonomy_name);
1108 - $html = ob_get_contents();
1109 - ob_end_clean();
1110 -
1111 - $folder_fields['html'] = $html;
1112 - $form_fields[$taxonomy_name] = $folder_fields;
1113 -
1114 - return $form_fields;
1115 - }
1116 -
1117 - public function render_terms_dropdown($post_id, $taxonomy) {
1118 - $selected_terms = wp_get_object_terms($post_id, $taxonomy, array('fields' => 'ids'));
1119 - $selected_term = !empty($selected_terms) ? $selected_terms[0] : 0;
1120 -
1121 - $terms = get_terms(array(
1122 - 'taxonomy' => $taxonomy,
1123 - 'hide_empty' => false,
1124 - 'parent' => 0
1125 - ));
1126 -
1127 - echo '<select name="media_folder_select" class="media-folder-select" data-attachment-id="' . esc_attr( $post_id ) . '">';
1128 - echo '<option value="">— Select Folder —</option>';
1129 -
1130 - if (!empty($terms) && !is_wp_error($terms)) {
1131 - foreach ($terms as $term) {
1132 - $this->render_term_option($term, $selected_term, $taxonomy);
921 + public function wp_adminify_render_term_option(
922 + $term,
923 + $selected_term,
924 + $taxonomy,
925 + $depth = 0
926 + ) {
927 + $indent = str_repeat( '&nbsp;&nbsp;&nbsp;', $depth );
928 + $selected = selected( $term->term_id, $selected_term, false );
929 + echo sprintf(
930 + '<option value="%s" %s>%s%s</option>',
931 + $term->term_id,
932 + $selected,
933 + $indent,
934 + esc_html( $term->name )
935 + );
936 + // Get children
937 + $children = get_terms( array(
938 + 'taxonomy' => $taxonomy,
939 + 'hide_empty' => false,
940 + 'parent' => $term->term_id,
941 + ) );
942 + if ( !empty( $children ) && !is_wp_error( $children ) ) {
943 + foreach ( $children as $child ) {
944 + $this->wp_adminify_render_term_option(
945 + $child,
946 + $selected_term,
947 + $taxonomy,
948 + $depth + 1
949 + );
950 + }
1133 951 }
1134 952 }
1135 -
1136 - echo '</select>';
1137 953
1138 - $this->add_folder_script();
1139 - }
1140 -
1141 - public function render_term_option($term, $selected_term, $taxonomy, $depth = 0) {
1142 - // Build the indentation from real non-breaking-space characters so it survives esc_html().
1143 - $indent = str_repeat( "\xC2\xA0\xC2\xA0\xC2\xA0", $depth );
1144 - $is_selected = ( (int) $term->term_id === (int) $selected_term );
1145 -
1146 - echo '<option value="' . esc_attr( $term->term_id ) . '"';
1147 - if ( $is_selected ) {
1148 - echo ' selected="selected"';
1149 - }
1150 - echo '>' . esc_html( $indent ) . esc_html( $term->name ) . '</option>';
1151 -
1152 - // Get children
1153 - $children = get_terms(array(
1154 - 'taxonomy' => $taxonomy,
1155 - 'hide_empty' => false,
1156 - 'parent' => $term->term_id
1157 - ));
1158 -
1159 - if (!empty($children) && !is_wp_error($children)) {
1160 - foreach ($children as $child) {
1161 - $this->render_term_option($child, $selected_term, $taxonomy, $depth + 1);
1162 - }
1163 - }
1164 - }
1165 -
1166 - public function add_folder_script() {
1167 - ?>
954 + public function wp_adminify_add_folder_script() {
955 + ?>
1168 956 <script type="text/javascript">
1169 957 jQuery(document).ready(function($) {
1170 958 $('.media-folder-select').on('change', function() {
1171 959 var $select = $(this);
@@ -1186,12 +974,14 @@
1186 974 $.ajax({
1187 975 url: ajaxurl,
1188 976 type: 'POST',
1189 977 data: {
1190 - action: 'pxlbsadminify_assign_media_folder',
978 + action: 'wp_adminify_assign_media_folder',
1191 979 attachment_id: attachment_id,
1192 980 term_id: term_id,
1193 - security: '<?php echo esc_attr( wp_create_nonce("pxlbsadminify_media_folder_nonce") ); ?>'
981 + security: '<?php
982 + echo wp_create_nonce( "wp_adminify_media_folder" );
983 + ?>'
1194 984 },
1195 985 success: function(response) {
1196 986 if (response.success) {
1197 987 } else {
@@ -1211,55 +1001,42 @@
1211 1001 });
1212 1002 });
1213 1003 });
1214 1004 </script>
1215 - <?php
1216 - }
1217 -
1218 - public function handle_folder_assignment() {
1219 - check_ajax_referer('pxlbsadminify_media_folder_nonce', 'security');
1005 + <?php
1006 + }
1220 1007
1221 - if ( ! current_user_can( 'upload_files' ) ) {
1222 - wp_send_json_error( __( 'You do not have permission to perform this action.', 'adminify' ) );
1223 - }
1224 -
1225 - $attachment_id = isset($_POST['attachment_id']) ? intval($_POST['attachment_id']) : 0;
1226 - $term_id = isset($_POST['term_id']) ? intval($_POST['term_id']) : 0;
1227 - $taxonomy = 'media_folder';
1228 -
1229 - if (!$attachment_id || !$term_id) {
1230 - wp_send_json_error('Invalid data');
1231 - }
1232 -
1233 - // First remove all terms from this taxonomy
1234 - wp_delete_object_term_relationships($attachment_id, $taxonomy);
1235 -
1236 - // Add the new term
1237 - $result = wp_set_object_terms($attachment_id, $term_id, $taxonomy);
1238 -
1239 - if (is_wp_error($result)) {
1240 - wp_send_json_error($result->get_error_message());
1241 - }
1242 -
1243 - wp_send_json_success();
1244 - }
1245 -
1246 - public function show_folders_in_list_filter() {
1247 - global $typenow;
1248 - if (! $this->is_module_active()) {
1249 - return;
1008 + public function wp_adminify_handle_folder_assignment() {
1009 + check_ajax_referer( 'wp_adminify_media_folder', 'security' );
1010 + $attachment_id = ( isset( $_POST['attachment_id'] ) ? intval( $_POST['attachment_id'] ) : 0 );
1011 + $term_id = ( isset( $_POST['term_id'] ) ? intval( $_POST['term_id'] ) : 0 );
1012 + $taxonomy = 'media_folder';
1013 + if ( !$attachment_id || !$term_id ) {
1014 + wp_send_json_error( 'Invalid data' );
1015 + }
1016 + // First remove all terms from this taxonomy
1017 + wp_delete_object_term_relationships( $attachment_id, $taxonomy );
1018 + // Add the new term
1019 + $result = wp_set_object_terms( $attachment_id, $term_id, $taxonomy );
1020 + if ( is_wp_error( $result ) ) {
1021 + wp_send_json_error( $result->get_error_message() );
1022 + }
1023 + wp_send_json_success();
1250 1024 }
1251 - if ('attachment' !== $typenow) {
1252 - return;
1253 - }
1254 1025
1255 - // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only check, no state change.
1256 - $selected = isset($_GET['media_folder']) ? sanitize_text_field( wp_unslash( $_GET['media_folder'] ) ) : '';
1257 - wp_dropdown_categories(
1258 - array(
1026 + public function wp_adminify_show_folders_in_list_filter() {
1027 + global $typenow;
1028 + if ( !$this->is_module_active() ) {
1029 + return;
1030 + }
1031 + if ( 'attachment' !== $typenow ) {
1032 + return;
1033 + }
1034 + $selected = ( isset( $_GET['media_folder'] ) ? $_GET['media_folder'] : '' );
1035 + wp_dropdown_categories( array(
1259 1036 'show_option_all' => 'All folders',
1260 1037 'taxonomy' => 'media_folder',
1261 - 'name' => 'folder_id',
1038 + 'name' => 'folder_id',
1262 1039 'id' => 'wp-adminify-media-folder-filter',
1263 1040 'orderby' => 'name',
1264 1041 'selected' => $selected,
1265 1042 'hierarchical' => true,
@@ -1265,8 +1042,8 @@
1265 1042 'hierarchical' => true,
1266 1043 'value_field' => 'slug',
1267 1044 'depth' => 3,
1268 1045 'hide_empty' => false,
1269 - )
1270 - );
1271 - }
1046 + ) );
1047 + }
1048 +
1272 1049 }