ÿØÿà JFIF    ÿÛ „  ( %"1!%)+...383,7(-.+  -+++--++++---+-+-----+---------------+---+-++7-----ÿÀ  ß â" ÿÄ     ÿÄ H    !1AQaq"‘¡2B±ÁÑð#R“Ò Tbr‚²á3csƒ’ÂñDS¢³$CÿÄ   ÿÄ %  !1AQa"23‘ÿÚ   ? ôÿ ¨pŸªáÿ —åYõõ\?àÒü©ŠÄï¨pŸªáÿ —åYõõ\?àÓü©ŠÄá 0Ÿªáÿ Ÿå[úƒ ú®ði~TÁbqÐ8OÕpÿ ƒOò¤Oè`–RÂáœá™êi€ßÉ< FtŸI“öÌ8úDf´°å}“¾œ6  öFá°y¥jñÇh†ˆ¢ã/ÃÐ:ªcÈ "Y¡ðÑl>ÿ ”ÏËte:qž\oäŠe÷󲍷˜HT4&ÿ ÓÐü6ö®¿øþßèô Ÿ•7Ñi’•j|“ñì>b…þS?*Óôÿ ÓÐü*h¥£ír¶ü UãS炟[AÐaè[ûª•õ&õj?†Éö+EzP—WeÒírJFt ‘BŒ†Ï‡%#tE Øz ¥OÛ«!1›üä±Í™%ºÍãö]°î(–:@<‹ŒÊö×òÆt¦ãº+‡¦%ÌÁ²h´OƒJŒtMÜ>ÀÜÊw3Y´•牋4ǍýʏTì>œú=Íwhyë,¾Ôò×õ¿ßÊa»«þˆѪQ|%6ž™A õ%:øj<>É—ÿ Å_ˆCbõ¥š±ý¯Ýƒï…¶|RëócÍf溪“t.СøTÿ *Ä¿-{†çàczůŽ_–^XþŒ±miB[X±d 1,é”zEù»& î9gœf™9Ð'.;—™i}!ôšåîqêÛ٤ёý£½ÆA–àôe"A$˝Úsäÿ ÷Û #°xŸëí(l »ý3—¥5m! rt`†0~'j2(]S¦¦kv,ÚÇ l¦øJA£Šƒ J3E8ÙiŽ:cÉžúeZ°€¯\®kÖ(79«Ž:¯X”¾³Š&¡* ….‰Ž(ÜíŸ2¥ª‡×Hi²TF¤ò[¨íÈRëÉ䢍mgÑ.Ÿ<öäS0í„ǹÁU´f#Vß;Õ–…P@3ío<ä-±»Ž.L|kªÀê›fÂ6@»eu‚|ÓaÞÆŸ…¨ááå>åŠ?cKü6ùTÍÆ”†sĤÚ;H2RÚ†õ\Ö·Ÿn'¾ ñ#ºI¤Å´%çÁ­‚â7›‹qT3Iï¨ÖÚ5I7Ë!ÅOóŸ¶øÝñØôת¦$Tcö‘[«Ö³šÒ';Aþ ¸èíg A2Z"i¸vdÄ÷.iõ®§)¿]¤À†–‡É&ä{V¶iŽ”.Ó×Õÿ û?h¬Mt–íª[ÿ Ñÿ ÌV(í}=ibÔ¡›¥¢±b Lô¥‡piη_Z<‡z§èŒ)iÖwiÇ 2hÙ3·=’d÷8éŽ1¦¸c¤µ€7›7Ø ð\á)} ¹fËí›pAÃL%âc2 í§æQz¿;T8sæ°qø)QFMð‰XŒÂ±N¢aF¨…8¯!U  Z©RÊ ÖPVÄÀÍin™Ì-GˆªÅËŠ›•zË}º±ŽÍFò¹}Uw×#ä5B¤{î}Ð<ÙD é©¤&‡ïDbàÁôMÁ.set( 'jm-ajax', sanitize_text_field( wp_unslash( $_GET['jm-ajax'] ) ) ); } $action = $wp_query->get( 'jm-ajax' ); if ( $action ) { if ( ! defined( 'DOING_AJAX' ) ) { define( 'DOING_AJAX', true ); } // Not home - this is an ajax endpoint. $wp_query->is_home = false; /** * Performs an Ajax action. * The dynamic part of the action, $action, is the predefined Ajax action to be performed. * * @since 1.23.0 */ do_action( 'job_manager_ajax_' . sanitize_text_field( $action ) ); wp_die(); } } /** * Returns Job Listings for Ajax endpoint. */ public function get_listings() { // Get input variables. // phpcs:disable WordPress.Security.NonceVerification.Recommended -- Fetching data only; often for logged out visitors. $search_location = isset( $_REQUEST['search_location'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['search_location'] ) ) : ''; $search_keywords = isset( $_REQUEST['search_keywords'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['search_keywords'] ) ) : ''; $search_categories = isset( $_REQUEST['search_categories'] ) ? wp_unslash( $_REQUEST['search_categories'] ) : ''; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Input is sanitized below. $filter_job_types = isset( $_REQUEST['filter_job_type'] ) ? array_filter( array_map( 'sanitize_title', wp_unslash( (array) $_REQUEST['filter_job_type'] ) ) ) : null; $filter_post_status = isset( $_REQUEST['filter_post_status'] ) ? array_filter( array_map( 'sanitize_title', wp_unslash( (array) $_REQUEST['filter_post_status'] ) ) ) : null; $order = isset( $_REQUEST['order'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['order'] ) ) : 'DESC'; $orderby = isset( $_REQUEST['orderby'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['orderby'] ) ) : 'featured'; $page = isset( $_REQUEST['page'] ) ? absint( $_REQUEST['page'] ) : 1; $per_page = isset( $_REQUEST['per_page'] ) ? absint( $_REQUEST['per_page'] ) : absint( get_option( 'job_manager_per_page' ) ); $filled = isset( $_REQUEST['filled'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['filled'] ) ) : null; $featured = isset( $_REQUEST['featured'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['featured'] ) ) : null; $remote_position = isset( $_REQUEST['remote_position'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['remote_position'] ) ) : null; $show_pagination = isset( $_REQUEST['show_pagination'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['show_pagination'] ) ) : null; $featured_first = isset( $_REQUEST['featured_first'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['featured_first'] ) ) : null; // phpcs:enable WordPress.Security.NonceVerification.Recommended if ( is_array( $search_categories ) ) { $search_categories = array_filter( array_map( 'sanitize_text_field', array_map( 'stripslashes', $search_categories ) ) ); } else { $search_categories = array_filter( [ sanitize_text_field( wp_unslash( $search_categories ) ) ] ); } $types = get_job_listing_types(); $job_types_filtered = ! is_null( $filter_job_types ) && count( $types ) !== count( $filter_job_types ); $args = [ 'search_location' => $search_location, 'search_keywords' => $search_keywords, 'search_categories' => $search_categories, 'job_types' => is_null( $filter_job_types ) || count( $types ) === count( $filter_job_types ) ? '' : $filter_job_types + [ 0 ], 'post_status' => $filter_post_status, 'orderby' => $orderby, 'order' => $order, 'featured_first' => $featured_first, 'offset' => ( $page - 1 ) * $per_page, 'posts_per_page' => max( 1, $per_page ), // phpcs:ignore WordPress.WP.PostsPerPage.posts_per_page_posts_per_page -- Known slow query. ]; if ( 'true' === $filled || 'false' === $filled ) { $args['filled'] = 'true' === $filled; } if ( 'true' === $remote_position || 'false' === $remote_position ) { $args['remote_position'] = 'true' === $remote_position; } if ( 'true' === $featured || 'false' === $featured ) { $args['featured'] = 'true' === $featured; $args['orderby'] = 'featured' === $orderby ? 'date' : $orderby; } /** * Get the arguments to use when building the Job Listing WP Query. * * @since 1.0.0 * * @param array $args Arguments used for generating Job Listing query (see `get_job_listings()`). */ $jobs = get_job_listings( apply_filters( 'job_manager_get_listings_args', $args ) ); $result = [ 'found_jobs' => $jobs->have_posts(), 'showing' => '', 'max_num_pages' => $jobs->max_num_pages, ]; if ( ( $search_location || $search_keywords || $search_categories || $job_types_filtered ) ) { // translators: Placeholder %d is the number of found search results. $message = sprintf( _n( 'Search completed. Found %d matching record.', 'Search completed. Found %d matching records.', $jobs->found_posts, 'wp-job-manager' ), $jobs->found_posts ); $result['showing_all'] = true; } else { $message = ''; } $search_values = [ 'location' => $search_location, 'keywords' => $search_keywords, 'categories' => $search_categories, ]; /** * Filter the message that describes the results of the search query. * * @since 1.0.0 * * @param string $message Default message that is generated when posts are found. * @param array $search_values { * Helpful values often used in the generation of this message. * * @type string $location Query used to filter by job listing location. * @type string $keywords Query used to filter by general keywords. * @type array $categories List of the categories to filter by. * } */ $result['showing'] = apply_filters( 'job_manager_get_listings_custom_filter_text', $message, $search_values ); // Generate RSS link. $result['showing_links'] = job_manager_get_filtered_links( [ 'filter_job_types' => $filter_job_types, 'search_location' => $search_location, 'search_categories' => $search_categories, 'search_keywords' => $search_keywords, ] ); /** * Send back a response to the AJAX request without creating HTML. * * @since 1.26.0 * * @param array $result * @param WP_Query $jobs * @return bool True by default. Change to false to halt further response. */ if ( true !== apply_filters( 'job_manager_ajax_get_jobs_html_results', true, $result, $jobs ) ) { /** * Filters the results of the job listing Ajax query to be sent back to the client. * * @since 1.0.0 * * @param array $result { * Package of the query results along with meta information. * * @type bool $found_jobs Whether or not jobs were found in the query. * @type string $showing Description of the search query and results. * @type int $max_num_pages Number of pages in the search result. * @type string $html HTML representation of the search results (only if filter * `job_manager_ajax_get_jobs_html_results` returns true). * @type array $pagination Pagination links to use for stepping through filter results. * } */ wp_send_json( apply_filters( 'job_manager_get_listings_result', $result, $jobs ) ); return; } ob_start(); if ( $result['found_jobs'] ) { while ( $jobs->have_posts() ) { $jobs->the_post(); get_job_manager_template_part( 'content', \WP_Job_Manager_Post_Types::PT_LISTING ); } } else { get_job_manager_template_part( 'content', 'no-jobs-found' ); } $result['html'] = ob_get_clean(); // Generate pagination. if ( 'true' === $show_pagination ) { $result['pagination'] = get_job_listing_pagination( $jobs->max_num_pages, $page ); } /** This filter is documented in includes/class-wp-job-manager-ajax.php (above) */ wp_send_json( apply_filters( 'job_manager_get_listings_result', $result, $jobs ) ); } /** * Uploads file from an Ajax request. * * No nonce field since the form may be statically cached. */ public function upload_file() { if ( ! job_manager_user_can_upload_file_via_ajax() ) { wp_send_json_error( __( 'You must be logged in to upload files using this method.', 'wp-job-manager' ) ); return; } $data = [ 'files' => [], ]; if ( ! empty( $_FILES ) ) { foreach ( $_FILES as $file_key => $file ) { $files_to_upload = job_manager_prepare_uploaded_files( $file ); foreach ( $files_to_upload as $file_to_upload ) { $uploaded_file = job_manager_upload_file( $file_to_upload, [ 'file_key' => $file_key, ] ); if ( is_wp_error( $uploaded_file ) ) { $data['files'][] = [ 'error' => $uploaded_file->get_error_message(), ]; } else { $data['files'][] = $uploaded_file; } } } } wp_send_json( $data ); } /** * Checks if user can search for other users in ajax call. * * @return bool */ private static function user_can_search_users() { $user_can_search_users = false; /** * Filter the capabilities that are allowed to search for users in ajax call. * * @since 1.32.0 * * @param array $user_caps Array of capabilities/roles that are allowed to search for users. */ $allowed_capabilities = apply_filters( 'job_manager_caps_can_search_users', [ \WP_Job_Manager_Post_Types::CAP_EDIT_LISTINGS ] ); foreach ( $allowed_capabilities as $cap ) { if ( current_user_can( $cap ) ) { $user_can_search_users = true; break; } } /** * Filters whether the current user can search for users in ajax call. * * @since 1.32.0 * * @param bool $user_can_search_users True if they are allowed, false if not. */ return apply_filters( 'job_manager_user_can_search_users', $user_can_search_users ); } /** * Search for users and return json. */ public static function ajax_search_users() { check_ajax_referer( 'search-users', 'security' ); if ( ! self::user_can_search_users() ) { wp_die( -1 ); } $term = isset( $_GET['term'] ) ? sanitize_text_field( wp_unslash( $_GET['term'] ) ) : ''; $page = isset( $_GET['page'] ) ? intval( $_GET['page'] ) : 1; $per_page = 20; $exclude = []; if ( ! empty( $_GET['exclude'] ) ) { $exclude = array_map( 'intval', $_GET['exclude'] ); } if ( empty( $term ) ) { wp_die(); } $more_exist = false; $users = []; // Search by ID. if ( is_numeric( $term ) && ! in_array( intval( $term ), $exclude, true ) ) { $user = get_user_by( 'ID', intval( $term ) ); if ( $user instanceof WP_User ) { $users[ $user->ID ] = $user; } } if ( empty( $users ) ) { $search_args = [ 'exclude' => $exclude, 'search' => '*' . esc_attr( $term ) . '*', 'search_columns' => [ 'user_login', 'user_email', 'user_nicename', 'display_name' ], 'number' => $per_page, 'paged' => $page, 'orderby' => 'display_name', 'order' => 'ASC', ]; /** * Modify the arguments used for `WP_User_Query` constructor. * * @since 1.32.0 * * @see https://codex.wordpress.org/Class_Reference/WP_User_Query * * @param array $search_args Argument array used in `WP_User_Query` constructor. * @param string $term Search term. * @param int[] $exclude Array of IDs to exclude. * @param int $page Current page. */ $search_args = apply_filters( 'job_manager_search_users_args', $search_args, $term, $exclude, $page ); $user_query = new WP_User_Query( $search_args ); $users = $user_query->get_results(); $total_pages = ceil( $user_query->get_total() / $per_page ); $more_exist = $total_pages > $page; } $found_users = []; foreach ( $users as $user ) { $found_users[ $user->ID ] = sprintf( // translators: Used in user select. %1$s is the user's display name; #%2$s is the user ID; %3$s is the user email. esc_html__( '%1$s (#%2$s – %3$s)', 'wp-job-manager' ), htmlentities( $user->display_name ), absint( $user->ID ), $user->user_email ); } $response = [ 'results' => $found_users, 'more' => $more_exist, ]; /** * Modify the search results response for users in ajax call. * * @since 1.32.0 * * @param array $response { * @type array $results Array of all found users; id => string descriptor * @type boolean $more True if there is an additional page. * } * @param string $term Search term. * @param int[] $exclude Array of IDs to exclude. * @param int $page Current page. */ $response = apply_filters( 'job_manager_search_users_response', $response, $term, $exclude, $page ); wp_send_json( $response ); } } WP_Job_Manager_Ajax::instance();