PluginProbe
WP EXtra – One Click Optimize / 8.7.0
WP EXtra – One Click Optimize v8.7.0
8.7.1 8.6.8 8.7.0 trunk 5.9 8.0 8.5.0 8.5.4 8.5.5 8.6.0 8.6.1 8.6.2 8.6.3 8.6.5
wp-extra / src / Modules / Common / Posts.php

Posts.php in WP EXtra – One Click Optimize 8.7.0, at src/Modules/Common/Posts.php

644 lines 22.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 namespace WPEXtra\Modules\Common;
3
4 if ( ! defined( 'ABSPATH' ) ) {
5 exit;
6 }
7
8 use WPEXtra\Settings;
9 use WPEXtra\Helper;
10 use WPEXtra\Base;
11
12 class Posts extends Base {
13
14 public function __construct() {
15 parent::__construct();
16 }
17
18 protected $features = [
19 'mce_classic',
20 'mce_plugins',
21 'signature',
22 'classic_widget',
23 'disable_widget',
24 'publish_btn',
25 'post_revisions',
26 'delete_attached',
27 'lock_modified',
28 'show_modified',
29 'img_column',
30 'disable_tags',
31 ];
32
33 public function disable_widget() {
34 add_action('widgets_init', [$this, 'disable_sidebar_widgets'], 100);
35 }
36
37 public function disable_sidebar_widgets() {
38 if (!is_admin() || (isset($_GET['page']) && $_GET['page'] === 'wp-extra')) {
39 return;
40 }
41 $widgets = (array) Helper::get_option('disable_widget', []);
42 if (!empty($widgets)) {
43 foreach ($widgets as $widget_class) {
44 if (class_exists($widget_class)) {
45 unregister_widget($widget_class);
46 }
47 }
48 }
49 }
50
51 public function mce_classic() {
52 add_action( 'current_screen', [$this, 'remove_gutenberg'] );
53 add_filter( 'page_row_actions', [$this, 'classic_editor_add_edit_links'], 15, 2 );
54 add_filter( 'post_row_actions', [$this, 'classic_editor_add_edit_links'], 15, 2 );
55 if ( isset( $_GET['classic-editor'] )) {
56 add_filter( 'use_block_editor_for_post_type', '__return_false', 100 );
57 add_filter( 'tiny_mce_before_init', [$this, 'disable_wpautop_for_page_classic'] );
58 }
59 add_filter( 'redirect_post_location', [$this, 'classic_editor_redirect' ]);
60 add_action('admin_enqueue_scripts', [$this, 'enqueue_scripts']);
61 add_action('wp_ajax_getimage_image', [$this, 'ajax_download_image']);
62
63 }
64
65 public function enqueue_scripts($hook) {
66 if ($hook === 'post.php' || $hook === 'post-new.php') {
67 wp_localize_script('jquery', 'EXTRA_DL', [
68 'ajax_url' => admin_url('admin-ajax.php'),
69 'nonce' => wp_create_nonce('extra_dl_nonce'),
70 'i18n' => [
71 'no_image' => __('Please select an image in the editor.', 'wp-extra'),
72 'already_local' => __('This image is already in your Media Library.', 'wp-extra'),
73 'success' => __('�
74 Image successfully downloaded and replaced.', 'wp-extra'),
75 'error' => __(' Failed to download the image.', 'wp-extra'),
76 'connection' => __(' Connection error.', 'wp-extra'),
77 ],
78 ]);
79 }
80 }
81
82 public function ajax_download_image() {
83 check_ajax_referer('extra_dl_nonce', 'nonce');
84
85 $url = esc_url_raw($_POST['url'] ?? '');
86 $post_id = intval($_POST['post_id'] ?? 0);
87 $alt = sanitize_text_field($_POST['alt'] ?? '');
88 $title = sanitize_text_field($_POST['title'] ?? '');
89
90 if (empty($url) || !$post_id || !wp_http_validate_url($url)) {
91 wp_send_json_error(['message' => __('Missing or invalid data.', 'wp-extra')]);
92 }
93
94 if (!current_user_can('edit_post', $post_id)) {
95 wp_send_json_error(['message' => __('You do not have permission to edit this post.', 'wp-extra')]);
96 }
97
98 $post = get_post($post_id);
99 if (!$post) {
100 wp_send_json_error(['message' => __('Post not found.', 'wp-extra')]);
101 }
102
103 require_once(ABSPATH . 'wp-admin/includes/file.php');
104 require_once(ABSPATH . 'wp-admin/includes/media.php');
105 require_once(ABSPATH . 'wp-admin/includes/image.php');
106
107 $tmp = download_url($url);
108 if (is_wp_error($tmp)) {
109 wp_send_json_error(['message' => sprintf(__('Download failed: %s', 'wp-extra'), $tmp->get_error_message())]);
110 }
111
112 $slug = sanitize_title($post->post_name ?: $post->post_title);
113 $ext = pathinfo(parse_url($url, PHP_URL_PATH), PATHINFO_EXTENSION) ?: 'jpg';
114
115 if (empty($slug)) {
116 $filename = basename(parse_url($url, PHP_URL_PATH));
117 } else {
118 $filename = "{$slug}.{$ext}";
119 }
120
121 $file = [
122 'name' => $filename,
123 'type' => mime_content_type($tmp),
124 'tmp_name' => $tmp,
125 'size' => filesize($tmp),
126 ];
127
128 $attachment_id = media_handle_sideload($file, $post_id);
129
130 if (is_wp_error($attachment_id)) {
131 @unlink($tmp);
132 wp_send_json_error(['message' => __('Could not import image.', 'wp-extra')]);
133 }
134
135 if ($alt) update_post_meta($attachment_id, '_wp_attachment_image_alt', $alt);
136 if ($title) wp_update_post(['ID' => $attachment_id, 'post_title' => $title]);
137
138 $new_url = wp_get_attachment_url($attachment_id);
139
140 wp_send_json_success(['new_url' => $new_url]);
141 }
142
143 public function remove_gutenberg() {
144 $current_screen = get_current_screen();
145 if($current_screen->id !== 'page' ) {
146 add_filter('use_block_editor_for_post_type', '__return_false', 100);
147 }
148 }
149
150 public function classic_editor_add_edit_links ( $actions, $post ) {
151 if ( 'trash' === $post->post_status || ! post_type_supports( $post->post_type, 'editor' ) ) {
152 return $actions;
153 }
154 $edit_url = get_edit_post_link( $post->ID, 'raw' );
155 if ( ! $edit_url ) {
156 return $actions;
157 }
158 if ( $post->post_type == 'page' ) {
159 $edit_url = add_query_arg( 'classic-editor', '', $edit_url );
160 $title = _draft_or_post_title( $post->ID );
161 $edit_action = array(
162 'classic' => sprintf(
163 '<a href="%s" aria-label="%s">%s</a>',
164 esc_url( $edit_url ),
165 esc_attr( sprintf(
166 __( 'Classic Block Keyboard Shortcuts' ),
167 $title
168 ) ),
169 __('Edit Classic')
170 ),
171 );
172 $edit_offset = array_search( 'edit', array_keys( $actions ), true );
173 array_splice( $actions, $edit_offset, 0, $edit_action );
174 }
175 return $actions;
176 }
177
178 public function disable_wpautop_for_page_classic( $init ) {
179 if ( ! is_admin() ) {
180 return $init;
181 }
182 if ( ! function_exists( 'get_current_screen' ) ) {
183 return $init;
184 }
185 $screen = get_current_screen();
186 if ( $screen->post_type !== 'page' ) {
187 return $init;
188 }
189 $init['wpautop'] = false;
190 $init['forced_root_block'] = false;
191 return $init;
192 }
193
194 public function classic_editor_redirect ( $location ) {
195 if ( isset( $_REQUEST['classic-editor'] ) || ( isset( $_POST['_wp_http_referer'] ) && strpos( $_POST['_wp_http_referer'], '&classic-editor' ) !== false ) ) {
196 $location = add_query_arg( 'classic-editor', '', $location );
197 }
198 return $location;
199 }
200
201 public function mce_plugins() {
202 if ( 'flatsome' === wp_get_theme()->template ) {
203 add_action( 'admin_head', [$this, 'remove_ux_mce'], 1 );
204 }
205 add_filter( 'mce_external_plugins', [$this, 'mce_plugin' ]);
206 add_filter( 'mce_buttons', [$this, 'mce_buttons' ]);
207 add_filter( 'mce_buttons_2', [$this, 'mce_buttons_2']);
208 add_action( 'wp_enqueue_scripts', [$this, 'enqueue_frontend_styles'] );
209 add_filter( 'mce_css', [$this, 'add_editor_styles'] );
210 if(Settings::get_option('signature')) {
211 add_shortcode('signature', [$this, 'shortcode_signature']);
212 if(Settings::get_option('signature_pos') == 'top') {
213 add_filter('the_content', [$this, 'add_signature_top']);
214 }
215 if(Settings::get_option('signature_pos') == 'bottom') {
216 add_filter('the_content', [$this, 'add_signature_bottom']);
217 }
218 }
219 if (Settings::get_option('mce_plugins') && !class_exists( 'RankMath' )) {
220 add_action( 'admin_enqueue_scripts', [$this, 'overwrite_wplink'], 999 );
221 }
222 }
223
224 public function enqueue_frontend_styles() {
225 wp_enqueue_style( 'wpex-checklist', plugins_url('/assets/css/checklist.min.css', WPEX_FILE), [], defined('WPEX_VERSION') ? WPEX_VERSION : null );
226 }
227
228 public function add_editor_styles( $mce_css ) {
229 $checklist_css = plugins_url('/assets/css/checklist.min.css', WPEX_FILE);
230 if ( ! empty( $mce_css ) ) {
231 $mce_css .= ',' . $checklist_css;
232 } else {
233 $mce_css = $checklist_css;
234 }
235 return $mce_css;
236 }
237
238 public function mce_plugin( $init ) {
239 $plugins = [];
240 if ( Settings::get_option( 'mce_plugins' ) ) {
241 $plugins = [
242 'table',
243 'visualblocks',
244 'searchreplace',
245 'letterspacing',
246 'changecase',
247 'cleanhtml',
248 'ultable',
249 'getimage',
250 'checklist',
251 ];
252 }
253 if ( Settings::get_option( 'signature' ) ) {
254 $plugins[] = 'signature';
255 }
256 foreach ($plugins as $item) {
257 $init[$item] = plugins_url('/assets/tinymce/' . $item . '/plugin.min.js', WPEX_FILE);
258 }
259 return $init;
260 }
261
262 public function remove_ux_mce() {
263 remove_filter('mce_buttons', 'flatsome_mce_buttons_2');
264 remove_filter('mce_buttons_2', 'flatsome_font_buttons');
265 }
266
267 public function mce_buttons( $buttons ) {
268 array_splice( $buttons, 3, 0, 'underline' );
269 array_splice( $buttons, 4, 0, 'strikethrough' );
270 //array_splice( $buttons, 5, 0, 'hr' );
271 array_splice( $buttons, 11, 0, 'alignjustify' );
272 array_splice( $buttons, 13, 0, 'unlink' );
273 array_splice( $buttons, 14, 0, 'visualblocks' );
274 array_splice( $buttons, 15, 0, 'searchreplace' );
275 array_splice( $buttons, 16, 0, 'wp_code' );
276
277 // Place checklist dropdown right next to list buttons (numlist / bullist)
278 $pos = array_search( 'numlist', $buttons, true );
279 if ( false !== $pos ) {
280 array_splice( $buttons, $pos + 1, 0, 'checklist' );
281 } else {
282 $pos = array_search( 'bullist', $buttons, true );
283 if ( false !== $pos ) {
284 array_splice( $buttons, $pos + 1, 0, 'checklist' );
285 } else {
286 $buttons[] = 'checklist';
287 }
288 }
289
290 return $buttons;
291 }
292
293 public function mce_buttons_2( $buttons ) {
294 if(Settings::get_option('signature')) {
295 array_splice( $buttons, 6, 0, 'signature' );
296 }
297 array_splice( $buttons, 1, 0, 'fontselect' );
298 array_splice( $buttons, 2, 0, 'fontsizeselect' );
299 array_splice( $buttons, 3, 0, 'letterspacing' );
300 array_splice( $buttons, 4, 0, 'changecase' );
301 array_splice( $buttons, 7, 0, 'backcolor' );
302 array_splice( $buttons, 9, 0, 'table' );
303 array_splice( $buttons, 10, 0, 'cleanhtml' );
304 array_splice( $buttons, 12, 0, 'getimage' );
305 array_splice( $buttons, 20, 0, 'ultable' );
306 return $buttons;
307 }
308
309 public function remove_mce_buttons_2( $buttons ) {
310 $remove = array( 'hr', 'charmap', 'strikethrough', 'wp_help' );
311 return array_diff( $buttons, $remove );
312 }
313
314 public function overwrite_wplink() {
315 wp_deregister_script( 'wplink' );
316 wp_register_script( 'wplink', plugins_url('/assets/js/wplink.min.js', WPEX_FILE ), [ 'jquery', 'wp-a11y' ], '1.0', true );
317 wp_localize_script(
318 'wplink',
319 'wpLinkL10n',
320 [
321 'title' => esc_html__( 'Insert/edit link' ),
322 'update' => esc_html__( 'Update' ),
323 'save' => esc_html__( 'Add Link' ),
324 'noTitle' => esc_html__( '(no title)' ),
325 'noMatchesFound' => esc_html__( 'No matches found.' ),
326 'linkSelected' => esc_html__( 'Link selected.' ),
327 'linkInserted' => esc_html__( 'Link inserted.' ),
328 'relCheckbox' => __( 'Add <code>rel="nofollow"</code>' ),
329 'sponsoredCheckbox' => __( 'Add <code>rel="sponsored"</code>' ),
330 'linkTitle' => esc_html__( 'Link Title' ),
331 ]
332 );
333 }
334
335 public function shortcode_signature() {
336 return do_shortcode(Settings::get_option('signature_content'));
337 }
338
339 public function add_signature_top($content) {
340 if ( ! is_singular( 'post' ) && ! is_singular( 'product' ) ) {
341 return $content;
342 }
343
344 $signature = do_shortcode('[signature]');
345 $content_with_signature_top = $signature . $content;
346 return $content_with_signature_top;
347 }
348
349 public function add_signature_bottom($content) {
350 if ( ! is_singular( 'post' ) && ! is_singular( 'product' ) ) {
351 return $content;
352 }
353
354 $signature = do_shortcode('[signature]');
355 $content_with_signature_bottom = $content . $signature;
356 return $content_with_signature_bottom;
357 }
358
359 public function signature() {
360 add_action('wp_ajax_get_signature_content', [$this, 'get_signature_content_callback']);
361 add_action('wp_ajax_nopriv_get_signature_content', [$this, 'get_signature_content_callback']);
362 }
363
364 public function get_signature_content_callback() {
365 wp_send_json_success(do_shortcode('[signature]'));
366 }
367
368 public function classic_widget() {
369 add_filter('gutenberg_use_widgets_block_editor', '__return_false');
370 add_filter('use_widgets_block_editor', '__return_false');
371 }
372
373 public function publish_btn() {
374 add_action( 'admin_enqueue_scripts', [$this, 'publish_button_enqueue'], 20 );
375 }
376
377 public function publish_button_enqueue() {
378 global $pagenow;
379 if ( is_admin() && ($pagenow == 'post.php' || $pagenow == 'post-new.php') ) {
380 wp_enqueue_script('publish-button', plugins_url('/assets/js/publish-button.min.js', WPEX_FILE ), array('jquery'), '1.0', true );
381 }
382 }
383
384 public function post_revisions() {
385 add_filter('wp_revisions_to_keep', [$this, 'limit_revisions'], 10, 2);
386 }
387
388 public function limit_revisions($num, $post) {
389 $limit = Settings::get_option('post_revisions');
390 if ($limit === '' || $limit === null || !is_numeric($limit)) {
391 return $num;
392 }
393 return max(0, (int) $limit);
394 }
395
396 public function delete_attached() {
397 add_action('before_delete_post', [$this, 'delete_attachments']);
398 }
399
400 public function delete_attachments($post_id) {
401 if (wp_is_post_revision($post_id) || wp_is_post_autosave($post_id)) {
402 return;
403 }
404 $attachments = get_attached_media('', $post_id);
405 if (empty($attachments)) {
406 return;
407 }
408 global $wpdb;
409 foreach ($attachments as $attachment) {
410 if ($attachment->post_parent !== (int)$post_id) {
411 continue;
412 }
413 $other_thumb = $wpdb->get_var($wpdb->prepare(
414 "SELECT post_id FROM {$wpdb->postmeta} WHERE meta_key = '_thumbnail_id' AND meta_value = %d AND post_id != %d LIMIT 1",
415 $attachment->ID,
416 $post_id
417 ));
418
419 if ($other_thumb) {
420 wp_update_post([
421 'ID' => $attachment->ID,
422 'post_parent' => (int)$other_thumb,
423 ]);
424 } else {
425 wp_delete_attachment($attachment->ID, true);
426 }
427 }
428 }
429
430 public function show_modified() {
431 add_filter('manage_post_posts_columns', [$this, 'modified_column_register']);
432 add_action('manage_post_posts_custom_column', [$this, 'modified_column_display'], 10, 2);
433 add_filter('manage_edit-post_sortable_columns', [$this, 'modified_column_register_sortable']);
434
435 add_action('admin_footer', [$this, 'script_modified']);
436 add_action('wp_ajax_convert_post_date', [$this, 'convert_post_date']);
437 }
438
439 public function modified_column_register($columns) {
440 $columns['modified'] = __('Last Modified');
441 return $columns;
442 }
443
444 public function modified_column_display($column_name, $post_id) {
445 if ($column_name !== 'modified') return;
446
447 $author_id = get_post_field('post_modified_by', $post_id);
448 if ($author_id) {
449 echo '<small>' . esc_html(get_the_author_meta('display_name', $author_id)) . '</small><br>';
450 }
451
452 echo '<button class="button-link convert-date-btn" data-id="' . esc_attr($post_id) . '">
453 <span class="dashicons dashicons-backup"></span>
454 </button> ';
455
456 echo sprintf(
457 esc_html__('%1$s at %2$s'),
458 esc_html(get_the_modified_date('d/m/Y', $post_id)),
459 esc_html(get_the_modified_time('', $post_id))
460 );
461 }
462
463 public function modified_column_register_sortable($columns) {
464 $columns['modified'] = 'modified';
465 return $columns;
466 }
467
468 public function script_modified() {
469 $screen = get_current_screen();
470
471 if (!$screen || $screen->base !== 'edit' || $screen->post_type !== 'post') return;
472
473 $nonce = wp_create_nonce('convert_post_date_nonce');
474 ?>
475 <script>
476 jQuery(function($){
477
478 const confirmText = "<?php echo esc_js(sprintf('%s %s?', __('Last Modified'), __('Published'))); ?>";
479 const done = "<?php echo esc_js(__('Done')); ?>";
480 const error = "<?php echo esc_js(__('An error occurred.')); ?>";
481
482 $(document).on('click', '.convert-date-btn', function(){
483 if (!confirm(confirmText)) return;
484
485 $.post(ajaxurl, {
486 action: 'convert_post_date',
487 post_id: $(this).data('id'),
488 nonce: '<?php echo $nonce; ?>'
489 }, function(res){
490 if(res.success){
491 alert(done);
492 location.reload();
493 } else {
494 alert(error);
495 }
496 });
497 });
498
499 });
500 </script>
501 <?php
502 }
503
504 public function convert_post_date() {
505 if (
506 !isset($_POST['nonce']) ||
507 !wp_verify_nonce($_POST['nonce'], 'convert_post_date_nonce')
508 ) {
509 wp_send_json_error();
510 }
511
512 $post_id = isset($_POST['post_id']) ? intval($_POST['post_id']) : 0;
513 if (!$post_id) {
514 wp_send_json_error();
515 }
516
517 if (!current_user_can('edit_post', $post_id)) {
518 wp_send_json_error();
519 }
520
521 $post = get_post($post_id);
522 if (!$post || $post->post_type !== 'post') {
523 wp_send_json_error();
524 }
525
526 global $wpdb;
527
528 $publish_date = $post->post_date;
529 $gmt = get_gmt_from_date($publish_date);
530
531 $result = $wpdb->update(
532 $wpdb->posts,
533 [
534 'post_modified' => $publish_date,
535 'post_modified_gmt' => $gmt
536 ],
537 ['ID' => $post_id],
538 ['%s', '%s'],
539 ['%d']
540 );
541
542 if ($result === false) {
543 wp_send_json_error();
544 }
545
546 clean_post_cache($post_id);
547
548 wp_send_json_success();
549 }
550
551 public function lock_modified() {
552 add_filter('wp_insert_post_data', [$this, 'disable_post_modified'], 99, 2);
553 }
554
555 public function disable_post_modified($data, $postarr) {
556 if (empty($postarr['ID'])) return $data;
557
558 $post = get_post($postarr['ID']);
559 if (!$post || $post->post_type !== 'post') return $data;
560
561 if ($post->post_status !== 'publish') return $data;
562
563 if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) return $data;
564
565 $data['post_modified'] = $post->post_modified;
566 $data['post_modified_gmt'] = $post->post_modified_gmt;
567
568 return $data;
569 }
570
571 public function img_column() {
572 add_filter('manage_post_posts_columns', [$this, 'add_img_column']);
573 add_action('manage_post_posts_custom_column', [$this, 'manage_img_column'], 10, 2);
574 add_action('admin_head-edit.php', [$this, 'img_column_css']);
575 }
576
577 public function img_column_css() {
578 $screen = get_current_screen();
579 if (!$screen || $screen->post_type !== 'post') {
580 return;
581 }
582
583 echo '<style>
584 .wp-list-table th.column-thumbnail,.wp-list-table td.column-thumbnail{width:52px!important;text-align:center!important;vertical-align:top!important;padding:10px 4px!important;box-sizing:border-box!important}
585 .wp-list-table th.check-column,.wp-list-table td.check-column{vertical-align:top!important;padding-top:14px!important}
586 .wp-list-table td.column-title{vertical-align:top!important}
587 .wpex-thumb-box{width:40px;height:40px;margin:0 auto;display:flex;align-items:center;justify-content:center;background:#f8fafc;border:1px solid #e2e8f0;border-radius:4px;overflow:hidden;box-sizing:border-box}
588 .wpex-thumb-box a{display:flex;align-items:center;justify-content:center;width:100%;height:100%;text-decoration:none}
589 .wpex-thumb-box img{width:100%!important;height:100%!important;object-fit:cover!important;display:block!important}
590 .wpex-thumb-box .dashicons{color:#94a3b8;font-size:18px;width:18px;height:18px;line-height:18px;display:block}
591 </style>';
592 }
593
594 public function add_img_column($columns) {
595 $new_columns = [];
596 foreach ($columns as $key => $title) {
597 if ($key === 'title') {
598 $new_columns['thumbnail'] = '<span class="screen-reader-text">' . esc_html__('Thumbnail', 'wp-extra') . '</span>';
599 }
600 $new_columns[$key] = $title;
601 }
602 return $new_columns;
603 }
604
605 public function manage_img_column($column_name, $post_id) {
606 if ('thumbnail' === $column_name) {
607 $edit_link = get_edit_post_link($post_id);
608 echo '<div class="wpex-thumb-box">';
609 if (has_post_thumbnail($post_id)) {
610 $img_html = get_the_post_thumbnail($post_id, [80, 80], ['loading' => 'lazy']);
611 echo $edit_link ? '<a href="' . esc_url($edit_link) . '">' . $img_html . '</a>' : $img_html;
612 } else {
613 $placeholder = '<span class="dashicons dashicons-format-image"></span>';
614 echo $edit_link ? '<a href="' . esc_url($edit_link) . '">' . $placeholder . '</a>' : $placeholder;
615 }
616 echo '</div>';
617 }
618 }
619
620 public function disable_tags() {
621 add_action('init', [$this, 'unregister_post_tags']);
622 add_action('admin_menu', [$this, 'remove_tags_admin_menu']);
623 add_action('template_redirect', [$this, 'block_tag_archives']);
624 }
625
626 public function unregister_post_tags() {
627 unregister_taxonomy_for_object_type('post_tag', 'post');
628 }
629
630 public function remove_tags_admin_menu() {
631 remove_submenu_page('edit.php', 'edit-tags.php?taxonomy=post_tag');
632 }
633
634 public function block_tag_archives() {
635 if (is_tag()) {
636 global $wp_query;
637 $wp_query->set_404();
638 status_header(404);
639 nocache_headers();
640 }
641 }
642
643 }
644