__( 'Approve %s', 'wp-job-manager' ), // translators: Placeholder (%s) is the plural name of the job listings post type. 'notice' => __( '%s approved', 'wp-job-manager' ), 'handler' => [ $this, 'bulk_action_handle_approve_job' ], ]; $actions_handled['expire_jobs'] = [ // translators: Placeholder (%s) is the plural name of the job listings post type. 'label' => __( 'Expire %s', 'wp-job-manager' ), // translators: Placeholder (%s) is the plural name of the job listings post type. 'notice' => __( '%s expired', 'wp-job-manager' ), 'handler' => [ $this, 'bulk_action_handle_expire_job' ], ]; $actions_handled['mark_jobs_filled'] = [ // translators: Placeholder (%s) is the plural name of the job listings post type. 'label' => __( 'Mark %s Filled', 'wp-job-manager' ), // translators: Placeholder (%s) is the plural name of the job listings post type. 'notice' => __( '%s marked as filled', 'wp-job-manager' ), 'handler' => [ $this, 'bulk_action_handle_mark_job_filled' ], ]; $actions_handled['mark_jobs_not_filled'] = [ // translators: Placeholder (%s) is the plural name of the job listings post type. 'label' => __( 'Mark %s Not Filled', 'wp-job-manager' ), // translators: Placeholder (%s) is the plural name of the job listings post type. 'notice' => __( '%s marked as not filled', 'wp-job-manager' ), 'handler' => [ $this, 'bulk_action_handle_mark_job_not_filled' ], ]; /** * Filters the bulk actions that can be applied to job listings. * * @since 1.27.0 * * @param array $actions_handled { * Bulk actions that can be handled, indexed by a unique key name (approve_jobs, expire_jobs, etc). Handlers * are responsible for checking abilities (`current_user_can( 'manage_job_listings', $post_id )`) before * performing action. * * @type string $label Label for the bulk actions dropdown. Passed through sprintf with label name of job listing post type. * @type string $notice Success notice shown after performing the action. Passed through sprintf with title(s) of affected job listings. * @type callback $handler Callable handler for performing action. Passed one argument (int $post_id) and should return true on success and false on failure. * } */ return apply_filters( 'wpjm_job_listing_bulk_actions', $actions_handled ); } /** * Adds bulk actions to drop downs on Job Listing admin page. * * @param array $bulk_actions * @return array */ public function add_bulk_actions( $bulk_actions ) { global $wp_post_types; foreach ( $this->get_bulk_actions() as $key => $bulk_action ) { if ( isset( $bulk_action['label'] ) ) { $bulk_actions[ $key ] = sprintf( $bulk_action['label'], $wp_post_types['job_listing']->labels->name ); } } return $bulk_actions; } /** * Performs bulk actions on Job Listing admin page. * * @since 1.27.0 * * @param string $redirect_url The redirect URL. * @param string $action The action being taken. * @param array $post_ids The posts to take the action on. */ public function do_bulk_actions( $redirect_url, $action, $post_ids ) { $actions_handled = $this->get_bulk_actions(); if ( isset( $actions_handled[ $action ] ) && isset( $actions_handled[ $action ]['handler'] ) ) { $handled_jobs = []; if ( ! empty( $post_ids ) ) { foreach ( $post_ids as $post_id ) { if ( 'job_listing' === get_post_type( $post_id ) && call_user_func( $actions_handled[ $action ]['handler'], $post_id ) ) { $handled_jobs[] = $post_id; } } wp_safe_redirect( add_query_arg( 'handled_jobs', $handled_jobs, add_query_arg( 'action_performed', $action, $redirect_url ) ) ); exit; } } } /** * Performs bulk action to approve a single job listing. * * @param int $post_id Post ID. * * @return bool */ public function bulk_action_handle_approve_job( $post_id ) { $job_data = [ 'ID' => $post_id, 'post_status' => 'publish', ]; if ( in_array( get_post_status( $post_id ), [ 'pending', 'pending_payment' ], true ) && current_user_can( 'publish_post', $post_id ) && wp_update_post( $job_data ) ) { return true; } return false; } /** * Performs bulk action to expire a single job listing. * * @param int $post_id Post ID. * @return bool */ public function bulk_action_handle_expire_job( $post_id ) { $job_data = [ 'ID' => $post_id, 'post_status' => 'expired', ]; if ( current_user_can( 'manage_job_listings', $post_id ) && wp_update_post( $job_data ) ) { return true; } return false; } /** * Performs bulk action to mark a single job listing as filled. * * @param int $post_id Post ID. * * @return bool */ public function bulk_action_handle_mark_job_filled( $post_id ) { if ( current_user_can( 'manage_job_listings', $post_id ) && update_post_meta( $post_id, '_filled', 1 ) ) { return true; } return false; } /** * Performs bulk action to mark a single job listing as not filled. * * @param int $post_id Post ID. * @return bool */ public function bulk_action_handle_mark_job_not_filled( $post_id ) { if ( current_user_can( 'manage_job_listings', $post_id ) && update_post_meta( $post_id, '_filled', 0 ) ) { return true; } return false; } /** * Approves a single job. */ public function approve_job() { if ( ! empty( $_GET['approve_job'] ) && ! empty( $_REQUEST['_wpnonce'] ) && wp_verify_nonce( wp_unslash( $_REQUEST['_wpnonce'] ), 'approve_job' ) // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Nonce should not be modified. && current_user_can( 'publish_post', absint( $_GET['approve_job'] ) ) ) { $post_id = absint( $_GET['approve_job'] ); $job_data = [ 'ID' => $post_id, 'post_status' => 'publish', ]; wp_update_post( $job_data ); wp_safe_redirect( remove_query_arg( 'approve_job', add_query_arg( 'handled_jobs', $post_id, add_query_arg( 'action_performed', 'approve_jobs', admin_url( 'edit.php?post_type=job_listing' ) ) ) ) ); exit; } } /** * Shows a notice if we did a bulk action. */ public function action_notices() { global $post_type, $pagenow; // phpcs:disable WordPress.Security.NonceVerification.Recommended -- Input is used safely. $handled_jobs = isset( $_REQUEST['handled_jobs'] ) && is_array( $_REQUEST['handled_jobs'] ) ? array_map( 'absint', $_REQUEST['handled_jobs'] ) : false; $action = isset( $_REQUEST['action_performed'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['action_performed'] ) ) : false; $actions_handled = $this->get_bulk_actions(); // phpcs:enable WordPress.Security.NonceVerification.Recommended if ( 'edit.php' === $pagenow && 'job_listing' === $post_type && $action && ! empty( $handled_jobs ) && isset( $actions_handled[ $action ] ) && isset( $actions_handled[ $action ]['notice'] ) ) { if ( is_array( $handled_jobs ) ) { $titles = []; foreach ( $handled_jobs as $job_id ) { $titles[] = wpjm_get_the_job_title( $job_id ); } echo '

' . wp_kses_post( sprintf( $actions_handled[ $action ]['notice'], '"' . implode( '", "', $titles ) . '"' ) ) . '

'; } else { echo '

' . wp_kses_post( sprintf( $actions_handled[ $action ]['notice'], '"' . wpjm_get_the_job_title( absint( $handled_jobs ) ) . '"' ) ) . '

'; } } } /** * Shows category dropdown. */ public function jobs_by_category() { global $typenow, $wp_query; if ( 'job_listing' !== $typenow || ! taxonomy_exists( 'job_listing_category' ) ) { return; } include_once JOB_MANAGER_PLUGIN_DIR . '/includes/class-wp-job-manager-category-walker.php'; $r = []; $r['taxonomy'] = 'job_listing_category'; $r['pad_counts'] = 1; $r['hierarchical'] = 1; $r['hide_empty'] = 0; $r['show_count'] = 1; $r['selected'] = ( isset( $wp_query->query['job_listing_category'] ) ) ? $wp_query->query['job_listing_category'] : ''; $r['menu_order'] = false; $terms = get_terms( $r ); $walker = new WP_Job_Manager_Category_Walker(); if ( ! $terms ) { return; } $allowed_html = [ 'option' => [ 'value' => [], 'selected' => [], 'class' => [], ], ]; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- No changes or data exposed based on input. $selected_category = isset( $_GET['job_listing_category'] ) ? sanitize_text_field( wp_unslash( $_GET['job_listing_category'] ) ) : ''; echo "'; } /** * Output dropdowns for filters based on post meta. * * @since 1.31.0 */ public function jobs_meta_filters() { global $typenow; // Only add the filters for job_listings. if ( 'job_listing' !== $typenow ) { return; } // Filter by Filled. $this->jobs_filter_dropdown( 'job_listing_filled', [ [ 'value' => '', 'text' => __( 'Select Filled', 'wp-job-manager' ), ], [ 'value' => '1', 'text' => __( 'Filled', 'wp-job-manager' ), ], [ 'value' => '0', 'text' => __( 'Not Filled', 'wp-job-manager' ), ], ] ); // Filter by Featured. $this->jobs_filter_dropdown( 'job_listing_featured', [ [ 'value' => '', 'text' => __( 'Select Featured', 'wp-job-manager' ), ], [ 'value' => '1', 'text' => __( 'Featured', 'wp-job-manager' ), ], [ 'value' => '0', 'text' => __( 'Not Featured', 'wp-job-manager' ), ], ] ); } /** * Shows dropdown to filter by the given URL parameter. The dropdown will * have three options: "Select $name", "$name", and "Not $name". * * The $options element should be an array of arrays, each with the * attributes needed to create an '; } ?>