diff --git a/contextual-related-posts.php b/contextual-related-posts.php index 5a3b726..e917481 100644 --- a/contextual-related-posts.php +++ b/contextual-related-posts.php @@ -128,6 +128,7 @@ require_once CRP_PLUGIN_DIR . 'includes/admin/modules/tools.php'; require_once CRP_PLUGIN_DIR . 'includes/admin/modules/loader.php'; require_once CRP_PLUGIN_DIR . 'includes/admin/modules/metabox.php'; + require_once CRP_PLUGIN_DIR . 'includes/admin/modules/class-bulk-edit.php'; } // End if. diff --git a/includes/admin/js/bulk-edit.js b/includes/admin/js/bulk-edit.js new file mode 100644 index 0000000..fb1bbb1 --- /dev/null +++ b/includes/admin/js/bulk-edit.js @@ -0,0 +1,70 @@ +jQuery(document).ready(function ($) { + + // we create a copy of the WP inline edit post function + const wp_inline_edit = inlineEditPost.edit; + + // and then we overwrite the function with our own code + inlineEditPost.edit = function (post_id) { + + // "call" the original WP edit function + // we don't want to leave WordPress hanging + wp_inline_edit.apply(this, arguments); + + // now we take care of our business + + // get the post ID from the argument + if (typeof (post_id) == 'object') { // if it is object, get the ID number + post_id = parseInt(this.getId(post_id)); + } + + if (post_id > 0) { + // define the edit row + const edit_row = $('#edit-' + post_id); + const post_row = $('#post-' + post_id); + + // get the data + const crp_manual_related = $('.crp_manual_related', post_row).text(); + const crp_exclude_this_post = 1 == $('.crp_exclude_this_post', post_row).val() ? true : false; + + // populate the data + $(':input[name="crp_manual_related"]', edit_row).val(crp_manual_related); + $(':input[name="crp_exclude_this_post"]', edit_row).prop('checked', crp_exclude_this_post); + } + }; + + $('#bulk_edit').on('click', function () { + const bulk_row = $('#bulk-edit'); + + // get the selected post ids that are being edited + const post_ids = []; + + // get the data + const crp_manual_related = $(':input[name="crp_manual_related"]', bulk_row).val(); + const crp_exclude_this_post = $('select[name="crp_exclude_this_post"]', bulk_row).val(); + + // get post ids from bulk_edit + bulk_row.find('#bulk-titles-list .ntdelbutton').each(function () { + post_ids.push($(this).attr('id').replace(/^(_)/i, '')); + }); + // convert all post_ids to integer + post_ids.map(function (value, index, array) { + array[index] = parseInt(value); + }); + + // save the data + $.ajax({ + url: ajaxurl, // this is a variable that WordPress has already defined for us + type: 'POST', + async: false, + cache: false, + data: { + action: 'crp_save_bulk_edit', // this is the name of our WP AJAX function that we'll set up next + post_ids: post_ids, // and these are the 2 parameters we're passing to our function + crp_manual_related: crp_manual_related, + crp_exclude_this_post: crp_exclude_this_post, + crp_bulk_edit_nonce: crp_bulk_edit.nonce + } + }); + }); + +}); diff --git a/includes/admin/js/bulk-edit.min.js b/includes/admin/js/bulk-edit.min.js new file mode 100644 index 0000000..55cdb88 --- /dev/null +++ b/includes/admin/js/bulk-edit.min.js @@ -0,0 +1 @@ +jQuery(document).ready((function(t){const e=inlineEditPost.edit;inlineEditPost.edit=function(n){if(e.apply(this,arguments),"object"==typeof n&&(n=parseInt(this.getId(n))),n>0){const e=t("#edit-"+n),a=t("#post-"+n),c=t(".crp_manual_related",a).text(),i=1==t(".crp_exclude_this_post",a).val();t(':input[name="crp_manual_related"]',e).val(c),t(':input[name="crp_exclude_this_post"]',e).prop("checked",i)}},t("#bulk_edit").on("click",(function(){const e=t("#bulk-edit"),n=[],a=t(':input[name="crp_manual_related"]',e).val(),c=t('select[name="crp_exclude_this_post"]',e).val();e.find("#bulk-titles-list .ntdelbutton").each((function(){n.push(t(this).attr("id").replace(/^(_)/i,""))})),n.map((function(t,e,n){n[e]=parseInt(t)})),t.ajax({url:ajaxurl,type:"POST",async:!1,cache:!1,data:{action:"crp_save_bulk_edit",post_ids:n,crp_manual_related:a,crp_exclude_this_post:c,crp_bulk_edit_nonce:crp_bulk_edit.nonce}})}))})); \ No newline at end of file diff --git a/includes/admin/modules/class-bulk-edit.php b/includes/admin/modules/class-bulk-edit.php new file mode 100644 index 0000000..dbc3114 --- /dev/null +++ b/includes/admin/modules/class-bulk-edit.php @@ -0,0 +1,273 @@ + wp_create_nonce( 'crp_bulk_edit_nonce' ), + ) + ); + } + + /** + * Add custom columns to the posts list table. + */ + public function add_custom_columns() { + // Get all post types present on the site. + $post_types = get_post_types( array( 'public' => true ) ); + + // For each post type, add the bulk edit functionality and the columns. + foreach ( $post_types as $post_type ) { + add_filter( 'manage_' . $post_type . '_posts_columns', array( $this, 'add_admin_columns' ) ); + add_action( 'manage_' . $post_type . '_posts_custom_column', array( $this, 'populate_custom_columns' ), 10, 2 ); + } + } + + /** + * Add custom columns to the posts list table. + * + * @param array $columns The existing columns. + * @return array The modified columns. + */ + public function add_admin_columns( $columns ) { + $columns['crp_columns'] = __( 'Contextual Related Posts', 'contextual-related-posts' ); + return $columns; + } + + /** + * Populate the custom columns with data. + * + * @param string $column_name The name of the column. + * @param int $post_id The ID of the post. + */ + public function populate_custom_columns( $column_name, $post_id ) { + switch ( $column_name ) { + case 'crp_columns': + // Get related posts specific meta. + $post_meta = get_post_meta( $post_id, 'crp_post_meta', true ); + + // Manual related. + $manual_related = isset( $post_meta['manual_related'] ) ? $post_meta['manual_related'] : ''; + $manual_related_array = wp_parse_id_list( $manual_related ); + + // For each of the manual related posts, display the post ID with a link to open this in a new tab. + if ( ! empty( $manual_related_array ) ) { + $html = '

' . __( 'Manual related posts:', 'contextual-related-posts' ); + foreach ( $manual_related_array as $related_post_id ) { + $html .= ' ' . esc_html( (string) $related_post_id ) . ','; + } + $html = rtrim( $html, ',' ); + $html .= '

'; + $html .= '

'; + + echo wp_kses_post( $html ); + } + + // Exclude this post. + $exclude_this_post = isset( $post_meta['exclude_this_post'] ) ? $post_meta['exclude_this_post'] : 0; + + // Display the checkbox. + echo '

'; + esc_html_e( 'Exclude from list:', 'contextual-related-posts' ); + echo wp_kses_post( $exclude_this_post ? '' : '' ); + echo ''; + echo '

'; + + break; + } + } + + /** + * Add custom field to quick edit screen. + * + * @param string $column_name The name of the column. + */ + public function quick_edit_custom_box( $column_name ) { + + switch ( $column_name ) { + case 'crp_columns': + if ( current_filter() === 'quick_edit_custom_box' ) { + wp_nonce_field( 'crp_quick_edit_nonce', 'crp_quick_edit_nonce' ); + } else { + wp_nonce_field( 'crp_bulk_edit_nonce', 'crp_bulk_edit_nonce' ); + } + ?> +
+
+ + +
+
+ $value ) { + if ( 'publish' !== get_post_status( $value ) ) { + unset( $manual_related_array[ $key ] ); + } + } + $manual_related = implode( ',', $manual_related_array ); + $post_meta['manual_related'] = $manual_related; + } + + if ( isset( $_REQUEST['crp_exclude_this_post'] ) ) { + $post_meta['exclude_this_post'] = 1; + } else { + $post_meta['exclude_this_post'] = 0; + } + + $meta = get_post_meta( $post_id, 'crp_post_meta', true ); + if ( $meta ) { + $post_meta = array_merge( $meta, $post_meta ); + } + + $post_meta_filtered = array_filter( $post_meta ); + + /**** Now we can start saving */ + if ( empty( $post_meta_filtered ) ) { // Checks if all the array items are 0 or empty. + delete_post_meta( $post_id, 'crp_post_meta' ); // Delete the post meta if no options are set. + } else { + update_post_meta( $post_id, 'crp_post_meta', $post_meta_filtered ); + } + } + + /** + * Save bulk edit data. + */ + public function save_bulk_edit() { + // Security check. + check_ajax_referer( 'crp_bulk_edit_nonce', 'crp_bulk_edit_nonce' ); + + // Get the post IDs. + $post_ids = isset( $_POST['post_ids'] ) ? wp_parse_id_list( wp_unslash( $_POST['post_ids'] ) ) : array(); + + // Get the post meta. + $post_meta = array(); + + if ( isset( $_POST['crp_manual_related'] ) ) { + $manual_related_array = wp_parse_id_list( wp_unslash( $_POST['crp_manual_related'] ) ); + + if ( ! empty( $manual_related_array ) ) { + foreach ( $manual_related_array as $key => $value ) { + if ( 'publish' !== get_post_status( $value ) ) { + unset( $manual_related_array[ $key ] ); + } + } + $manual_related = implode( ',', $manual_related_array ); + $post_meta['manual_related'] = $manual_related; + } + } + + if ( isset( $_POST['crp_exclude_this_post'] ) && -1 !== (int) $_POST['crp_exclude_this_post'] ) { + $post_meta['exclude_this_post'] = intval( wp_unslash( $_POST['crp_exclude_this_post'] ) ); + } + + // Now we can start saving. + foreach ( $post_ids as $post_id ) { + if ( ! current_user_can( 'edit_post', $post_id ) ) { + continue; + } + $meta = get_post_meta( $post_id, 'crp_post_meta', true ); + $meta = $meta ? array_merge( $meta, $post_meta ) : $post_meta; + $meta_filtered = array_filter( $meta ); + + if ( empty( $meta_filtered ) ) { // Checks if all the array items are 0 or empty. + delete_post_meta( $post_id, 'crp_post_meta' ); // Delete the post meta if no options are set. + } else { + update_post_meta( $post_id, 'crp_post_meta', $meta_filtered ); + } + } + + wp_send_json_success(); + } +} + +new Bulk_Edit(); diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 1d9f88f..37ac47f 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -10,6 +10,11 @@ parameters: count: 1 path: includes/admin/default-settings.php + - + message: "#^Constant CRP_PLUGIN_URL not found\\.$#" + count: 1 + path: includes/admin/modules/class-bulk-edit.php + - message: "#^Constant CRP_PLUGIN_DIR not found\\.$#" count: 1 @@ -32,7 +37,7 @@ parameters: - message: "#^Variable \\$meta_key might not be defined\\.$#" - count: 3 + count: 2 path: includes/main-query.php - diff --git a/readme.txt b/readme.txt index 7eb1458..ac22f5c 100644 --- a/readme.txt +++ b/readme.txt @@ -148,6 +148,9 @@ Contextual Related Posts is one of the many plugins developed by WebberZone. Che = 3.4.0 = +Features: + * Bulk edit posts, pages and custom post types to add the manual relatd posts and/or exclude posts from the related posts list + * Enhancements/Modifications: * Caching of the entire HTML output is enabled by default. You can disable it in the settings page. This will reduce the number of database queries and improve performance. If you have customised the output, you will need to clear the cache for the changes to take effect. Applies to new installs and when you reset the settings * The plugin no longer check for pre v2.5 settings key