WP Job Manager - Version 1.33.4

Version Description

  • Fix: job-submission.js throws js error expects job_description to be WP Editor
  • Fix: checking typeof undefined should be in quotes (in job_submission.js)
  • Fix: plugin activation issue
Download this release

Release Info

Developer panosktn
Plugin Icon 128x128 WP Job Manager
Version 1.33.4
Comparing to
See all releases

Code changes from version 1.33.3 to 1.33.4

Files changed (49) hide show
  1. changelog.txt +5 -0
  2. includes/3rd-party/polylang.php +11 -6
  3. includes/3rd-party/wpml.php +12 -2
  4. includes/abstracts/abstract-wp-job-manager-email.php +1 -1
  5. includes/abstracts/abstract-wp-job-manager-form.php +38 -21
  6. includes/admin/class-wp-job-manager-addons.php +12 -6
  7. includes/admin/class-wp-job-manager-admin-notices.php +6 -4
  8. includes/admin/class-wp-job-manager-admin.php +4 -4
  9. includes/admin/class-wp-job-manager-cpt.php +65 -38
  10. includes/admin/class-wp-job-manager-permalink-settings.php +25 -19
  11. includes/admin/class-wp-job-manager-settings.php +18 -16
  12. includes/admin/class-wp-job-manager-setup.php +15 -9
  13. includes/admin/class-wp-job-manager-taxonomy-meta.php +11 -7
  14. includes/admin/class-wp-job-manager-writepanels.php +34 -20
  15. includes/admin/views/html-admin-page-addons.php +8 -6
  16. includes/admin/views/html-admin-setup-step-2.php +2 -1
  17. includes/admin/views/html-admin-setup-step-3.php +2 -1
  18. includes/class-wp-job-manager-ajax.php +50 -42
  19. includes/class-wp-job-manager-api.php +7 -5
  20. includes/class-wp-job-manager-blocks.php +4 -4
  21. includes/class-wp-job-manager-cache-helper.php +8 -19
  22. includes/class-wp-job-manager-category-walker.php +3 -2
  23. includes/class-wp-job-manager-data-cleaner.php +15 -2
  24. includes/class-wp-job-manager-dependency-checker.php +12 -2
  25. includes/class-wp-job-manager-email-notifications.php +30 -12
  26. includes/class-wp-job-manager-forms.php +10 -7
  27. includes/class-wp-job-manager-geocode.php +4 -4
  28. includes/class-wp-job-manager-install.php +10 -8
  29. includes/class-wp-job-manager-post-types.php +119 -72
  30. includes/class-wp-job-manager-shortcodes.php +38 -25
  31. includes/class-wp-job-manager-usage-tracking.php +11 -7
  32. includes/class-wp-job-manager-widget.php +1 -1
  33. includes/class-wp-job-manager.php +21 -44
  34. includes/forms/class-wp-job-manager-form-edit-job.php +10 -6
  35. includes/forms/class-wp-job-manager-form-submit-job.php +55 -24
  36. includes/helper/class-wp-job-manager-helper-api.php +8 -7
  37. includes/helper/class-wp-job-manager-helper.php +28 -18
  38. includes/helper/views/html-licence-key-error.php +1 -1
  39. includes/helper/views/html-licence-key-notice.php +1 -1
  40. includes/helper/views/html-licences.php +2 -2
  41. includes/widgets/class-wp-job-manager-widget-featured-jobs.php +4 -4
  42. includes/widgets/class-wp-job-manager-widget-recent-jobs.php +4 -4
  43. languages/wp-job-manager.pot +238 -228
  44. readme.txt +8 -2
  45. templates/emails/admin-expiring-job.php +11 -5
  46. uninstall.php +15 -5
  47. wp-job-manager-functions.php +30 -15
  48. wp-job-manager-template.php +14 -9
  49. wp-job-manager.php +11 -3
changelog.txt CHANGED
@@ -1,3 +1,8 @@
 
 
 
 
 
1
  = 1.33.3 =
2
  * Fix: Upgrade jquery-fileupload to v9.32.0
3
  * Fix: Set frame origin on pages where shortcodes are embedded
1
+ = 1.33.4 =
2
+ * Fix: job-submission.js throws js error expects job_description to be WP Editor
3
+ * Fix: checking typeof undefined should be in quotes (in job_submission.js)
4
+ * Fix: plugin activation issue
5
+
6
  = 1.33.3 =
7
  * Fix: Upgrade jquery-fileupload to v9.32.0
8
  * Fix: Set frame origin on pages where shortcodes are embedded
includes/3rd-party/polylang.php CHANGED
@@ -27,8 +27,11 @@ add_action( 'pll_init', 'polylang_wpjm_init' );
27
  * @return array
28
  */
29
  function polylang_wpjm_query_language( $query_args ) {
30
- if ( isset( $_POST['lang'] ) ) {
31
- $query_args['lang'] = $_POST['lang'];
 
 
 
32
  }
33
  return $query_args;
34
  }
@@ -42,9 +45,11 @@ function polylang_wpjm_query_language( $query_args ) {
42
  * @return string
43
  */
44
  function polylang_wpjm_get_job_listings_lang( $lang ) {
45
- if ( function_exists( 'pll_current_language' )
46
- && function_exists( 'pll_is_translated_post_type' )
47
- && pll_is_translated_post_type( 'job_listing' ) ) {
 
 
48
  return pll_current_language();
49
  }
50
  return $lang;
@@ -75,6 +80,6 @@ function polylang_wpjm_page_id( $page_id ) {
75
  * @return bool
76
  */
77
  function polylang_wpjm_doing_ajax( $is_ajax ) {
78
- return false === strpos( $_SERVER['REQUEST_URI'], '/jm-ajax/' ) ? $is_ajax : true;
79
  }
80
  add_filter( 'pll_is_ajax_on_front', 'polylang_wpjm_doing_ajax' );
27
  * @return array
28
  */
29
  function polylang_wpjm_query_language( $query_args ) {
30
+ // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Input is used safely.
31
+ $input_lang = isset( $_POST['lang'] ) ? sanitize_text_field( wp_unslash( $_POST['lang'] ) ) : false;
32
+
33
+ if ( $input_lang ) {
34
+ $query_args['lang'] = $input_lang;
35
  }
36
  return $query_args;
37
  }
45
  * @return string
46
  */
47
  function polylang_wpjm_get_job_listings_lang( $lang ) {
48
+ if (
49
+ function_exists( 'pll_current_language' )
50
+ && function_exists( 'pll_is_translated_post_type' )
51
+ && pll_is_translated_post_type( 'job_listing' )
52
+ ) {
53
  return pll_current_language();
54
  }
55
  return $lang;
80
  * @return bool
81
  */
82
  function polylang_wpjm_doing_ajax( $is_ajax ) {
83
+ return isset( $_SERVER['REQUEST_URI'] ) && false === strpos( sanitize_text_field( wp_unslash( $_SERVER['REQUEST_URI'] ) ), '/jm-ajax/' ) ? $is_ajax : true;
84
  }
85
  add_filter( 'pll_is_ajax_on_front', 'polylang_wpjm_doing_ajax' );
includes/3rd-party/wpml.php CHANGED
@@ -37,8 +37,18 @@ add_action( 'wpml_loaded', 'wpml_wpjm_set_language' );
37
  * @since 1.26.0
38
  */
39
  function wpml_wpjm_set_language() {
40
- if ( ( strstr( $_SERVER['REQUEST_URI'], '/jm-ajax/' ) || ! empty( $_GET['jm-ajax'] ) ) && isset( $_POST['lang'] ) ) {
41
- do_action( 'wpml_switch_language', sanitize_text_field( $_POST['lang'] ) );
 
 
 
 
 
 
 
 
 
 
42
  }
43
  }
44
 
37
  * @since 1.26.0
38
  */
39
  function wpml_wpjm_set_language() {
40
+ // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Input is used safely.
41
+ $input_lang = isset( $_POST['lang'] ) ? sanitize_text_field( wp_unslash( $_POST['lang'] ) ) : false;
42
+
43
+ if (
44
+ isset( $_SERVER['REQUEST_URI'] )
45
+ && (
46
+ strstr( sanitize_text_field( wp_unslash( $_SERVER['REQUEST_URI'] ) ), '/jm-ajax/' )
47
+ || ! empty( $_GET['jm-ajax'] ) // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Input is used safely.
48
+ )
49
+ && $input_lang
50
+ ) {
51
+ do_action( 'wpml_switch_language', $input_lang );
52
  }
53
  }
54
 
includes/abstracts/abstract-wp-job-manager-email.php CHANGED
@@ -188,7 +188,7 @@ abstract class WP_Job_Manager_Email {
188
  * @return string
189
  */
190
  public function get_plain_content() {
191
- return strip_tags( $this->get_rich_content() );
192
  }
193
 
194
  /**
188
  * @return string
189
  */
190
  public function get_plain_content() {
191
+ return wp_strip_all_tags( $this->get_rich_content() );
192
  }
193
 
194
  /**
includes/abstracts/abstract-wp-job-manager-form.php CHANGED
@@ -77,14 +77,14 @@ abstract class WP_Job_Manager_Form {
77
  * Cloning is forbidden.
78
  */
79
  public function __clone() {
80
- _doing_it_wrong( __FUNCTION__ );
81
  }
82
 
83
  /**
84
  * Unserializes instances of this class is forbidden.
85
  */
86
  public function __wakeup() {
87
- _doing_it_wrong( __FUNCTION__ );
88
  }
89
 
90
  /**
@@ -94,15 +94,16 @@ abstract class WP_Job_Manager_Form {
94
 
95
  // reset cookie.
96
  if (
97
- isset( $_GET['new'] ) &&
98
  isset( $_COOKIE['wp-job-manager-submitting-job-id'] ) &&
99
  isset( $_COOKIE['wp-job-manager-submitting-job-key'] ) &&
100
- get_post_meta( $_COOKIE['wp-job-manager-submitting-job-id'], '_submitting_key', true ) === $_COOKIE['wp-job-manager-submitting-job-key']
101
  ) {
102
- delete_post_meta( $_COOKIE['wp-job-manager-submitting-job-id'], '_submitting_key' );
103
  setcookie( 'wp-job-manager-submitting-job-id', '', time() - 3600, COOKIEPATH, COOKIE_DOMAIN, false );
104
  setcookie( 'wp-job-manager-submitting-job-key', '', time() - 3600, COOKIEPATH, COOKIE_DOMAIN, false );
105
- wp_redirect( remove_query_arg( array( 'new', 'key' ), $_SERVER['REQUEST_URI'] ) );
 
106
  }
107
 
108
  $step_key = $this->get_step_key( $this->step );
@@ -114,10 +115,11 @@ abstract class WP_Job_Manager_Form {
114
  $next_step_key = $this->get_step_key( $this->step );
115
 
116
  // If the next step has a handler to call before going to the view, run it now.
117
- if ( $next_step_key
118
- && $step_key !== $next_step_key
119
- && isset( $this->steps[ $next_step_key ]['before'] )
120
- && is_callable( $this->steps[ $next_step_key ]['before'] )
 
121
  ) {
122
  call_user_func( $this->steps[ $next_step_key ]['before'] );
123
  }
@@ -187,7 +189,9 @@ abstract class WP_Job_Manager_Form {
187
  * @return string
188
  */
189
  public function get_action() {
190
- return esc_url_raw( $this->action ? $this->action : wp_unslash( $_SERVER['REQUEST_URI'] ) );
 
 
191
  }
192
 
193
  /**
@@ -299,7 +303,8 @@ abstract class WP_Job_Manager_Form {
299
  */
300
  public function enqueue_scripts() {
301
  if ( $this->use_recaptcha_field() ) {
302
- wp_enqueue_script( 'recaptcha', 'https://www.google.com/recaptcha/api.js' );
 
303
  }
304
  }
305
 
@@ -357,18 +362,22 @@ abstract class WP_Job_Manager_Form {
357
  * @return bool|WP_Error
358
  */
359
  public function validate_recaptcha_field( $success ) {
 
 
 
360
  $recaptcha_field_label = get_option( 'job_manager_recaptcha_label' );
361
- if ( empty( $_POST['g-recaptcha-response'] ) ) {
362
  // translators: Placeholder is for the label of the reCAPTCHA field.
363
  return new WP_Error( 'validation-error', sprintf( esc_html__( '"%s" check failed. Please try again.', 'wp-job-manager' ), $recaptcha_field_label ) );
364
  }
365
 
366
- $response = wp_remote_get(
 
367
  add_query_arg(
368
  array(
369
  'secret' => get_option( 'job_manager_recaptcha_secret_key' ),
370
- 'response' => isset( $_POST['g-recaptcha-response'] ) ? $_POST['g-recaptcha-response'] : '',
371
- 'remoteip' => isset( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ? $_SERVER['HTTP_X_FORWARDED_FOR'] : $_SERVER['REMOTE_ADDR'],
372
  ),
373
  'https://www.google.com/recaptcha/api/siteverify'
374
  )
@@ -471,7 +480,7 @@ abstract class WP_Job_Manager_Form {
471
  }
472
 
473
  // Use standard text sanitizer.
474
- return sanitize_text_field( stripslashes( $value ) );
475
  }
476
 
477
  /**
@@ -486,7 +495,9 @@ abstract class WP_Job_Manager_Form {
486
  if ( ! isset( $field['sanitizer'] ) ) {
487
  $field['sanitizer'] = null;
488
  }
489
- return isset( $_POST[ $key ] ) ? $this->sanitize_posted_field( $_POST[ $key ], $field['sanitizer'] ) : '';
 
 
490
  }
491
 
492
  /**
@@ -497,7 +508,8 @@ abstract class WP_Job_Manager_Form {
497
  * @return array
498
  */
499
  protected function get_posted_multiselect_field( $key, $field ) {
500
- return isset( $_POST[ $key ] ) ? array_map( 'sanitize_text_field', $_POST[ $key ] ) : array();
 
501
  }
502
 
503
  /**
@@ -529,7 +541,8 @@ abstract class WP_Job_Manager_Form {
529
  * @return string
530
  */
531
  protected function get_posted_textarea_field( $key, $field ) {
532
- return isset( $_POST[ $key ] ) ? wp_kses_post( trim( stripslashes( $_POST[ $key ] ) ) ) : '';
 
533
  }
534
 
535
  /**
@@ -551,7 +564,9 @@ abstract class WP_Job_Manager_Form {
551
  * @return array
552
  */
553
  protected function get_posted_term_checklist_field( $key, $field ) {
 
554
  if ( isset( $_POST['tax_input'] ) && isset( $_POST['tax_input'][ $field['taxonomy'] ] ) ) {
 
555
  return array_map( 'absint', $_POST['tax_input'][ $field['taxonomy'] ] );
556
  } else {
557
  return array();
@@ -566,6 +581,7 @@ abstract class WP_Job_Manager_Form {
566
  * @return array
567
  */
568
  protected function get_posted_term_multiselect_field( $key, $field ) {
 
569
  return isset( $_POST[ $key ] ) ? array_map( 'absint', $_POST[ $key ] ) : array();
570
  }
571
 
@@ -577,6 +593,7 @@ abstract class WP_Job_Manager_Form {
577
  * @return int
578
  */
579
  protected function get_posted_term_select_field( $key, $field ) {
 
580
  return ! empty( $_POST[ $key ] ) && $_POST[ $key ] > 0 ? absint( $_POST[ $key ] ) : '';
581
  }
582
 
@@ -597,7 +614,7 @@ abstract class WP_Job_Manager_Form {
597
  }
598
 
599
  $file_urls = array();
600
- $files_to_upload = job_manager_prepare_uploaded_files( $_FILES[ $field_key ] );
601
 
602
  foreach ( $files_to_upload as $file_to_upload ) {
603
  $uploaded_file = job_manager_upload_file(
77
  * Cloning is forbidden.
78
  */
79
  public function __clone() {
80
+ _doing_it_wrong( __FUNCTION__, 'Unable to clone ' . __CLASS__, '1.0.0' );
81
  }
82
 
83
  /**
84
  * Unserializes instances of this class is forbidden.
85
  */
86
  public function __wakeup() {
87
+ _doing_it_wrong( __FUNCTION__, 'Unable to wake up ' . __CLASS__, '1.0.0' );
88
  }
89
 
90
  /**
94
 
95
  // reset cookie.
96
  if (
97
+ isset( $_GET['new'] ) && // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Input is used safely.
98
  isset( $_COOKIE['wp-job-manager-submitting-job-id'] ) &&
99
  isset( $_COOKIE['wp-job-manager-submitting-job-key'] ) &&
100
+ get_post_meta( sanitize_text_field( wp_unslash( $_COOKIE['wp-job-manager-submitting-job-id'] ) ), '_submitting_key', true ) === $_COOKIE['wp-job-manager-submitting-job-key']
101
  ) {
102
+ delete_post_meta( sanitize_text_field( wp_unslash( $_COOKIE['wp-job-manager-submitting-job-id'] ) ), '_submitting_key' );
103
  setcookie( 'wp-job-manager-submitting-job-id', '', time() - 3600, COOKIEPATH, COOKIE_DOMAIN, false );
104
  setcookie( 'wp-job-manager-submitting-job-key', '', time() - 3600, COOKIEPATH, COOKIE_DOMAIN, false );
105
+ wp_safe_redirect( remove_query_arg( array( 'new', 'key' ) ) );
106
+ exit;
107
  }
108
 
109
  $step_key = $this->get_step_key( $this->step );
115
  $next_step_key = $this->get_step_key( $this->step );
116
 
117
  // If the next step has a handler to call before going to the view, run it now.
118
+ if (
119
+ $next_step_key
120
+ && $step_key !== $next_step_key
121
+ && isset( $this->steps[ $next_step_key ]['before'] )
122
+ && is_callable( $this->steps[ $next_step_key ]['before'] )
123
  ) {
124
  call_user_func( $this->steps[ $next_step_key ]['before'] );
125
  }
189
  * @return string
190
  */
191
  public function get_action() {
192
+ $default_action = isset( $_SERVER['REQUEST_URI'] ) ? sanitize_text_field( wp_unslash( $_SERVER['REQUEST_URI'] ) ) : '';
193
+
194
+ return esc_url_raw( $this->action ? $this->action : $default_action );
195
  }
196
 
197
  /**
303
  */
304
  public function enqueue_scripts() {
305
  if ( $this->use_recaptcha_field() ) {
306
+ // phpcs:ignore WordPress.WP.EnqueuedResourceParameters.NoExplicitVersion
307
+ wp_enqueue_script( 'recaptcha', 'https://www.google.com/recaptcha/api.js', array(), false, false );
308
  }
309
  }
310
 
362
  * @return bool|WP_Error
363
  */
364
  public function validate_recaptcha_field( $success ) {
365
+ // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce check happens earlier (when possible).
366
+ $input_recaptcha_response = isset( $_POST['g-recaptcha-response'] ) ? sanitize_text_field( wp_unslash( $_POST['g-recaptcha-response'] ) ) : '';
367
+
368
  $recaptcha_field_label = get_option( 'job_manager_recaptcha_label' );
369
+ if ( empty( $input_recaptcha_response ) ) {
370
  // translators: Placeholder is for the label of the reCAPTCHA field.
371
  return new WP_Error( 'validation-error', sprintf( esc_html__( '"%s" check failed. Please try again.', 'wp-job-manager' ), $recaptcha_field_label ) );
372
  }
373
 
374
+ $default_remote_addr = isset( $_SERVER['REMOTE_ADDR'] ) ? sanitize_text_field( wp_unslash( $_SERVER['REMOTE_ADDR'] ) ) : '';
375
+ $response = wp_remote_get(
376
  add_query_arg(
377
  array(
378
  'secret' => get_option( 'job_manager_recaptcha_secret_key' ),
379
+ 'response' => $input_recaptcha_response,
380
+ 'remoteip' => isset( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ? sanitize_text_field( wp_unslash( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) : $default_remote_addr,
381
  ),
382
  'https://www.google.com/recaptcha/api/siteverify'
383
  )
480
  }
481
 
482
  // Use standard text sanitizer.
483
+ return sanitize_text_field( wp_unslash( $value ) );
484
  }
485
 
486
  /**
495
  if ( ! isset( $field['sanitizer'] ) ) {
496
  $field['sanitizer'] = null;
497
  }
498
+
499
+ // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.NonceVerification -- WP_Job_Manager_Form::sanitize_posted_field handles the sanitization based on the type of data passed; nonce check happens elsewhere.
500
+ return isset( $_POST[ $key ] ) ? $this->sanitize_posted_field( wp_unslash( $_POST[ $key ] ), $field['sanitizer'] ) : '';
501
  }
502
 
503
  /**
508
  * @return array
509
  */
510
  protected function get_posted_multiselect_field( $key, $field ) {
511
+ // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce check happens earlier.
512
+ return isset( $_POST[ $key ] ) ? array_map( 'sanitize_text_field', wp_unslash( $_POST[ $key ] ) ) : array();
513
  }
514
 
515
  /**
541
  * @return string
542
  */
543
  protected function get_posted_textarea_field( $key, $field ) {
544
+ // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce check happens earlier.
545
+ return isset( $_POST[ $key ] ) ? trim( wp_kses_post( wp_unslash( $_POST[ $key ] ) ) ) : '';
546
  }
547
 
548
  /**
564
  * @return array
565
  */
566
  protected function get_posted_term_checklist_field( $key, $field ) {
567
+ // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce check happens earlier.
568
  if ( isset( $_POST['tax_input'] ) && isset( $_POST['tax_input'][ $field['taxonomy'] ] ) ) {
569
+ // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce check happens earlier.
570
  return array_map( 'absint', $_POST['tax_input'][ $field['taxonomy'] ] );
571
  } else {
572
  return array();
581
  * @return array
582
  */
583
  protected function get_posted_term_multiselect_field( $key, $field ) {
584
+ // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce check happens earlier.
585
  return isset( $_POST[ $key ] ) ? array_map( 'absint', $_POST[ $key ] ) : array();
586
  }
587
 
593
  * @return int
594
  */
595
  protected function get_posted_term_select_field( $key, $field ) {
596
+ // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce check happens earlier.
597
  return ! empty( $_POST[ $key ] ) && $_POST[ $key ] > 0 ? absint( $_POST[ $key ] ) : '';
598
  }
599
 
614
  }
615
 
616
  $file_urls = array();
617
+ $files_to_upload = job_manager_prepare_uploaded_files( $_FILES[ $field_key ] ); //phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.ValidatedSanitizedInput.MissingUnslash -- see https://github.com/WordPress-Coding-Standards/WordPress-Coding-Standards/issues/1720.
618
 
619
  foreach ( $files_to_upload as $file_to_upload ) {
620
  $uploaded_file = job_manager_upload_file(
includes/admin/class-wp-job-manager-addons.php CHANGED
@@ -23,7 +23,7 @@ class WP_Job_Manager_Addons {
23
  * @var self
24
  * @since 1.26.0
25
  */
26
- private static $_instance = null;
27
 
28
  /**
29
  * Allows for accessing single instance of class. Class should only be constructed once per call.
@@ -33,10 +33,10 @@ class WP_Job_Manager_Addons {
33
  * @return self Main instance.
34
  */
35
  public static function instance() {
36
- if ( is_null( self::$_instance ) ) {
37
- self::$_instance = new self();
38
  }
39
- return self::$_instance;
40
  }
41
 
42
  /**
@@ -94,7 +94,8 @@ class WP_Job_Manager_Addons {
94
  array(
95
  'version' => JOB_MANAGER_VERSION,
96
  'lang' => get_locale(),
97
- ), self::WPJM_COM_PRODUCTS_API_BASE_URL . '/messages'
 
98
  )
99
  );
100
  if ( ! is_wp_error( $raw_messages ) ) {
@@ -116,6 +117,7 @@ class WP_Job_Manager_Addons {
116
  <nav class="nav-tab-wrapper woo-nav-tab-wrapper">
117
  <a href="<?php echo esc_url( admin_url( 'edit.php?post_type=job_listing&page=job-manager-addons' ) ); ?>" class="nav-tab
118
  <?php
 
119
  if ( ! isset( $_GET['section'] ) || 'helper' !== $_GET['section'] ) {
120
  echo ' nav-tab-active';
121
  }
@@ -124,6 +126,7 @@ class WP_Job_Manager_Addons {
124
  <?php if ( current_user_can( 'update_plugins' ) ) : ?>
125
  <a href="<?php echo esc_url( admin_url( 'edit.php?post_type=job_listing&page=job-manager-addons&section=helper' ) ); ?>" class="nav-tab
126
  <?php
 
127
  if ( isset( $_GET['section'] ) && 'helper' === $_GET['section'] ) {
128
  echo ' nav-tab-active'; }
129
  ?>
@@ -131,13 +134,16 @@ class WP_Job_Manager_Addons {
131
  <?php endif; ?>
132
  </nav>
133
  <?php
 
134
  if ( isset( $_GET['section'] ) && 'helper' === $_GET['section'] ) {
135
  do_action( 'job_manager_helper_output' );
136
  } else {
137
- $category = isset( $_GET['category'] ) ? sanitize_text_field( $_GET['category'] ) : null;
 
138
  $messages = $this->get_messages();
139
  $categories = $this->get_categories();
140
  $add_ons = $this->get_add_ons( $category );
 
141
  include_once dirname( __FILE__ ) . '/views/html-admin-page-addons.php';
142
  }
143
  ?>
23
  * @var self
24
  * @since 1.26.0
25
  */
26
+ private static $instance = null;
27
 
28
  /**
29
  * Allows for accessing single instance of class. Class should only be constructed once per call.
33
  * @return self Main instance.
34
  */
35
  public static function instance() {
36
+ if ( is_null( self::$instance ) ) {
37
+ self::$instance = new self();
38
  }
39
+ return self::$instance;
40
  }
41
 
42
  /**
94
  array(
95
  'version' => JOB_MANAGER_VERSION,
96
  'lang' => get_locale(),
97
+ ),
98
+ self::WPJM_COM_PRODUCTS_API_BASE_URL . '/messages'
99
  )
100
  );
101
  if ( ! is_wp_error( $raw_messages ) ) {
117
  <nav class="nav-tab-wrapper woo-nav-tab-wrapper">
118
  <a href="<?php echo esc_url( admin_url( 'edit.php?post_type=job_listing&page=job-manager-addons' ) ); ?>" class="nav-tab
119
  <?php
120
+ // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Input is used safely.
121
  if ( ! isset( $_GET['section'] ) || 'helper' !== $_GET['section'] ) {
122
  echo ' nav-tab-active';
123
  }
126
  <?php if ( current_user_can( 'update_plugins' ) ) : ?>
127
  <a href="<?php echo esc_url( admin_url( 'edit.php?post_type=job_listing&page=job-manager-addons&section=helper' ) ); ?>" class="nav-tab
128
  <?php
129
+ // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Input is used safely.
130
  if ( isset( $_GET['section'] ) && 'helper' === $_GET['section'] ) {
131
  echo ' nav-tab-active'; }
132
  ?>
134
  <?php endif; ?>
135
  </nav>
136
  <?php
137
+ // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Input is used safely.
138
  if ( isset( $_GET['section'] ) && 'helper' === $_GET['section'] ) {
139
  do_action( 'job_manager_helper_output' );
140
  } else {
141
+ // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Input is used safely.
142
+ $category = isset( $_GET['category'] ) ? sanitize_text_field( wp_unslash( $_GET['category'] ) ) : null;
143
  $messages = $this->get_messages();
144
  $categories = $this->get_categories();
145
  $add_ons = $this->get_add_ons( $category );
146
+
147
  include_once dirname( __FILE__ ) . '/views/html-admin-page-addons.php';
148
  }
149
  ?>
includes/admin/class-wp-job-manager-admin-notices.php CHANGED
@@ -104,8 +104,8 @@ class WP_Job_Manager_Admin_Notices {
104
  * Dismiss notices as requested by user. Inspired by WooCommerce's approach.
105
  */
106
  public static function dismiss_notices() {
107
- if ( isset( $_GET['wpjm_hide_notice'] ) && isset( $_GET['_wpjm_notice_nonce'] ) ) { // WPCS: input var ok, CSRF ok.
108
- if ( ! wp_verify_nonce( sanitize_key( wp_unslash( $_GET['_wpjm_notice_nonce'] ) ), 'job_manager_hide_notices_nonce' ) ) { // WPCS: input var ok, CSRF ok.
109
  wp_die( esc_html__( 'Action failed. Please refresh the page and retry.', 'wp-job-manager' ) );
110
  }
111
 
@@ -113,10 +113,12 @@ class WP_Job_Manager_Admin_Notices {
113
  wp_die( esc_html__( 'You don&#8217;t have permission to do this.', 'wp-job-manager' ) );
114
  }
115
 
116
- $hide_notice = sanitize_key( wp_unslash( $_GET['wpjm_hide_notice'] ) ); // WPCS: input var ok, CSRF ok.
117
 
118
  self::remove_notice( $hide_notice );
119
- wp_redirect( remove_query_arg( array( 'wpjm_hide_notice', '_wpjm_notice_nonce' ), $_SERVER['REQUEST_URI'] ) );
 
 
120
  }
121
  }
122
 
104
  * Dismiss notices as requested by user. Inspired by WooCommerce's approach.
105
  */
106
  public static function dismiss_notices() {
107
+ if ( isset( $_GET['wpjm_hide_notice'] ) && isset( $_GET['_wpjm_notice_nonce'] ) ) {
108
+ if ( ! wp_verify_nonce( wp_unslash( $_GET['_wpjm_notice_nonce'] ), 'job_manager_hide_notices_nonce' ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Nonce should not be modified.
109
  wp_die( esc_html__( 'Action failed. Please refresh the page and retry.', 'wp-job-manager' ) );
110
  }
111
 
113
  wp_die( esc_html__( 'You don&#8217;t have permission to do this.', 'wp-job-manager' ) );
114
  }
115
 
116
+ $hide_notice = sanitize_key( wp_unslash( $_GET['wpjm_hide_notice'] ) );
117
 
118
  self::remove_notice( $hide_notice );
119
+
120
+ wp_safe_redirect( remove_query_arg( array( 'wpjm_hide_notice', '_wpjm_notice_nonce' ) ) );
121
+ exit;
122
  }
123
  }
124
 
includes/admin/class-wp-job-manager-admin.php CHANGED
@@ -22,7 +22,7 @@ class WP_Job_Manager_Admin {
22
  * @var self
23
  * @since 1.26.0
24
  */
25
- private static $_instance = null;
26
 
27
  /**
28
  * Allows for accessing single instance of class. Class should only be constructed once per call.
@@ -32,10 +32,10 @@ class WP_Job_Manager_Admin {
32
  * @return self Main instance.
33
  */
34
  public static function instance() {
35
- if ( is_null( self::$_instance ) ) {
36
- self::$_instance = new self();
37
  }
38
- return self::$_instance;
39
  }
40
 
41
  /**
22
  * @var self
23
  * @since 1.26.0
24
  */
25
+ private static $instance = null;
26
 
27
  /**
28
  * Allows for accessing single instance of class. Class should only be constructed once per call.
32
  * @return self Main instance.
33
  */
34
  public static function instance() {
35
+ if ( is_null( self::$instance ) ) {
36
+ self::$instance = new self();
37
  }
38
+ return self::$instance;
39
  }
40
 
41
  /**
includes/admin/class-wp-job-manager-cpt.php CHANGED
@@ -22,7 +22,7 @@ class WP_Job_Manager_CPT {
22
  * @var self
23
  * @since 1.26.0
24
  */
25
- private static $_instance = null;
26
 
27
  /**
28
  * Allows for accessing single instance of class. Class should only be constructed once per call.
@@ -32,10 +32,10 @@ class WP_Job_Manager_CPT {
32
  * @return self Main instance.
33
  */
34
  public static function instance() {
35
- if ( is_null( self::$_instance ) ) {
36
- self::$_instance = new self();
37
  }
38
- return self::$_instance;
39
  }
40
 
41
  /**
@@ -155,12 +155,14 @@ class WP_Job_Manager_CPT {
155
  $handled_jobs = array();
156
  if ( ! empty( $post_ids ) ) {
157
  foreach ( $post_ids as $post_id ) {
158
- if ( 'job_listing' === get_post_type( $post_id )
159
- && call_user_func( $actions_handled[ $action ]['handler'], $post_id ) ) {
 
 
160
  $handled_jobs[] = $post_id;
161
  }
162
  }
163
- wp_redirect( add_query_arg( 'handled_jobs', $handled_jobs, add_query_arg( 'action_performed', $action, $redirect_url ) ) );
164
  exit;
165
  }
166
  }
@@ -178,9 +180,10 @@ class WP_Job_Manager_CPT {
178
  'ID' => $post_id,
179
  'post_status' => 'publish',
180
  );
181
- if ( in_array( get_post_status( $post_id ), array( 'pending', 'pending_payment' ), true )
182
- && current_user_can( 'publish_post', $post_id )
183
- && wp_update_post( $job_data )
 
184
  ) {
185
  return true;
186
  }
@@ -198,8 +201,9 @@ class WP_Job_Manager_CPT {
198
  'ID' => $post_id,
199
  'post_status' => 'expired',
200
  );
201
- if ( current_user_can( 'manage_job_listings', $post_id )
202
- && wp_update_post( $job_data )
 
203
  ) {
204
  return true;
205
  }
@@ -214,8 +218,9 @@ class WP_Job_Manager_CPT {
214
  * @return bool
215
  */
216
  public function bulk_action_handle_mark_job_filled( $post_id ) {
217
- if ( current_user_can( 'manage_job_listings', $post_id )
218
- && update_post_meta( $post_id, '_filled', 1 )
 
219
  ) {
220
  return true;
221
  }
@@ -229,8 +234,9 @@ class WP_Job_Manager_CPT {
229
  * @return bool
230
  */
231
  public function bulk_action_handle_mark_job_not_filled( $post_id ) {
232
- if ( current_user_can( 'manage_job_listings', $post_id )
233
- && update_post_meta( $post_id, '_filled', 0 )
 
234
  ) {
235
  return true;
236
  }
@@ -241,14 +247,19 @@ class WP_Job_Manager_CPT {
241
  * Approves a single job.
242
  */
243
  public function approve_job() {
244
- if ( ! empty( $_GET['approve_job'] ) && wp_verify_nonce( $_REQUEST['_wpnonce'], 'approve_job' ) && current_user_can( 'publish_post', $_GET['approve_job'] ) ) {
 
 
 
 
 
245
  $post_id = absint( $_GET['approve_job'] );
246
  $job_data = array(
247
  'ID' => $post_id,
248
  'post_status' => 'publish',
249
  );
250
  wp_update_post( $job_data );
251
- wp_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' ) ) ) ) );
252
  exit;
253
  }
254
  }
@@ -259,20 +270,22 @@ class WP_Job_Manager_CPT {
259
  public function action_notices() {
260
  global $post_type, $pagenow;
261
 
262
- $handled_jobs = isset( $_REQUEST['handled_jobs'] ) ? $_REQUEST['handled_jobs'] : false;
263
- $action = isset( $_REQUEST['action_performed'] ) ? $_REQUEST['action_performed'] : false;
 
264
  $actions_handled = $this->get_bulk_actions();
265
-
266
- if ( 'edit.php' === $pagenow
267
- && 'job_listing' === $post_type
268
- && $action
269
- && ! empty( $handled_jobs )
270
- && isset( $actions_handled[ $action ] )
271
- && isset( $actions_handled[ $action ]['notice'] )
 
 
272
  ) {
273
  if ( is_array( $handled_jobs ) ) {
274
- $handled_jobs = array_map( 'absint', $handled_jobs );
275
- $titles = array();
276
  foreach ( $handled_jobs as $job_id ) {
277
  $titles[] = wpjm_get_the_job_title( $job_id );
278
  }
@@ -318,8 +331,10 @@ class WP_Job_Manager_CPT {
318
  ),
319
  );
320
 
 
 
321
  echo "<select name='job_listing_category' id='dropdown_job_listing_category'>";
322
- echo '<option value="" ' . selected( isset( $_GET['job_listing_category'] ) ? $_GET['job_listing_category'] : '', '', false ) . '>' . esc_html__( 'Select category', 'wp-job-manager' ) . '</option>';
323
  echo wp_kses( $walker->walk( $terms, 0, $r ), $allowed_html );
324
  echo '</select>';
325
 
@@ -394,7 +409,8 @@ class WP_Job_Manager_CPT {
394
  * @param array $options The options for the dropdown. See the description above.
395
  */
396
  private function jobs_filter_dropdown( $param, $options ) {
397
- $selected = isset( $_GET[ $param ] ) ? $_GET[ $param ] : '';
 
398
 
399
  echo '<select name="' . esc_attr( $param ) . '" id="dropdown_' . esc_attr( $param ) . '">';
400
 
@@ -430,6 +446,9 @@ class WP_Job_Manager_CPT {
430
  public function post_updated_messages( $messages ) {
431
  global $post, $post_ID, $wp_post_types;
432
 
 
 
 
433
  $messages['job_listing'] = array(
434
  0 => '',
435
  // translators: %1$s is the singular name of the job listing post type; %2$s is the URL to view the listing.
@@ -439,7 +458,7 @@ class WP_Job_Manager_CPT {
439
  // translators: %s is the singular name of the job listing post type.
440
  4 => sprintf( esc_html__( '%s updated.', 'wp-job-manager' ), $wp_post_types['job_listing']->labels->singular_name ),
441
  // translators: %1$s is the singular name of the job listing post type; %2$s is the revision number.
442
- 5 => isset( $_GET['revision'] ) ? sprintf( __( '%1$s restored to revision from %2$s', 'wp-job-manager' ), $wp_post_types['job_listing']->labels->singular_name, wp_post_revision_title( (int) $_GET['revision'], false ) ) : false,
443
  // translators: %1$s is the singular name of the job listing post type; %2$s is the URL to view the listing.
444
  6 => sprintf( __( '%1$s published. <a href="%2$s">View</a>', 'wp-job-manager' ), $wp_post_types['job_listing']->labels->singular_name, esc_url( get_permalink( $post_ID ) ) ),
445
  // translators: %1$s is the singular name of the job listing post type; %2$s is the URL to view the listing.
@@ -713,6 +732,7 @@ class WP_Job_Manager_CPT {
713
 
714
  $post_ids = array_unique(
715
  array_merge(
 
716
  $wpdb->get_col(
717
  $wpdb->prepare(
718
  "SELECT posts.ID
@@ -754,24 +774,29 @@ class WP_Job_Manager_CPT {
754
  return;
755
  }
756
 
 
 
 
 
 
757
  $meta_query = $wp->get( 'meta_query' );
758
  if ( ! is_array( $meta_query ) ) {
759
  $meta_query = array();
760
  }
761
 
762
  // Filter on _filled meta.
763
- if ( isset( $_GET['job_listing_filled'] ) && '' !== $_GET['job_listing_filled'] ) {
764
  $meta_query[] = array(
765
  'key' => '_filled',
766
- 'value' => $_GET['job_listing_filled'],
767
  );
768
  }
769
 
770
  // Filter on _featured meta.
771
- if ( isset( $_GET['job_listing_featured'] ) && '' !== $_GET['job_listing_featured'] ) {
772
  $meta_query[] = array(
773
  'key' => '_featured',
774
- 'value' => $_GET['job_listing_featured'],
775
  );
776
  }
777
 
@@ -790,11 +815,13 @@ class WP_Job_Manager_CPT {
790
  public function search_meta_label( $query ) {
791
  global $pagenow, $typenow;
792
 
793
- if ( 'edit.php' !== $pagenow || 'job_listing' !== $typenow || ! get_query_var( 'job_listing_search' ) ) {
 
794
  return $query;
795
  }
796
 
797
- return wp_unslash( sanitize_text_field( $_GET['s'] ) );
 
798
  }
799
 
800
  /**
22
  * @var self
23
  * @since 1.26.0
24
  */
25
+ private static $instance = null;
26
 
27
  /**
28
  * Allows for accessing single instance of class. Class should only be constructed once per call.
32
  * @return self Main instance.
33
  */
34
  public static function instance() {
35
+ if ( is_null( self::$instance ) ) {
36
+ self::$instance = new self();
37
  }
38
+ return self::$instance;
39
  }
40
 
41
  /**
155
  $handled_jobs = array();
156
  if ( ! empty( $post_ids ) ) {
157
  foreach ( $post_ids as $post_id ) {
158
+ if (
159
+ 'job_listing' === get_post_type( $post_id )
160
+ && call_user_func( $actions_handled[ $action ]['handler'], $post_id )
161
+ ) {
162
  $handled_jobs[] = $post_id;
163
  }
164
  }
165
+ wp_safe_redirect( add_query_arg( 'handled_jobs', $handled_jobs, add_query_arg( 'action_performed', $action, $redirect_url ) ) );
166
  exit;
167
  }
168
  }
180
  'ID' => $post_id,
181
  'post_status' => 'publish',
182
  );
183
+ if (
184
+ in_array( get_post_status( $post_id ), array( 'pending', 'pending_payment' ), true )
185
+ && current_user_can( 'publish_post', $post_id )
186
+ && wp_update_post( $job_data )
187
  ) {
188
  return true;
189
  }
201
  'ID' => $post_id,
202
  'post_status' => 'expired',
203
  );
204
+ if (
205
+ current_user_can( 'manage_job_listings', $post_id )
206
+ && wp_update_post( $job_data )
207
  ) {
208
  return true;
209
  }
218
  * @return bool
219
  */
220
  public function bulk_action_handle_mark_job_filled( $post_id ) {
221
+ if (
222
+ current_user_can( 'manage_job_listings', $post_id )
223
+ && update_post_meta( $post_id, '_filled', 1 )
224
  ) {
225
  return true;
226
  }
234
  * @return bool
235
  */
236
  public function bulk_action_handle_mark_job_not_filled( $post_id ) {
237
+ if (
238
+ current_user_can( 'manage_job_listings', $post_id )
239
+ && update_post_meta( $post_id, '_filled', 0 )
240
  ) {
241
  return true;
242
  }
247
  * Approves a single job.
248
  */
249
  public function approve_job() {
250
+ if (
251
+ ! empty( $_GET['approve_job'] )
252
+ && ! empty( $_REQUEST['_wpnonce'] )
253
+ && wp_verify_nonce( wp_unslash( $_REQUEST['_wpnonce'] ), 'approve_job' ) // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Nonce should not be modified.
254
+ && current_user_can( 'publish_post', absint( $_GET['approve_job'] ) )
255
+ ) {
256
  $post_id = absint( $_GET['approve_job'] );
257
  $job_data = array(
258
  'ID' => $post_id,
259
  'post_status' => 'publish',
260
  );
261
  wp_update_post( $job_data );
262
+ 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' ) ) ) ) );
263
  exit;
264
  }
265
  }
270
  public function action_notices() {
271
  global $post_type, $pagenow;
272
 
273
+ // phpcs:disable WordPress.Security.NonceVerification.Recommended -- Input is used safely.
274
+ $handled_jobs = isset( $_REQUEST['handled_jobs'] ) && is_array( $_REQUEST['handled_jobs'] ) ? array_map( 'absint', $_REQUEST['handled_jobs'] ) : false;
275
+ $action = isset( $_REQUEST['action_performed'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['action_performed'] ) ) : false;
276
  $actions_handled = $this->get_bulk_actions();
277
+ // phpcs:enable WordPress.Security.NonceVerification.Recommended
278
+
279
+ if (
280
+ 'edit.php' === $pagenow
281
+ && 'job_listing' === $post_type
282
+ && $action
283
+ && ! empty( $handled_jobs )
284
+ && isset( $actions_handled[ $action ] )
285
+ && isset( $actions_handled[ $action ]['notice'] )
286
  ) {
287
  if ( is_array( $handled_jobs ) ) {
288
+ $titles = array();
 
289
  foreach ( $handled_jobs as $job_id ) {
290
  $titles[] = wpjm_get_the_job_title( $job_id );
291
  }
331
  ),
332
  );
333
 
334
+ // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- No changes or data exposed based on input.
335
+ $selected_category = isset( $_GET['job_listing_category'] ) ? sanitize_text_field( wp_unslash( $_GET['job_listing_category'] ) ) : '';
336
  echo "<select name='job_listing_category' id='dropdown_job_listing_category'>";
337
+ echo '<option value="" ' . selected( $selected_category, '', false ) . '>' . esc_html__( 'Select category', 'wp-job-manager' ) . '</option>';
338
  echo wp_kses( $walker->walk( $terms, 0, $r ), $allowed_html );
339
  echo '</select>';
340
 
409
  * @param array $options The options for the dropdown. See the description above.
410
  */
411
  private function jobs_filter_dropdown( $param, $options ) {
412
+ // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- No changes or data exposed based on input.
413
+ $selected = isset( $_GET[ $param ] ) ? sanitize_text_field( wp_unslash( $_GET[ $param ] ) ) : '';
414
 
415
  echo '<select name="' . esc_attr( $param ) . '" id="dropdown_' . esc_attr( $param ) . '">';
416
 
446
  public function post_updated_messages( $messages ) {
447
  global $post, $post_ID, $wp_post_types;
448
 
449
+ // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- No changes based on input.
450
+ $revision_title = isset( $_GET['revision'] ) ? wp_post_revision_title( (int) $_GET['revision'], false ) : false;
451
+
452
  $messages['job_listing'] = array(
453
  0 => '',
454
  // translators: %1$s is the singular name of the job listing post type; %2$s is the URL to view the listing.
458
  // translators: %s is the singular name of the job listing post type.
459
  4 => sprintf( esc_html__( '%s updated.', 'wp-job-manager' ), $wp_post_types['job_listing']->labels->singular_name ),
460
  // translators: %1$s is the singular name of the job listing post type; %2$s is the revision number.
461
+ 5 => $revision_title ? sprintf( __( '%1$s restored to revision from %2$s', 'wp-job-manager' ), $wp_post_types['job_listing']->labels->singular_name, $revision_title ) : false,
462
  // translators: %1$s is the singular name of the job listing post type; %2$s is the URL to view the listing.
463
  6 => sprintf( __( '%1$s published. <a href="%2$s">View</a>', 'wp-job-manager' ), $wp_post_types['job_listing']->labels->singular_name, esc_url( get_permalink( $post_ID ) ) ),
464
  // translators: %1$s is the singular name of the job listing post type; %2$s is the URL to view the listing.
732
 
733
  $post_ids = array_unique(
734
  array_merge(
735
+ // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- WP_Query doesn't allow for meta query to be an optional match.
736
  $wpdb->get_col(
737
  $wpdb->prepare(
738
  "SELECT posts.ID
774
  return;
775
  }
776
 
777
+ // phpcs:disable WordPress.Security.NonceVerification.Recommended -- Input is used safely.
778
+ $input_job_listing_filled = isset( $_GET['job_listing_filled'] ) && '' !== $_GET['job_listing_filled'] ? absint( $_GET['job_listing_filled'] ) : false;
779
+ $input_job_listing_featured = isset( $_GET['job_listing_featured'] ) && '' !== $_GET['job_listing_featured'] ? absint( $_GET['job_listing_featured'] ) : false;
780
+ // phpcs:enable WordPress.Security.NonceVerification.Recommended
781
+
782
  $meta_query = $wp->get( 'meta_query' );
783
  if ( ! is_array( $meta_query ) ) {
784
  $meta_query = array();
785
  }
786
 
787
  // Filter on _filled meta.
788
+ if ( false !== $input_job_listing_filled ) {
789
  $meta_query[] = array(
790
  'key' => '_filled',
791
+ 'value' => $input_job_listing_filled,
792
  );
793
  }
794
 
795
  // Filter on _featured meta.
796
+ if ( false !== $input_job_listing_featured ) {
797
  $meta_query[] = array(
798
  'key' => '_featured',
799
+ 'value' => $input_job_listing_featured,
800
  );
801
  }
802
 
815
  public function search_meta_label( $query ) {
816
  global $pagenow, $typenow;
817
 
818
+ // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Input is used safely.
819
+ if ( 'edit.php' !== $pagenow || 'job_listing' !== $typenow || ! get_query_var( 'job_listing_search' ) || ! isset( $_GET['s'] ) ) {
820
  return $query;
821
  }
822
 
823
+ // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Input is used safely.
824
+ return sanitize_text_field( wp_unslash( $_GET['s'] ) );
825
  }
826
 
827
  /**
includes/admin/class-wp-job-manager-permalink-settings.php CHANGED
@@ -22,7 +22,7 @@ class WP_Job_Manager_Permalink_Settings {
22
  * @var self
23
  * @since 1.27.0
24
  */
25
- private static $_instance = null;
26
 
27
  /**
28
  * Permalink settings.
@@ -40,10 +40,10 @@ class WP_Job_Manager_Permalink_Settings {
40
  * @return self Main instance.
41
  */
42
  public static function instance() {
43
- if ( is_null( self::$_instance ) ) {
44
- self::$_instance = new self();
45
  }
46
- return self::$_instance;
47
  }
48
 
49
  /**
@@ -135,26 +135,32 @@ class WP_Job_Manager_Permalink_Settings {
135
  return;
136
  }
137
 
138
- if ( isset( $_POST['permalink_structure'] ) ) {
139
- if ( function_exists( 'switch_to_locale' ) ) {
140
- switch_to_locale( get_locale() );
141
- }
 
142
 
143
- $permalink_settings = WP_Job_Manager_Post_Types::get_raw_permalink_settings();
 
 
144
 
145
- $permalink_settings['job_base'] = sanitize_title_with_dashes( $_POST['wpjm_job_base_slug'] );
146
- $permalink_settings['category_base'] = sanitize_title_with_dashes( $_POST['wpjm_job_category_slug'] );
147
- $permalink_settings['type_base'] = sanitize_title_with_dashes( $_POST['wpjm_job_type_slug'] );
148
 
149
- if ( isset( $_POST['wpjm_job_listings_archive_slug'] ) ) {
150
- $permalink_settings['jobs_archive'] = sanitize_title_with_dashes( $_POST['wpjm_job_listings_archive_slug'] );
151
- }
 
 
 
 
 
 
152
 
153
- update_option( WP_Job_Manager_Post_Types::PERMALINK_OPTION_NAME, wp_json_encode( $permalink_settings ) );
154
 
155
- if ( function_exists( 'restore_current_locale' ) ) {
156
- restore_current_locale();
157
- }
158
  }
159
  }
160
  }
22
  * @var self
23
  * @since 1.27.0
24
  */
25
+ private static $instance = null;
26
 
27
  /**
28
  * Permalink settings.
40
  * @return self Main instance.
41
  */
42
  public static function instance() {
43
+ if ( is_null( self::$instance ) ) {
44
+ self::$instance = new self();
45
  }
46
+ return self::$instance;
47
  }
48
 
49
  /**
135
  return;
136
  }
137
 
138
+ // phpcs:ignore WordPress.Security.NonceVerification.Missing -- WP core handles nonce check for settings save.
139
+ if ( ! isset( $_POST['permalink_structure'] ) ) {
140
+ // We must not be saving permalinks.
141
+ return;
142
+ }
143
 
144
+ if ( function_exists( 'switch_to_locale' ) ) {
145
+ switch_to_locale( get_locale() );
146
+ }
147
 
148
+ $permalink_settings = WP_Job_Manager_Post_Types::get_raw_permalink_settings();
 
 
149
 
150
+ // phpcs:disable WordPress.Security.NonceVerification.Missing -- WP core handles nonce check for settings save.
151
+ $permalink_settings['job_base'] = isset( $_POST['wpjm_job_base_slug'] ) ? sanitize_title_with_dashes( wp_unslash( $_POST['wpjm_job_base_slug'] ) ) : '';
152
+ $permalink_settings['category_base'] = isset( $_POST['wpjm_job_category_slug'] ) ? sanitize_title_with_dashes( wp_unslash( $_POST['wpjm_job_category_slug'] ) ) : '';
153
+ $permalink_settings['type_base'] = isset( $_POST['wpjm_job_type_slug'] ) ? sanitize_title_with_dashes( wp_unslash( $_POST['wpjm_job_type_slug'] ) ) : '';
154
+
155
+ if ( isset( $_POST['wpjm_job_listings_archive_slug'] ) ) {
156
+ $permalink_settings['jobs_archive'] = sanitize_title_with_dashes( wp_unslash( $_POST['wpjm_job_listings_archive_slug'] ) );
157
+ }
158
+ // phpcs:enable WordPress.Security.NonceVerification.Missing
159
 
160
+ update_option( WP_Job_Manager_Post_Types::PERMALINK_OPTION_NAME, wp_json_encode( $permalink_settings ) );
161
 
162
+ if ( function_exists( 'restore_current_locale' ) ) {
163
+ restore_current_locale();
 
164
  }
165
  }
166
  }
includes/admin/class-wp-job-manager-settings.php CHANGED
@@ -22,7 +22,7 @@ class WP_Job_Manager_Settings {
22
  * @var self
23
  * @since 1.26.0
24
  */
25
- private static $_instance = null;
26
 
27
  /**
28
  * Our Settings.
@@ -39,10 +39,10 @@ class WP_Job_Manager_Settings {
39
  * @return self Main instance.
40
  */
41
  public static function instance() {
42
- if ( is_null( self::$_instance ) ) {
43
- self::$_instance = new self();
44
  }
45
- return self::$_instance;
46
  }
47
 
48
  /**
@@ -411,6 +411,7 @@ class WP_Job_Manager_Settings {
411
  </h2>
412
 
413
  <?php
 
414
  if ( ! empty( $_GET['settings-updated'] ) ) {
415
  flush_rewrite_rules();
416
  echo '<div class="updated fade job-manager-updated"><p>' . esc_html__( 'Settings successfully saved', 'wp-job-manager' ) . '</p></div>';
@@ -534,7 +535,7 @@ class WP_Job_Manager_Settings {
534
  type="checkbox"
535
  value="1"
536
  <?php
537
- echo implode( ' ', $attributes ) . ' '; // WPCS: XSS ok.
538
  checked( '1', $value );
539
  ?>
540
  /> <?php echo wp_kses_post( $option['cb_label'] ); ?></label>
@@ -561,8 +562,8 @@ class WP_Job_Manager_Settings {
561
  rows="3"
562
  name="<?php echo esc_attr( $option['name'] ); ?>"
563
  <?php
564
- echo implode( ' ', $attributes ) . ' '; // WPCS: XSS ok.
565
- echo $placeholder; // WPCS: XSS ok.
566
  ?>
567
  >
568
  <?php echo esc_textarea( $value ); ?>
@@ -589,7 +590,7 @@ class WP_Job_Manager_Settings {
589
  class="regular-text"
590
  name="<?php echo esc_attr( $option['name'] ); ?>"
591
  <?php
592
- echo implode( ' ', $attributes ); // WPCS: XSS ok.
593
  ?>
594
  >
595
  <?php
@@ -651,7 +652,8 @@ class WP_Job_Manager_Settings {
651
  'selected' => absint( $value ),
652
  );
653
 
654
- echo str_replace( ' id=', " data-placeholder='" . esc_attr__( 'Select a page&hellip;', 'wp-job-manager' ) . "' id=", wp_dropdown_pages( $args ) ); // WPCS: XSS ok.
 
655
 
656
  if ( ! empty( $option['desc'] ) ) {
657
  echo ' <p class="description">' . wp_kses_post( $option['desc'] ) . '</p>';
@@ -678,7 +680,7 @@ class WP_Job_Manager_Settings {
678
  name="<?php echo esc_attr( $option['name'] ); ?>"
679
  value="<?php echo esc_attr( $value ); ?>"
680
  <?php
681
- echo implode( ' ', $attributes ); // WPCS: XSS ok.
682
  ?>
683
  /><strong><?php echo esc_html( $human_value ); ?></strong>
684
  <?php
@@ -705,8 +707,8 @@ class WP_Job_Manager_Settings {
705
  name="<?php echo esc_attr( $option['name'] ); ?>"
706
  value="<?php echo esc_attr( $value ); ?>"
707
  <?php
708
- echo implode( ' ', $attributes ) . ' '; // WPCS: XSS ok.
709
- echo $placeholder; // WPCS: XSS ok.
710
  ?>
711
  />
712
  <?php
@@ -734,8 +736,8 @@ class WP_Job_Manager_Settings {
734
  name="<?php echo esc_attr( $option['name'] ); ?>"
735
  value="<?php echo esc_attr( $value ); ?>"
736
  <?php
737
- echo implode( ' ', $attributes ) . ' '; // WPCS: XSS ok.
738
- echo $placeholder; // WPCS: XSS ok.
739
  ?>
740
  />
741
  <?php
@@ -762,8 +764,8 @@ class WP_Job_Manager_Settings {
762
  name="<?php echo esc_attr( $option['name'] ); ?>"
763
  value="<?php echo esc_attr( $value ); ?>"
764
  <?php
765
- echo implode( ' ', $attributes ) . ' '; // WPCS: XSS ok.
766
- echo $placeholder; // WPCS: XSS ok.
767
  ?>
768
  />
769
  <?php
22
  * @var self
23
  * @since 1.26.0
24
  */
25
+ private static $instance = null;
26
 
27
  /**
28
  * Our Settings.
39
  * @return self Main instance.
40
  */
41
  public static function instance() {
42
+ if ( is_null( self::$instance ) ) {
43
+ self::$instance = new self();
44
  }
45
+ return self::$instance;
46
  }
47
 
48
  /**
411
  </h2>
412
 
413
  <?php
414
+ // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Used for basic flow.
415
  if ( ! empty( $_GET['settings-updated'] ) ) {
416
  flush_rewrite_rules();
417
  echo '<div class="updated fade job-manager-updated"><p>' . esc_html__( 'Settings successfully saved', 'wp-job-manager' ) . '</p></div>';
535
  type="checkbox"
536
  value="1"
537
  <?php
538
+ echo implode( ' ', $attributes ) . ' '; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
539
  checked( '1', $value );
540
  ?>
541
  /> <?php echo wp_kses_post( $option['cb_label'] ); ?></label>
562
  rows="3"
563
  name="<?php echo esc_attr( $option['name'] ); ?>"
564
  <?php
565
+ echo implode( ' ', $attributes ) . ' '; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
566
+ echo $placeholder; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
567
  ?>
568
  >
569
  <?php echo esc_textarea( $value ); ?>
590
  class="regular-text"
591
  name="<?php echo esc_attr( $option['name'] ); ?>"
592
  <?php
593
+ echo implode( ' ', $attributes ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
594
  ?>
595
  >
596
  <?php
652
  'selected' => absint( $value ),
653
  );
654
 
655
+ // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Safe output.
656
+ echo str_replace( ' id=', " data-placeholder='" . esc_attr__( 'Select a page&hellip;', 'wp-job-manager' ) . "' id=", wp_dropdown_pages( $args ) );
657
 
658
  if ( ! empty( $option['desc'] ) ) {
659
  echo ' <p class="description">' . wp_kses_post( $option['desc'] ) . '</p>';
680
  name="<?php echo esc_attr( $option['name'] ); ?>"
681
  value="<?php echo esc_attr( $value ); ?>"
682
  <?php
683
+ echo implode( ' ', $attributes ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
684
  ?>
685
  /><strong><?php echo esc_html( $human_value ); ?></strong>
686
  <?php
707
  name="<?php echo esc_attr( $option['name'] ); ?>"
708
  value="<?php echo esc_attr( $value ); ?>"
709
  <?php
710
+ echo implode( ' ', $attributes ) . ' '; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
711
+ echo $placeholder; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
712
  ?>
713
  />
714
  <?php
736
  name="<?php echo esc_attr( $option['name'] ); ?>"
737
  value="<?php echo esc_attr( $value ); ?>"
738
  <?php
739
+ echo implode( ' ', $attributes ) . ' '; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
740
+ echo $placeholder; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
741
  ?>
742
  />
743
  <?php
764
  name="<?php echo esc_attr( $option['name'] ); ?>"
765
  value="<?php echo esc_attr( $value ); ?>"
766
  <?php
767
+ echo implode( ' ', $attributes ) . ' '; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
768
+ echo $placeholder; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
769
  ?>
770
  />
771
  <?php
includes/admin/class-wp-job-manager-setup.php CHANGED
@@ -22,7 +22,7 @@ class WP_Job_Manager_Setup {
22
  * @var self
23
  * @since 1.26.0
24
  */
25
- private static $_instance = null;
26
 
27
  /**
28
  * Allows for accessing single instance of class. Class should only be constructed once per call.
@@ -32,10 +32,10 @@ class WP_Job_Manager_Setup {
32
  * @return self Main instance.
33
  */
34
  public static function instance() {
35
- if ( is_null( self::$_instance ) ) {
36
- self::$_instance = new self();
37
  }
38
- return self::$_instance;
39
  }
40
 
41
  /**
@@ -44,6 +44,8 @@ class WP_Job_Manager_Setup {
44
  public function __construct() {
45
  add_action( 'admin_menu', array( $this, 'admin_menu' ), 12 );
46
  add_action( 'admin_head', array( $this, 'admin_head' ) );
 
 
47
  if ( isset( $_GET['page'] ) && 'job-manager-setup' === $_GET['page'] ) {
48
  add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ), 12 );
49
  }
@@ -102,12 +104,12 @@ class WP_Job_Manager_Setup {
102
  $usage_tracking = WP_Job_Manager_Usage_Tracking::get_instance();
103
  $step = ! empty( $_GET['step'] ) ? absint( $_GET['step'] ) : 1;
104
 
105
- if ( 'POST' === $_SERVER['REQUEST_METHOD'] ) {
106
  // Handle step 1 (usage tracking).
107
  $enable = isset( $_POST['job_manager_usage_tracking_enabled'] )
108
  && '1' === $_POST['job_manager_usage_tracking_enabled'];
109
 
110
- $nonce = isset( $_POST['nonce'] ) ? $_POST['nonce'] : null;
111
  $valid_nonce = wp_verify_nonce( $nonce, 'enable-usage-tracking' );
112
 
113
  if ( $valid_nonce ) {
@@ -117,11 +119,14 @@ class WP_Job_Manager_Setup {
117
 
118
  // Handle step 2 -> step 3 (setting up pages).
119
  if ( 3 === $step && ! empty( $_POST ) ) {
120
- if ( false === wp_verify_nonce( $_REQUEST['setup_wizard'], 'step_3' ) ) {
 
 
 
121
  wp_die( 'Error in nonce. Try again.', 'wp-job-manager' );
122
  }
123
- $create_pages = isset( $_POST['wp-job-manager-create-page'] ) ? $_POST['wp-job-manager-create-page'] : array();
124
- $page_titles = $_POST['wp-job-manager-page-title'];
125
  $pages_to_create = array(
126
  'submit_job_form' => '[submit_job_form]',
127
  'job_dashboard' => '[job_dashboard]',
@@ -171,6 +176,7 @@ class WP_Job_Manager_Setup {
171
  * Displays setup page.
172
  */
173
  public function output() {
 
174
  $step = ! empty( $_GET['step'] ) ? absint( $_GET['step'] ) : 1;
175
 
176
  include dirname( __FILE__ ) . '/views/html-admin-setup-header.php';
22
  * @var self
23
  * @since 1.26.0
24
  */
25
+ private static $instance = null;
26
 
27
  /**
28
  * Allows for accessing single instance of class. Class should only be constructed once per call.
32
  * @return self Main instance.
33
  */
34
  public static function instance() {
35
+ if ( is_null( self::$instance ) ) {
36
+ self::$instance = new self();
37
  }
38
+ return self::$instance;
39
  }
40
 
41
  /**
44
  public function __construct() {
45
  add_action( 'admin_menu', array( $this, 'admin_menu' ), 12 );
46
  add_action( 'admin_head', array( $this, 'admin_head' ) );
47
+
48
+ // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Input is used safely.
49
  if ( isset( $_GET['page'] ) && 'job-manager-setup' === $_GET['page'] ) {
50
  add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ), 12 );
51
  }
104
  $usage_tracking = WP_Job_Manager_Usage_Tracking::get_instance();
105
  $step = ! empty( $_GET['step'] ) ? absint( $_GET['step'] ) : 1;
106
 
107
+ if ( isset( $_SERVER['REQUEST_METHOD'] ) && 'POST' === $_SERVER['REQUEST_METHOD'] ) {
108
  // Handle step 1 (usage tracking).
109
  $enable = isset( $_POST['job_manager_usage_tracking_enabled'] )
110
  && '1' === $_POST['job_manager_usage_tracking_enabled'];
111
 
112
+ $nonce = isset( $_POST['nonce'] ) ? wp_unslash( $_POST['nonce'] ) : null; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Nonce should not be modified.
113
  $valid_nonce = wp_verify_nonce( $nonce, 'enable-usage-tracking' );
114
 
115
  if ( $valid_nonce ) {
119
 
120
  // Handle step 2 -> step 3 (setting up pages).
121
  if ( 3 === $step && ! empty( $_POST ) ) {
122
+ if (
123
+ ! isset( $_REQUEST['setup_wizard'] )
124
+ || false === wp_verify_nonce( wp_unslash( $_REQUEST['setup_wizard'] ), 'step_3' ) // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Nonce should not be modified.
125
+ ) {
126
  wp_die( 'Error in nonce. Try again.', 'wp-job-manager' );
127
  }
128
+ $create_pages = isset( $_POST['wp-job-manager-create-page'] ) ? array_map( 'sanitize_text_field', wp_unslash( $_POST['wp-job-manager-create-page'] ) ) : array();
129
+ $page_titles = isset( $_POST['wp-job-manager-page-title'] ) ? array_map( 'sanitize_title', wp_unslash( $_POST['wp-job-manager-page-title'] ) ) : array();
130
  $pages_to_create = array(
131
  'submit_job_form' => '[submit_job_form]',
132
  'job_dashboard' => '[job_dashboard]',
176
  * Displays setup page.
177
  */
178
  public function output() {
179
+ // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Input is used safely.
180
  $step = ! empty( $_GET['step'] ) ? absint( $_GET['step'] ) : 1;
181
 
182
  include dirname( __FILE__ ) . '/views/html-admin-setup-header.php';
includes/admin/class-wp-job-manager-taxonomy-meta.php CHANGED
@@ -21,7 +21,7 @@ class WP_Job_Manager_Taxonomy_Meta {
21
  * @var self
22
  * @since 1.28.0
23
  */
24
- private static $_instance = null;
25
 
26
  /**
27
  * Allows for accessing single instance of class. Class should only be constructed once per call.
@@ -31,10 +31,10 @@ class WP_Job_Manager_Taxonomy_Meta {
31
  * @return self Main instance.
32
  */
33
  public static function instance() {
34
- if ( is_null( self::$_instance ) ) {
35
- self::$_instance = new self();
36
  }
37
- return self::$_instance;
38
  }
39
 
40
  /**
@@ -60,9 +60,13 @@ class WP_Job_Manager_Taxonomy_Meta {
60
  */
61
  public function set_schema_org_employment_type_field( $term_id, $tt_id ) {
62
  $employment_types = wpjm_job_listing_employment_type_options();
63
- if ( isset( $_POST['employment_type'] ) && isset( $employment_types[ $_POST['employment_type'] ] ) ) {
64
- update_term_meta( $term_id, 'employment_type', $_POST['employment_type'] );
65
- } elseif ( isset( $_POST['employment_type'] ) ) {
 
 
 
 
66
  delete_term_meta( $term_id, 'employment_type' );
67
  }
68
  }
21
  * @var self
22
  * @since 1.28.0
23
  */
24
+ private static $instance = null;
25
 
26
  /**
27
  * Allows for accessing single instance of class. Class should only be constructed once per call.
31
  * @return self Main instance.
32
  */
33
  public static function instance() {
34
+ if ( is_null( self::$instance ) ) {
35
+ self::$instance = new self();
36
  }
37
+ return self::$instance;
38
  }
39
 
40
  /**
60
  */
61
  public function set_schema_org_employment_type_field( $term_id, $tt_id ) {
62
  $employment_types = wpjm_job_listing_employment_type_options();
63
+
64
+ // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce check handled by WP core.
65
+ $input_employment_type = isset( $_POST['employment_type'] ) ? sanitize_text_field( wp_unslash( $_POST['employment_type'] ) ) : null;
66
+
67
+ if ( $input_employment_type && isset( $employment_types[ $input_employment_type ] ) ) {
68
+ update_term_meta( $term_id, 'employment_type', sanitize_text_field( wp_unslash( $input_employment_type ) ) );
69
+ } elseif ( null !== $input_employment_type ) {
70
  delete_term_meta( $term_id, 'employment_type' );
71
  }
72
  }
includes/admin/class-wp-job-manager-writepanels.php CHANGED
@@ -22,7 +22,7 @@ class WP_Job_Manager_Writepanels {
22
  * @var self
23
  * @since 1.26.0
24
  */
25
- private static $_instance = null;
26
 
27
  /**
28
  * Allows for accessing single instance of class. Class should only be constructed once per call.
@@ -32,10 +32,10 @@ class WP_Job_Manager_Writepanels {
32
  * @return self Main instance.
33
  */
34
  public static function instance() {
35
- if ( is_null( self::$_instance ) ) {
36
- self::$_instance = new self();
37
  }
38
- return self::$_instance;
39
  }
40
 
41
  /**
@@ -458,8 +458,8 @@ class WP_Job_Manager_Writepanels {
458
  $author_id = $post->post_author;
459
  }
460
 
461
- $posted_by = get_user_by( 'id', $author_id );
462
- $name = ! empty( $field['name'] ) ? $field['name'] : $key;
463
  ?>
464
  <p class="form-field form-field-author">
465
  <label for="<?php echo esc_attr( $key ); ?>"><?php echo esc_html( wp_strip_all_tags( $field['label'] ) ); ?>:</label>
@@ -479,7 +479,7 @@ class WP_Job_Manager_Writepanels {
479
  echo esc_html( $user_string );
480
  }
481
  ?>
482
- <a href="#" class="change-author button button-small"><?php esc_html_e( 'Change', 'wp-job-manager' ); ?></a>
483
  </span>
484
  <span class="hidden change-author">
485
  <select class="wpjm-user-search" id="job_manager_user_search" name="<?php echo esc_attr( $name ); ?>" data-placeholder="<?php esc_attr_e( 'Guest', 'wp-job-manager' ); ?>" data-allow_clear="true">
@@ -581,7 +581,10 @@ class WP_Job_Manager_Writepanels {
581
  if ( is_int( wp_is_post_autosave( $post ) ) ) {
582
  return;
583
  }
584
- if ( empty( $_POST['job_manager_nonce'] ) || ! wp_verify_nonce( $_POST['job_manager_nonce'], 'save_meta_data' ) ) {
 
 
 
585
  return;
586
  }
587
  if ( ! current_user_can( 'edit_post', $post_id ) ) {
@@ -601,8 +604,6 @@ class WP_Job_Manager_Writepanels {
601
  * @param WP_Post $post (Unused).
602
  */
603
  public function save_job_listing_data( $post_id, $post ) {
604
- global $wpdb;
605
-
606
  // These need to exist.
607
  add_post_meta( $post_id, '_filled', 0, true );
608
  add_post_meta( $post_id, '_featured', 0, true );
@@ -615,6 +616,7 @@ class WP_Job_Manager_Writepanels {
615
 
616
  // Checkboxes that aren't sent are unchecked.
617
  if ( 'checkbox' === $field['type'] ) {
 
618
  if ( ! empty( $_POST[ $key ] ) ) {
619
  $_POST[ $key ] = 1;
620
  } else {
@@ -624,6 +626,7 @@ class WP_Job_Manager_Writepanels {
624
 
625
  // Expirey date.
626
  if ( '_job_expires' === $key ) {
 
627
  if ( empty( $_POST[ $key ] ) ) {
628
  if ( get_option( 'job_manager_submission_duration' ) ) {
629
  update_post_meta( $post_id, $key, calculate_job_expiry( $post_id ) );
@@ -631,15 +634,24 @@ class WP_Job_Manager_Writepanels {
631
  delete_post_meta( $post_id, $key );
632
  }
633
  } else {
634
- update_post_meta( $post_id, $key, date( 'Y-m-d', strtotime( sanitize_text_field( $_POST[ $key ] ) ) ) );
 
635
  }
636
  } elseif ( '_job_author' === $key ) {
 
637
  if ( empty( $_POST[ $key ] ) ) {
638
  $_POST[ $key ] = 0;
639
  }
640
- $wpdb->update( $wpdb->posts, array( 'post_author' => $_POST[ $key ] > 0 ? absint( $_POST[ $key ] ) : 0 ), array( 'ID' => $post_id ) );
641
- } elseif ( isset( $_POST[ $key ] ) ) {
642
- update_post_meta( $post_id, $key, $_POST[ $key ] );
 
 
 
 
 
 
 
643
  }
644
  }
645
 
@@ -648,7 +660,7 @@ class WP_Job_Manager_Writepanels {
648
  $today_date = date( 'Y-m-d', current_time( 'timestamp' ) );
649
  $is_job_listing_expired = $expiry_date && $today_date > $expiry_date;
650
  if ( $is_job_listing_expired && ! $this->is_job_listing_status_changing( null, 'draft' ) ) {
651
- remove_action( 'job_manager_save_job_listing', array( $this, 'save_job_listing_data' ), 20, 2 );
652
  if ( $this->is_job_listing_status_changing( 'expired', 'publish' ) ) {
653
  update_post_meta( $post_id, '_job_expires', calculate_job_expiry( $post_id ) );
654
  } else {
@@ -671,14 +683,16 @@ class WP_Job_Manager_Writepanels {
671
  * @return bool True if status is changing from $from_status to $to_status.
672
  */
673
  private function is_job_listing_status_changing( $from_status, $to_status ) {
 
674
  return isset( $_POST['post_status'] )
675
- && isset( $_POST['original_post_status'] )
676
- && $_POST['original_post_status'] !== $_POST['post_status']
677
- && (
678
  null === $from_status
679
  || $from_status === $_POST['original_post_status']
680
- )
681
- && $to_status === $_POST['post_status'];
 
682
  }
683
  }
684
 
22
  * @var self
23
  * @since 1.26.0
24
  */
25
+ private static $instance = null;
26
 
27
  /**
28
  * Allows for accessing single instance of class. Class should only be constructed once per call.
32
  * @return self Main instance.
33
  */
34
  public static function instance() {
35
+ if ( is_null( self::$instance ) ) {
36
+ self::$instance = new self();
37
  }
38
+ return self::$instance;
39
  }
40
 
41
  /**
458
  $author_id = $post->post_author;
459
  }
460
 
461
+ $posted_by = get_user_by( 'id', $author_id );
462
+ $name = ! empty( $field['name'] ) ? $field['name'] : $key;
463
  ?>
464
  <p class="form-field form-field-author">
465
  <label for="<?php echo esc_attr( $key ); ?>"><?php echo esc_html( wp_strip_all_tags( $field['label'] ) ); ?>:</label>
479
  echo esc_html( $user_string );
480
  }
481
  ?>
482
+ <a href="#" class="change-author button button-small"><?php esc_html_e( 'Change', 'wp-job-manager' ); ?></a>
483
  </span>
484
  <span class="hidden change-author">
485
  <select class="wpjm-user-search" id="job_manager_user_search" name="<?php echo esc_attr( $name ); ?>" data-placeholder="<?php esc_attr_e( 'Guest', 'wp-job-manager' ); ?>" data-allow_clear="true">
581
  if ( is_int( wp_is_post_autosave( $post ) ) ) {
582
  return;
583
  }
584
+ if (
585
+ empty( $_POST['job_manager_nonce'] )
586
+ || ! wp_verify_nonce( wp_unslash( $_POST['job_manager_nonce'] ), 'save_meta_data' ) // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Nonce should not be modified.
587
+ ) {
588
  return;
589
  }
590
  if ( ! current_user_can( 'edit_post', $post_id ) ) {
604
  * @param WP_Post $post (Unused).
605
  */
606
  public function save_job_listing_data( $post_id, $post ) {
 
 
607
  // These need to exist.
608
  add_post_meta( $post_id, '_filled', 0, true );
609
  add_post_meta( $post_id, '_featured', 0, true );
616
 
617
  // Checkboxes that aren't sent are unchecked.
618
  if ( 'checkbox' === $field['type'] ) {
619
+ // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce check handled by WP core.
620
  if ( ! empty( $_POST[ $key ] ) ) {
621
  $_POST[ $key ] = 1;
622
  } else {
626
 
627
  // Expirey date.
628
  if ( '_job_expires' === $key ) {
629
+ // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce check handled by WP core.
630
  if ( empty( $_POST[ $key ] ) ) {
631
  if ( get_option( 'job_manager_submission_duration' ) ) {
632
  update_post_meta( $post_id, $key, calculate_job_expiry( $post_id ) );
634
  delete_post_meta( $post_id, $key );
635
  }
636
  } else {
637
+ // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce check handled by WP core.
638
+ update_post_meta( $post_id, $key, date( 'Y-m-d', strtotime( sanitize_text_field( wp_unslash( $_POST[ $key ] ) ) ) ) );
639
  }
640
  } elseif ( '_job_author' === $key ) {
641
+ // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce check handled by WP core.
642
  if ( empty( $_POST[ $key ] ) ) {
643
  $_POST[ $key ] = 0;
644
  }
645
+ $job_data = array();
646
+ $job_data['ID'] = $post_id;
647
+ $job_data['post_author'] = $_POST[ $key ] > 0 ? intval( $_POST[ $key ] ) : 0; // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce check handled by WP core.
648
+
649
+ remove_action( 'job_manager_save_job_listing', array( $this, 'save_job_listing_data' ), 20 );
650
+ wp_update_post( $job_data );
651
+ add_action( 'job_manager_save_job_listing', array( $this, 'save_job_listing_data' ), 20, 2 );
652
+ } elseif ( isset( $_POST[ $key ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce check handled by WP core.
653
+ // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.NonceVerification.Missing -- Input sanitized in registered post meta config; see WP_Job_Manager_Post_Types::register_meta_fields() and WP_Job_Manager_Post_Types::get_job_listing_fields() methods.
654
+ update_post_meta( $post_id, $key, wp_unslash( $_POST[ $key ] ) );
655
  }
656
  }
657
 
660
  $today_date = date( 'Y-m-d', current_time( 'timestamp' ) );
661
  $is_job_listing_expired = $expiry_date && $today_date > $expiry_date;
662
  if ( $is_job_listing_expired && ! $this->is_job_listing_status_changing( null, 'draft' ) ) {
663
+ remove_action( 'job_manager_save_job_listing', array( $this, 'save_job_listing_data' ), 20 );
664
  if ( $this->is_job_listing_status_changing( 'expired', 'publish' ) ) {
665
  update_post_meta( $post_id, '_job_expires', calculate_job_expiry( $post_id ) );
666
  } else {
683
  * @return bool True if status is changing from $from_status to $to_status.
684
  */
685
  private function is_job_listing_status_changing( $from_status, $to_status ) {
686
+ // phpcs:disable WordPress.Security.NonceVerification.Missing -- Nonce check handled by WP core.
687
  return isset( $_POST['post_status'] )
688
+ && isset( $_POST['original_post_status'] )
689
+ && $_POST['original_post_status'] !== $_POST['post_status']
690
+ && (
691
  null === $from_status
692
  || $from_status === $_POST['original_post_status']
693
+ )
694
+ && $to_status === $_POST['post_status'];
695
+ // phpcs:enable WordPress.Security.NonceVerification.Missing
696
  }
697
  }
698
 
includes/admin/views/html-admin-page-addons.php CHANGED
@@ -15,10 +15,10 @@ if ( ! empty( $messages ) ) {
15
  if ( empty( $message->message ) ) {
16
  continue;
17
  }
18
- $type = 'info';
19
  if ( isset( $message->type )
20
  && in_array( $message->type, array( 'info', 'success', 'warning', 'error' ), true ) ) {
21
- $type = $message->type;
22
  }
23
  $action_label = isset( $message->action_label ) ? esc_attr( $message->action_label ) : __( 'More Information &rarr;', 'wp-job-manager' );
24
  $action_url = isset( $message->action_url ) ? esc_url( $message->action_url, array( 'http', 'https' ) ) : false;
@@ -28,17 +28,18 @@ if ( ! empty( $messages ) ) {
28
  $action_str = ' <a href="' . esc_url( $action_url ) . '" target="' . esc_attr( $action_target ) . '" class="button">' . esc_html( $action_label ) . '</a>';
29
  }
30
 
31
- echo '<div class="notice notice-' . esc_attr( $type ) . ' below-h2"><p><strong>' . esc_html( $message->message ) . '</strong>' . wp_kses_post( $action_str ) . '</p></div>';
32
  }
33
  }
34
  if ( ! empty( $categories ) ) {
35
- $current_category = isset( $_GET['category'] ) ? $_GET['category'] : '_all';
 
36
  echo '<ul class="subsubsub">';
37
  foreach ( $categories as $category ) {
38
  ?>
39
  <li>
40
  <a class="<?php echo $current_category === $category->slug ? 'current' : ''; ?>"
41
- href="<?php echo esc_url( admin_url( 'edit.php?post_type=job_listing&page=job-manager-addons&category=' . esc_attr( $category->slug ) ) ); ?>">
42
  <?php echo esc_html( $category->label ); ?>
43
  </a>
44
  </li>
@@ -60,7 +61,8 @@ if ( empty( $add_ons ) ) {
60
  'utm_medium' => 'addonpage',
61
  'utm_campaign' => 'wpjmplugin',
62
  'utm_content' => 'listing',
63
- ), $add_on->link
 
64
  );
65
  ?>
66
  <li class="product">
15
  if ( empty( $message->message ) ) {
16
  continue;
17
  }
18
+ $message_type = 'info';
19
  if ( isset( $message->type )
20
  && in_array( $message->type, array( 'info', 'success', 'warning', 'error' ), true ) ) {
21
+ $message_type = $message->type;
22
  }
23
  $action_label = isset( $message->action_label ) ? esc_attr( $message->action_label ) : __( 'More Information &rarr;', 'wp-job-manager' );
24
  $action_url = isset( $message->action_url ) ? esc_url( $message->action_url, array( 'http', 'https' ) ) : false;
28
  $action_str = ' <a href="' . esc_url( $action_url ) . '" target="' . esc_attr( $action_target ) . '" class="button">' . esc_html( $action_label ) . '</a>';
29
  }
30
 
31
+ echo '<div class="notice notice-' . esc_attr( $message_type ) . ' below-h2"><p><strong>' . esc_html( $message->message ) . '</strong>' . wp_kses_post( $action_str ) . '</p></div>';
32
  }
33
  }
34
  if ( ! empty( $categories ) ) {
35
+ // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Input is used safely.
36
+ $current_category = isset( $_GET['category'] ) ? sanitize_text_field( wp_unslash( $_GET['category'] ) ) : '_all';
37
  echo '<ul class="subsubsub">';
38
  foreach ( $categories as $category ) {
39
  ?>
40
  <li>
41
  <a class="<?php echo $current_category === $category->slug ? 'current' : ''; ?>"
42
+ href="<?php echo esc_url( admin_url( 'edit.php?post_type=job_listing&page=job-manager-addons&category=' . esc_attr( $category->slug ) ) ); ?>">
43
  <?php echo esc_html( $category->label ); ?>
44
  </a>
45
  </li>
61
  'utm_medium' => 'addonpage',
62
  'utm_campaign' => 'wpjmplugin',
63
  'utm_content' => 'listing',
64
+ ),
65
+ $add_on->link
66
  );
67
  ?>
68
  <li class="product">
includes/admin/views/html-admin-setup-step-2.php CHANGED
@@ -20,7 +20,8 @@ if ( ! defined( 'ABSPATH' ) ) {
20
  __(
21
  '(These pages are created using <a href="%1$s" title="What is a shortcode?" class="help-page-link">shortcodes</a>,
22
  which we take care of in this step. If you\'d like to build these pages yourself or want to add one of these options to an existing
23
- page on your site, you can skip this step and take a look at <a href="%2$s" class="help-page-link">shortcode documentation</a> for detailed instructions.)', 'wp-job-manager'
 
24
  ),
25
  'http://codex.wordpress.org/Shortcode',
26
  'https://wpjobmanager.com/document/shortcode-reference/'
20
  __(
21
  '(These pages are created using <a href="%1$s" title="What is a shortcode?" class="help-page-link">shortcodes</a>,
22
  which we take care of in this step. If you\'d like to build these pages yourself or want to add one of these options to an existing
23
+ page on your site, you can skip this step and take a look at <a href="%2$s" class="help-page-link">shortcode documentation</a> for detailed instructions.)',
24
+ 'wp-job-manager'
25
  ),
26
  'http://codex.wordpress.org/Shortcode',
27
  'https://wpjobmanager.com/document/shortcode-reference/'
includes/admin/views/html-admin-setup-step-3.php CHANGED
@@ -52,7 +52,8 @@ if ( ! defined( 'ABSPATH' ) ) {
52
  __(
53
  'If you need help, you can find more detail in our
54
  <a href="%1$s">support documentation</a> or post your question on the
55
- <a href="%2$s">WP Job Manager support forums</a>. Happy hiring!', 'wp-job-manager'
 
56
  ),
57
  'https://wpjobmanager.com/documentation/',
58
  'https://wordpress.org/support/plugin/wp-job-manager'
52
  __(
53
  'If you need help, you can find more detail in our
54
  <a href="%1$s">support documentation</a> or post your question on the
55
+ <a href="%2$s">WP Job Manager support forums</a>. Happy hiring!',
56
+ 'wp-job-manager'
57
  ),
58
  'https://wpjobmanager.com/documentation/',
59
  'https://wordpress.org/support/plugin/wp-job-manager'
includes/class-wp-job-manager-ajax.php CHANGED
@@ -22,7 +22,7 @@ class WP_Job_Manager_Ajax {
22
  * @var self
23
  * @since 1.26.0
24
  */
25
- private static $_instance = null;
26
 
27
  /**
28
  * Allows for accessing single instance of class. Class should only be constructed once per call.
@@ -32,10 +32,10 @@ class WP_Job_Manager_Ajax {
32
  * @return self Main instance.
33
  */
34
  public static function instance() {
35
- if ( is_null( self::$_instance ) ) {
36
- self::$_instance = new self();
37
  }
38
- return self::$_instance;
39
  }
40
 
41
  /**
@@ -70,10 +70,9 @@ class WP_Job_Manager_Ajax {
70
  * Gets Job Manager's Ajax Endpoint.
71
  *
72
  * @param string $request Optional.
73
- * @param string $ssl (Unused) Optional.
74
  * @return string
75
  */
76
- public static function get_endpoint( $request = '%%endpoint%%', $ssl = null ) {
77
  if ( strstr( get_option( 'permalink_structure' ), '/index.php/' ) ) {
78
  $endpoint = trailingslashit( home_url( '/index.php/jm-ajax/' . $request . '/', 'relative' ) );
79
  } elseif ( get_option( 'permalink_structure' ) ) {
@@ -90,8 +89,10 @@ class WP_Job_Manager_Ajax {
90
  public static function do_jm_ajax() {
91
  global $wp_query;
92
 
 
93
  if ( ! empty( $_GET['jm-ajax'] ) ) {
94
- $wp_query->set( 'jm-ajax', sanitize_text_field( $_GET['jm-ajax'] ) );
 
95
  }
96
 
97
  $action = $wp_query->get( 'jm-ajax' );
@@ -118,24 +119,29 @@ class WP_Job_Manager_Ajax {
118
  * Returns Job Listings for Ajax endpoint.
119
  */
120
  public function get_listings() {
121
- global $wp_post_types;
122
-
123
- $result = array();
124
- $search_location = sanitize_text_field( stripslashes( $_REQUEST['search_location'] ) );
125
- $search_keywords = sanitize_text_field( stripslashes( $_REQUEST['search_keywords'] ) );
126
- $search_categories = isset( $_REQUEST['search_categories'] ) ? $_REQUEST['search_categories'] : '';
127
- $filter_job_types = isset( $_REQUEST['filter_job_type'] ) ? array_filter( array_map( 'sanitize_title', (array) $_REQUEST['filter_job_type'] ) ) : null;
128
- $filter_post_status = isset( $_REQUEST['filter_post_status'] ) ? array_filter( array_map( 'sanitize_title', (array) $_REQUEST['filter_post_status'] ) ) : null;
129
- $types = get_job_listing_types();
130
- $post_type_label = $wp_post_types['job_listing']->labels->name;
131
- $orderby = sanitize_text_field( $_REQUEST['orderby'] );
 
 
 
 
132
 
133
  if ( is_array( $search_categories ) ) {
134
  $search_categories = array_filter( array_map( 'sanitize_text_field', array_map( 'stripslashes', $search_categories ) ) );
135
  } else {
136
- $search_categories = array_filter( array( sanitize_text_field( stripslashes( $search_categories ) ) ) );
137
  }
138
 
 
139
  $job_types_filtered = ! is_null( $filter_job_types ) && count( $types ) !== count( $filter_job_types );
140
 
141
  $args = array(
@@ -145,17 +151,17 @@ class WP_Job_Manager_Ajax {
145
  'job_types' => is_null( $filter_job_types ) || count( $types ) === count( $filter_job_types ) ? '' : $filter_job_types + array( 0 ),
146
  'post_status' => $filter_post_status,
147
  'orderby' => $orderby,
148
- 'order' => sanitize_text_field( $_REQUEST['order'] ),
149
- 'offset' => ( absint( $_REQUEST['page'] ) - 1 ) * absint( $_REQUEST['per_page'] ),
150
- 'posts_per_page' => max( 1, absint( $_REQUEST['per_page'] ) ),
151
  );
152
 
153
- if ( isset( $_REQUEST['filled'] ) && ( 'true' === $_REQUEST['filled'] || 'false' === $_REQUEST['filled'] ) ) {
154
- $args['filled'] = 'true' === $_REQUEST['filled'];
155
  }
156
 
157
- if ( isset( $_REQUEST['featured'] ) && ( 'true' === $_REQUEST['featured'] || 'false' === $_REQUEST['featured'] ) ) {
158
- $args['featured'] = 'true' === $_REQUEST['featured'];
159
  $args['orderby'] = 'featured' === $orderby ? 'date' : $orderby;
160
  }
161
 
@@ -240,7 +246,9 @@ class WP_Job_Manager_Ajax {
240
  * @type array $pagination Pagination links to use for stepping through filter results.
241
  * }
242
  */
243
- return wp_send_json( apply_filters( 'job_manager_get_listings_result', $result, $jobs ) );
 
 
244
  }
245
 
246
  ob_start();
@@ -257,8 +265,8 @@ class WP_Job_Manager_Ajax {
257
  $result['html'] = ob_get_clean();
258
 
259
  // Generate pagination.
260
- if ( isset( $_REQUEST['show_pagination'] ) && 'true' === $_REQUEST['show_pagination'] ) {
261
- $result['pagination'] = get_job_listing_pagination( $jobs->max_num_pages, absint( $_REQUEST['page'] ) );
262
  }
263
 
264
  /** This filter is documented in includes/class-wp-job-manager-ajax.php (above) */
@@ -317,7 +325,7 @@ class WP_Job_Manager_Ajax {
317
  *
318
  * @since 1.32.0
319
  *
320
- * @params array $user_caps Array of capabilities/roles that are allowed to search for users.
321
  */
322
  $allowed_capabilities = apply_filters( 'job_manager_caps_can_search_users', array( 'edit_job_listings' ) );
323
  foreach ( $allowed_capabilities as $cap ) {
@@ -332,7 +340,7 @@ class WP_Job_Manager_Ajax {
332
  *
333
  * @since 1.32.0
334
  *
335
- * @params bool $user_can_search_users True if they are allowed, false if not.
336
  */
337
  return apply_filters( 'job_manager_user_can_search_users', $user_can_search_users );
338
  }
@@ -347,7 +355,7 @@ class WP_Job_Manager_Ajax {
347
  wp_die( -1 );
348
  }
349
 
350
- $term = sanitize_text_field( wp_unslash( $_GET['term'] ) );
351
  $page = isset( $_GET['page'] ) ? intval( $_GET['page'] ) : 1;
352
  $per_page = 20;
353
 
@@ -389,10 +397,10 @@ class WP_Job_Manager_Ajax {
389
  *
390
  * @see https://codex.wordpress.org/Class_Reference/WP_User_Query
391
  *
392
- * @params array $search_args Argument array used in `WP_User_Query` constructor.
393
- * @params string $term Search term.
394
- * @params int[] $exclude Array of IDs to exclude.
395
- * @params int $page Current page.
396
  */
397
  $search_args = apply_filters( 'job_manager_search_users_args', $search_args, $term, $exclude, $page );
398
 
@@ -424,13 +432,13 @@ class WP_Job_Manager_Ajax {
424
  *
425
  * @since 1.32.0
426
  *
427
- * @params array $response {
428
- * @type $results Array of all found users; id => string descriptor
429
- * @type $more True if there is an additional page.
430
  * }
431
- * @params string $term Search term.
432
- * @params int[] $exclude Array of IDs to exclude.
433
- * @params int $page Current page.
434
  */
435
  $response = apply_filters( 'job_manager_search_users_response', $response, $term, $exclude, $page );
436
 
22
  * @var self
23
  * @since 1.26.0
24
  */
25
+ private static $instance = null;
26
 
27
  /**
28
  * Allows for accessing single instance of class. Class should only be constructed once per call.
32
  * @return self Main instance.
33
  */
34
  public static function instance() {
35
+ if ( is_null( self::$instance ) ) {
36
+ self::$instance = new self();
37
  }
38
+ return self::$instance;
39
  }
40
 
41
  /**
70
  * Gets Job Manager's Ajax Endpoint.
71
  *
72
  * @param string $request Optional.
 
73
  * @return string
74
  */
75
+ public static function get_endpoint( $request = '%%endpoint%%' ) {
76
  if ( strstr( get_option( 'permalink_structure' ), '/index.php/' ) ) {
77
  $endpoint = trailingslashit( home_url( '/index.php/jm-ajax/' . $request . '/', 'relative' ) );
78
  } elseif ( get_option( 'permalink_structure' ) ) {
89
  public static function do_jm_ajax() {
90
  global $wp_query;
91
 
92
+ // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Input is used safely.
93
  if ( ! empty( $_GET['jm-ajax'] ) ) {
94
+ // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Input is used safely.
95
+ $wp_query->set( 'jm-ajax', sanitize_text_field( wp_unslash( $_GET['jm-ajax'] ) ) );
96
  }
97
 
98
  $action = $wp_query->get( 'jm-ajax' );
119
  * Returns Job Listings for Ajax endpoint.
120
  */
121
  public function get_listings() {
122
+ // Get input variables.
123
+ // phpcs:disable WordPress.Security.NonceVerification.Recommended -- Fetching data only; often for logged out visitors.
124
+ $search_location = isset( $_REQUEST['search_location'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['search_location'] ) ) : '';
125
+ $search_keywords = isset( $_REQUEST['search_keywords'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['search_keywords'] ) ) : '';
126
+ $search_categories = isset( $_REQUEST['search_categories'] ) ? wp_unslash( $_REQUEST['search_categories'] ) : ''; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Input is sanitized below.
127
+ $filter_job_types = isset( $_REQUEST['filter_job_type'] ) ? array_filter( array_map( 'sanitize_title', wp_unslash( (array) $_REQUEST['filter_job_type'] ) ) ) : null;
128
+ $filter_post_status = isset( $_REQUEST['filter_post_status'] ) ? array_filter( array_map( 'sanitize_title', wp_unslash( (array) $_REQUEST['filter_post_status'] ) ) ) : null;
129
+ $order = isset( $_REQUEST['order'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['order'] ) ) : 'DESC';
130
+ $orderby = isset( $_REQUEST['orderby'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['orderby'] ) ) : 'featured';
131
+ $page = isset( $_REQUEST['page'] ) ? absint( $_REQUEST['page'] ) : 1;
132
+ $per_page = isset( $_REQUEST['per_page'] ) ? absint( $_REQUEST['per_page'] ) : absint( get_option( 'job_manager_per_page' ) );
133
+ $filled = isset( $_REQUEST['filled'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['filled'] ) ) : null;
134
+ $featured = isset( $_REQUEST['featured'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['featured'] ) ) : null;
135
+ $show_pagination = isset( $_REQUEST['show_pagination'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['show_pagination'] ) ) : null;
136
+ // phpcs:enable WordPress.Security.NonceVerification.Recommended
137
 
138
  if ( is_array( $search_categories ) ) {
139
  $search_categories = array_filter( array_map( 'sanitize_text_field', array_map( 'stripslashes', $search_categories ) ) );
140
  } else {
141
+ $search_categories = array_filter( array( sanitize_text_field( wp_unslash( $search_categories ) ) ) );
142
  }
143
 
144
+ $types = get_job_listing_types();
145
  $job_types_filtered = ! is_null( $filter_job_types ) && count( $types ) !== count( $filter_job_types );
146
 
147
  $args = array(
151
  'job_types' => is_null( $filter_job_types ) || count( $types ) === count( $filter_job_types ) ? '' : $filter_job_types + array( 0 ),
152
  'post_status' => $filter_post_status,
153
  'orderby' => $orderby,
154
+ 'order' => $order,
155
+ 'offset' => ( $page - 1 ) * $per_page,
156
+ 'posts_per_page' => max( 1, $per_page ),
157
  );
158
 
159
+ if ( 'true' === $filled || 'false' === $filled ) {
160
+ $args['filled'] = 'true' === $filled;
161
  }
162
 
163
+ if ( 'true' === $featured || 'false' === $featured ) {
164
+ $args['featured'] = 'true' === $featured;
165
  $args['orderby'] = 'featured' === $orderby ? 'date' : $orderby;
166
  }
167
 
246
  * @type array $pagination Pagination links to use for stepping through filter results.
247
  * }
248
  */
249
+ wp_send_json( apply_filters( 'job_manager_get_listings_result', $result, $jobs ) );
250
+
251
+ return;
252
  }
253
 
254
  ob_start();
265
  $result['html'] = ob_get_clean();
266
 
267
  // Generate pagination.
268
+ if ( 'true' === $show_pagination ) {
269
+ $result['pagination'] = get_job_listing_pagination( $jobs->max_num_pages, $page );
270
  }
271
 
272
  /** This filter is documented in includes/class-wp-job-manager-ajax.php (above) */
325
  *
326
  * @since 1.32.0
327
  *
328
+ * @param array $user_caps Array of capabilities/roles that are allowed to search for users.
329
  */
330
  $allowed_capabilities = apply_filters( 'job_manager_caps_can_search_users', array( 'edit_job_listings' ) );
331
  foreach ( $allowed_capabilities as $cap ) {
340
  *
341
  * @since 1.32.0
342
  *
343
+ * @param bool $user_can_search_users True if they are allowed, false if not.
344
  */
345
  return apply_filters( 'job_manager_user_can_search_users', $user_can_search_users );
346
  }
355
  wp_die( -1 );
356
  }
357
 
358
+ $term = isset( $_GET['term'] ) ? sanitize_text_field( wp_unslash( $_GET['term'] ) ) : '';
359
  $page = isset( $_GET['page'] ) ? intval( $_GET['page'] ) : 1;
360
  $per_page = 20;
361
 
397
  *
398
  * @see https://codex.wordpress.org/Class_Reference/WP_User_Query
399
  *
400
+ * @param array $search_args Argument array used in `WP_User_Query` constructor.
401
+ * @param string $term Search term.
402
+ * @param int[] $exclude Array of IDs to exclude.
403
+ * @param int $page Current page.
404
  */
405
  $search_args = apply_filters( 'job_manager_search_users_args', $search_args, $term, $exclude, $page );
406
 
432
  *
433
  * @since 1.32.0
434
  *
435
+ * @param array $response {
436
+ * @type array $results Array of all found users; id => string descriptor
437
+ * @type boolean $more True if there is an additional page.
438
  * }
439
+ * @param string $term Search term.
440
+ * @param int[] $exclude Array of IDs to exclude.
441
+ * @param int $page Current page.
442
  */
443
  $response = apply_filters( 'job_manager_search_users_response', $response, $term, $exclude, $page );
444
 
includes/class-wp-job-manager-api.php CHANGED
@@ -23,7 +23,7 @@ class WP_Job_Manager_API {
23
  * @var self
24
  * @since 1.26.0
25
  */
26
- private static $_instance = null;
27
 
28
  /**
29
  * Allows for accessing single instance of class. Class should only be constructed once per call.
@@ -33,10 +33,10 @@ class WP_Job_Manager_API {
33
  * @return self Main instance.
34
  */
35
  public static function instance() {
36
- if ( is_null( self::$_instance ) ) {
37
- self::$_instance = new self();
38
  }
39
- return self::$_instance;
40
  }
41
 
42
  /**
@@ -71,8 +71,10 @@ class WP_Job_Manager_API {
71
  public function api_requests() {
72
  global $wp;
73
 
 
74
  if ( ! empty( $_GET['job-manager-api'] ) ) {
75
- $wp->query_vars['job-manager-api'] = $_GET['job-manager-api'];
 
76
  }
77
 
78
  if ( ! empty( $wp->query_vars['job-manager-api'] ) ) {
23
  * @var self
24
  * @since 1.26.0
25
  */
26
+ private static $instance = null;
27
 
28
  /**
29
  * Allows for accessing single instance of class. Class should only be constructed once per call.
33
  * @return self Main instance.
34
  */
35
  public static function instance() {
36
+ if ( is_null( self::$instance ) ) {
37
+ self::$instance = new self();
38
  }
39
+ return self::$instance;
40
  }
41
 
42
  /**
71
  public function api_requests() {
72
  global $wp;
73
 
74
+ // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- If necessary/possible, nonce should be checked by API handler.
75
  if ( ! empty( $_GET['job-manager-api'] ) ) {
76
+ // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- If necessary/possible, nonce should be checked by API handler.
77
+ $wp->query_vars['job-manager-api'] = sanitize_text_field( wp_unslash( $_GET['job-manager-api'] ) );
78
  }
79
 
80
  if ( ! empty( $wp->query_vars['job-manager-api'] ) ) {
includes/class-wp-job-manager-blocks.php CHANGED
@@ -19,7 +19,7 @@ class WP_Job_Manager_Blocks {
19
  *
20
  * @var self
21
  */
22
- private static $_instance = null;
23
 
24
  /**
25
  * Singleton instance getter
@@ -27,11 +27,11 @@ class WP_Job_Manager_Blocks {
27
  * @return self
28
  */
29
  public static function get_instance() {
30
- if ( ! self::$_instance ) {
31
- self::$_instance = new WP_Job_Manager_Blocks();
32
  }
33
 
34
- return self::$_instance;
35
  }
36
 
37
  /**
19
  *
20
  * @var self
21
  */
22
+ private static $instance = null;
23
 
24
  /**
25
  * Singleton instance getter
27
  * @return self
28
  */
29
  public static function get_instance() {
30
+ if ( ! self::$instance ) {
31
+ self::$instance = new WP_Job_Manager_Blocks();
32
  }
33
 
34
+ return self::$instance;
35
  }
36
 
37
  /**
includes/class-wp-job-manager-cache-helper.php CHANGED
@@ -29,7 +29,6 @@ class WP_Job_Manager_Cache_Helper {
29
  add_action( 'edited_term', array( __CLASS__, 'edited_term' ), 10, 3 );
30
  add_action( 'create_term', array( __CLASS__, 'edited_term' ), 10, 3 );
31
  add_action( 'delete_term', array( __CLASS__, 'edited_term' ), 10, 3 );
32
- add_action( 'job_manager_clear_expired_transients', array( __CLASS__, 'clear_expired_transients' ), 10 );
33
  add_action( 'transition_post_status', array( __CLASS__, 'maybe_clear_count_transients' ), 10, 3 );
34
  }
35
 
@@ -109,37 +108,26 @@ class WP_Job_Manager_Cache_Helper {
109
  /**
110
  * When the transient version increases, this is used to remove all past transients to avoid filling the DB.
111
  *
112
- * Note; this only works on transients appended with the transient version, and when object caching is not being used.
113
  *
114
  * @param string $version
115
  */
116
  private static function delete_version_transients( $version ) {
 
 
117
  if ( ! wp_using_ext_object_cache() && ! empty( $version ) ) {
118
- global $wpdb;
119
  $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->options} WHERE option_name LIKE %s;", '\_transient\_%' . $version ) );
120
  }
121
  }
122
 
123
  /**
124
  * Clear expired transients.
 
 
125
  */
126
  public static function clear_expired_transients() {
127
- global $wpdb;
128
-
129
- if ( ! wp_using_ext_object_cache() && ! defined( 'WP_SETUP_CONFIG' ) && ! defined( 'WP_INSTALLING' ) ) {
130
- $wpdb->query(
131
- $wpdb->prepare(
132
- "DELETE a, b FROM $wpdb->options a, $wpdb->options b
133
- WHERE a.option_name LIKE %s
134
- AND a.option_name NOT LIKE %s
135
- AND b.option_name = CONCAT( '_transient_timeout_', SUBSTRING( a.option_name, 12 ) )
136
- AND b.option_value < %s;",
137
- $wpdb->esc_like( '_transient_jm_' ) . '%',
138
- $wpdb->esc_like( '_transient_timeout_jm_' ) . '%',
139
- time()
140
- )
141
- );
142
- }
143
  }
144
 
145
  /**
@@ -200,6 +188,7 @@ class WP_Job_Manager_Cache_Helper {
200
  return;
201
  }
202
 
 
203
  $transients = $wpdb->get_col(
204
  $wpdb->prepare(
205
  "SELECT option_name FROM $wpdb->options WHERE option_name RLIKE %s",
29
  add_action( 'edited_term', array( __CLASS__, 'edited_term' ), 10, 3 );
30
  add_action( 'create_term', array( __CLASS__, 'edited_term' ), 10, 3 );
31
  add_action( 'delete_term', array( __CLASS__, 'edited_term' ), 10, 3 );
 
32
  add_action( 'transition_post_status', array( __CLASS__, 'maybe_clear_count_transients' ), 10, 3 );
33
  }
34
 
108
  /**
109
  * When the transient version increases, this is used to remove all past transients to avoid filling the DB.
110
  *
111
+ * Note: this only works on transients appended with the transient version, and when object caching is not being used.
112
  *
113
  * @param string $version
114
  */
115
  private static function delete_version_transients( $version ) {
116
+ global $wpdb;
117
+
118
  if ( ! wp_using_ext_object_cache() && ! empty( $version ) ) {
119
+ // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Only used when object caching is disabled.
120
  $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->options} WHERE option_name LIKE %s;", '\_transient\_%' . $version ) );
121
  }
122
  }
123
 
124
  /**
125
  * Clear expired transients.
126
+ *
127
+ * @deprecated 1.34.0 Handled by WordPress since 4.9.
128
  */
129
  public static function clear_expired_transients() {
130
+ _deprecated_function( __METHOD__, '1.34.0', 'handled by WordPress core since 4.9' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
131
  }
132
 
133
  /**
188
  return;
189
  }
190
 
191
+ // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Fetches dynamic list of cached counts.
192
  $transients = $wpdb->get_col(
193
  $wpdb->prepare(
194
  "SELECT option_name FROM $wpdb->options WHERE option_name RLIKE %s",
includes/class-wp-job-manager-category-walker.php CHANGED
@@ -62,10 +62,11 @@ class WP_Job_Manager_Category_Walker extends Walker {
62
 
63
  $output .= "\t<option class=\"level-" . intval( $depth ) . '" value="' . esc_attr( $value ) . '"';
64
 
65
- if ( isset( $args['selected'] ) && (
 
66
  $value == $args['selected'] // phpcs:ignore WordPress.PHP.StrictComparisons
67
  || ( is_array( $args['selected'] ) && in_array( $value, $args['selected'] ) ) // phpcs:ignore WordPress.PHP.StrictInArray
68
- )
69
  ) {
70
  $output .= ' selected="selected"';
71
  }
62
 
63
  $output .= "\t<option class=\"level-" . intval( $depth ) . '" value="' . esc_attr( $value ) . '"';
64
 
65
+ if (
66
+ isset( $args['selected'] ) && (
67
  $value == $args['selected'] // phpcs:ignore WordPress.PHP.StrictComparisons
68
  || ( is_array( $args['selected'] ) && in_array( $value, $args['selected'] ) ) // phpcs:ignore WordPress.PHP.StrictInArray
69
+ )
70
  ) {
71
  $output .= ' selected="selected"';
72
  }
includes/class-wp-job-manager-data-cleaner.php CHANGED
@@ -43,9 +43,11 @@ class WP_Job_Manager_Data_Cleaner {
43
  private static $cron_jobs = array(
44
  'job_manager_check_for_expired_jobs',
45
  'job_manager_delete_old_previews',
46
- 'job_manager_clear_expired_transients',
47
  'job_manager_email_daily_notices',
48
  'job_manager_usage_tracking_send_usage_data',
 
 
 
49
  );
50
 
51
  /**
@@ -115,7 +117,7 @@ class WP_Job_Manager_Data_Cleaner {
115
  * @var $transients
116
  */
117
  private static $transients = array(
118
- '_job_manager_activation_redirect',
119
  'get_job_listings-transient-version',
120
  'jm_.*',
121
  );
@@ -214,6 +216,8 @@ class WP_Job_Manager_Data_Cleaner {
214
  private static function cleanup_taxonomies() {
215
  global $wpdb;
216
 
 
 
217
  foreach ( self::$taxonomies as $taxonomy ) {
218
  $terms = $wpdb->get_results(
219
  $wpdb->prepare(
@@ -234,6 +238,9 @@ class WP_Job_Manager_Data_Cleaner {
234
  clean_taxonomy_cache( $taxonomy );
235
  }
236
  }
 
 
 
237
  }
238
 
239
  /**
@@ -291,6 +298,8 @@ class WP_Job_Manager_Data_Cleaner {
291
  private static function cleanup_transients() {
292
  global $wpdb;
293
 
 
 
294
  foreach ( array( '_transient_', '_transient_timeout_' ) as $prefix ) {
295
  foreach ( self::$transients as $transient ) {
296
  $wpdb->query(
@@ -301,6 +310,8 @@ class WP_Job_Manager_Data_Cleaner {
301
  );
302
  }
303
  }
 
 
304
  }
305
 
306
  /**
@@ -349,7 +360,9 @@ class WP_Job_Manager_Data_Cleaner {
349
  global $wpdb;
350
 
351
  foreach ( self::$user_meta_keys as $meta_key ) {
 
352
  $wpdb->delete( $wpdb->usermeta, array( 'meta_key' => $meta_key ) );
 
353
  }
354
  }
355
 
43
  private static $cron_jobs = array(
44
  'job_manager_check_for_expired_jobs',
45
  'job_manager_delete_old_previews',
 
46
  'job_manager_email_daily_notices',
47
  'job_manager_usage_tracking_send_usage_data',
48
+
49
+ // Old cron jobs.
50
+ 'job_manager_clear_expired_transients',
51
  );
52
 
53
  /**
117
  * @var $transients
118
  */
119
  private static $transients = array(
120
+ '_job_manager_activation_redirect', // Legacy transient that should still be removed.
121
  'get_job_listings-transient-version',
122
  'jm_.*',
123
  );
216
  private static function cleanup_taxonomies() {
217
  global $wpdb;
218
 
219
+ // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery
220
+ // phpcs:disable WordPress.DB.DirectDatabaseQuery.NoCaching
221
  foreach ( self::$taxonomies as $taxonomy ) {
222
  $terms = $wpdb->get_results(
223
  $wpdb->prepare(
238
  clean_taxonomy_cache( $taxonomy );
239
  }
240
  }
241
+
242
+ // phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery
243
+ // phpcs:enable WordPress.DB.DirectDatabaseQuery.NoCaching
244
  }
245
 
246
  /**
298
  private static function cleanup_transients() {
299
  global $wpdb;
300
 
301
+ // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery
302
+ // phpcs:disable WordPress.DB.DirectDatabaseQuery.NoCaching
303
  foreach ( array( '_transient_', '_transient_timeout_' ) as $prefix ) {
304
  foreach ( self::$transients as $transient ) {
305
  $wpdb->query(
310
  );
311
  }
312
  }
313
+ // phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery
314
+ // phpcs:enable WordPress.DB.DirectDatabaseQuery.NoCaching
315
  }
316
 
317
  /**
360
  global $wpdb;
361
 
362
  foreach ( self::$user_meta_keys as $meta_key ) {
363
+ // phpcs:disable WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.DirectQuery -- Delete data across all users.
364
  $wpdb->delete( $wpdb->usermeta, array( 'meta_key' => $meta_key ) );
365
+ // phpcs:enable WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.DirectQuery
366
  }
367
  }
368
 
includes/class-wp-job-manager-dependency-checker.php CHANGED
@@ -17,7 +17,7 @@ if ( ! defined( 'ABSPATH' ) ) {
17
  */
18
  class WP_Job_Manager_Dependency_Checker {
19
  const MINIMUM_PHP_VERSION = '5.6.20';
20
- const MINIMUM_WP_VERSION = '4.7.0';
21
 
22
  /**
23
  * Check if WP Job Manager's dependencies have been met.
@@ -27,6 +27,9 @@ class WP_Job_Manager_Dependency_Checker {
27
  public static function check_dependencies() {
28
  if ( ! self::check_php() ) {
29
  add_action( 'admin_notices', array( 'WP_Job_Manager_Dependency_Checker', 'add_php_notice' ) );
 
 
 
30
  }
31
 
32
  if ( ! self::check_wp() ) {
@@ -60,7 +63,7 @@ class WP_Job_Manager_Dependency_Checker {
60
  }
61
 
62
  // translators: %1$s is version of PHP that WP Job Manager requires; %2$s is the version of PHP WordPress is running on.
63
- $message = sprintf( __( 'The next release of <strong>WP Job Manager</strong> will require a minimum PHP version of %1$s, but you are running %2$s. Please update PHP to continue using this plugin.', 'wp-job-manager' ), self::MINIMUM_PHP_VERSION, phpversion() );
64
 
65
  echo '<div class="error"><p>';
66
  echo wp_kses( $message, array( 'strong' => array() ) );
@@ -78,6 +81,13 @@ class WP_Job_Manager_Dependency_Checker {
78
  echo '</p></div>';
79
  }
80
 
 
 
 
 
 
 
 
81
  /**
82
  * Checks for our WordPress version requirement.
83
  *
17
  */
18
  class WP_Job_Manager_Dependency_Checker {
19
  const MINIMUM_PHP_VERSION = '5.6.20';
20
+ const MINIMUM_WP_VERSION = '4.9.0';
21
 
22
  /**
23
  * Check if WP Job Manager's dependencies have been met.
27
  public static function check_dependencies() {
28
  if ( ! self::check_php() ) {
29
  add_action( 'admin_notices', array( 'WP_Job_Manager_Dependency_Checker', 'add_php_notice' ) );
30
+ add_action( 'admin_init', array( __CLASS__, 'deactivate_self' ) );
31
+
32
+ return false;
33
  }
34
 
35
  if ( ! self::check_wp() ) {
63
  }
64
 
65
  // translators: %1$s is version of PHP that WP Job Manager requires; %2$s is the version of PHP WordPress is running on.
66
+ $message = sprintf( __( '<strong>WP Job Manager</strong> requires a minimum PHP version of %1$s, but you are running %2$s.', 'wp-job-manager' ), self::MINIMUM_PHP_VERSION, phpversion() );
67
 
68
  echo '<div class="error"><p>';
69
  echo wp_kses( $message, array( 'strong' => array() ) );
81
  echo '</p></div>';
82
  }
83
 
84
+ /**
85
+ * Deactivate self.
86
+ */
87
+ public static function deactivate_self() {
88
+ deactivate_plugins( JOB_MANAGER_PLUGIN_BASENAME );
89
+ }
90
+
91
  /**
92
  * Checks for our WordPress version requirement.
93
  *
includes/class-wp-job-manager-email-notifications.php CHANGED
@@ -548,19 +548,19 @@ final class WP_Job_Manager_Email_Notifications {
548
  * @param int $days_notice
549
  */
550
  private static function send_expiring_notice( $email_notification_key, $days_notice ) {
551
- global $wpdb;
552
-
553
  $notice_before_ts = current_time( 'timestamp' ) + ( DAY_IN_SECONDS * $days_notice );
554
- $job_ids = $wpdb->get_col(
555
- $wpdb->prepare(
556
- "
557
- SELECT postmeta.post_id FROM {$wpdb->postmeta} as postmeta
558
- LEFT JOIN {$wpdb->posts} as posts ON postmeta.post_id = posts.ID
559
- WHERE postmeta.meta_key = '_job_expires'
560
- AND postmeta.meta_value = %s
561
- AND posts.post_status = 'publish'
562
- AND posts.post_type = 'job_listing'
563
- ", date( 'Y-m-d', $notice_before_ts )
 
 
564
  )
565
  );
566
 
@@ -660,6 +660,24 @@ final class WP_Job_Manager_Email_Notifications {
660
  return count( self::$deferred_notifications );
661
  }
662
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
663
  /**
664
  * Confirms an email notification is valid.
665
  *
548
  * @param int $days_notice
549
  */
550
  private static function send_expiring_notice( $email_notification_key, $days_notice ) {
 
 
551
  $notice_before_ts = current_time( 'timestamp' ) + ( DAY_IN_SECONDS * $days_notice );
552
+ $job_ids = get_posts(
553
+ array(
554
+ 'post_type' => 'job_listing',
555
+ 'post_status' => 'publish',
556
+ 'fields' => 'ids',
557
+ 'posts_per_page' => -1,
558
+ 'meta_query' => array(
559
+ array(
560
+ 'key' => '_job_expires',
561
+ 'value' => date( 'Y-m-d', $notice_before_ts ),
562
+ ),
563
+ ),
564
  )
565
  );
566
 
660
  return count( self::$deferred_notifications );
661
  }
662
 
663
+ /**
664
+ * Returns the hash representation of the notifications to be sent.
665
+ *
666
+ * Do not use. Used just in unit tests.
667
+ *
668
+ * @access private
669
+ *
670
+ * @return string[]
671
+ */
672
+ public static function get_deferred_notification_hashes() {
673
+ return array_map(
674
+ function( $value ) {
675
+ return sha1( wp_json_encode( $value ) );
676
+ },
677
+ self::$deferred_notifications
678
+ );
679
+ }
680
+
681
  /**
682
  * Confirms an email notification is valid.
683
  *
includes/class-wp-job-manager-forms.php CHANGED
@@ -22,7 +22,7 @@ class WP_Job_Manager_Forms {
22
  * @var self
23
  * @since 1.26.0
24
  */
25
- private static $_instance = null;
26
 
27
  /**
28
  * Allows for accessing single instance of class. Class should only be constructed once per call.
@@ -32,10 +32,10 @@ class WP_Job_Manager_Forms {
32
  * @return self Main instance.
33
  */
34
  public static function instance() {
35
- if ( is_null( self::$_instance ) ) {
36
- self::$_instance = new self();
37
  }
38
- return self::$_instance;
39
  }
40
 
41
  /**
@@ -49,8 +49,11 @@ class WP_Job_Manager_Forms {
49
  * If a form was posted, load its class so that it can be processed before display.
50
  */
51
  public function load_posted_form() {
52
- if ( ! empty( $_POST['job_manager_form'] ) ) {
53
- $this->load_form_class( sanitize_title( $_POST['job_manager_form'] ) );
 
 
 
54
  }
55
  }
56
 
@@ -58,7 +61,7 @@ class WP_Job_Manager_Forms {
58
  * Load a form's class
59
  *
60
  * @param string $form_name
61
- * @return string class name on success, false on failure.
62
  */
63
  private function load_form_class( $form_name ) {
64
  if ( ! class_exists( 'WP_Job_Manager_Form' ) ) {
22
  * @var self
23
  * @since 1.26.0
24
  */
25
+ private static $instance = null;
26
 
27
  /**
28
  * Allows for accessing single instance of class. Class should only be constructed once per call.
32
  * @return self Main instance.
33
  */
34
  public static function instance() {
35
+ if ( is_null( self::$instance ) ) {
36
+ self::$instance = new self();
37
  }
38
+ return self::$instance;
39
  }
40
 
41
  /**
49
  * If a form was posted, load its class so that it can be processed before display.
50
  */
51
  public function load_posted_form() {
52
+ // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Input is used safely.
53
+ $job_manager_form = ! empty( $_POST['job_manager_form'] ) ? sanitize_title( wp_unslash( $_POST['job_manager_form'] ) ) : false;
54
+
55
+ if ( ! empty( $job_manager_form ) ) {
56
+ $this->load_form_class( $job_manager_form );
57
  }
58
  }
59
 
61
  * Load a form's class
62
  *
63
  * @param string $form_name
64
+ * @return bool|WP_Job_Manager_Form Class instance on success, false on failure.
65
  */
66
  private function load_form_class( $form_name ) {
67
  if ( ! class_exists( 'WP_Job_Manager_Form' ) ) {
includes/class-wp-job-manager-geocode.php CHANGED
@@ -24,7 +24,7 @@ class WP_Job_Manager_Geocode {
24
  * @var self
25
  * @since 1.26.0
26
  */
27
- private static $_instance = null;
28
 
29
  /**
30
  * Allows for accessing single instance of class. Class should only be constructed once per call.
@@ -34,10 +34,10 @@ class WP_Job_Manager_Geocode {
34
  * @return self Main instance.
35
  */
36
  public static function instance() {
37
- if ( is_null( self::$_instance ) ) {
38
- self::$_instance = new self();
39
  }
40
- return self::$_instance;
41
  }
42
 
43
  /**
24
  * @var self
25
  * @since 1.26.0
26
  */
27
+ private static $instance = null;
28
 
29
  /**
30
  * Allows for accessing single instance of class. Class should only be constructed once per call.
34
  * @return self Main instance.
35
  */
36
  public static function instance() {
37
+ if ( is_null( self::$instance ) ) {
38
+ self::$instance = new self();
39
  }
40
+ return self::$instance;
41
  }
42
 
43
  /**
includes/class-wp-job-manager-install.php CHANGED
@@ -32,12 +32,13 @@ class WP_Job_Manager_Install {
32
  include_once JOB_MANAGER_PLUGIN_DIR . '/includes/admin/class-wp-job-manager-admin-notices.php';
33
  WP_Job_Manager_Admin_Notices::add_notice( WP_Job_Manager_Admin_Notices::NOTICE_CORE_SETUP );
34
  $is_new_install = true;
35
- set_transient( '_job_manager_activation_redirect', 1, HOUR_IN_SECONDS );
36
  }
37
 
38
  // Update featured posts ordering.
39
  if ( version_compare( get_option( 'wp_job_manager_version', JOB_MANAGER_VERSION ), '1.22.0', '<' ) ) {
 
40
  $wpdb->query( "UPDATE {$wpdb->posts} p SET p.menu_order = 0 WHERE p.post_type='job_listing';" );
 
41
  $wpdb->query( "UPDATE {$wpdb->posts} p LEFT JOIN {$wpdb->postmeta} pm ON p.ID = pm.post_id SET p.menu_order = -1 WHERE pm.meta_key = '_featured' AND pm.meta_value='1' AND p.post_type='job_listing';" );
42
  }
43
 
@@ -56,6 +57,11 @@ class WP_Job_Manager_Install {
56
  update_option( 'job_manager_job_dashboard_page_id', $page_id );
57
  }
58
 
 
 
 
 
 
59
  if ( $is_new_install ) {
60
  $permalink_options = (array) json_decode( get_option( 'job_manager_permalinks', '[]' ), true );
61
  $permalink_options['jobs_archive'] = '';
@@ -70,13 +76,9 @@ class WP_Job_Manager_Install {
70
  * Initializes user roles.
71
  */
72
  private static function init_user_roles() {
73
- global $wp_roles;
74
-
75
- if ( class_exists( 'WP_Roles' ) && ! isset( $wp_roles ) ) {
76
- $wp_roles = new WP_Roles(); // WPCS: override ok.
77
- }
78
 
79
- if ( is_object( $wp_roles ) ) {
80
  add_role(
81
  'employer',
82
  __( 'Employer', 'wp-job-manager' ),
@@ -91,7 +93,7 @@ class WP_Job_Manager_Install {
91
 
92
  foreach ( $capabilities as $cap_group ) {
93
  foreach ( $cap_group as $cap ) {
94
- $wp_roles->add_cap( 'administrator', $cap );
95
  }
96
  }
97
  }
32
  include_once JOB_MANAGER_PLUGIN_DIR . '/includes/admin/class-wp-job-manager-admin-notices.php';
33
  WP_Job_Manager_Admin_Notices::add_notice( WP_Job_Manager_Admin_Notices::NOTICE_CORE_SETUP );
34
  $is_new_install = true;
 
35
  }
36
 
37
  // Update featured posts ordering.
38
  if ( version_compare( get_option( 'wp_job_manager_version', JOB_MANAGER_VERSION ), '1.22.0', '<' ) ) {
39
+ // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- One time data update.
40
  $wpdb->query( "UPDATE {$wpdb->posts} p SET p.menu_order = 0 WHERE p.post_type='job_listing';" );
41
+ // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- One time data update.
42
  $wpdb->query( "UPDATE {$wpdb->posts} p LEFT JOIN {$wpdb->postmeta} pm ON p.ID = pm.post_id SET p.menu_order = -1 WHERE pm.meta_key = '_featured' AND pm.meta_value='1' AND p.post_type='job_listing';" );
43
  }
44
 
57
  update_option( 'job_manager_job_dashboard_page_id', $page_id );
58
  }
59
 
60
+ // Scheduled hook was removed in 1.34.0.
61
+ if ( wp_next_scheduled( 'job_manager_clear_expired_transients' ) ) {
62
+ wp_clear_scheduled_hook( 'job_manager_clear_expired_transients' );
63
+ }
64
+
65
  if ( $is_new_install ) {
66
  $permalink_options = (array) json_decode( get_option( 'job_manager_permalinks', '[]' ), true );
67
  $permalink_options['jobs_archive'] = '';
76
  * Initializes user roles.
77
  */
78
  private static function init_user_roles() {
79
+ $roles = wp_roles();
 
 
 
 
80
 
81
+ if ( is_object( $roles ) ) {
82
  add_role(
83
  'employer',
84
  __( 'Employer', 'wp-job-manager' ),
93
 
94
  foreach ( $capabilities as $cap_group ) {
95
  foreach ( $cap_group as $cap ) {
96
+ $roles->add_cap( 'administrator', $cap );
97
  }
98
  }
99
  }
includes/class-wp-job-manager-post-types.php CHANGED
@@ -24,7 +24,7 @@ class WP_Job_Manager_Post_Types {
24
  * @var self
25
  * @since 1.26.0
26
  */
27
- private static $_instance = null;
28
 
29
  /**
30
  * Allows for accessing single instance of class. Class should only be constructed once per call.
@@ -34,10 +34,10 @@ class WP_Job_Manager_Post_Types {
34
  * @return self Main instance.
35
  */
36
  public static function instance() {
37
- if ( is_null( self::$_instance ) ) {
38
- self::$_instance = new self();
39
  }
40
- return self::$_instance;
41
  }
42
 
43
  /**
@@ -128,7 +128,7 @@ class WP_Job_Manager_Post_Types {
128
  public function hide_job_type_block_editor_selector( $response, $taxonomy, $request ) {
129
  if (
130
  'job_listing_type' === $taxonomy->name
131
- && 'edit' === $request->get_param( 'context' )
132
  ) {
133
  $response->data['visibility']['show_ui'] = false;
134
  }
@@ -145,7 +145,7 @@ class WP_Job_Manager_Post_Types {
145
 
146
  $admin_capability = 'manage_job_listings';
147
 
148
- $permalink_structure = WP_Job_Manager_Post_Types::get_permalink_structure();
149
 
150
  /**
151
  * Taxonomies
@@ -431,7 +431,8 @@ class WP_Job_Manager_Post_Types {
431
 
432
  foreach ( $menu as $key => $menu_item ) {
433
  if ( strpos( $menu_item[0], $plural ) === 0 ) {
434
- $menu[ $key ][0] .= " <span class='awaiting-mod update-plugins count-" . esc_attr( $pending_jobs ) . "'><span class='pending-count'>" . absint( number_format_i18n( $pending_jobs ) ) . '</span></span>'; // WPCS: override ok.
 
435
  break;
436
  }
437
  }
@@ -544,39 +545,47 @@ class WP_Job_Manager_Post_Types {
544
  public function job_feed() {
545
  global $job_manager_keyword;
546
 
 
 
 
 
 
 
 
 
547
  $query_args = array(
548
  'post_type' => 'job_listing',
549
  'post_status' => 'publish',
550
  'ignore_sticky_posts' => 1,
551
- 'posts_per_page' => isset( $_GET['posts_per_page'] ) ? absint( $_GET['posts_per_page'] ) : 10,
552
  'paged' => absint( get_query_var( 'paged', 1 ) ),
553
  'tax_query' => array(),
554
  'meta_query' => array(),
555
  );
556
 
557
- if ( ! empty( $_GET['search_location'] ) ) {
558
  $location_meta_keys = array( 'geolocation_formatted_address', '_job_location', 'geolocation_state_long' );
559
  $location_search = array( 'relation' => 'OR' );
560
  foreach ( $location_meta_keys as $meta_key ) {
561
  $location_search[] = array(
562
  'key' => $meta_key,
563
- 'value' => sanitize_text_field( $_GET['search_location'] ),
564
  'compare' => 'like',
565
  );
566
  }
567
  $query_args['meta_query'][] = $location_search;
568
  }
569
 
570
- if ( ! empty( $_GET['job_types'] ) ) {
571
  $query_args['tax_query'][] = array(
572
  'taxonomy' => 'job_listing_type',
573
  'field' => 'slug',
574
- 'terms' => explode( ',', sanitize_text_field( $_GET['job_types'] ) ) + array( 0 ),
575
  );
576
  }
577
 
578
- if ( ! empty( $_GET['job_categories'] ) ) {
579
- $cats = explode( ',', sanitize_text_field( $_GET['job_categories'] ) ) + array( 0 );
580
  $field = is_numeric( $cats ) ? 'term_id' : 'slug';
581
  $operator = 'all' === get_option( 'job_manager_category_filter_type', 'all' ) && count( $cats ) > 1 ? 'AND' : 'IN';
582
  $query_args['tax_query'][] = array(
@@ -588,7 +597,6 @@ class WP_Job_Manager_Post_Types {
588
  );
589
  }
590
 
591
- $job_manager_keyword = isset( $_GET['search_keywords'] ) ? sanitize_text_field( $_GET['search_keywords'] ) : '';
592
  if ( ! empty( $job_manager_keyword ) ) {
593
  $query_args['s'] = $job_manager_keyword;
594
  add_filter( 'posts_search', 'get_job_listings_keyword_search' );
@@ -602,7 +610,8 @@ class WP_Job_Manager_Post_Types {
602
  unset( $query_args['tax_query'] );
603
  }
604
 
605
- query_posts( apply_filters( 'job_feed_args', $query_args ) ); // phpcs:ignore WordPress.WP.DiscouragedFunctions
 
606
  add_action( 'rss2_ns', array( $this, 'job_feed_namespace' ) );
607
  add_action( 'rss2_item', array( $this, 'job_feed_item' ) );
608
  do_feed_rss2( false );
@@ -666,26 +675,33 @@ class WP_Job_Manager_Post_Types {
666
  *
667
  * @param int $post_id The post ID of the job.
668
  */
669
- do_action( 'job_feed_item', $post_id );
670
  }
671
 
672
  /**
673
  * Maintenance task to expire jobs.
674
  */
675
  public function check_for_expired_jobs() {
676
- global $wpdb;
677
-
678
  // Change status to expired.
679
- $job_ids = $wpdb->get_col(
680
- $wpdb->prepare(
681
- "SELECT postmeta.post_id FROM {$wpdb->postmeta} as postmeta
682
- LEFT JOIN {$wpdb->posts} as posts ON postmeta.post_id = posts.ID
683
- WHERE postmeta.meta_key = '_job_expires'
684
- AND postmeta.meta_value > 0
685
- AND postmeta.meta_value < %s
686
- AND posts.post_status = 'publish'
687
- AND posts.post_type = 'job_listing'",
688
- date( 'Y-m-d', current_time( 'timestamp' ) )
 
 
 
 
 
 
 
 
 
689
  )
690
  );
691
 
@@ -699,14 +715,36 @@ class WP_Job_Manager_Post_Types {
699
  }
700
 
701
  // Delete old expired jobs.
 
 
 
 
 
 
 
 
702
  if ( apply_filters( 'job_manager_delete_expired_jobs', false ) ) {
703
- $job_ids = $wpdb->get_col(
704
- $wpdb->prepare(
705
- "SELECT posts.ID FROM {$wpdb->posts} as posts
706
- WHERE posts.post_type = 'job_listing'
707
- AND posts.post_modified < %s
708
- AND posts.post_status = 'expired'",
709
- date( 'Y-m-d', strtotime( '-' . apply_filters( 'job_manager_delete_expired_jobs_days', 30 ) . ' days', current_time( 'timestamp' ) ) )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
710
  )
711
  );
712
 
@@ -722,16 +760,19 @@ class WP_Job_Manager_Post_Types {
722
  * Deletes old previewed jobs after 30 days to keep the DB clean.
723
  */
724
  public function delete_old_previews() {
725
- global $wpdb;
726
-
727
- // Delete old expired jobs.
728
- $job_ids = $wpdb->get_col(
729
- $wpdb->prepare(
730
- "SELECT posts.ID FROM {$wpdb->posts} as posts
731
- WHERE posts.post_type = 'job_listing'
732
- AND posts.post_modified < %s
733
- AND posts.post_status = 'preview'",
734
- date( 'Y-m-d', strtotime( '-30 days', current_time( 'timestamp' ) ) )
 
 
 
735
  )
736
  );
737
 
@@ -772,16 +813,19 @@ class WP_Job_Manager_Post_Types {
772
  }
773
  }
774
 
 
 
 
775
  // See if the user has set the expiry manually.
776
- if ( ! empty( $_POST['_job_expires'] ) ) {
777
- update_post_meta( $post->ID, '_job_expires', date( 'Y-m-d', strtotime( sanitize_text_field( $_POST['_job_expires'] ) ) ) );
778
  } elseif ( ! isset( $expires ) ) {
779
  // No manual setting? Lets generate a date if there isn't already one.
780
  $expires = calculate_job_expiry( $post->ID );
781
  update_post_meta( $post->ID, '_job_expires', $expires );
782
 
783
  // In case we are saving a post, ensure post data is updated so the field is not overridden.
784
- if ( isset( $_POST['_job_expires'] ) ) {
785
  $_POST['_job_expires'] = $expires;
786
  }
787
  }
@@ -933,16 +977,20 @@ class WP_Job_Manager_Post_Types {
933
  * @param mixed $meta_value
934
  */
935
  public function update_post_meta( $meta_id, $object_id, $meta_key, $meta_value ) {
936
- if ( 'job_listing' === get_post_type( $object_id ) ) {
937
- switch ( $meta_key ) {
938
- case '_job_location':
939
- $this->maybe_update_geolocation_data( $meta_id, $object_id, $meta_key, $meta_value );
940
- break;
941
- case '_featured':
942
- $this->maybe_update_menu_order( $meta_id, $object_id, $meta_key, $meta_value );
943
- break;
944
- }
 
 
 
945
  }
 
946
  }
947
 
948
  /**
@@ -966,26 +1014,25 @@ class WP_Job_Manager_Post_Types {
966
  * @param mixed $meta_value
967
  */
968
  public function maybe_update_menu_order( $meta_id, $object_id, $meta_key, $meta_value ) {
969
- global $wpdb;
970
-
971
  if ( 1 === intval( $meta_value ) ) {
972
- $wpdb->update(
973
- $wpdb->posts,
974
- array( 'menu_order' => -1 ),
975
- array( 'ID' => $object_id )
976
- );
977
- } else {
978
- $wpdb->update(
979
- $wpdb->posts,
980
- array( 'menu_order' => 0 ),
981
  array(
982
  'ID' => $object_id,
983
  'menu_order' => -1,
984
  )
985
  );
986
- }
 
987
 
988
- clean_post_cache( $object_id );
 
 
 
 
 
 
 
 
989
  }
990
 
991
  /**
@@ -1116,7 +1163,7 @@ class WP_Job_Manager_Post_Types {
1116
  * Registers job listing meta fields.
1117
  */
1118
  public function register_meta_fields() {
1119
- $fields = WP_Job_Manager_Post_Types::get_job_listing_fields();
1120
 
1121
  foreach ( $fields as $meta_key => $field ) {
1122
  register_meta(
24
  * @var self
25
  * @since 1.26.0
26
  */
27
+ private static $instance = null;
28
 
29
  /**
30
  * Allows for accessing single instance of class. Class should only be constructed once per call.
34
  * @return self Main instance.
35
  */
36
  public static function instance() {
37
+ if ( is_null( self::$instance ) ) {
38
+ self::$instance = new self();
39
  }
40
+ return self::$instance;
41
  }
42
 
43
  /**
128
  public function hide_job_type_block_editor_selector( $response, $taxonomy, $request ) {
129
  if (
130
  'job_listing_type' === $taxonomy->name
131
+ && 'edit' === $request->get_param( 'context' )
132
  ) {
133
  $response->data['visibility']['show_ui'] = false;
134
  }
145
 
146
  $admin_capability = 'manage_job_listings';
147
 
148
+ $permalink_structure = self::get_permalink_structure();
149
 
150
  /**
151
  * Taxonomies
431
 
432
  foreach ( $menu as $key => $menu_item ) {
433
  if ( strpos( $menu_item[0], $plural ) === 0 ) {
434
+ // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited -- Only way to add pending listing count.
435
+ $menu[ $key ][0] .= " <span class='awaiting-mod update-plugins count-" . esc_attr( $pending_jobs ) . "'><span class='pending-count'>" . absint( number_format_i18n( $pending_jobs ) ) . '</span></span>';
436
  break;
437
  }
438
  }
545
  public function job_feed() {
546
  global $job_manager_keyword;
547
 
548
+ // phpcs:disable WordPress.Security.NonceVerification.Recommended -- Input used to filter public data in feed.
549
+ $input_posts_per_page = isset( $_GET['posts_per_page'] ) ? absint( $_GET['posts_per_page'] ) : 10;
550
+ $input_search_location = isset( $_GET['search_location'] ) ? sanitize_text_field( wp_unslash( $_GET['search_location'] ) ) : false;
551
+ $input_job_types = isset( $_GET['job_types'] ) ? explode( ',', sanitize_text_field( wp_unslash( $_GET['job_types'] ) ) ) : false;
552
+ $input_job_categories = isset( $_GET['job_categories'] ) ? explode( ',', sanitize_text_field( wp_unslash( $_GET['job_categories'] ) ) ) : false;
553
+ $job_manager_keyword = isset( $_GET['search_keywords'] ) ? sanitize_text_field( wp_unslash( $_GET['search_keywords'] ) ) : '';
554
+ // phpcs:enable WordPress.Security.NonceVerification.Recommended
555
+
556
  $query_args = array(
557
  'post_type' => 'job_listing',
558
  'post_status' => 'publish',
559
  'ignore_sticky_posts' => 1,
560
+ 'posts_per_page' => $input_posts_per_page,
561
  'paged' => absint( get_query_var( 'paged', 1 ) ),
562
  'tax_query' => array(),
563
  'meta_query' => array(),
564
  );
565
 
566
+ if ( ! empty( $input_search_location ) ) {
567
  $location_meta_keys = array( 'geolocation_formatted_address', '_job_location', 'geolocation_state_long' );
568
  $location_search = array( 'relation' => 'OR' );
569
  foreach ( $location_meta_keys as $meta_key ) {
570
  $location_search[] = array(
571
  'key' => $meta_key,
572
+ 'value' => $input_search_location,
573
  'compare' => 'like',
574
  );
575
  }
576
  $query_args['meta_query'][] = $location_search;
577
  }
578
 
579
+ if ( ! empty( $input_job_types ) ) {
580
  $query_args['tax_query'][] = array(
581
  'taxonomy' => 'job_listing_type',
582
  'field' => 'slug',
583
+ 'terms' => $input_job_types + array( 0 ),
584
  );
585
  }
586
 
587
+ if ( ! empty( $input_job_categories ) ) {
588
+ $cats = $input_job_categories + array( 0 );
589
  $field = is_numeric( $cats ) ? 'term_id' : 'slug';
590
  $operator = 'all' === get_option( 'job_manager_category_filter_type', 'all' ) && count( $cats ) > 1 ? 'AND' : 'IN';
591
  $query_args['tax_query'][] = array(
597
  );
598
  }
599
 
 
600
  if ( ! empty( $job_manager_keyword ) ) {
601
  $query_args['s'] = $job_manager_keyword;
602
  add_filter( 'posts_search', 'get_job_listings_keyword_search' );
610
  unset( $query_args['tax_query'] );
611
  }
612
 
613
+ // phpcs:ignore WordPress.WP.DiscouragedFunctions
614
+ query_posts( apply_filters( 'job_feed_args', $query_args ) );
615
  add_action( 'rss2_ns', array( $this, 'job_feed_namespace' ) );
616
  add_action( 'rss2_item', array( $this, 'job_feed_item' ) );
617
  do_feed_rss2( false );
675
  *
676
  * @param int $post_id The post ID of the job.
677
  */
678
+ do_action( 'job_feed_item', $post_id );
679
  }
680
 
681
  /**
682
  * Maintenance task to expire jobs.
683
  */
684
  public function check_for_expired_jobs() {
 
 
685
  // Change status to expired.
686
+ $job_ids = get_posts(
687
+ array(
688
+ 'post_type' => 'job_listing',
689
+ 'post_status' => 'publish',
690
+ 'fields' => 'ids',
691
+ 'posts_per_page' => -1,
692
+ 'meta_query' => array(
693
+ 'relation' => 'AND',
694
+ array(
695
+ 'key' => '_job_expires',
696
+ 'value' => 0,
697
+ 'compare' => '>',
698
+ ),
699
+ array(
700
+ 'key' => '_job_expires',
701
+ 'value' => date( 'Y-m-d', current_time( 'timestamp' ) ),
702
+ 'compare' => '<',
703
+ ),
704
+ ),
705
  )
706
  );
707
 
715
  }
716
 
717
  // Delete old expired jobs.
718
+
719
+ /**
720
+ * Set whether or not we should delete expired jobs after a certain amount of time.
721
+ *
722
+ * @since 1.0.0
723
+ *
724
+ * @param bool $delete_expired_jobs Whether we should delete expired jobs after a certain amount of time. Defaults to false.
725
+ */
726
  if ( apply_filters( 'job_manager_delete_expired_jobs', false ) ) {
727
+ /**
728
+ * Days to preserve expired job listings before deleting them.
729
+ *
730
+ * @since 1.0.0
731
+ *
732
+ * @param int $delete_expired_jobs_days Number of days to preserve expired job listings before deleting them.
733
+ */
734
+ $delete_expired_jobs_days = apply_filters( 'job_manager_delete_expired_jobs_days', 30 );
735
+
736
+ $job_ids = get_posts(
737
+ array(
738
+ 'post_type' => 'job_listing',
739
+ 'post_status' => 'expired',
740
+ 'fields' => 'ids',
741
+ 'date_query' => array(
742
+ array(
743
+ 'column' => 'post_modified',
744
+ 'before' => date( 'Y-m-d', strtotime( '-' . $delete_expired_jobs_days . ' days', current_time( 'timestamp' ) ) ),
745
+ ),
746
+ ),
747
+ 'posts_per_page' => -1,
748
  )
749
  );
750
 
760
  * Deletes old previewed jobs after 30 days to keep the DB clean.
761
  */
762
  public function delete_old_previews() {
763
+ // Delete old jobs stuck in preview.
764
+ $job_ids = get_posts(
765
+ array(
766
+ 'post_type' => 'job_listing',
767
+ 'post_status' => 'preview',
768
+ 'fields' => 'ids',
769
+ 'date_query' => array(
770
+ array(
771
+ 'column' => 'post_modified',
772
+ 'before' => date( 'Y-m-d', strtotime( '-30 days', current_time( 'timestamp' ) ) ),
773
+ ),
774
+ ),
775
+ 'posts_per_page' => -1,
776
  )
777
  );
778
 
813
  }
814
  }
815
 
816
+ // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce check handled by WP core.
817
+ $input_job_expires = isset( $_POST['_job_expires'] ) ? sanitize_text_field( wp_unslash( $_POST['_job_expires'] ) ) : null;
818
+
819
  // See if the user has set the expiry manually.
820
+ if ( ! empty( $input_job_expires ) ) {
821
+ update_post_meta( $post->ID, '_job_expires', date( 'Y-m-d', strtotime( $input_job_expires ) ) );
822
  } elseif ( ! isset( $expires ) ) {
823
  // No manual setting? Lets generate a date if there isn't already one.
824
  $expires = calculate_job_expiry( $post->ID );
825
  update_post_meta( $post->ID, '_job_expires', $expires );
826
 
827
  // In case we are saving a post, ensure post data is updated so the field is not overridden.
828
+ if ( null !== $input_job_expires ) {
829
  $_POST['_job_expires'] = $expires;
830
  }
831
  }
977
  * @param mixed $meta_value
978
  */
979
  public function update_post_meta( $meta_id, $object_id, $meta_key, $meta_value ) {
980
+ if ( 'job_listing' !== get_post_type( $object_id ) ) {
981
+ return;
982
+ }
983
+
984
+ remove_action( 'update_post_meta', array( $this, 'update_post_meta' ) );
985
+ switch ( $meta_key ) {
986
+ case '_job_location':
987
+ $this->maybe_update_geolocation_data( $meta_id, $object_id, $meta_key, $meta_value );
988
+ break;
989
+ case '_featured':
990
+ $this->maybe_update_menu_order( $meta_id, $object_id, $meta_key, $meta_value );
991
+ break;
992
  }
993
+ add_action( 'update_post_meta', array( $this, 'update_post_meta' ), 10, 4 );
994
  }
995
 
996
  /**
1014
  * @param mixed $meta_value
1015
  */
1016
  public function maybe_update_menu_order( $meta_id, $object_id, $meta_key, $meta_value ) {
 
 
1017
  if ( 1 === intval( $meta_value ) ) {
1018
+ wp_update_post(
 
 
 
 
 
 
 
 
1019
  array(
1020
  'ID' => $object_id,
1021
  'menu_order' => -1,
1022
  )
1023
  );
1024
+ } else {
1025
+ $post = get_post( $object_id );
1026
 
1027
+ if ( -1 === intval( $post->menu_order ) ) {
1028
+ wp_update_post(
1029
+ array(
1030
+ 'ID' => $object_id,
1031
+ 'menu_order' => 0,
1032
+ )
1033
+ );
1034
+ }
1035
+ }
1036
  }
1037
 
1038
  /**
1163
  * Registers job listing meta fields.
1164
  */
1165
  public function register_meta_fields() {
1166
+ $fields = self::get_job_listing_fields();
1167
 
1168
  foreach ( $fields as $meta_key => $field ) {
1169
  register_meta(
includes/class-wp-job-manager-shortcodes.php CHANGED
@@ -30,7 +30,7 @@ class WP_Job_Manager_Shortcodes {
30
  * @var self
31
  * @since 1.26.0
32
  */
33
- private static $_instance = null;
34
 
35
  /**
36
  * Allows for accessing single instance of class. Class should only be constructed once per call.
@@ -40,10 +40,10 @@ class WP_Job_Manager_Shortcodes {
40
  * @return self Main instance.
41
  */
42
  public static function instance() {
43
- if ( is_null( self::$_instance ) ) {
44
- self::$_instance = new self();
45
  }
46
- return self::$_instance;
47
  }
48
 
49
  /**
@@ -90,10 +90,14 @@ class WP_Job_Manager_Shortcodes {
90
  * @throws Exception On action handling error.
91
  */
92
  public function job_dashboard_handler() {
93
- if ( ! empty( $_REQUEST['action'] ) && ! empty( $_REQUEST['_wpnonce'] ) && wp_verify_nonce( $_REQUEST['_wpnonce'], 'job_manager_my_job_actions' ) ) {
 
 
 
 
94
 
95
- $action = sanitize_title( $_REQUEST['action'] );
96
- $job_id = absint( $_REQUEST['job_id'] );
97
 
98
  try {
99
  // Get Job.
@@ -148,7 +152,7 @@ class WP_Job_Manager_Shortcodes {
148
  $new_job_id = job_manager_duplicate_listing( $job_id );
149
 
150
  if ( $new_job_id ) {
151
- wp_redirect( add_query_arg( array( 'job_id' => absint( $new_job_id ) ), job_manager_get_permalink( 'submit_job_form' ) ) );
152
  exit;
153
  }
154
 
@@ -160,7 +164,7 @@ class WP_Job_Manager_Shortcodes {
160
  }
161
 
162
  // redirect to post page.
163
- wp_redirect( add_query_arg( array( 'job_id' => absint( $job_id ) ), job_manager_get_permalink( 'submit_job_form' ) ) );
164
  exit;
165
  default:
166
  do_action( 'job_manager_job_dashboard_do_action_' . $action, $job_id );
@@ -206,7 +210,8 @@ class WP_Job_Manager_Shortcodes {
206
  $new_atts = shortcode_atts(
207
  array(
208
  'posts_per_page' => '25',
209
- ), $atts
 
210
  );
211
  $posts_per_page = $new_atts['posts_per_page'];
212
 
@@ -215,9 +220,9 @@ class WP_Job_Manager_Shortcodes {
215
  ob_start();
216
 
217
  // If doing an action, show conditional content if needed....
218
- if ( ! empty( $_REQUEST['action'] ) ) {
219
- $action = sanitize_title( $_REQUEST['action'] );
220
-
221
  // Show alternative content if a plugin wants to.
222
  if ( has_action( 'job_manager_job_dashboard_content_' . $action ) ) {
223
  do_action( 'job_manager_job_dashboard_content_' . $action, $atts );
@@ -273,7 +278,8 @@ class WP_Job_Manager_Shortcodes {
273
  public function edit_job() {
274
  global $job_manager;
275
 
276
- echo $job_manager->forms->get_form( 'edit-job' ); // WPCS: XSS ok.
 
277
  }
278
 
279
  /**
@@ -313,7 +319,8 @@ class WP_Job_Manager_Shortcodes {
313
  'selected_category' => '',
314
  'selected_job_types' => implode( ',', array_values( get_job_listing_types( 'id=>slug' ) ) ),
315
  )
316
- ), $atts
 
317
  );
318
 
319
  if ( ! get_option( 'job_manager_enable_categories' ) ) {
@@ -336,18 +343,20 @@ class WP_Job_Manager_Shortcodes {
336
  }
337
 
338
  // Get keywords, location, category and type from querystring if set.
 
339
  if ( ! empty( $_GET['search_keywords'] ) ) {
340
- $atts['keywords'] = sanitize_text_field( $_GET['search_keywords'] );
341
  }
342
  if ( ! empty( $_GET['search_location'] ) ) {
343
- $atts['location'] = sanitize_text_field( $_GET['search_location'] );
344
  }
345
  if ( ! empty( $_GET['search_category'] ) ) {
346
- $atts['selected_category'] = sanitize_text_field( $_GET['search_category'] );
347
  }
348
  if ( ! empty( $_GET['search_job_type'] ) ) {
349
- $atts['selected_job_types'] = sanitize_text_field( $_GET['search_job_type'] );
350
  }
 
351
 
352
  // Array handling.
353
  $atts['categories'] = is_array( $atts['categories'] ) ? $atts['categories'] : array_filter( array_map( 'trim', explode( ',', $atts['categories'] ) ) );
@@ -365,8 +374,8 @@ class WP_Job_Manager_Shortcodes {
365
  'order' => $atts['order'],
366
  'categories' => implode( ',', $atts['categories'] ),
367
  );
368
- if ( $atts['show_filters'] ) {
369
 
 
370
  get_job_manager_template(
371
  'job-filters.php',
372
  array(
@@ -424,7 +433,8 @@ class WP_Job_Manager_Shortcodes {
424
  if ( $jobs->found_posts > $atts['per_page'] && $atts['show_more'] ) {
425
  wp_enqueue_script( 'wp-job-manager-ajax-filters' );
426
  if ( $atts['show_pagination'] ) {
427
- echo get_job_listing_pagination( $jobs->max_num_pages ); // WPCS: XSS ok.
 
428
  } else {
429
  echo '<a class="load_more_jobs" href="#"><strong>' . esc_html__( 'Load more listings', 'wp-job-manager' ) . '</strong></a>';
430
  }
@@ -510,11 +520,12 @@ class WP_Job_Manager_Shortcodes {
510
  $atts = shortcode_atts(
511
  array(
512
  'id' => '',
513
- ), $atts
 
514
  );
515
 
516
  if ( ! $atts['id'] ) {
517
- return;
518
  }
519
 
520
  ob_start();
@@ -554,7 +565,8 @@ class WP_Job_Manager_Shortcodes {
554
  'align' => 'left',
555
  'featured' => null, // True to show only featured, false to hide featured, leave null to show both (when leaving out id).
556
  'limit' => 1,
557
- ), $atts
 
558
  );
559
 
560
  ob_start();
@@ -607,7 +619,8 @@ class WP_Job_Manager_Shortcodes {
607
  $new_atts = shortcode_atts(
608
  array(
609
  'id' => '',
610
- ), $atts
 
611
  );
612
  $id = $new_atts['id'];
613
 
30
  * @var self
31
  * @since 1.26.0
32
  */
33
+ private static $instance = null;
34
 
35
  /**
36
  * Allows for accessing single instance of class. Class should only be constructed once per call.
40
  * @return self Main instance.
41
  */
42
  public static function instance() {
43
+ if ( is_null( self::$instance ) ) {
44
+ self::$instance = new self();
45
  }
46
+ return self::$instance;
47
  }
48
 
49
  /**
90
  * @throws Exception On action handling error.
91
  */
92
  public function job_dashboard_handler() {
93
+ if (
94
+ ! empty( $_REQUEST['action'] )
95
+ && ! empty( $_REQUEST['_wpnonce'] )
96
+ && wp_verify_nonce( wp_unslash( $_REQUEST['_wpnonce'] ), 'job_manager_my_job_actions' ) // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Nonce should not be modified.
97
+ ) {
98
 
99
+ $action = sanitize_title( wp_unslash( $_REQUEST['action'] ) );
100
+ $job_id = isset( $_REQUEST['job_id'] ) ? absint( $_REQUEST['job_id'] ) : 0;
101
 
102
  try {
103
  // Get Job.
152
  $new_job_id = job_manager_duplicate_listing( $job_id );
153
 
154
  if ( $new_job_id ) {
155
+ wp_safe_redirect( add_query_arg( array( 'job_id' => absint( $new_job_id ) ), job_manager_get_permalink( 'submit_job_form' ) ) );
156
  exit;
157
  }
158
 
164
  }
165
 
166
  // redirect to post page.
167
+ wp_safe_redirect( add_query_arg( array( 'job_id' => absint( $job_id ) ), job_manager_get_permalink( 'submit_job_form' ) ) );
168
  exit;
169
  default:
170
  do_action( 'job_manager_job_dashboard_do_action_' . $action, $job_id );
210
  $new_atts = shortcode_atts(
211
  array(
212
  'posts_per_page' => '25',
213
+ ),
214
+ $atts
215
  );
216
  $posts_per_page = $new_atts['posts_per_page'];
217
 
220
  ob_start();
221
 
222
  // If doing an action, show conditional content if needed....
223
+ // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Input is used safely.
224
+ $action = isset( $_REQUEST['action'] ) ? sanitize_title( wp_unslash( $_REQUEST['action'] ) ) : false;
225
+ if ( ! empty( $action ) ) {
226
  // Show alternative content if a plugin wants to.
227
  if ( has_action( 'job_manager_job_dashboard_content_' . $action ) ) {
228
  do_action( 'job_manager_job_dashboard_content_' . $action, $atts );
278
  public function edit_job() {
279
  global $job_manager;
280
 
281
+ // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Output should be appropriately escaped in the form generator.
282
+ echo $job_manager->forms->get_form( 'edit-job' );
283
  }
284
 
285
  /**
319
  'selected_category' => '',
320
  'selected_job_types' => implode( ',', array_values( get_job_listing_types( 'id=>slug' ) ) ),
321
  )
322
+ ),
323
+ $atts
324
  );
325
 
326
  if ( ! get_option( 'job_manager_enable_categories' ) ) {
343
  }
344
 
345
  // Get keywords, location, category and type from querystring if set.
346
+ // phpcs:disable WordPress.Security.NonceVerification.Recommended -- Input is used safely.
347
  if ( ! empty( $_GET['search_keywords'] ) ) {
348
+ $atts['keywords'] = sanitize_text_field( wp_unslash( $_GET['search_keywords'] ) );
349
  }
350
  if ( ! empty( $_GET['search_location'] ) ) {
351
+ $atts['location'] = sanitize_text_field( wp_unslash( $_GET['search_location'] ) );
352
  }
353
  if ( ! empty( $_GET['search_category'] ) ) {
354
+ $atts['selected_category'] = sanitize_text_field( wp_unslash( $_GET['search_category'] ) );
355
  }
356
  if ( ! empty( $_GET['search_job_type'] ) ) {
357
+ $atts['selected_job_types'] = sanitize_text_field( wp_unslash( $_GET['search_job_type'] ) );
358
  }
359
+ // phpcs:enable WordPress.Security.NonceVerification.Recommended
360
 
361
  // Array handling.
362
  $atts['categories'] = is_array( $atts['categories'] ) ? $atts['categories'] : array_filter( array_map( 'trim', explode( ',', $atts['categories'] ) ) );
374
  'order' => $atts['order'],
375
  'categories' => implode( ',', $atts['categories'] ),
376
  );
 
377
 
378
+ if ( $atts['show_filters'] ) {
379
  get_job_manager_template(
380
  'job-filters.php',
381
  array(
433
  if ( $jobs->found_posts > $atts['per_page'] && $atts['show_more'] ) {
434
  wp_enqueue_script( 'wp-job-manager-ajax-filters' );
435
  if ( $atts['show_pagination'] ) {
436
+ // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Template output.
437
+ echo get_job_listing_pagination( $jobs->max_num_pages );
438
  } else {
439
  echo '<a class="load_more_jobs" href="#"><strong>' . esc_html__( 'Load more listings', 'wp-job-manager' ) . '</strong></a>';
440
  }
520
  $atts = shortcode_atts(
521
  array(
522
  'id' => '',
523
+ ),
524
+ $atts
525
  );
526
 
527
  if ( ! $atts['id'] ) {
528
+ return null;
529
  }
530
 
531
  ob_start();
565
  'align' => 'left',
566
  'featured' => null, // True to show only featured, false to hide featured, leave null to show both (when leaving out id).
567
  'limit' => 1,
568
+ ),
569
+ $atts
570
  );
571
 
572
  ob_start();
619
  $new_atts = shortcode_atts(
620
  array(
621
  'id' => '',
622
+ ),
623
+ $atts
624
  );
625
  $id = $new_atts['id'];
626
 
includes/class-wp-job-manager-usage-tracking.php CHANGED
@@ -30,6 +30,7 @@ class WP_Job_Manager_Usage_Tracking extends WP_Job_Manager_Usage_Tracking_Base {
30
  add_filter( 'job_manager_settings', array( $this, 'add_setting_field' ) );
31
 
32
  // In the setup wizard, do not display the normal opt-in dialog.
 
33
  if ( isset( $_GET['page'] ) && 'job-manager-setup' === $_GET['page'] ) {
34
  remove_action( 'admin_notices', array( $this, 'maybe_display_tracking_opt_in' ) );
35
  }
@@ -115,12 +116,12 @@ class WP_Job_Manager_Usage_Tracking extends WP_Job_Manager_Usage_Tracking_Base {
115
  $properties['job_id'] = intval( $post_id );
116
  $properties['post_status'] = get_post_status( $post_id );
117
 
118
- $user_role = self::get_current_role();
119
  if ( $user_role ) {
120
  $properties['user_role'] = $user_role;
121
  }
122
 
123
- WP_Job_Manager_Usage_Tracking::log_event( 'job_listing_submitted', $properties );
124
  }
125
 
126
  /**
@@ -141,12 +142,12 @@ class WP_Job_Manager_Usage_Tracking extends WP_Job_Manager_Usage_Tracking_Base {
141
  $properties['job_id'] = intval( $post_id );
142
  $properties['age'] = time() - strtotime( $post->post_date_gmt );
143
 
144
- $user_role = self::get_current_role();
145
  if ( $user_role ) {
146
  $properties['user_role'] = $user_role;
147
  }
148
 
149
- WP_Job_Manager_Usage_Tracking::log_event( 'job_listing_approved', $properties );
150
  }
151
 
152
  /**
@@ -229,7 +230,8 @@ class WP_Job_Manager_Usage_Tracking extends WP_Job_Manager_Usage_Tracking_Base {
229
  <a href="%s">usage tracking data</a>. No sensitive information is
230
  collected, and you can opt out at any time.',
231
  'wp-job-manager'
232
- ), self::WPJM_TRACKING_INFO_URL
 
233
  );
234
  }
235
 
@@ -295,8 +297,10 @@ class WP_Job_Manager_Usage_Tracking extends WP_Job_Manager_Usage_Tracking_Base {
295
  __(
296
  'Help us make WP Job Manager better by allowing us to collect
297
  <a href="%s">usage tracking data</a>.
298
- No sensitive information is collected.', 'wp-job-manager'
299
- ), self::WPJM_TRACKING_INFO_URL
 
 
300
  );
301
  }
302
 
30
  add_filter( 'job_manager_settings', array( $this, 'add_setting_field' ) );
31
 
32
  // In the setup wizard, do not display the normal opt-in dialog.
33
+ // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Input is used safely.
34
  if ( isset( $_GET['page'] ) && 'job-manager-setup' === $_GET['page'] ) {
35
  remove_action( 'admin_notices', array( $this, 'maybe_display_tracking_opt_in' ) );
36
  }
116
  $properties['job_id'] = intval( $post_id );
117
  $properties['post_status'] = get_post_status( $post_id );
118
 
119
+ $user_role = self::get_current_role();
120
  if ( $user_role ) {
121
  $properties['user_role'] = $user_role;
122
  }
123
 
124
+ self::log_event( 'job_listing_submitted', $properties );
125
  }
126
 
127
  /**
142
  $properties['job_id'] = intval( $post_id );
143
  $properties['age'] = time() - strtotime( $post->post_date_gmt );
144
 
145
+ $user_role = self::get_current_role();
146
  if ( $user_role ) {
147
  $properties['user_role'] = $user_role;
148
  }
149
 
150
+ self::log_event( 'job_listing_approved', $properties );
151
  }
152
 
153
  /**
230
  <a href="%s">usage tracking data</a>. No sensitive information is
231
  collected, and you can opt out at any time.',
232
  'wp-job-manager'
233
+ ),
234
+ self::WPJM_TRACKING_INFO_URL
235
  );
236
  }
237
 
297
  __(
298
  'Help us make WP Job Manager better by allowing us to collect
299
  <a href="%s">usage tracking data</a>.
300
+ No sensitive information is collected.',
301
+ 'wp-job-manager'
302
+ ),
303
+ self::WPJM_TRACKING_INFO_URL
304
  );
305
  }
306
 
includes/class-wp-job-manager-widget.php CHANGED
@@ -88,7 +88,7 @@ class WP_Job_Manager_Widget extends WP_Widget {
88
  }
89
 
90
  if ( isset( $cache[ $args['widget_id'] ] ) ) {
91
- echo $cache[ $args['widget_id'] ]; // WPCS: XSS ok.
92
  return true;
93
  }
94
 
88
  }
89
 
90
  if ( isset( $cache[ $args['widget_id'] ] ) ) {
91
+ echo $cache[ $args['widget_id'] ]; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
92
  return true;
93
  }
94
 
includes/class-wp-job-manager.php CHANGED
@@ -22,7 +22,7 @@ class WP_Job_Manager {
22
  * @var self
23
  * @since 1.26.0
24
  */
25
- private static $_instance = null;
26
 
27
  /**
28
  * Main WP Job Manager Instance.
@@ -35,10 +35,10 @@ class WP_Job_Manager {
35
  * @return self Main instance.
36
  */
37
  public static function instance() {
38
- if ( is_null( self::$_instance ) ) {
39
- self::$_instance = new self();
40
  }
41
- return self::$_instance;
42
  }
43
 
44
  /**
@@ -75,9 +75,6 @@ class WP_Job_Manager {
75
  // Schedule cron jobs.
76
  self::maybe_schedule_cron_jobs();
77
 
78
- // Activation - works with symlinks.
79
- register_activation_hook( basename( dirname( __FILE__ ) ) . '/' . basename( __FILE__ ), array( $this, 'activate' ) );
80
-
81
  // Switch theme.
82
  add_action( 'after_switch_theme', array( 'WP_Job_Manager_Ajax', 'add_endpoint' ), 10 );
83
  add_action( 'after_switch_theme', array( $this->post_types, 'register_post_types' ), 11 );
@@ -94,16 +91,11 @@ class WP_Job_Manager {
94
  add_action( 'wp_logout', array( $this, 'cleanup_job_posting_cookies' ) );
95
  add_action( 'init', array( 'WP_Job_Manager_Email_Notifications', 'init' ) );
96
  add_action( 'rest_api_init', array( $this, 'rest_init' ) );
97
- add_action( 'template_redirect', array( $this, 'send_frame_options_header' ) );
98
 
99
  // Filters.
100
  add_filter( 'wp_privacy_personal_data_exporters', array( 'WP_Job_Manager_Data_Exporter', 'register_wpjm_user_data_exporter' ) );
101
 
102
  add_action( 'init', array( $this, 'usage_tracking_init' ) );
103
- register_deactivation_hook( __FILE__, array( $this, 'usage_tracking_cleanup' ) );
104
-
105
- // Other cleanup.
106
- register_deactivation_hook( __FILE__, array( $this, 'unschedule_cron_jobs' ) );
107
 
108
  // Defaults for WPJM core actions.
109
  add_action( 'wpjm_notify_new_user', 'wp_job_manager_notify_new_user', 10, 2 );
@@ -128,6 +120,7 @@ class WP_Job_Manager {
128
  public function updater() {
129
  if ( version_compare( JOB_MANAGER_VERSION, get_option( 'wp_job_manager_version' ), '>' ) ) {
130
  WP_Job_Manager_Install::install();
 
131
  flush_rewrite_rules();
132
  }
133
  }
@@ -143,10 +136,12 @@ class WP_Job_Manager {
143
  $content = sprintf(
144
  // translators: Placeholders %1$s and %2$s are the names of the two cookies used in WP Job Manager.
145
  __(
146
- 'This site adds the following cookies to help users resume job submissions that they
147
- have started but have not completed: %1$s and %2$s', 'wp-job-manager'
 
148
  ),
149
- '<code>wp-job-manager-submitting-job-id</code>', '<code>wp-job-manager-submitting-job-key</code>'
 
150
  );
151
 
152
  wp_add_privacy_policy_content(
@@ -160,7 +155,7 @@ class WP_Job_Manager {
160
  */
161
  public function load_plugin_textdomain() {
162
  load_textdomain( 'wp-job-manager', WP_LANG_DIR . '/wp-job-manager/wp-job-manager-' . apply_filters( 'plugin_locale', get_locale(), 'wp-job-manager' ) . '.mo' );
163
- load_plugin_textdomain( 'wp-job-manager', false, dirname( plugin_basename( __FILE__ ) ) . '/languages/' );
164
  }
165
 
166
  /**
@@ -222,9 +217,6 @@ class WP_Job_Manager {
222
  if ( ! wp_next_scheduled( 'job_manager_delete_old_previews' ) ) {
223
  wp_schedule_event( time(), 'daily', 'job_manager_delete_old_previews' );
224
  }
225
- if ( ! wp_next_scheduled( 'job_manager_clear_expired_transients' ) ) {
226
- wp_schedule_event( time(), 'twicedaily', 'job_manager_clear_expired_transients' );
227
- }
228
  if ( ! wp_next_scheduled( 'job_manager_email_daily_notices' ) ) {
229
  wp_schedule_event( time(), 'daily', 'job_manager_email_daily_notices' );
230
  }
@@ -236,7 +228,6 @@ class WP_Job_Manager {
236
  public static function unschedule_cron_jobs() {
237
  wp_clear_scheduled_hook( 'job_manager_check_for_expired_jobs' );
238
  wp_clear_scheduled_hook( 'job_manager_delete_old_previews' );
239
- wp_clear_scheduled_hook( 'job_manager_clear_expired_transients' );
240
  wp_clear_scheduled_hook( 'job_manager_email_daily_notices' );
241
  }
242
 
@@ -266,7 +257,7 @@ class WP_Job_Manager {
266
  * Registers select2 assets when needed.
267
  */
268
  public static function register_select2_assets() {
269
- wp_register_script( 'select2', JOB_MANAGER_PLUGIN_URL . '/assets/js/select2/select2.full.min.js', array( 'jquery' ), '4.0.5' );
270
  wp_register_style( 'select2', JOB_MANAGER_PLUGIN_URL . '/assets/js/select2/select2.min.css', array(), '4.0.5' );
271
  }
272
 
@@ -296,6 +287,7 @@ class WP_Job_Manager {
296
 
297
  $enhanced_select_shortcodes = array( 'submit_job_form', 'job_dashboard', 'jobs' );
298
  $enhanced_select_used_on_page = has_wpjm_shortcode( null, $enhanced_select_shortcodes );
 
299
  /**
300
  * Set the constant `JOB_MANAGER_DISABLE_CHOSEN_LEGACY_COMPAT` to true to test for future behavior once
301
  * this legacy code is removed and `chosen` is no longer packaged with the plugin.
@@ -313,9 +305,11 @@ class WP_Job_Manager {
313
 
314
  // Backwards compatibility for third-party themes/plugins while they transition to Select2.
315
  wp_localize_script(
316
- 'chosen', 'job_manager_chosen_multiselect_args',
 
317
  apply_filters(
318
- 'job_manager_chosen_multiselect_args', array(
 
319
  'search_contains' => true,
320
  )
321
  )
@@ -366,14 +360,15 @@ class WP_Job_Manager {
366
  $select2_args['width'] = '100%';
367
 
368
  wp_localize_script(
369
- 'select2', 'job_manager_select2_args',
 
370
  apply_filters( 'job_manager_select2_args', $select2_args )
371
  );
372
  }
373
 
374
  if ( job_manager_user_can_upload_file_via_ajax() ) {
375
- wp_register_script( 'jquery-iframe-transport', JOB_MANAGER_PLUGIN_URL . '/assets/js/jquery-fileupload/jquery.iframe-transport.js', array( 'jquery' ), '9.32.0', true );
376
- wp_register_script( 'jquery-fileupload', JOB_MANAGER_PLUGIN_URL . '/assets/js/jquery-fileupload/jquery.fileupload.js', array( 'jquery', 'jquery-iframe-transport', 'jquery-ui-widget' ), '9.32.0', true );
377
  wp_register_script( 'wp-job-manager-ajax-file-upload', JOB_MANAGER_PLUGIN_URL . '/assets/js/ajax-file-upload.min.js', array( 'jquery', 'jquery-fileupload' ), JOB_MANAGER_VERSION, true );
378
 
379
  ob_start();
@@ -472,22 +467,4 @@ class WP_Job_Manager {
472
  wp_register_style( 'wp-job-manager-job-listings', JOB_MANAGER_PLUGIN_URL . '/assets/css/job-listings.css', array(), JOB_MANAGER_VERSION );
473
  }
474
  }
475
-
476
- /**
477
- *
478
- * Ensure all user wpjm pages or pages containing wpjm shortcodes
479
- * get an X-Frame-Options header.
480
- *
481
- * Disabling is not recommended, but if you must you can
482
- *
483
- * remove_action( 'template_redirect', array( WPJM(), 'send_frame_options_header' ) )
484
- *
485
- * @since 1.33.3
486
- *
487
- **/
488
- public function send_frame_options_header() {
489
- if ( is_wpjm() ) {
490
- send_frame_options_header();
491
- }
492
- }
493
  }
22
  * @var self
23
  * @since 1.26.0
24
  */
25
+ private static $instance = null;
26
 
27
  /**
28
  * Main WP Job Manager Instance.
35
  * @return self Main instance.
36
  */
37
  public static function instance() {
38
+ if ( is_null( self::$instance ) ) {
39
+ self::$instance = new self();
40
  }
41
+ return self::$instance;
42
  }
43
 
44
  /**
75
  // Schedule cron jobs.
76
  self::maybe_schedule_cron_jobs();
77
 
 
 
 
78
  // Switch theme.
79
  add_action( 'after_switch_theme', array( 'WP_Job_Manager_Ajax', 'add_endpoint' ), 10 );
80
  add_action( 'after_switch_theme', array( $this->post_types, 'register_post_types' ), 11 );
91
  add_action( 'wp_logout', array( $this, 'cleanup_job_posting_cookies' ) );
92
  add_action( 'init', array( 'WP_Job_Manager_Email_Notifications', 'init' ) );
93
  add_action( 'rest_api_init', array( $this, 'rest_init' ) );
 
94
 
95
  // Filters.
96
  add_filter( 'wp_privacy_personal_data_exporters', array( 'WP_Job_Manager_Data_Exporter', 'register_wpjm_user_data_exporter' ) );
97
 
98
  add_action( 'init', array( $this, 'usage_tracking_init' ) );
 
 
 
 
99
 
100
  // Defaults for WPJM core actions.
101
  add_action( 'wpjm_notify_new_user', 'wp_job_manager_notify_new_user', 10, 2 );
120
  public function updater() {
121
  if ( version_compare( JOB_MANAGER_VERSION, get_option( 'wp_job_manager_version' ), '>' ) ) {
122
  WP_Job_Manager_Install::install();
123
+
124
  flush_rewrite_rules();
125
  }
126
  }
136
  $content = sprintf(
137
  // translators: Placeholders %1$s and %2$s are the names of the two cookies used in WP Job Manager.
138
  __(
139
+ 'This site adds the following cookies to help users resume job submissions that they
140
+ have started but have not completed: %1$s and %2$s',
141
+ 'wp-job-manager'
142
  ),
143
+ '<code>wp-job-manager-submitting-job-id</code>',
144
+ '<code>wp-job-manager-submitting-job-key</code>'
145
  );
146
 
147
  wp_add_privacy_policy_content(
155
  */
156
  public function load_plugin_textdomain() {
157
  load_textdomain( 'wp-job-manager', WP_LANG_DIR . '/wp-job-manager/wp-job-manager-' . apply_filters( 'plugin_locale', get_locale(), 'wp-job-manager' ) . '.mo' );
158
+ load_plugin_textdomain( 'wp-job-manager', false, JOB_MANAGER_PLUGIN_DIR . '/languages/' );
159
  }
160
 
161
  /**
217
  if ( ! wp_next_scheduled( 'job_manager_delete_old_previews' ) ) {
218
  wp_schedule_event( time(), 'daily', 'job_manager_delete_old_previews' );
219
  }
 
 
 
220
  if ( ! wp_next_scheduled( 'job_manager_email_daily_notices' ) ) {
221
  wp_schedule_event( time(), 'daily', 'job_manager_email_daily_notices' );
222
  }
228
  public static function unschedule_cron_jobs() {
229
  wp_clear_scheduled_hook( 'job_manager_check_for_expired_jobs' );
230
  wp_clear_scheduled_hook( 'job_manager_delete_old_previews' );
 
231
  wp_clear_scheduled_hook( 'job_manager_email_daily_notices' );
232
  }
233
 
257
  * Registers select2 assets when needed.
258
  */
259
  public static function register_select2_assets() {
260
+ wp_register_script( 'select2', JOB_MANAGER_PLUGIN_URL . '/assets/js/select2/select2.full.min.js', array( 'jquery' ), '4.0.5', false );
261
  wp_register_style( 'select2', JOB_MANAGER_PLUGIN_URL . '/assets/js/select2/select2.min.css', array(), '4.0.5' );
262
  }
263
 
287
 
288
  $enhanced_select_shortcodes = array( 'submit_job_form', 'job_dashboard', 'jobs' );
289
  $enhanced_select_used_on_page = has_wpjm_shortcode( null, $enhanced_select_shortcodes );
290
+
291
  /**
292
  * Set the constant `JOB_MANAGER_DISABLE_CHOSEN_LEGACY_COMPAT` to true to test for future behavior once
293
  * this legacy code is removed and `chosen` is no longer packaged with the plugin.
305
 
306
  // Backwards compatibility for third-party themes/plugins while they transition to Select2.
307
  wp_localize_script(
308
+ 'chosen',
309
+ 'job_manager_chosen_multiselect_args',
310
  apply_filters(
311
+ 'job_manager_chosen_multiselect_args',
312
+ array(
313
  'search_contains' => true,
314
  )
315
  )
360
  $select2_args['width'] = '100%';
361
 
362
  wp_localize_script(
363
+ 'select2',
364
+ 'job_manager_select2_args',
365
  apply_filters( 'job_manager_select2_args', $select2_args )
366
  );
367
  }
368
 
369
  if ( job_manager_user_can_upload_file_via_ajax() ) {
370
+ wp_register_script( 'jquery-iframe-transport', JOB_MANAGER_PLUGIN_URL . '/assets/js/jquery-fileupload/jquery.iframe-transport.js', array( 'jquery' ), '9.30.0', true );
371
+ wp_register_script( 'jquery-fileupload', JOB_MANAGER_PLUGIN_URL . '/assets/js/jquery-fileupload/jquery.fileupload.js', array( 'jquery', 'jquery-iframe-transport', 'jquery-ui-widget' ), '9.30.0', true );
372
  wp_register_script( 'wp-job-manager-ajax-file-upload', JOB_MANAGER_PLUGIN_URL . '/assets/js/ajax-file-upload.min.js', array( 'jquery', 'jquery-fileupload' ), JOB_MANAGER_VERSION, true );
373
 
374
  ob_start();
467
  wp_register_style( 'wp-job-manager-job-listings', JOB_MANAGER_PLUGIN_URL . '/assets/css/job-listings.css', array(), JOB_MANAGER_VERSION );
468
  }
469
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
470
  }
includes/forms/class-wp-job-manager-form-edit-job.php CHANGED
@@ -46,16 +46,16 @@ class WP_Job_Manager_Form_Edit_Job extends WP_Job_Manager_Form_Submit_Job {
46
  * @access protected
47
  * @var WP_Job_Manager_Form_Edit_Job The single instance of the class
48
  */
49
- protected static $_instance = null;
50
 
51
  /**
52
  * Main Instance
53
  */
54
  public static function instance() {
55
- if ( is_null( self::$_instance ) ) {
56
- self::$_instance = new self();
57
  }
58
- return self::$_instance;
59
  }
60
 
61
  /**
@@ -65,6 +65,7 @@ class WP_Job_Manager_Form_Edit_Job extends WP_Job_Manager_Form_Submit_Job {
65
  add_action( 'wp', array( $this, 'submit_handler' ) );
66
  add_action( 'submit_job_form_start', array( $this, 'output_submit_form_nonce_field' ) );
67
 
 
68
  $this->job_id = ! empty( $_REQUEST['job_id'] ) ? absint( $_REQUEST['job_id'] ) : 0;
69
 
70
  if ( ! job_manager_user_can_edit_job( $this->job_id ) ) {
@@ -137,8 +138,10 @@ class WP_Job_Manager_Form_Edit_Job extends WP_Job_Manager_Form_Submit_Job {
137
  $this->enqueue_job_form_assets();
138
 
139
  $save_button_text = __( 'Save changes', 'wp-job-manager' );
140
- if ( 'publish' === get_post_status( $this->job_id )
141
- && wpjm_published_submission_edits_require_moderation() ) {
 
 
142
  $save_button_text = __( 'Submit changes for approval', 'wp-job-manager' );
143
  }
144
 
@@ -164,6 +167,7 @@ class WP_Job_Manager_Form_Edit_Job extends WP_Job_Manager_Form_Submit_Job {
164
  * @throws Exception When invalid fields are submitted.
165
  */
166
  public function submit_handler() {
 
167
  if ( empty( $_POST['submit_job'] ) ) {
168
  return;
169
  }
46
  * @access protected
47
  * @var WP_Job_Manager_Form_Edit_Job The single instance of the class
48
  */
49
+ protected static $instance = null;
50
 
51
  /**
52
  * Main Instance
53
  */
54
  public static function instance() {
55
+ if ( is_null( self::$instance ) ) {
56
+ self::$instance = new self();
57
  }
58
+ return self::$instance;
59
  }
60
 
61
  /**
65
  add_action( 'wp', array( $this, 'submit_handler' ) );
66
  add_action( 'submit_job_form_start', array( $this, 'output_submit_form_nonce_field' ) );
67
 
68
+ // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Check happens later when possible.
69
  $this->job_id = ! empty( $_REQUEST['job_id'] ) ? absint( $_REQUEST['job_id'] ) : 0;
70
 
71
  if ( ! job_manager_user_can_edit_job( $this->job_id ) ) {
138
  $this->enqueue_job_form_assets();
139
 
140
  $save_button_text = __( 'Save changes', 'wp-job-manager' );
141
+ if (
142
+ 'publish' === get_post_status( $this->job_id )
143
+ && wpjm_published_submission_edits_require_moderation()
144
+ ) {
145
  $save_button_text = __( 'Submit changes for approval', 'wp-job-manager' );
146
  }
147
 
167
  * @throws Exception When invalid fields are submitted.
168
  */
169
  public function submit_handler() {
170
+ // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Check happens later when possible.
171
  if ( empty( $_POST['submit_job'] ) ) {
172
  return;
173
  }
includes/forms/class-wp-job-manager-form-submit-job.php CHANGED
@@ -46,7 +46,7 @@ class WP_Job_Manager_Form_Submit_Job extends WP_Job_Manager_Form {
46
  * @access protected
47
  * @var WP_Job_Manager_Form_Submit_Job The single instance of the class
48
  */
49
- protected static $_instance = null;
50
 
51
  /**
52
  * Returns static instance of class.
@@ -54,10 +54,10 @@ class WP_Job_Manager_Form_Submit_Job extends WP_Job_Manager_Form {
54
  * @return self
55
  */
56
  public static function instance() {
57
- if ( is_null( self::$_instance ) ) {
58
- self::$_instance = new self();
59
  }
60
- return self::$_instance;
61
  }
62
 
63
  /**
@@ -101,6 +101,7 @@ class WP_Job_Manager_Form_Submit_Job extends WP_Job_Manager_Form {
101
 
102
  uasort( $this->steps, array( $this, 'sort_by_priority' ) );
103
 
 
104
  // Get step/job.
105
  if ( isset( $_POST['step'] ) ) {
106
  $this->step = is_numeric( $_POST['step'] ) ? max( absint( $_POST['step'] ), 0 ) : array_search( intval( $_POST['step'] ), array_keys( $this->steps ), true );
@@ -109,6 +110,7 @@ class WP_Job_Manager_Form_Submit_Job extends WP_Job_Manager_Form {
109
  }
110
 
111
  $this->job_id = ! empty( $_REQUEST['job_id'] ) ? absint( $_REQUEST['job_id'] ) : 0;
 
112
 
113
  if ( ! job_manager_user_can_edit_job( $this->job_id ) ) {
114
  $this->job_id = 0;
@@ -116,11 +118,25 @@ class WP_Job_Manager_Form_Submit_Job extends WP_Job_Manager_Form {
116
 
117
  // Allow resuming from cookie.
118
  $this->resume_edit = false;
119
- if ( ! isset( $_GET['new'] ) && ( 'before' === get_option( 'job_manager_paid_listings_flow' ) || ! $this->job_id ) && ! empty( $_COOKIE['wp-job-manager-submitting-job-id'] ) && ! empty( $_COOKIE['wp-job-manager-submitting-job-key'] ) ) {
 
 
 
 
 
 
 
 
120
  $job_id = absint( $_COOKIE['wp-job-manager-submitting-job-id'] );
121
  $job_status = get_post_status( $job_id );
122
 
123
- if ( ( 'preview' === $job_status || 'pending_payment' === $job_status ) && get_post_meta( $job_id, '_submitting_key', true ) === $_COOKIE['wp-job-manager-submitting-job-key'] ) {
 
 
 
 
 
 
124
  $this->job_id = $job_id;
125
  $this->resume_edit = get_post_meta( $job_id, '_submitting_key', true );
126
  }
@@ -531,7 +547,7 @@ class WP_Job_Manager_Form_Submit_Job extends WP_Job_Manager_Form {
531
  $this->fields = apply_filters( 'submit_job_form_fields_get_job_data', $this->fields, $job );
532
 
533
  // Get user meta.
534
- } elseif ( is_user_logged_in() && empty( $_POST['submit_job'] ) ) {
535
  if ( ! empty( $this->fields['company'] ) ) {
536
  foreach ( $this->fields['company'] as $key => $field ) {
537
  $this->fields['company'][ $key ]['value'] = get_user_meta( get_current_user_id(), '_' . $key, true );
@@ -577,11 +593,17 @@ class WP_Job_Manager_Form_Submit_Job extends WP_Job_Manager_Form {
577
  // Get posted values.
578
  $values = $this->get_posted_fields();
579
 
580
- $is_saving_draft = $this->can_continue_later() && ! empty( $_POST['save_draft'] );
 
 
 
 
 
581
 
582
  if ( empty( $_POST['submit_job'] ) && ! $is_saving_draft ) {
583
  return;
584
  }
 
585
 
586
  $this->check_submit_form_nonce_field();
587
 
@@ -611,24 +633,24 @@ class WP_Job_Manager_Form_Submit_Job extends WP_Job_Manager_Form {
611
 
612
  if ( job_manager_enable_registration() ) {
613
  if ( job_manager_user_requires_account() ) {
614
- if ( ! job_manager_generate_username_from_email() && empty( $_POST['create_account_username'] ) ) {
615
  throw new Exception( __( 'Please enter a username.', 'wp-job-manager' ) );
616
  }
617
  if ( ! wpjm_use_standard_password_setup_email() ) {
618
- if ( empty( $_POST['create_account_password'] ) ) {
619
  throw new Exception( __( 'Please enter a password.', 'wp-job-manager' ) );
620
  }
621
  }
622
- if ( empty( $_POST['create_account_email'] ) ) {
623
  throw new Exception( __( 'Please enter your email address.', 'wp-job-manager' ) );
624
  }
625
  }
626
 
627
- if ( ! wpjm_use_standard_password_setup_email() && ! empty( $_POST['create_account_password'] ) ) {
628
- if ( empty( $_POST['create_account_password_verify'] ) || $_POST['create_account_password_verify'] !== $_POST['create_account_password'] ) {
629
  throw new Exception( __( 'Passwords must match.', 'wp-job-manager' ) );
630
  }
631
- if ( ! wpjm_validate_new_password( $_POST['create_account_password'] ) ) {
632
  $password_hint = wpjm_get_password_rules_hint();
633
  if ( $password_hint ) {
634
  // translators: Placeholder %s is the password hint.
@@ -639,12 +661,12 @@ class WP_Job_Manager_Form_Submit_Job extends WP_Job_Manager_Form {
639
  }
640
  }
641
 
642
- if ( ! empty( $_POST['create_account_email'] ) ) {
643
  $create_account = wp_job_manager_create_account(
644
  array(
645
- 'username' => ( job_manager_generate_username_from_email() || empty( $_POST['create_account_username'] ) ) ? '' : $_POST['create_account_username'],
646
- 'password' => ( wpjm_use_standard_password_setup_email() || empty( $_POST['create_account_password'] ) ) ? '' : $_POST['create_account_password'],
647
- 'email' => $_POST['create_account_email'],
648
  'role' => get_option( 'job_manager_registration_role' ),
649
  )
650
  );
@@ -903,8 +925,9 @@ class WP_Job_Manager_Form_Submit_Job extends WP_Job_Manager_Form {
903
  global $post, $job_preview;
904
 
905
  if ( $this->job_id ) {
 
 
906
  $job_preview = true;
907
- $post = get_post( $this->job_id ); // WPCS: override ok.
908
  $post->post_status = 'preview';
909
 
910
  setup_postdata( $post );
@@ -924,19 +947,20 @@ class WP_Job_Manager_Form_Submit_Job extends WP_Job_Manager_Form {
924
  * Handles the preview step form response.
925
  */
926
  public function preview_handler() {
927
- if ( ! $_POST ) {
 
928
  return;
929
  }
930
 
931
  $this->check_preview_form_nonce_field();
932
 
933
  // Edit = show submit form again.
934
- if ( ! empty( $_POST['edit_job'] ) ) {
935
  $this->step --;
936
  }
937
 
938
  // Continue = change job status then show next screen.
939
- if ( ! empty( $_POST['continue'] ) ) {
940
  $job = get_post( $this->job_id );
941
 
942
  if ( in_array( $job->post_status, array( 'preview', 'expired' ), true ) ) {
@@ -975,7 +999,10 @@ class WP_Job_Manager_Form_Submit_Job extends WP_Job_Manager_Form {
975
  if ( ! is_user_logged_in() ) {
976
  return;
977
  }
978
- if ( empty( $_REQUEST['_wpjm_nonce'] ) || ! wp_verify_nonce( $_REQUEST['_wpjm_nonce'], 'submit-job-' . $this->job_id ) ) {
 
 
 
979
  wp_nonce_ays( 'submit-job-' . $this->job_id );
980
  die();
981
  }
@@ -998,7 +1025,11 @@ class WP_Job_Manager_Form_Submit_Job extends WP_Job_Manager_Form {
998
  if ( ! is_user_logged_in() ) {
999
  return;
1000
  }
1001
- if ( empty( $_REQUEST['_wpjm_nonce'] ) || ! wp_verify_nonce( $_REQUEST['_wpjm_nonce'], 'preview-job-' . $this->job_id ) ) {
 
 
 
 
1002
  wp_nonce_ays( 'preview-job-' . $this->job_id );
1003
  die();
1004
  }
46
  * @access protected
47
  * @var WP_Job_Manager_Form_Submit_Job The single instance of the class
48
  */
49
+ protected static $instance = null;
50
 
51
  /**
52
  * Returns static instance of class.
54
  * @return self
55
  */
56
  public static function instance() {
57
+ if ( is_null( self::$instance ) ) {
58
+ self::$instance = new self();
59
  }
60
+ return self::$instance;
61
  }
62
 
63
  /**
101
 
102
  uasort( $this->steps, array( $this, 'sort_by_priority' ) );
103
 
104
+ // phpcs:disable WordPress.Security.NonceVerification.Missing, WordPress.Security.NonceVerification.Recommended -- Check happens later when possible. Input is used safely.
105
  // Get step/job.
106
  if ( isset( $_POST['step'] ) ) {
107
  $this->step = is_numeric( $_POST['step'] ) ? max( absint( $_POST['step'] ), 0 ) : array_search( intval( $_POST['step'] ), array_keys( $this->steps ), true );
110
  }
111
 
112
  $this->job_id = ! empty( $_REQUEST['job_id'] ) ? absint( $_REQUEST['job_id'] ) : 0;
113
+ // phpcs:enable WordPress.Security.NonceVerification.Missing, WordPress.Security.NonceVerification.Recommended
114
 
115
  if ( ! job_manager_user_can_edit_job( $this->job_id ) ) {
116
  $this->job_id = 0;
118
 
119
  // Allow resuming from cookie.
120
  $this->resume_edit = false;
121
+ if (
122
+ ! isset( $_GET['new'] ) // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Input is used safely.
123
+ && (
124
+ 'before' === get_option( 'job_manager_paid_listings_flow' )
125
+ || ! $this->job_id
126
+ )
127
+ && ! empty( $_COOKIE['wp-job-manager-submitting-job-id'] )
128
+ && ! empty( $_COOKIE['wp-job-manager-submitting-job-key'] )
129
+ ) {
130
  $job_id = absint( $_COOKIE['wp-job-manager-submitting-job-id'] );
131
  $job_status = get_post_status( $job_id );
132
 
133
+ if (
134
+ (
135
+ 'preview' === $job_status
136
+ || 'pending_payment' === $job_status
137
+ )
138
+ && get_post_meta( $job_id, '_submitting_key', true ) === $_COOKIE['wp-job-manager-submitting-job-key']
139
+ ) {
140
  $this->job_id = $job_id;
141
  $this->resume_edit = get_post_meta( $job_id, '_submitting_key', true );
142
  }
547
  $this->fields = apply_filters( 'submit_job_form_fields_get_job_data', $this->fields, $job );
548
 
549
  // Get user meta.
550
+ } elseif ( is_user_logged_in() && empty( $_POST['submit_job'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Safe input.
551
  if ( ! empty( $this->fields['company'] ) ) {
552
  foreach ( $this->fields['company'] as $key => $field ) {
553
  $this->fields['company'][ $key ]['value'] = get_user_meta( get_current_user_id(), '_' . $key, true );
593
  // Get posted values.
594
  $values = $this->get_posted_fields();
595
 
596
+ // phpcs:disable WordPress.Security.NonceVerification.Missing -- Input is used safely. Nonce checked below when possible.
597
+ $input_create_account_username = isset( $_POST['create_account_username'] ) ? sanitize_text_field( wp_unslash( $_POST['create_account_username'] ) ) : false;
598
+ $input_create_account_password = isset( $_POST['create_account_password'] ) ? sanitize_text_field( wp_unslash( $_POST['create_account_password'] ) ) : false;
599
+ $input_create_account_password_verify = isset( $_POST['create_account_password_verify'] ) ? sanitize_text_field( wp_unslash( $_POST['create_account_password_verify'] ) ) : false;
600
+ $input_create_account_email = isset( $_POST['create_account_email'] ) ? sanitize_text_field( wp_unslash( $_POST['create_account_email'] ) ) : false;
601
+ $is_saving_draft = $this->can_continue_later() && ! empty( $_POST['save_draft'] );
602
 
603
  if ( empty( $_POST['submit_job'] ) && ! $is_saving_draft ) {
604
  return;
605
  }
606
+ // phpcs:enable WordPress.Security.NonceVerification.Missing
607
 
608
  $this->check_submit_form_nonce_field();
609
 
633
 
634
  if ( job_manager_enable_registration() ) {
635
  if ( job_manager_user_requires_account() ) {
636
+ if ( ! job_manager_generate_username_from_email() && empty( $input_create_account_username ) ) {
637
  throw new Exception( __( 'Please enter a username.', 'wp-job-manager' ) );
638
  }
639
  if ( ! wpjm_use_standard_password_setup_email() ) {
640
+ if ( empty( $input_create_account_password ) ) {
641
  throw new Exception( __( 'Please enter a password.', 'wp-job-manager' ) );
642
  }
643
  }
644
+ if ( empty( $input_create_account_email ) ) {
645
  throw new Exception( __( 'Please enter your email address.', 'wp-job-manager' ) );
646
  }
647
  }
648
 
649
+ if ( ! wpjm_use_standard_password_setup_email() && ! empty( $input_create_account_password ) ) {
650
+ if ( empty( $input_create_account_password_verify ) || $input_create_account_password_verify !== $input_create_account_password ) {
651
  throw new Exception( __( 'Passwords must match.', 'wp-job-manager' ) );
652
  }
653
+ if ( ! wpjm_validate_new_password( sanitize_text_field( wp_unslash( $input_create_account_password ) ) ) ) {
654
  $password_hint = wpjm_get_password_rules_hint();
655
  if ( $password_hint ) {
656
  // translators: Placeholder %s is the password hint.
661
  }
662
  }
663
 
664
+ if ( ! empty( $input_create_account_email ) ) {
665
  $create_account = wp_job_manager_create_account(
666
  array(
667
+ 'username' => ( job_manager_generate_username_from_email() || empty( $input_create_account_username ) ) ? '' : $input_create_account_username,
668
+ 'password' => ( wpjm_use_standard_password_setup_email() || empty( $input_create_account_password ) ) ? '' : $input_create_account_password,
669
+ 'email' => sanitize_text_field( wp_unslash( $input_create_account_email ) ),
670
  'role' => get_option( 'job_manager_registration_role' ),
671
  )
672
  );
925
  global $post, $job_preview;
926
 
927
  if ( $this->job_id ) {
928
+ // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited -- Job preview depends on temporary override. Reset below.
929
+ $post = get_post( $this->job_id );
930
  $job_preview = true;
 
931
  $post->post_status = 'preview';
932
 
933
  setup_postdata( $post );
947
  * Handles the preview step form response.
948
  */
949
  public function preview_handler() {
950
+ // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Input is used safely.
951
+ if ( empty( $_POST ) ) {
952
  return;
953
  }
954
 
955
  $this->check_preview_form_nonce_field();
956
 
957
  // Edit = show submit form again.
958
+ if ( ! empty( $_POST['edit_job'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Input is used safely.
959
  $this->step --;
960
  }
961
 
962
  // Continue = change job status then show next screen.
963
+ if ( ! empty( $_POST['continue'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Input is used safely.
964
  $job = get_post( $this->job_id );
965
 
966
  if ( in_array( $job->post_status, array( 'preview', 'expired' ), true ) ) {
999
  if ( ! is_user_logged_in() ) {
1000
  return;
1001
  }
1002
+ if (
1003
+ empty( $_REQUEST['_wpjm_nonce'] )
1004
+ || ! wp_verify_nonce( wp_unslash( $_REQUEST['_wpjm_nonce'] ), 'submit-job-' . $this->job_id ) // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Nonce should not be modified.
1005
+ ) {
1006
  wp_nonce_ays( 'submit-job-' . $this->job_id );
1007
  die();
1008
  }
1025
  if ( ! is_user_logged_in() ) {
1026
  return;
1027
  }
1028
+
1029
+ if (
1030
+ empty( $_REQUEST['_wpjm_nonce'] )
1031
+ || ! wp_verify_nonce( wp_unslash( $_REQUEST['_wpjm_nonce'] ), 'preview-job-' . $this->job_id ) // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Nonce should not be modified.
1032
+ ) {
1033
  wp_nonce_ays( 'preview-job-' . $this->job_id );
1034
  die();
1035
  }
includes/helper/class-wp-job-manager-helper-api.php CHANGED
@@ -22,7 +22,7 @@ class WP_Job_Manager_Helper_API {
22
  * @var self
23
  * @since 1.29.0
24
  */
25
- private static $_instance = null;
26
 
27
  /**
28
  * Allows for accessing single instance of class. Class should only be constructed once per call.
@@ -32,10 +32,10 @@ class WP_Job_Manager_Helper_API {
32
  * @return self Main instance.
33
  */
34
  public static function instance() {
35
- if ( is_null( self::$_instance ) ) {
36
- self::$_instance = new self();
37
  }
38
- return self::$_instance;
39
  }
40
 
41
  /**
@@ -170,9 +170,10 @@ class WP_Job_Manager_Helper_API {
170
  * @return string
171
  */
172
  private function get_api_base_url() {
173
- if ( defined( 'JOB_MANAGER_VERSION' )
174
- && defined( 'JOB_MANAGER_DEV_API_BASE_URL' )
175
- && '-dev' === substr( JOB_MANAGER_VERSION, -4 )
 
176
  ) {
177
  return JOB_MANAGER_DEV_API_BASE_URL;
178
  }
22
  * @var self
23
  * @since 1.29.0
24
  */
25
+ private static $instance = null;
26
 
27
  /**
28
  * Allows for accessing single instance of class. Class should only be constructed once per call.
32
  * @return self Main instance.
33
  */
34
  public static function instance() {
35
+ if ( is_null( self::$instance ) ) {
36
+ self::$instance = new self();
37
  }
38
+ return self::$instance;
39
  }
40
 
41
  /**
170
  * @return string
171
  */
172
  private function get_api_base_url() {
173
+ if (
174
+ defined( 'JOB_MANAGER_VERSION' )
175
+ && defined( 'JOB_MANAGER_DEV_API_BASE_URL' )
176
+ && '-dev' === substr( JOB_MANAGER_VERSION, -4 )
177
  ) {
178
  return JOB_MANAGER_DEV_API_BASE_URL;
179
  }
includes/helper/class-wp-job-manager-helper.php CHANGED
@@ -36,7 +36,7 @@ class WP_Job_Manager_Helper {
36
  * @var self
37
  * @since 1.29.0
38
  */
39
- private static $_instance = null;
40
 
41
  /**
42
  * True if the plugin cache has already been cleared.
@@ -54,10 +54,10 @@ class WP_Job_Manager_Helper {
54
  * @return self Main instance.
55
  */
56
  public static function instance() {
57
- if ( is_null( self::$_instance ) ) {
58
- self::$_instance = new self();
59
  }
60
- return self::$_instance;
61
  }
62
 
63
  /**
@@ -94,9 +94,15 @@ class WP_Job_Manager_Helper {
94
  * Handles special tasks on admin requests.
95
  */
96
  private function handle_admin_request() {
97
- if ( ! empty( $_GET['dismiss-wpjm-licence-notice'] ) ) {
 
 
 
 
 
 
 
98
  $product_plugins = $this->get_installed_plugins();
99
- $product_slug = sanitize_text_field( $_GET['dismiss-wpjm-licence-notice'] );
100
  if ( isset( $product_plugins[ $product_slug ] ) ) {
101
  WP_Job_Manager_Helper_Options::update( $product_slug, 'hide_key_notice', true );
102
  }
@@ -144,9 +150,10 @@ class WP_Job_Manager_Helper {
144
  foreach ( $this->get_installed_plugins() as $product_slug => $plugin_data ) {
145
  $response = $this->get_plugin_version( $plugin_data['_filename'] );
146
  // If there is a new version, modify the transient to reflect an update is available.
147
- if ( $response
148
- && isset( $response['new_version'] )
149
- && version_compare( $response['new_version'], $plugin_data['Version'], '>' )
 
150
  ) {
151
  $check_for_updates_data->response[ $plugin_data['_filename'] ] = (object) $response;
152
  }
@@ -435,6 +442,8 @@ class WP_Job_Manager_Helper {
435
  if ( ! current_user_can( 'update_plugins' ) ) {
436
  return;
437
  }
 
 
438
  if ( ! empty( $_POST ) ) {
439
  $this->handle_request();
440
  }
@@ -467,25 +476,26 @@ class WP_Job_Manager_Helper {
467
  */
468
  private function handle_request() {
469
  $licenced_plugins = $this->get_installed_plugins();
470
- if ( empty( $_POST )
471
- || empty( $_POST['_wpnonce'] )
472
- || empty( $_POST['action'] )
473
- || empty( $_POST['product_slug'] )
474
- || ! isset( $licenced_plugins[ $_POST['product_slug'] ] )
475
- || ! wp_verify_nonce( $_POST['_wpnonce'], 'wpjm-manage-licence' )
 
476
  ) {
477
  return false;
478
  }
479
 
480
- $product_slug = sanitize_text_field( $_POST['product_slug'] );
481
  switch ( $_POST['action'] ) {
482
  case 'activate':
483
  if ( empty( $_POST['email'] ) || empty( $_POST['licence_key'] ) ) {
484
  $this->add_error( $product_slug, __( 'Please enter a valid license key and email address in order to activate this plugin\'s license.', 'wp-job-manager' ) );
485
  break;
486
  }
487
- $email = sanitize_email( $_POST['email'] );
488
- $licence_key = sanitize_text_field( $_POST['licence_key'] );
489
  $this->activate_licence( $product_slug, $licence_key, $email );
490
  break;
491
  case 'deactivate':
36
  * @var self
37
  * @since 1.29.0
38
  */
39
+ private static $instance = null;
40
 
41
  /**
42
  * True if the plugin cache has already been cleared.
54
  * @return self Main instance.
55
  */
56
  public static function instance() {
57
+ if ( is_null( self::$instance ) ) {
58
+ self::$instance = new self();
59
  }
60
+ return self::$instance;
61
  }
62
 
63
  /**
94
  * Handles special tasks on admin requests.
95
  */
96
  private function handle_admin_request() {
97
+ // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Nonce should not be modified.
98
+ if ( ! isset( $_GET['_wpjm_nonce'] ) || ! wp_verify_nonce( wp_unslash( $_GET['_wpjm_nonce'] ), 'dismiss-wpjm-licence-notice' ) ) {
99
+ return;
100
+ }
101
+
102
+ $product_slug = isset( $_GET['dismiss-wpjm-licence-notice'] ) ? sanitize_text_field( wp_unslash( $_GET['dismiss-wpjm-licence-notice'] ) ) : false;
103
+
104
+ if ( ! empty( $product_slug ) ) {
105
  $product_plugins = $this->get_installed_plugins();
 
106
  if ( isset( $product_plugins[ $product_slug ] ) ) {
107
  WP_Job_Manager_Helper_Options::update( $product_slug, 'hide_key_notice', true );
108
  }
150
  foreach ( $this->get_installed_plugins() as $product_slug => $plugin_data ) {
151
  $response = $this->get_plugin_version( $plugin_data['_filename'] );
152
  // If there is a new version, modify the transient to reflect an update is available.
153
+ if (
154
+ $response
155
+ && isset( $response['new_version'] )
156
+ && version_compare( $response['new_version'], $plugin_data['Version'], '>' )
157
  ) {
158
  $check_for_updates_data->response[ $plugin_data['_filename'] ] = (object) $response;
159
  }
442
  if ( ! current_user_can( 'update_plugins' ) ) {
443
  return;
444
  }
445
+
446
+ // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Flow use only. Method does nonce check.
447
  if ( ! empty( $_POST ) ) {
448
  $this->handle_request();
449
  }
476
  */
477
  private function handle_request() {
478
  $licenced_plugins = $this->get_installed_plugins();
479
+ if (
480
+ empty( $_POST )
481
+ || empty( $_POST['_wpnonce'] )
482
+ || empty( $_POST['action'] )
483
+ || empty( $_POST['product_slug'] )
484
+ || ! isset( $licenced_plugins[ $_POST['product_slug'] ] )
485
+ || ! wp_verify_nonce( wp_unslash( $_POST['_wpnonce'] ), 'wpjm-manage-licence' ) // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Nonce should not be modified.
486
  ) {
487
  return false;
488
  }
489
 
490
+ $product_slug = sanitize_text_field( wp_unslash( $_POST['product_slug'] ) );
491
  switch ( $_POST['action'] ) {
492
  case 'activate':
493
  if ( empty( $_POST['email'] ) || empty( $_POST['licence_key'] ) ) {
494
  $this->add_error( $product_slug, __( 'Please enter a valid license key and email address in order to activate this plugin\'s license.', 'wp-job-manager' ) );
495
  break;
496
  }
497
+ $email = sanitize_email( wp_unslash( $_POST['email'] ) );
498
+ $licence_key = sanitize_text_field( wp_unslash( $_POST['licence_key'] ) );
499
  $this->activate_licence( $product_slug, $licence_key, $email );
500
  break;
501
  case 'deactivate':
includes/helper/views/html-licence-key-error.php CHANGED
@@ -10,6 +10,6 @@ if ( ! defined( 'ABSPATH' ) ) {
10
  }
11
  ?>
12
  <div class="error">
13
- <p class="wpjm-updater-dismiss" style="float:right;"><a href="<?php echo esc_url( add_query_arg( 'dismiss-wpjm-licence-notice', $product_slug ) ); ?>"><?php esc_html_e( 'Hide notice', 'wp-job-manager' ); ?></a></p>
14
  <p><?php printf( 'There is a problem with the license for "%s". Please <a href="%s">manage the license</a> to check for a solution and continue receiving updates.', esc_html( $plugin_data['Name'] ), esc_url( admin_url( 'edit.php?post_type=job_listing&page=job-manager-addons&section=helper#' . sanitize_title( $product_slug . '_row' ) ) ) ); ?></p>
15
  </div>
10
  }
11
  ?>
12
  <div class="error">
13
+ <p class="wpjm-updater-dismiss" style="float:right;"><a href="<?php echo esc_url( wp_nonce_url( add_query_arg( 'dismiss-wpjm-licence-notice', $product_slug ), 'dismiss-wpjm-licence-notice', '_wpjm_nonce' ) ); ?>"><?php esc_html_e( 'Hide notice', 'wp-job-manager' ); ?></a></p>
14
  <p><?php printf( 'There is a problem with the license for "%s". Please <a href="%s">manage the license</a> to check for a solution and continue receiving updates.', esc_html( $plugin_data['Name'] ), esc_url( admin_url( 'edit.php?post_type=job_listing&page=job-manager-addons&section=helper#' . sanitize_title( $product_slug . '_row' ) ) ) ); ?></p>
15
  </div>
includes/helper/views/html-licence-key-notice.php CHANGED
@@ -10,6 +10,6 @@ if ( ! defined( 'ABSPATH' ) ) {
10
  }
11
  ?>
12
  <div class="updated">
13
- <p class="wpjm-updater-dismiss" style="float:right;"><a href="<?php echo esc_url( add_query_arg( 'dismiss-wpjm-licence-notice', $product_slug ) ); ?>"><?php esc_html_e( 'Hide notice', 'wp-job-manager' ); ?></a></p>
14
  <p><?php printf( '<a href="%s">Please enter your license key</a> to get updates for "%s".', esc_url( admin_url( 'edit.php?post_type=job_listing&page=job-manager-addons&section=helper#' . sanitize_title( $product_slug . '_row' ) ) ), esc_html( $plugin_data['Name'] ) ); ?></p>
15
  </div>
10
  }
11
  ?>
12
  <div class="updated">
13
+ <p class="wpjm-updater-dismiss" style="float:right;"><a href="<?php echo esc_url( wp_nonce_url( add_query_arg( 'dismiss-wpjm-licence-notice', $product_slug ), 'dismiss-wpjm-licence-notice', '_wpjm_nonce' ) ); ?>"><?php esc_html_e( 'Hide notice', 'wp-job-manager' ); ?></a></p>
14
  <p><?php printf( '<a href="%s">Please enter your license key</a> to get updates for "%s".', esc_url( admin_url( 'edit.php?post_type=job_listing&page=job-manager-addons&section=helper#' . sanitize_title( $product_slug . '_row' ) ) ), esc_html( $plugin_data['Name'] ) ); ?></p>
15
  </div>
includes/helper/views/html-licences.php CHANGED
@@ -34,10 +34,10 @@ if ( ! defined( 'ABSPATH' ) ) {
34
  $notices = WP_Job_Manager_Helper::get_messages( $product_slug );
35
  if ( empty( $notices ) && ! empty( $licence['errors'] ) ) {
36
  $notices = array();
37
- foreach ( $licence['errors'] as $key => $error ) {
38
  $notices[] = array(
39
  'type' => 'error',
40
- 'message' => $error,
41
  );
42
  }
43
  }
34
  $notices = WP_Job_Manager_Helper::get_messages( $product_slug );
35
  if ( empty( $notices ) && ! empty( $licence['errors'] ) ) {
36
  $notices = array();
37
+ foreach ( $licence['errors'] as $key => $error_message ) {
38
  $notices[] = array(
39
  'type' => 'error',
40
+ 'message' => $error_message,
41
  );
42
  }
43
  }
includes/widgets/class-wp-job-manager-widget-featured-jobs.php CHANGED
@@ -107,11 +107,11 @@ class WP_Job_Manager_Widget_Featured_Jobs extends WP_Job_Manager_Widget {
107
 
108
  if ( $jobs->have_posts() ) : ?>
109
 
110
- <?php echo $args['before_widget']; // WPCS: XSS ok. ?>
111
 
112
  <?php
113
  if ( $title ) {
114
- echo $args['before_title'] . esc_html( $title ) . $args['after_title']; // WPCS: XSS ok.
115
  }
116
  ?>
117
 
@@ -128,7 +128,7 @@ class WP_Job_Manager_Widget_Featured_Jobs extends WP_Job_Manager_Widget {
128
 
129
  </ul>
130
 
131
- <?php echo $args['after_widget']; // WPCS: XSS ok. ?>
132
 
133
  <?php else : ?>
134
 
@@ -141,7 +141,7 @@ class WP_Job_Manager_Widget_Featured_Jobs extends WP_Job_Manager_Widget {
141
 
142
  $content = ob_get_clean();
143
 
144
- echo $content; // WPCS: XSS ok.
145
 
146
  $this->cache_widget( $args, $content );
147
  }
107
 
108
  if ( $jobs->have_posts() ) : ?>
109
 
110
+ <?php echo $args['before_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
111
 
112
  <?php
113
  if ( $title ) {
114
+ echo $args['before_title'] . esc_html( $title ) . $args['after_title']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
115
  }
116
  ?>
117
 
128
 
129
  </ul>
130
 
131
+ <?php echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
132
 
133
  <?php else : ?>
134
 
141
 
142
  $content = ob_get_clean();
143
 
144
+ echo $content; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
145
 
146
  $this->cache_widget( $args, $content );
147
  }
includes/widgets/class-wp-job-manager-widget-recent-jobs.php CHANGED
@@ -107,11 +107,11 @@ class WP_Job_Manager_Widget_Recent_Jobs extends WP_Job_Manager_Widget {
107
 
108
  if ( $jobs->have_posts() ) : ?>
109
 
110
- <?php echo $args['before_widget']; // WPCS: XSS ok. ?>
111
 
112
  <?php
113
  if ( $title ) {
114
- echo $args['before_title'] . esc_html( $title ) . $args['after_title']; // WPCS: XSS ok.
115
  }
116
  ?>
117
 
@@ -128,7 +128,7 @@ class WP_Job_Manager_Widget_Recent_Jobs extends WP_Job_Manager_Widget {
128
 
129
  </ul>
130
 
131
- <?php echo $args['after_widget']; // WPCS: XSS ok. ?>
132
 
133
  <?php else : ?>
134
 
@@ -152,7 +152,7 @@ class WP_Job_Manager_Widget_Recent_Jobs extends WP_Job_Manager_Widget {
152
 
153
  $content = ob_get_clean();
154
 
155
- echo $content; // WPCS: XSS ok.
156
 
157
  $this->cache_widget( $args, $content );
158
  }
107
 
108
  if ( $jobs->have_posts() ) : ?>
109
 
110
+ <?php echo $args['before_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
111
 
112
  <?php
113
  if ( $title ) {
114
+ echo $args['before_title'] . esc_html( $title ) . $args['after_title']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
115
  }
116
  ?>
117
 
128
 
129
  </ul>
130
 
131
+ <?php echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
132
 
133
  <?php else : ?>
134
 
152
 
153
  $content = ob_get_clean();
154
 
155
+ echo $content; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
156
 
157
  $this->cache_widget( $args, $content );
158
  }
languages/wp-job-manager.pot CHANGED
@@ -2,9 +2,9 @@
2
  # This file is distributed under the GPL2+.
3
  msgid ""
4
  msgstr ""
5
- "Project-Id-Version: WP Job Manager 1.33.3\n"
6
  "Report-Msgid-Bugs-To: https://github.com/Automattic/WP-Job-Manager/issues\n"
7
- "POT-Creation-Date: 2019-07-08 16:37:22+00:00\n"
8
  "MIME-Version: 1.0\n"
9
  "Content-Type: text/plain; charset=utf-8\n"
10
  "Content-Transfer-Encoding: 8bit\n"
@@ -13,30 +13,30 @@ msgstr ""
13
  "Language-Team: LANGUAGE <EMAIL@ADDRESS>\n"
14
  "X-Generator: grunt-wp-i18n 1.0.3\n"
15
 
16
- #: includes/3rd-party/wpml.php:84
17
  msgid "Page Not Set"
18
  msgstr ""
19
 
20
- #: includes/3rd-party/wpml.php:98
21
  #. translators: Placeholder (%s) is the URL to edit the primary language in
22
  #. WPML.
23
  msgid "<a href=\"%s\">Switch to primary language</a> to edit this setting."
24
  msgstr ""
25
 
26
- #: includes/abstracts/abstract-wp-job-manager-form.php:363
27
- #: includes/abstracts/abstract-wp-job-manager-form.php:378
28
  #. translators: Placeholder is for the label of the reCAPTCHA field.
29
  #. translators: %s is the name of the form validation that failed.
30
  msgid "\"%s\" check failed. Please try again."
31
  msgstr ""
32
 
33
- #: includes/admin/class-wp-job-manager-addons.php:123
34
  #: includes/admin/class-wp-job-manager-admin.php:139
35
  #: includes/admin/views/html-admin-page-addons.php:12
36
  msgid "WP Job Manager Add-ons"
37
  msgstr ""
38
 
39
- #: includes/admin/class-wp-job-manager-addons.php:130
40
  #: includes/helper/views/html-licences.php:12
41
  msgid "Licenses"
42
  msgstr ""
@@ -105,83 +105,83 @@ msgstr ""
105
  msgid "%s marked as not filled"
106
  msgstr ""
107
 
108
- #: includes/admin/class-wp-job-manager-cpt.php:322
109
  msgid "Select category"
110
  msgstr ""
111
 
112
- #: includes/admin/class-wp-job-manager-cpt.php:347
113
  msgid "Select Filled"
114
  msgstr ""
115
 
116
- #: includes/admin/class-wp-job-manager-cpt.php:351
117
  msgid "Filled"
118
  msgstr ""
119
 
120
- #: includes/admin/class-wp-job-manager-cpt.php:355
121
  msgid "Not Filled"
122
  msgstr ""
123
 
124
- #: includes/admin/class-wp-job-manager-cpt.php:366
125
  msgid "Select Featured"
126
  msgstr ""
127
 
128
- #: includes/admin/class-wp-job-manager-cpt.php:370
129
  msgid "Featured"
130
  msgstr ""
131
 
132
- #: includes/admin/class-wp-job-manager-cpt.php:374
133
  msgid "Not Featured"
134
  msgstr ""
135
 
136
- #: includes/admin/class-wp-job-manager-cpt.php:419
137
- #: includes/admin/class-wp-job-manager-cpt.php:476
138
  msgid "Position"
139
  msgstr ""
140
 
141
- #: includes/admin/class-wp-job-manager-cpt.php:436
142
  #. translators: %1$s is the singular name of the job listing post type; %2$s is
143
  #. the URL to view the listing.
144
  msgid "%1$s updated. <a href=\"%2$s\">View</a>"
145
  msgstr ""
146
 
147
- #: includes/admin/class-wp-job-manager-cpt.php:437
148
  msgid "Custom field updated."
149
  msgstr ""
150
 
151
- #: includes/admin/class-wp-job-manager-cpt.php:438
152
  msgid "Custom field deleted."
153
  msgstr ""
154
 
155
- #: includes/admin/class-wp-job-manager-cpt.php:440
156
  #. translators: %s is the singular name of the job listing post type.
157
  msgid "%s updated."
158
  msgstr ""
159
 
160
- #: includes/admin/class-wp-job-manager-cpt.php:442
161
  #. translators: %1$s is the singular name of the job listing post type; %2$s is
162
  #. the revision number.
163
  msgid "%1$s restored to revision from %2$s"
164
  msgstr ""
165
 
166
- #: includes/admin/class-wp-job-manager-cpt.php:444
167
  #. translators: %1$s is the singular name of the job listing post type; %2$s is
168
  #. the URL to view the listing.
169
  msgid "%1$s published. <a href=\"%2$s\">View</a>"
170
  msgstr ""
171
 
172
- #: includes/admin/class-wp-job-manager-cpt.php:446
173
  #. translators: %1$s is the singular name of the job listing post type; %2$s is
174
  #. the URL to view the listing.
175
  msgid "%s saved."
176
  msgstr ""
177
 
178
- #: includes/admin/class-wp-job-manager-cpt.php:448
179
  #. translators: %1$s is the singular name of the job listing post type; %2$s is
180
  #. the URL to preview the listing.
181
  msgid "%1$s submitted. <a target=\"_blank\" href=\"%2$s\">Preview</a>"
182
  msgstr ""
183
 
184
- #: includes/admin/class-wp-job-manager-cpt.php:451
185
  #. translators: %1$s is the singular name of the post type; %2$s is the date
186
  #. the post will be published; %3$s is the URL to preview the listing.
187
  msgid ""
@@ -189,87 +189,87 @@ msgid ""
189
  "href=\"%3$s\">Preview</a>"
190
  msgstr ""
191
 
192
- #: includes/admin/class-wp-job-manager-cpt.php:457
193
  #. translators: %1$s is the singular name of the job listing post type; %2$s is
194
  #. the URL to view the listing.
195
  msgid "%1$s draft updated. <a target=\"_blank\" href=\"%2$s\">Preview</a>"
196
  msgstr ""
197
 
198
- #: includes/admin/class-wp-job-manager-cpt.php:477
199
  msgid "Type"
200
  msgstr ""
201
 
202
- #: includes/admin/class-wp-job-manager-cpt.php:478
203
  #: includes/class-wp-job-manager-email-notifications.php:238
204
- #: includes/class-wp-job-manager-post-types.php:1175
205
- #: includes/forms/class-wp-job-manager-form-submit-job.php:197
206
  #: includes/widgets/class-wp-job-manager-widget-recent-jobs.php:46
207
  #: templates/job-filters.php:35 templates/job-filters.php:36
208
  msgid "Location"
209
  msgstr ""
210
 
211
- #: includes/admin/class-wp-job-manager-cpt.php:479
212
  msgid "Status"
213
  msgstr ""
214
 
215
- #: includes/admin/class-wp-job-manager-cpt.php:480
216
  msgid "Posted"
217
  msgstr ""
218
 
219
- #: includes/admin/class-wp-job-manager-cpt.php:481
220
  msgid "Expires"
221
  msgstr ""
222
 
223
- #: includes/admin/class-wp-job-manager-cpt.php:482
224
  #: includes/admin/class-wp-job-manager-settings.php:162
225
  msgid "Categories"
226
  msgstr ""
227
 
228
- #: includes/admin/class-wp-job-manager-cpt.php:483
229
  msgid "Featured?"
230
  msgstr ""
231
 
232
- #: includes/admin/class-wp-job-manager-cpt.php:484
233
- #: includes/class-wp-job-manager-shortcodes.php:252
234
  msgid "Filled?"
235
  msgstr ""
236
 
237
- #: includes/admin/class-wp-job-manager-cpt.php:485
238
  msgid "Actions"
239
  msgstr ""
240
 
241
- #: includes/admin/class-wp-job-manager-cpt.php:550
242
  #. translators: %d is the post ID for the job listing.
243
  msgid "ID: %d"
244
  msgstr ""
245
 
246
- #: includes/admin/class-wp-job-manager-cpt.php:594
247
  #. translators: %s placeholder is the username of the user.
248
  msgid "by a guest"
249
  msgstr ""
250
 
251
- #: includes/admin/class-wp-job-manager-cpt.php:594
252
  msgid "by %s"
253
  msgstr ""
254
 
255
- #: includes/admin/class-wp-job-manager-cpt.php:613
256
  msgid "Approve"
257
  msgstr ""
258
 
259
- #: includes/admin/class-wp-job-manager-cpt.php:621
260
  #: includes/admin/class-wp-job-manager-writepanels.php:227
261
  #: includes/admin/class-wp-job-manager-writepanels.php:232
262
  #: includes/admin/class-wp-job-manager-writepanels.php:237
263
  msgid "View"
264
  msgstr ""
265
 
266
- #: includes/admin/class-wp-job-manager-cpt.php:628
267
  #: includes/class-wp-job-manager-post-types.php:334
268
  #: templates/job-dashboard.php:52 templates/job-dashboard.php:70
269
  msgid "Edit"
270
  msgstr ""
271
 
272
- #: includes/admin/class-wp-job-manager-cpt.php:635
273
  #: templates/job-dashboard.php:79
274
  msgid "Delete"
275
  msgstr ""
@@ -704,29 +704,29 @@ msgid ""
704
  "plugin know the location of the job listings page."
705
  msgstr ""
706
 
707
- #: includes/admin/class-wp-job-manager-settings.php:416
708
  msgid "Settings successfully saved"
709
  msgstr ""
710
 
711
- #: includes/admin/class-wp-job-manager-settings.php:441
712
  msgid "Save Changes"
713
  msgstr ""
714
 
715
- #: includes/admin/class-wp-job-manager-settings.php:649
716
  msgid "--no page--"
717
  msgstr ""
718
 
719
- #: includes/admin/class-wp-job-manager-settings.php:654
720
  msgid "Select a page&hellip;"
721
  msgstr ""
722
 
723
- #: includes/admin/class-wp-job-manager-setup.php:56
724
  msgid "Setup"
725
  msgstr ""
726
 
727
- #: includes/admin/class-wp-job-manager-taxonomy-meta.php:83
728
- #: includes/admin/class-wp-job-manager-taxonomy-meta.php:106
729
- #: includes/admin/class-wp-job-manager-taxonomy-meta.php:125
730
  #: includes/class-wp-job-manager-post-types.php:287
731
  msgid "Employment Type"
732
  msgstr ""
@@ -759,7 +759,7 @@ msgid "Add file"
759
  msgstr ""
760
 
761
  #: includes/admin/class-wp-job-manager-writepanels.php:471
762
- #: includes/class-wp-job-manager-ajax.php:410
763
  #. translators: Used in user select. %1$s is the user's display name; #%2$s is
764
  #. the user ID; %3$s is the user email.
765
  msgid "%1$s (#%2$s – %3$s)"
@@ -801,7 +801,7 @@ msgstr ""
801
  msgid "More Information &rarr;"
802
  msgstr ""
803
 
804
- #: includes/admin/views/html-admin-page-addons.php:53
805
  msgid "No add-ons were found."
806
  msgstr ""
807
 
@@ -876,19 +876,19 @@ msgid ""
876
  "for detailed instructions.)"
877
  msgstr ""
878
 
879
- #: includes/admin/views/html-admin-setup-step-2.php:38
880
  msgid "Page Title"
881
  msgstr ""
882
 
883
- #: includes/admin/views/html-admin-setup-step-2.php:39
884
  msgid "Page Description"
885
  msgstr ""
886
 
887
- #: includes/admin/views/html-admin-setup-step-2.php:40
888
  msgid "Content Shortcode"
889
  msgstr ""
890
 
891
- #: includes/admin/views/html-admin-setup-step-2.php:48
892
  msgid ""
893
  "Creates a page that allows employers to post new jobs directly from a page "
894
  "on your website, instead of requiring them to log in to an admin area. If "
@@ -896,7 +896,7 @@ msgid ""
896
  "the admin dashboard only -- you can uncheck this setting."
897
  msgstr ""
898
 
899
- #: includes/admin/views/html-admin-setup-step-2.php:56
900
  msgid ""
901
  "Creates a page that allows employers to manage their job listings directly "
902
  "from a page on your website, instead of requiring them to log in to an "
@@ -904,11 +904,11 @@ msgid ""
904
  "only, you can uncheck this setting."
905
  msgstr ""
906
 
907
- #: includes/admin/views/html-admin-setup-step-2.php:63
908
  msgid "Creates a page where visitors can browse, search, and filter job listings."
909
  msgstr ""
910
 
911
- #: includes/admin/views/html-admin-setup-step-2.php:71
912
  msgid "Skip this step"
913
  msgstr ""
914
 
@@ -963,11 +963,11 @@ msgid ""
963
  "hiring!"
964
  msgstr ""
965
 
966
- #: includes/admin/views/html-admin-setup-step-3.php:65
967
  msgid "Support WP Job Manager's Ongoing Development"
968
  msgstr ""
969
 
970
- #: includes/admin/views/html-admin-setup-step-3.php:66
971
  msgid ""
972
  "There are lots of ways you can support open source software projects like "
973
  "this one: contributing code, fixing a bug, assisting with non-English "
@@ -975,30 +975,30 @@ msgid ""
975
  "spread the word. We appreciate your support!"
976
  msgstr ""
977
 
978
- #: includes/admin/views/html-admin-setup-step-3.php:68
979
  msgid "Leave a positive review"
980
  msgstr ""
981
 
982
- #: includes/admin/views/html-admin-setup-step-3.php:69
983
  msgid "Contribute a localization"
984
  msgstr ""
985
 
986
- #: includes/admin/views/html-admin-setup-step-3.php:70
987
  msgid "Contribute code or report a bug"
988
  msgstr ""
989
 
990
- #: includes/admin/views/html-admin-setup-step-3.php:71
991
  msgid "Help other users on the forums"
992
  msgstr ""
993
 
994
- #: includes/class-wp-job-manager-ajax.php:179
995
  #. translators: Placeholder %d is the number of found search results.
996
  msgid "Search completed. Found %d matching record."
997
  msgid_plural "Search completed. Found %d matching records."
998
  msgstr[0] ""
999
  msgstr[1] ""
1000
 
1001
- #: includes/class-wp-job-manager-ajax.php:275
1002
  msgid "You must be logged in to upload files using this method."
1003
  msgstr ""
1004
 
@@ -1012,27 +1012,27 @@ msgid "Company Logo"
1012
  msgstr ""
1013
 
1014
  #: includes/class-wp-job-manager-data-exporter.php:52
1015
- #: includes/class-wp-job-manager-post-types.php:1194
1016
  msgid "Company Name"
1017
  msgstr ""
1018
 
1019
  #: includes/class-wp-job-manager-data-exporter.php:53
1020
- #: includes/class-wp-job-manager-post-types.php:1202
1021
  msgid "Company Website"
1022
  msgstr ""
1023
 
1024
  #: includes/class-wp-job-manager-data-exporter.php:54
1025
- #: includes/class-wp-job-manager-post-types.php:1211
1026
  msgid "Company Tagline"
1027
  msgstr ""
1028
 
1029
  #: includes/class-wp-job-manager-data-exporter.php:55
1030
- #: includes/class-wp-job-manager-post-types.php:1219
1031
  msgid "Company Twitter"
1032
  msgstr ""
1033
 
1034
  #: includes/class-wp-job-manager-data-exporter.php:56
1035
- #: includes/class-wp-job-manager-post-types.php:1227
1036
  msgid "Company Video"
1037
  msgstr ""
1038
 
@@ -1040,32 +1040,31 @@ msgstr ""
1040
  msgid "WP Job Manager User Data"
1041
  msgstr ""
1042
 
1043
- #: includes/class-wp-job-manager-dependency-checker.php:63
1044
  #. translators: %1$s is version of PHP that WP Job Manager requires; %2$s is
1045
  #. the version of PHP WordPress is running on.
1046
  msgid ""
1047
- "The next release of <strong>WP Job Manager</strong> will require a minimum "
1048
- "PHP version of %1$s, but you are running %2$s. Please update PHP to "
1049
- "continue using this plugin."
1050
  msgstr ""
1051
 
1052
- #: includes/class-wp-job-manager-dependency-checker.php:74
1053
  msgid "Learn more about updating PHP"
1054
  msgstr ""
1055
 
1056
- #: includes/class-wp-job-manager-dependency-checker.php:76
1057
  #. translators: accessibility text
1058
  msgid "(opens in a new tab)"
1059
  msgstr ""
1060
 
1061
- #: includes/class-wp-job-manager-dependency-checker.php:112
1062
  #. translators: %s is the URL for the page where users can go to update
1063
  #. WordPress.
1064
  msgid "<strong>WP Job Manager</strong> requires a more recent version of WordPress."
1065
  msgstr ""
1066
 
1067
- #: includes/class-wp-job-manager-dependency-checker.php:126
1068
- #: includes/class-wp-job-manager-dependency-checker.php:128
1069
  msgid "WordPress Update Required"
1070
  msgstr ""
1071
 
@@ -1075,18 +1074,18 @@ msgstr ""
1075
 
1076
  #: includes/class-wp-job-manager-email-notifications.php:247
1077
  #: includes/class-wp-job-manager-post-types.php:218
1078
- #: includes/forms/class-wp-job-manager-form-submit-job.php:205
1079
  msgid "Job type"
1080
  msgstr ""
1081
 
1082
  #: includes/class-wp-job-manager-email-notifications.php:257
1083
  #: includes/class-wp-job-manager-post-types.php:154
1084
- #: includes/forms/class-wp-job-manager-form-submit-job.php:214
1085
  msgid "Job category"
1086
  msgstr ""
1087
 
1088
  #: includes/class-wp-job-manager-email-notifications.php:266
1089
- #: includes/forms/class-wp-job-manager-form-submit-job.php:239
1090
  msgid "Company name"
1091
  msgstr ""
1092
 
@@ -1131,7 +1130,7 @@ msgstr ""
1131
  msgid "Geocoding error"
1132
  msgstr ""
1133
 
1134
- #: includes/class-wp-job-manager-install.php:82
1135
  msgid "Employer"
1136
  msgstr ""
1137
 
@@ -1302,134 +1301,134 @@ msgid_plural "Preview <span class=\"count\">(%s)</span>"
1302
  msgstr[0] ""
1303
  msgstr[1] ""
1304
 
1305
- #: includes/class-wp-job-manager-post-types.php:1162
1306
- #: includes/forms/class-wp-job-manager-form-submit-job.php:174
1307
  msgid "Application email/URL"
1308
  msgstr ""
1309
 
1310
- #: includes/class-wp-job-manager-post-types.php:1163
1311
- #: includes/forms/class-wp-job-manager-form-submit-job.php:175
1312
  msgid "Enter an email address or website URL"
1313
  msgstr ""
1314
 
1315
- #: includes/class-wp-job-manager-post-types.php:1166
1316
- #: includes/forms/class-wp-job-manager-form-submit-job.php:164
1317
  msgid "Application email"
1318
  msgstr ""
1319
 
1320
- #: includes/class-wp-job-manager-post-types.php:1167
1321
- #: includes/forms/class-wp-job-manager-form-submit-job.php:165
1322
  msgid "you@example.com"
1323
  msgstr ""
1324
 
1325
- #: includes/class-wp-job-manager-post-types.php:1169
1326
- #: includes/forms/class-wp-job-manager-form-submit-job.php:169
1327
  msgid "Application URL"
1328
  msgstr ""
1329
 
1330
- #: includes/class-wp-job-manager-post-types.php:1170
1331
- #: includes/forms/class-wp-job-manager-form-submit-job.php:170
1332
  msgid "https://"
1333
  msgstr ""
1334
 
1335
- #: includes/class-wp-job-manager-post-types.php:1176
1336
- #: includes/forms/class-wp-job-manager-form-submit-job.php:201
1337
  msgid "e.g. \"London\""
1338
  msgstr ""
1339
 
1340
- #: includes/class-wp-job-manager-post-types.php:1177
1341
  msgid "Leave this blank if the location is not important."
1342
  msgstr ""
1343
 
1344
- #: includes/class-wp-job-manager-post-types.php:1186
1345
  msgid ""
1346
  "This field is required for the \"application\" area to appear beneath the "
1347
  "listing."
1348
  msgstr ""
1349
 
1350
- #: includes/class-wp-job-manager-post-types.php:1212
1351
  msgid "Brief description about the company"
1352
  msgstr ""
1353
 
1354
- #: includes/class-wp-job-manager-post-types.php:1228
1355
  msgid "URL to the company video"
1356
  msgstr ""
1357
 
1358
- #: includes/class-wp-job-manager-post-types.php:1237
1359
  msgid "Position Filled"
1360
  msgstr ""
1361
 
1362
- #: includes/class-wp-job-manager-post-types.php:1243
1363
  msgid "Filled listings will no longer accept applications."
1364
  msgstr ""
1365
 
1366
- #: includes/class-wp-job-manager-post-types.php:1246
1367
  msgid "Featured Listing"
1368
  msgstr ""
1369
 
1370
- #: includes/class-wp-job-manager-post-types.php:1248
1371
  msgid ""
1372
  "Featured listings will be sticky during searches, and can be styled "
1373
  "differently."
1374
  msgstr ""
1375
 
1376
- #: includes/class-wp-job-manager-post-types.php:1256
1377
  msgid "Listing Expiry Date"
1378
  msgstr ""
1379
 
1380
- #: includes/class-wp-job-manager-shortcodes.php:104
1381
  msgid "Invalid ID"
1382
  msgstr ""
1383
 
1384
- #: includes/class-wp-job-manager-shortcodes.php:111
1385
  msgid "This position has already been filled"
1386
  msgstr ""
1387
 
1388
- #: includes/class-wp-job-manager-shortcodes.php:119
1389
  #. translators: Placeholder %s is the job listing title.
1390
  msgid "%s has been filled"
1391
  msgstr ""
1392
 
1393
- #: includes/class-wp-job-manager-shortcodes.php:124
1394
  msgid "This position is not filled"
1395
  msgstr ""
1396
 
1397
- #: includes/class-wp-job-manager-shortcodes.php:132
1398
  #. translators: Placeholder %s is the job listing title.
1399
  msgid "%s has been marked as not filled"
1400
  msgstr ""
1401
 
1402
- #: includes/class-wp-job-manager-shortcodes.php:140
1403
  #. translators: Placeholder %s is the job listing title.
1404
  msgid "%s has been deleted"
1405
  msgstr ""
1406
 
1407
- #: includes/class-wp-job-manager-shortcodes.php:145
1408
- #: includes/class-wp-job-manager-shortcodes.php:159
1409
  msgid "Missing submission page."
1410
  msgstr ""
1411
 
1412
- #: includes/class-wp-job-manager-shortcodes.php:251
1413
  #: includes/widgets/class-wp-job-manager-widget-featured-jobs.php:36
1414
  #: includes/widgets/class-wp-job-manager-widget-featured-jobs.php:52
1415
  #: includes/widgets/class-wp-job-manager-widget-recent-jobs.php:36
1416
  msgid "Title"
1417
  msgstr ""
1418
 
1419
- #: includes/class-wp-job-manager-shortcodes.php:253
1420
  msgid "Date Posted"
1421
  msgstr ""
1422
 
1423
- #: includes/class-wp-job-manager-shortcodes.php:254
1424
  msgid "Listing Expires"
1425
  msgstr ""
1426
 
1427
- #: includes/class-wp-job-manager-shortcodes.php:392
1428
- #: includes/class-wp-job-manager-shortcodes.php:429
1429
  msgid "Load more listings"
1430
  msgstr ""
1431
 
1432
- #: includes/class-wp-job-manager-usage-tracking.php:227
1433
  #. translators: Placeholder %s is a URL to the document on wpjobmanager.com
1434
  #. with info on usage tracking.
1435
  msgid ""
@@ -1439,7 +1438,7 @@ msgid ""
1439
  "\t\t\t\tcollected, and you can opt out at any time."
1440
  msgstr ""
1441
 
1442
- #: includes/class-wp-job-manager-usage-tracking.php:295
1443
  #. translators: the href tag contains the URL for the page telling users what
1444
  #. data WPJM tracks.
1445
  msgid ""
@@ -1448,40 +1447,40 @@ msgid ""
1448
  "\t\t\t\tNo sensitive information is collected."
1449
  msgstr ""
1450
 
1451
- #: includes/class-wp-job-manager-usage-tracking.php:320
1452
  #: lib/usage-tracking/class-usage-tracking-base.php:483
1453
  msgid "Enable Usage Tracking"
1454
  msgstr ""
1455
 
1456
- #: includes/class-wp-job-manager.php:145
1457
  #. translators: Placeholders %1$s and %2$s are the names of the two cookies
1458
  #. used in WP Job Manager.
1459
  msgid ""
1460
  "This site adds the following cookies to help users resume job submissions "
1461
- "that they\n"
1462
  "\t\t\t\thave started but have not completed: %1$s and %2$s"
1463
  msgstr ""
1464
 
1465
- #: includes/class-wp-job-manager.php:285
1466
  msgid "Load previous listings"
1467
  msgstr ""
1468
 
1469
- #: includes/class-wp-job-manager.php:408
1470
  msgid "Invalid file type. Accepted types:"
1471
  msgstr ""
1472
 
1473
- #: includes/class-wp-job-manager.php:425
1474
- #: includes/forms/class-wp-job-manager-form-submit-job.php:390
1475
  #. translators: Placeholder %d is the number of files to that users are limited
1476
  #. to.
1477
  msgid "You are only allowed to upload a maximum of %d files."
1478
  msgstr ""
1479
 
1480
- #: includes/class-wp-job-manager.php:433
1481
  msgid "Are you sure you want to delete this listing?"
1482
  msgstr ""
1483
 
1484
- #: includes/class-wp-job-manager.php:441
1485
  msgid "This field is required."
1486
  msgstr ""
1487
 
@@ -1544,27 +1543,27 @@ msgstr ""
1544
  msgid "days"
1545
  msgstr ""
1546
 
1547
- #: includes/forms/class-wp-job-manager-form-edit-job.php:107
1548
  msgid "Invalid listing"
1549
  msgstr ""
1550
 
1551
- #: includes/forms/class-wp-job-manager-form-edit-job.php:139
1552
  msgid "Save changes"
1553
  msgstr ""
1554
 
1555
- #: includes/forms/class-wp-job-manager-form-edit-job.php:142
1556
  msgid "Submit changes for approval"
1557
  msgstr ""
1558
 
1559
- #: includes/forms/class-wp-job-manager-form-edit-job.php:195
1560
  msgid "Your changes have been saved."
1561
  msgstr ""
1562
 
1563
- #: includes/forms/class-wp-job-manager-form-edit-job.php:201
1564
  msgid "View &rarr;"
1565
  msgstr ""
1566
 
1567
- #: includes/forms/class-wp-job-manager-form-edit-job.php:203
1568
  msgid ""
1569
  "Your changes have been submitted and your listing will be visible again "
1570
  "once approved."
@@ -1575,7 +1574,7 @@ msgid "Submit Details"
1575
  msgstr ""
1576
 
1577
  #: includes/forms/class-wp-job-manager-form-submit-job.php:88
1578
- #: includes/forms/class-wp-job-manager-form-submit-job.php:562
1579
  #: templates/job-preview.php:30
1580
  msgid "Preview"
1581
  msgstr ""
@@ -1584,79 +1583,79 @@ msgstr ""
1584
  msgid "Done"
1585
  msgstr ""
1586
 
1587
- #: includes/forms/class-wp-job-manager-form-submit-job.php:190
1588
  msgid "Job Title"
1589
  msgstr ""
1590
 
1591
- #: includes/forms/class-wp-job-manager-form-submit-job.php:198
1592
  msgid "Leave this blank if the location is not important"
1593
  msgstr ""
1594
 
1595
- #: includes/forms/class-wp-job-manager-form-submit-job.php:208
1596
  msgid "Choose job type&hellip;"
1597
  msgstr ""
1598
 
1599
- #: includes/forms/class-wp-job-manager-form-submit-job.php:223
1600
  msgid "Description"
1601
  msgstr ""
1602
 
1603
- #: includes/forms/class-wp-job-manager-form-submit-job.php:242
1604
  msgid "Enter the name of the company"
1605
  msgstr ""
1606
 
1607
- #: includes/forms/class-wp-job-manager-form-submit-job.php:246
1608
  #: templates/content-single-job_listing-company.php:30
1609
  msgid "Website"
1610
  msgstr ""
1611
 
1612
- #: includes/forms/class-wp-job-manager-form-submit-job.php:250
1613
  msgid "http://"
1614
  msgstr ""
1615
 
1616
- #: includes/forms/class-wp-job-manager-form-submit-job.php:254
1617
  msgid "Tagline"
1618
  msgstr ""
1619
 
1620
- #: includes/forms/class-wp-job-manager-form-submit-job.php:257
1621
  msgid "Briefly describe your company"
1622
  msgstr ""
1623
 
1624
- #: includes/forms/class-wp-job-manager-form-submit-job.php:262
1625
  msgid "Video"
1626
  msgstr ""
1627
 
1628
- #: includes/forms/class-wp-job-manager-form-submit-job.php:266
1629
  msgid "A link to a video about your company"
1630
  msgstr ""
1631
 
1632
- #: includes/forms/class-wp-job-manager-form-submit-job.php:270
1633
  msgid "Twitter username"
1634
  msgstr ""
1635
 
1636
- #: includes/forms/class-wp-job-manager-form-submit-job.php:273
1637
  msgid "@yourcompany"
1638
  msgstr ""
1639
 
1640
- #: includes/forms/class-wp-job-manager-form-submit-job.php:277
1641
  msgid "Logo"
1642
  msgstr ""
1643
 
1644
- #: includes/forms/class-wp-job-manager-form-submit-job.php:327
1645
  #. translators: Placeholder %s is the label for the required field.
1646
  msgid "%s is a required field"
1647
  msgstr ""
1648
 
1649
- #: includes/forms/class-wp-job-manager-form-submit-job.php:338
1650
  #. translators: Placeholder %s is the field label that is did not validate.
1651
  msgid "%s is invalid"
1652
  msgstr ""
1653
 
1654
- #: includes/forms/class-wp-job-manager-form-submit-job.php:355
1655
  msgid "Invalid attachment provided."
1656
  msgstr ""
1657
 
1658
- #: includes/forms/class-wp-job-manager-form-submit-job.php:373
1659
- #: wp-job-manager-functions.php:1291
1660
  #. translators: Placeholder %1$s is field label; %2$s is the file mime type;
1661
  #. %3$s is the allowed mime-types.
1662
  #. translators: %1$s is the file field label; %2$s is the file type; %3$s is
@@ -1664,90 +1663,90 @@ msgstr ""
1664
  msgid "\"%1$s\" (filetype %2$s) needs to be one of the following file types: %3$s"
1665
  msgstr ""
1666
 
1667
- #: includes/forms/class-wp-job-manager-form-submit-job.php:408
1668
  msgid "Please enter a valid application email address"
1669
  msgstr ""
1670
 
1671
- #: includes/forms/class-wp-job-manager-form-submit-job.php:417
1672
  msgid "Please enter a valid application URL"
1673
  msgstr ""
1674
 
1675
- #: includes/forms/class-wp-job-manager-form-submit-job.php:427
1676
  msgid "Please enter a valid application email address or URL"
1677
  msgstr ""
1678
 
1679
- #: includes/forms/class-wp-job-manager-form-submit-job.php:615
1680
  msgid "Please enter a username."
1681
  msgstr ""
1682
 
1683
- #: includes/forms/class-wp-job-manager-form-submit-job.php:619
1684
  msgid "Please enter a password."
1685
  msgstr ""
1686
 
1687
- #: includes/forms/class-wp-job-manager-form-submit-job.php:623
1688
  msgid "Please enter your email address."
1689
  msgstr ""
1690
 
1691
- #: includes/forms/class-wp-job-manager-form-submit-job.php:629
1692
  msgid "Passwords must match."
1693
  msgstr ""
1694
 
1695
- #: includes/forms/class-wp-job-manager-form-submit-job.php:635
1696
  #. translators: Placeholder %s is the password hint.
1697
  msgid "Invalid Password: %s"
1698
  msgstr ""
1699
 
1700
- #: includes/forms/class-wp-job-manager-form-submit-job.php:637
1701
  msgid "Password is not valid."
1702
  msgstr ""
1703
 
1704
- #: includes/forms/class-wp-job-manager-form-submit-job.php:660
1705
  msgid "You must be signed in to post a new listing."
1706
  msgstr ""
1707
 
1708
- #: includes/forms/class-wp-job-manager-form-submit-job.php:678
1709
  #. translators: placeholder is the URL to the job dashboard page.
1710
  msgid ""
1711
  "Draft was saved. Job listing drafts can be resumed from the <a "
1712
  "href=\"%s\">job dashboard</a>."
1713
  msgstr ""
1714
 
1715
- #: includes/helper/class-wp-job-manager-helper.php:272
1716
  msgid "Manage License (Requires Attention)"
1717
  msgstr ""
1718
 
1719
- #: includes/helper/class-wp-job-manager-helper.php:275
1720
  msgid "Manage License"
1721
  msgstr ""
1722
 
1723
- #: includes/helper/class-wp-job-manager-helper.php:278
1724
  #: includes/helper/views/html-licences.php:75
1725
  msgid "Activate License"
1726
  msgstr ""
1727
 
1728
- #: includes/helper/class-wp-job-manager-helper.php:484
1729
  msgid ""
1730
  "Please enter a valid license key and email address in order to activate "
1731
  "this plugin's license."
1732
  msgstr ""
1733
 
1734
- #: includes/helper/class-wp-job-manager-helper.php:516
1735
  msgid "Connection failed to the License Key API server - possible server issue."
1736
  msgstr ""
1737
 
1738
- #: includes/helper/class-wp-job-manager-helper.php:525
1739
  msgid "Plugin license has been activated."
1740
  msgstr ""
1741
 
1742
- #: includes/helper/class-wp-job-manager-helper.php:528
1743
  msgid "An unknown error occurred while attempting to activate the license"
1744
  msgstr ""
1745
 
1746
- #: includes/helper/class-wp-job-manager-helper.php:548
1747
  msgid "license is not active."
1748
  msgstr ""
1749
 
1750
- #: includes/helper/class-wp-job-manager-helper.php:564
1751
  msgid "Plugin license has been deactivated."
1752
  msgstr ""
1753
 
@@ -1923,17 +1922,20 @@ msgstr ""
1923
  msgid "This listing has expired."
1924
  msgstr ""
1925
 
1926
- #: templates/emails/admin-expiring-job.php:30
1927
- #: templates/emails/employer-expiring-job.php:32
1928
- msgid "The following job listing is expiring today from <a href=\"%s\">%s</a>."
1929
- msgstr ""
1930
-
1931
  #: templates/emails/admin-expiring-job.php:32
1932
- #: templates/emails/employer-expiring-job.php:40
1933
- msgid "The following job listing is expiring soon from <a href=\"%s\">%s</a>."
 
1934
  msgstr ""
1935
 
1936
  #: templates/emails/admin-expiring-job.php:35
 
 
 
 
 
 
 
1937
  msgid "Visit <a href=\"%s\">WordPress admin</a> to manage the listing."
1938
  msgstr ""
1939
 
@@ -1967,6 +1969,14 @@ msgid ""
1967
  "an administrator in the site's <a href=\"%s\">WordPress admin</a>."
1968
  msgstr ""
1969
 
 
 
 
 
 
 
 
 
1970
  #: templates/emails/employer-expiring-job.php:48
1971
  msgid "Visit the <a href=\"%s\">job listing dashboard</a> to manage the listing."
1972
  msgstr ""
@@ -2012,12 +2022,12 @@ msgid "Maximum file size: %s."
2012
  msgstr ""
2013
 
2014
  #: templates/form-fields/multiselect-field.php:20
2015
- #: wp-job-manager-functions.php:1074
2016
  msgid "No results match"
2017
  msgstr ""
2018
 
2019
  #: templates/form-fields/multiselect-field.php:20
2020
- #: wp-job-manager-functions.php:1075
2021
  msgid "Select Some Options"
2022
  msgstr ""
2023
 
@@ -2130,67 +2140,67 @@ msgstr ""
2130
  msgid "%s submitted successfully. Your listing will be visible once approved."
2131
  msgstr ""
2132
 
2133
- #: wp-job-manager-functions.php:445
2134
  msgid "Reset"
2135
  msgstr ""
2136
 
2137
- #: wp-job-manager-functions.php:449
2138
  msgid "RSS"
2139
  msgstr ""
2140
 
2141
- #: wp-job-manager-functions.php:554
2142
  msgid "Invalid email address."
2143
  msgstr ""
2144
 
2145
- #: wp-job-manager-functions.php:562
2146
  msgid "Your email address isn&#8217;t correct."
2147
  msgstr ""
2148
 
2149
- #: wp-job-manager-functions.php:566
2150
  msgid "This email is already registered, please choose another one."
2151
  msgstr ""
2152
 
2153
- #: wp-job-manager-functions.php:880
2154
  msgid "Full Time"
2155
  msgstr ""
2156
 
2157
- #: wp-job-manager-functions.php:881
2158
  msgid "Part Time"
2159
  msgstr ""
2160
 
2161
- #: wp-job-manager-functions.php:882
2162
  msgid "Contractor"
2163
  msgstr ""
2164
 
2165
- #: wp-job-manager-functions.php:883
2166
  msgid "Temporary"
2167
  msgstr ""
2168
 
2169
- #: wp-job-manager-functions.php:884
2170
  msgid "Intern"
2171
  msgstr ""
2172
 
2173
- #: wp-job-manager-functions.php:885
2174
  msgid "Volunteer"
2175
  msgstr ""
2176
 
2177
- #: wp-job-manager-functions.php:886
2178
  msgid "Per Diem"
2179
  msgstr ""
2180
 
2181
- #: wp-job-manager-functions.php:887
2182
  msgid "Other"
2183
  msgstr ""
2184
 
2185
- #: wp-job-manager-functions.php:954
2186
  msgid "Passwords must be at least 8 characters long."
2187
  msgstr ""
2188
 
2189
- #: wp-job-manager-functions.php:1073
2190
  msgid "Choose a category&hellip;"
2191
  msgstr ""
2192
 
2193
- #: wp-job-manager-functions.php:1294
2194
  #. translators: %s is the list of allowed file types.
2195
  msgid "Uploaded files need to be one of the following file types: %s"
2196
  msgstr ""
@@ -2209,33 +2219,33 @@ msgstr ""
2209
  msgid "Username"
2210
  msgstr ""
2211
 
2212
- #: wp-job-manager-template.php:701
2213
  msgid "Password"
2214
  msgstr ""
2215
 
2216
- #: wp-job-manager-template.php:711
2217
  msgid "Verify Password"
2218
  msgstr ""
2219
 
2220
- #: wp-job-manager-template.php:718
2221
  msgid "Your email"
2222
  msgstr ""
2223
 
2224
- #: wp-job-manager-template.php:719
2225
  msgid "you@yourdomain.com"
2226
  msgstr ""
2227
 
2228
- #: wp-job-manager-template.php:745
2229
  msgid "Posted on "
2230
  msgstr ""
2231
 
2232
- #: wp-job-manager-template.php:748 wp-job-manager-template.php:769
2233
  #. translators: Placeholder %s is the relative, human readable time since the
2234
  #. job listing was posted.
2235
  msgid "Posted %s ago"
2236
  msgstr ""
2237
 
2238
- #: wp-job-manager-template.php:798
2239
  msgid "Anywhere"
2240
  msgstr ""
2241
 
@@ -2284,7 +2294,7 @@ msgid "Searching&hellip;"
2284
  msgstr ""
2285
 
2286
  #: includes/admin/class-wp-job-manager-admin.php:123
2287
- #: includes/forms/class-wp-job-manager-form-submit-job.php:474
2288
  #. translators: jQuery date format, see
2289
  #. http:api.jqueryui.com/datepicker/#utility-formatDate
2290
  msgctxt "Date format for jQuery datepicker."
@@ -2292,71 +2302,71 @@ msgid "yy-mm-dd"
2292
  msgstr ""
2293
 
2294
  #: includes/admin/class-wp-job-manager-permalink-settings.php:108
2295
- #: includes/class-wp-job-manager-post-types.php:901
2296
  msgctxt "Job permalink - resave permalinks after changing this"
2297
  msgid "job"
2298
  msgstr ""
2299
 
2300
  #: includes/admin/class-wp-job-manager-permalink-settings.php:117
2301
- #: includes/class-wp-job-manager-post-types.php:902
2302
  msgctxt "Job category slug - resave permalinks after changing this"
2303
  msgid "job-category"
2304
  msgstr ""
2305
 
2306
  #: includes/admin/class-wp-job-manager-permalink-settings.php:126
2307
- #: includes/class-wp-job-manager-post-types.php:903
2308
  msgctxt "Job type slug - resave permalinks after changing this"
2309
  msgid "job-type"
2310
  msgstr ""
2311
 
2312
- #: includes/admin/views/html-admin-setup-step-2.php:46
2313
  msgctxt "Default page title (wizard)"
2314
  msgid "Post a Job"
2315
  msgstr ""
2316
 
2317
- #: includes/admin/views/html-admin-setup-step-2.php:54
2318
  msgctxt "Default page title (wizard)"
2319
  msgid "Job Dashboard"
2320
  msgstr ""
2321
 
2322
- #: includes/admin/views/html-admin-setup-step-2.php:62
2323
  msgctxt "Default page title (wizard)"
2324
  msgid "Jobs"
2325
  msgstr ""
2326
 
2327
  #: includes/class-wp-job-manager-post-types.php:391
2328
- #: wp-job-manager-functions.php:320
2329
  msgctxt "post status"
2330
  msgid "Expired"
2331
  msgstr ""
2332
 
2333
  #: includes/class-wp-job-manager-post-types.php:404
2334
- #: wp-job-manager-functions.php:321
2335
  msgctxt "post status"
2336
  msgid "Preview"
2337
  msgstr ""
2338
 
2339
- #: wp-job-manager-functions.php:319
2340
  msgctxt "post status"
2341
  msgid "Draft"
2342
  msgstr ""
2343
 
2344
- #: wp-job-manager-functions.php:322
2345
  msgctxt "post status"
2346
  msgid "Pending approval"
2347
  msgstr ""
2348
 
2349
- #: wp-job-manager-functions.php:323
2350
  msgctxt "post status"
2351
  msgid "Pending payment"
2352
  msgstr ""
2353
 
2354
- #: wp-job-manager-functions.php:324
2355
  msgctxt "post status"
2356
  msgid "Active"
2357
  msgstr ""
2358
 
2359
- #: includes/class-wp-job-manager-post-types.php:885
2360
  msgctxt "Post type archive slug - resave permalinks after changing this"
2361
  msgid "jobs"
2362
  msgstr ""
2
  # This file is distributed under the GPL2+.
3
  msgid ""
4
  msgstr ""
5
+ "Project-Id-Version: WP Job Manager 1.33.4\n"
6
  "Report-Msgid-Bugs-To: https://github.com/Automattic/WP-Job-Manager/issues\n"
7
+ "POT-Creation-Date: 2019-07-25 22:40:01+00:00\n"
8
  "MIME-Version: 1.0\n"
9
  "Content-Type: text/plain; charset=utf-8\n"
10
  "Content-Transfer-Encoding: 8bit\n"
13
  "Language-Team: LANGUAGE <EMAIL@ADDRESS>\n"
14
  "X-Generator: grunt-wp-i18n 1.0.3\n"
15
 
16
+ #: includes/3rd-party/wpml.php:94
17
  msgid "Page Not Set"
18
  msgstr ""
19
 
20
+ #: includes/3rd-party/wpml.php:108
21
  #. translators: Placeholder (%s) is the URL to edit the primary language in
22
  #. WPML.
23
  msgid "<a href=\"%s\">Switch to primary language</a> to edit this setting."
24
  msgstr ""
25
 
26
+ #: includes/abstracts/abstract-wp-job-manager-form.php:371
27
+ #: includes/abstracts/abstract-wp-job-manager-form.php:387
28
  #. translators: Placeholder is for the label of the reCAPTCHA field.
29
  #. translators: %s is the name of the form validation that failed.
30
  msgid "\"%s\" check failed. Please try again."
31
  msgstr ""
32
 
33
+ #: includes/admin/class-wp-job-manager-addons.php:125
34
  #: includes/admin/class-wp-job-manager-admin.php:139
35
  #: includes/admin/views/html-admin-page-addons.php:12
36
  msgid "WP Job Manager Add-ons"
37
  msgstr ""
38
 
39
+ #: includes/admin/class-wp-job-manager-addons.php:133
40
  #: includes/helper/views/html-licences.php:12
41
  msgid "Licenses"
42
  msgstr ""
105
  msgid "%s marked as not filled"
106
  msgstr ""
107
 
108
+ #: includes/admin/class-wp-job-manager-cpt.php:337
109
  msgid "Select category"
110
  msgstr ""
111
 
112
+ #: includes/admin/class-wp-job-manager-cpt.php:362
113
  msgid "Select Filled"
114
  msgstr ""
115
 
116
+ #: includes/admin/class-wp-job-manager-cpt.php:366
117
  msgid "Filled"
118
  msgstr ""
119
 
120
+ #: includes/admin/class-wp-job-manager-cpt.php:370
121
  msgid "Not Filled"
122
  msgstr ""
123
 
124
+ #: includes/admin/class-wp-job-manager-cpt.php:381
125
  msgid "Select Featured"
126
  msgstr ""
127
 
128
+ #: includes/admin/class-wp-job-manager-cpt.php:385
129
  msgid "Featured"
130
  msgstr ""
131
 
132
+ #: includes/admin/class-wp-job-manager-cpt.php:389
133
  msgid "Not Featured"
134
  msgstr ""
135
 
136
+ #: includes/admin/class-wp-job-manager-cpt.php:435
137
+ #: includes/admin/class-wp-job-manager-cpt.php:495
138
  msgid "Position"
139
  msgstr ""
140
 
141
+ #: includes/admin/class-wp-job-manager-cpt.php:455
142
  #. translators: %1$s is the singular name of the job listing post type; %2$s is
143
  #. the URL to view the listing.
144
  msgid "%1$s updated. <a href=\"%2$s\">View</a>"
145
  msgstr ""
146
 
147
+ #: includes/admin/class-wp-job-manager-cpt.php:456
148
  msgid "Custom field updated."
149
  msgstr ""
150
 
151
+ #: includes/admin/class-wp-job-manager-cpt.php:457
152
  msgid "Custom field deleted."
153
  msgstr ""
154
 
155
+ #: includes/admin/class-wp-job-manager-cpt.php:459
156
  #. translators: %s is the singular name of the job listing post type.
157
  msgid "%s updated."
158
  msgstr ""
159
 
160
+ #: includes/admin/class-wp-job-manager-cpt.php:461
161
  #. translators: %1$s is the singular name of the job listing post type; %2$s is
162
  #. the revision number.
163
  msgid "%1$s restored to revision from %2$s"
164
  msgstr ""
165
 
166
+ #: includes/admin/class-wp-job-manager-cpt.php:463
167
  #. translators: %1$s is the singular name of the job listing post type; %2$s is
168
  #. the URL to view the listing.
169
  msgid "%1$s published. <a href=\"%2$s\">View</a>"
170
  msgstr ""
171
 
172
+ #: includes/admin/class-wp-job-manager-cpt.php:465
173
  #. translators: %1$s is the singular name of the job listing post type; %2$s is
174
  #. the URL to view the listing.
175
  msgid "%s saved."
176
  msgstr ""
177
 
178
+ #: includes/admin/class-wp-job-manager-cpt.php:467
179
  #. translators: %1$s is the singular name of the job listing post type; %2$s is
180
  #. the URL to preview the listing.
181
  msgid "%1$s submitted. <a target=\"_blank\" href=\"%2$s\">Preview</a>"
182
  msgstr ""
183
 
184
+ #: includes/admin/class-wp-job-manager-cpt.php:470
185
  #. translators: %1$s is the singular name of the post type; %2$s is the date
186
  #. the post will be published; %3$s is the URL to preview the listing.
187
  msgid ""
189
  "href=\"%3$s\">Preview</a>"
190
  msgstr ""
191
 
192
+ #: includes/admin/class-wp-job-manager-cpt.php:476
193
  #. translators: %1$s is the singular name of the job listing post type; %2$s is
194
  #. the URL to view the listing.
195
  msgid "%1$s draft updated. <a target=\"_blank\" href=\"%2$s\">Preview</a>"
196
  msgstr ""
197
 
198
+ #: includes/admin/class-wp-job-manager-cpt.php:496
199
  msgid "Type"
200
  msgstr ""
201
 
202
+ #: includes/admin/class-wp-job-manager-cpt.php:497
203
  #: includes/class-wp-job-manager-email-notifications.php:238
204
+ #: includes/class-wp-job-manager-post-types.php:1222
205
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:213
206
  #: includes/widgets/class-wp-job-manager-widget-recent-jobs.php:46
207
  #: templates/job-filters.php:35 templates/job-filters.php:36
208
  msgid "Location"
209
  msgstr ""
210
 
211
+ #: includes/admin/class-wp-job-manager-cpt.php:498
212
  msgid "Status"
213
  msgstr ""
214
 
215
+ #: includes/admin/class-wp-job-manager-cpt.php:499
216
  msgid "Posted"
217
  msgstr ""
218
 
219
+ #: includes/admin/class-wp-job-manager-cpt.php:500
220
  msgid "Expires"
221
  msgstr ""
222
 
223
+ #: includes/admin/class-wp-job-manager-cpt.php:501
224
  #: includes/admin/class-wp-job-manager-settings.php:162
225
  msgid "Categories"
226
  msgstr ""
227
 
228
+ #: includes/admin/class-wp-job-manager-cpt.php:502
229
  msgid "Featured?"
230
  msgstr ""
231
 
232
+ #: includes/admin/class-wp-job-manager-cpt.php:503
233
+ #: includes/class-wp-job-manager-shortcodes.php:257
234
  msgid "Filled?"
235
  msgstr ""
236
 
237
+ #: includes/admin/class-wp-job-manager-cpt.php:504
238
  msgid "Actions"
239
  msgstr ""
240
 
241
+ #: includes/admin/class-wp-job-manager-cpt.php:569
242
  #. translators: %d is the post ID for the job listing.
243
  msgid "ID: %d"
244
  msgstr ""
245
 
246
+ #: includes/admin/class-wp-job-manager-cpt.php:613
247
  #. translators: %s placeholder is the username of the user.
248
  msgid "by a guest"
249
  msgstr ""
250
 
251
+ #: includes/admin/class-wp-job-manager-cpt.php:613
252
  msgid "by %s"
253
  msgstr ""
254
 
255
+ #: includes/admin/class-wp-job-manager-cpt.php:632
256
  msgid "Approve"
257
  msgstr ""
258
 
259
+ #: includes/admin/class-wp-job-manager-cpt.php:640
260
  #: includes/admin/class-wp-job-manager-writepanels.php:227
261
  #: includes/admin/class-wp-job-manager-writepanels.php:232
262
  #: includes/admin/class-wp-job-manager-writepanels.php:237
263
  msgid "View"
264
  msgstr ""
265
 
266
+ #: includes/admin/class-wp-job-manager-cpt.php:647
267
  #: includes/class-wp-job-manager-post-types.php:334
268
  #: templates/job-dashboard.php:52 templates/job-dashboard.php:70
269
  msgid "Edit"
270
  msgstr ""
271
 
272
+ #: includes/admin/class-wp-job-manager-cpt.php:654
273
  #: templates/job-dashboard.php:79
274
  msgid "Delete"
275
  msgstr ""
704
  "plugin know the location of the job listings page."
705
  msgstr ""
706
 
707
+ #: includes/admin/class-wp-job-manager-settings.php:417
708
  msgid "Settings successfully saved"
709
  msgstr ""
710
 
711
+ #: includes/admin/class-wp-job-manager-settings.php:442
712
  msgid "Save Changes"
713
  msgstr ""
714
 
715
+ #: includes/admin/class-wp-job-manager-settings.php:650
716
  msgid "--no page--"
717
  msgstr ""
718
 
719
+ #: includes/admin/class-wp-job-manager-settings.php:656
720
  msgid "Select a page&hellip;"
721
  msgstr ""
722
 
723
+ #: includes/admin/class-wp-job-manager-setup.php:58
724
  msgid "Setup"
725
  msgstr ""
726
 
727
+ #: includes/admin/class-wp-job-manager-taxonomy-meta.php:87
728
+ #: includes/admin/class-wp-job-manager-taxonomy-meta.php:110
729
+ #: includes/admin/class-wp-job-manager-taxonomy-meta.php:129
730
  #: includes/class-wp-job-manager-post-types.php:287
731
  msgid "Employment Type"
732
  msgstr ""
759
  msgstr ""
760
 
761
  #: includes/admin/class-wp-job-manager-writepanels.php:471
762
+ #: includes/class-wp-job-manager-ajax.php:418
763
  #. translators: Used in user select. %1$s is the user's display name; #%2$s is
764
  #. the user ID; %3$s is the user email.
765
  msgid "%1$s (#%2$s – %3$s)"
801
  msgid "More Information &rarr;"
802
  msgstr ""
803
 
804
+ #: includes/admin/views/html-admin-page-addons.php:54
805
  msgid "No add-ons were found."
806
  msgstr ""
807
 
876
  "for detailed instructions.)"
877
  msgstr ""
878
 
879
+ #: includes/admin/views/html-admin-setup-step-2.php:39
880
  msgid "Page Title"
881
  msgstr ""
882
 
883
+ #: includes/admin/views/html-admin-setup-step-2.php:40
884
  msgid "Page Description"
885
  msgstr ""
886
 
887
+ #: includes/admin/views/html-admin-setup-step-2.php:41
888
  msgid "Content Shortcode"
889
  msgstr ""
890
 
891
+ #: includes/admin/views/html-admin-setup-step-2.php:49
892
  msgid ""
893
  "Creates a page that allows employers to post new jobs directly from a page "
894
  "on your website, instead of requiring them to log in to an admin area. If "
896
  "the admin dashboard only -- you can uncheck this setting."
897
  msgstr ""
898
 
899
+ #: includes/admin/views/html-admin-setup-step-2.php:57
900
  msgid ""
901
  "Creates a page that allows employers to manage their job listings directly "
902
  "from a page on your website, instead of requiring them to log in to an "
904
  "only, you can uncheck this setting."
905
  msgstr ""
906
 
907
+ #: includes/admin/views/html-admin-setup-step-2.php:64
908
  msgid "Creates a page where visitors can browse, search, and filter job listings."
909
  msgstr ""
910
 
911
+ #: includes/admin/views/html-admin-setup-step-2.php:72
912
  msgid "Skip this step"
913
  msgstr ""
914
 
963
  "hiring!"
964
  msgstr ""
965
 
966
+ #: includes/admin/views/html-admin-setup-step-3.php:66
967
  msgid "Support WP Job Manager's Ongoing Development"
968
  msgstr ""
969
 
970
+ #: includes/admin/views/html-admin-setup-step-3.php:67
971
  msgid ""
972
  "There are lots of ways you can support open source software projects like "
973
  "this one: contributing code, fixing a bug, assisting with non-English "
975
  "spread the word. We appreciate your support!"
976
  msgstr ""
977
 
978
+ #: includes/admin/views/html-admin-setup-step-3.php:69
979
  msgid "Leave a positive review"
980
  msgstr ""
981
 
982
+ #: includes/admin/views/html-admin-setup-step-3.php:70
983
  msgid "Contribute a localization"
984
  msgstr ""
985
 
986
+ #: includes/admin/views/html-admin-setup-step-3.php:71
987
  msgid "Contribute code or report a bug"
988
  msgstr ""
989
 
990
+ #: includes/admin/views/html-admin-setup-step-3.php:72
991
  msgid "Help other users on the forums"
992
  msgstr ""
993
 
994
+ #: includes/class-wp-job-manager-ajax.php:185
995
  #. translators: Placeholder %d is the number of found search results.
996
  msgid "Search completed. Found %d matching record."
997
  msgid_plural "Search completed. Found %d matching records."
998
  msgstr[0] ""
999
  msgstr[1] ""
1000
 
1001
+ #: includes/class-wp-job-manager-ajax.php:283
1002
  msgid "You must be logged in to upload files using this method."
1003
  msgstr ""
1004
 
1012
  msgstr ""
1013
 
1014
  #: includes/class-wp-job-manager-data-exporter.php:52
1015
+ #: includes/class-wp-job-manager-post-types.php:1241
1016
  msgid "Company Name"
1017
  msgstr ""
1018
 
1019
  #: includes/class-wp-job-manager-data-exporter.php:53
1020
+ #: includes/class-wp-job-manager-post-types.php:1249
1021
  msgid "Company Website"
1022
  msgstr ""
1023
 
1024
  #: includes/class-wp-job-manager-data-exporter.php:54
1025
+ #: includes/class-wp-job-manager-post-types.php:1258
1026
  msgid "Company Tagline"
1027
  msgstr ""
1028
 
1029
  #: includes/class-wp-job-manager-data-exporter.php:55
1030
+ #: includes/class-wp-job-manager-post-types.php:1266
1031
  msgid "Company Twitter"
1032
  msgstr ""
1033
 
1034
  #: includes/class-wp-job-manager-data-exporter.php:56
1035
+ #: includes/class-wp-job-manager-post-types.php:1274
1036
  msgid "Company Video"
1037
  msgstr ""
1038
 
1040
  msgid "WP Job Manager User Data"
1041
  msgstr ""
1042
 
1043
+ #: includes/class-wp-job-manager-dependency-checker.php:66
1044
  #. translators: %1$s is version of PHP that WP Job Manager requires; %2$s is
1045
  #. the version of PHP WordPress is running on.
1046
  msgid ""
1047
+ "<strong>WP Job Manager</strong> requires a minimum PHP version of %1$s, but "
1048
+ "you are running %2$s."
 
1049
  msgstr ""
1050
 
1051
+ #: includes/class-wp-job-manager-dependency-checker.php:77
1052
  msgid "Learn more about updating PHP"
1053
  msgstr ""
1054
 
1055
+ #: includes/class-wp-job-manager-dependency-checker.php:79
1056
  #. translators: accessibility text
1057
  msgid "(opens in a new tab)"
1058
  msgstr ""
1059
 
1060
+ #: includes/class-wp-job-manager-dependency-checker.php:122
1061
  #. translators: %s is the URL for the page where users can go to update
1062
  #. WordPress.
1063
  msgid "<strong>WP Job Manager</strong> requires a more recent version of WordPress."
1064
  msgstr ""
1065
 
1066
+ #: includes/class-wp-job-manager-dependency-checker.php:136
1067
+ #: includes/class-wp-job-manager-dependency-checker.php:138
1068
  msgid "WordPress Update Required"
1069
  msgstr ""
1070
 
1074
 
1075
  #: includes/class-wp-job-manager-email-notifications.php:247
1076
  #: includes/class-wp-job-manager-post-types.php:218
1077
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:221
1078
  msgid "Job type"
1079
  msgstr ""
1080
 
1081
  #: includes/class-wp-job-manager-email-notifications.php:257
1082
  #: includes/class-wp-job-manager-post-types.php:154
1083
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:230
1084
  msgid "Job category"
1085
  msgstr ""
1086
 
1087
  #: includes/class-wp-job-manager-email-notifications.php:266
1088
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:255
1089
  msgid "Company name"
1090
  msgstr ""
1091
 
1130
  msgid "Geocoding error"
1131
  msgstr ""
1132
 
1133
+ #: includes/class-wp-job-manager-install.php:84
1134
  msgid "Employer"
1135
  msgstr ""
1136
 
1301
  msgstr[0] ""
1302
  msgstr[1] ""
1303
 
1304
+ #: includes/class-wp-job-manager-post-types.php:1209
1305
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:190
1306
  msgid "Application email/URL"
1307
  msgstr ""
1308
 
1309
+ #: includes/class-wp-job-manager-post-types.php:1210
1310
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:191
1311
  msgid "Enter an email address or website URL"
1312
  msgstr ""
1313
 
1314
+ #: includes/class-wp-job-manager-post-types.php:1213
1315
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:180
1316
  msgid "Application email"
1317
  msgstr ""
1318
 
1319
+ #: includes/class-wp-job-manager-post-types.php:1214
1320
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:181
1321
  msgid "you@example.com"
1322
  msgstr ""
1323
 
1324
+ #: includes/class-wp-job-manager-post-types.php:1216
1325
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:185
1326
  msgid "Application URL"
1327
  msgstr ""
1328
 
1329
+ #: includes/class-wp-job-manager-post-types.php:1217
1330
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:186
1331
  msgid "https://"
1332
  msgstr ""
1333
 
1334
+ #: includes/class-wp-job-manager-post-types.php:1223
1335
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:217
1336
  msgid "e.g. \"London\""
1337
  msgstr ""
1338
 
1339
+ #: includes/class-wp-job-manager-post-types.php:1224
1340
  msgid "Leave this blank if the location is not important."
1341
  msgstr ""
1342
 
1343
+ #: includes/class-wp-job-manager-post-types.php:1233
1344
  msgid ""
1345
  "This field is required for the \"application\" area to appear beneath the "
1346
  "listing."
1347
  msgstr ""
1348
 
1349
+ #: includes/class-wp-job-manager-post-types.php:1259
1350
  msgid "Brief description about the company"
1351
  msgstr ""
1352
 
1353
+ #: includes/class-wp-job-manager-post-types.php:1275
1354
  msgid "URL to the company video"
1355
  msgstr ""
1356
 
1357
+ #: includes/class-wp-job-manager-post-types.php:1284
1358
  msgid "Position Filled"
1359
  msgstr ""
1360
 
1361
+ #: includes/class-wp-job-manager-post-types.php:1290
1362
  msgid "Filled listings will no longer accept applications."
1363
  msgstr ""
1364
 
1365
+ #: includes/class-wp-job-manager-post-types.php:1293
1366
  msgid "Featured Listing"
1367
  msgstr ""
1368
 
1369
+ #: includes/class-wp-job-manager-post-types.php:1295
1370
  msgid ""
1371
  "Featured listings will be sticky during searches, and can be styled "
1372
  "differently."
1373
  msgstr ""
1374
 
1375
+ #: includes/class-wp-job-manager-post-types.php:1303
1376
  msgid "Listing Expiry Date"
1377
  msgstr ""
1378
 
1379
+ #: includes/class-wp-job-manager-shortcodes.php:108
1380
  msgid "Invalid ID"
1381
  msgstr ""
1382
 
1383
+ #: includes/class-wp-job-manager-shortcodes.php:115
1384
  msgid "This position has already been filled"
1385
  msgstr ""
1386
 
1387
+ #: includes/class-wp-job-manager-shortcodes.php:123
1388
  #. translators: Placeholder %s is the job listing title.
1389
  msgid "%s has been filled"
1390
  msgstr ""
1391
 
1392
+ #: includes/class-wp-job-manager-shortcodes.php:128
1393
  msgid "This position is not filled"
1394
  msgstr ""
1395
 
1396
+ #: includes/class-wp-job-manager-shortcodes.php:136
1397
  #. translators: Placeholder %s is the job listing title.
1398
  msgid "%s has been marked as not filled"
1399
  msgstr ""
1400
 
1401
+ #: includes/class-wp-job-manager-shortcodes.php:144
1402
  #. translators: Placeholder %s is the job listing title.
1403
  msgid "%s has been deleted"
1404
  msgstr ""
1405
 
1406
+ #: includes/class-wp-job-manager-shortcodes.php:149
1407
+ #: includes/class-wp-job-manager-shortcodes.php:163
1408
  msgid "Missing submission page."
1409
  msgstr ""
1410
 
1411
+ #: includes/class-wp-job-manager-shortcodes.php:256
1412
  #: includes/widgets/class-wp-job-manager-widget-featured-jobs.php:36
1413
  #: includes/widgets/class-wp-job-manager-widget-featured-jobs.php:52
1414
  #: includes/widgets/class-wp-job-manager-widget-recent-jobs.php:36
1415
  msgid "Title"
1416
  msgstr ""
1417
 
1418
+ #: includes/class-wp-job-manager-shortcodes.php:258
1419
  msgid "Date Posted"
1420
  msgstr ""
1421
 
1422
+ #: includes/class-wp-job-manager-shortcodes.php:259
1423
  msgid "Listing Expires"
1424
  msgstr ""
1425
 
1426
+ #: includes/class-wp-job-manager-shortcodes.php:401
1427
+ #: includes/class-wp-job-manager-shortcodes.php:439
1428
  msgid "Load more listings"
1429
  msgstr ""
1430
 
1431
+ #: includes/class-wp-job-manager-usage-tracking.php:228
1432
  #. translators: Placeholder %s is a URL to the document on wpjobmanager.com
1433
  #. with info on usage tracking.
1434
  msgid ""
1438
  "\t\t\t\tcollected, and you can opt out at any time."
1439
  msgstr ""
1440
 
1441
+ #: includes/class-wp-job-manager-usage-tracking.php:297
1442
  #. translators: the href tag contains the URL for the page telling users what
1443
  #. data WPJM tracks.
1444
  msgid ""
1447
  "\t\t\t\tNo sensitive information is collected."
1448
  msgstr ""
1449
 
1450
+ #: includes/class-wp-job-manager-usage-tracking.php:324
1451
  #: lib/usage-tracking/class-usage-tracking-base.php:483
1452
  msgid "Enable Usage Tracking"
1453
  msgstr ""
1454
 
1455
+ #: includes/class-wp-job-manager.php:138
1456
  #. translators: Placeholders %1$s and %2$s are the names of the two cookies
1457
  #. used in WP Job Manager.
1458
  msgid ""
1459
  "This site adds the following cookies to help users resume job submissions "
1460
+ "that they \n"
1461
  "\t\t\t\thave started but have not completed: %1$s and %2$s"
1462
  msgstr ""
1463
 
1464
+ #: includes/class-wp-job-manager.php:276
1465
  msgid "Load previous listings"
1466
  msgstr ""
1467
 
1468
+ #: includes/class-wp-job-manager.php:403
1469
  msgid "Invalid file type. Accepted types:"
1470
  msgstr ""
1471
 
1472
+ #: includes/class-wp-job-manager.php:420
1473
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:406
1474
  #. translators: Placeholder %d is the number of files to that users are limited
1475
  #. to.
1476
  msgid "You are only allowed to upload a maximum of %d files."
1477
  msgstr ""
1478
 
1479
+ #: includes/class-wp-job-manager.php:428
1480
  msgid "Are you sure you want to delete this listing?"
1481
  msgstr ""
1482
 
1483
+ #: includes/class-wp-job-manager.php:436
1484
  msgid "This field is required."
1485
  msgstr ""
1486
 
1543
  msgid "days"
1544
  msgstr ""
1545
 
1546
+ #: includes/forms/class-wp-job-manager-form-edit-job.php:108
1547
  msgid "Invalid listing"
1548
  msgstr ""
1549
 
1550
+ #: includes/forms/class-wp-job-manager-form-edit-job.php:140
1551
  msgid "Save changes"
1552
  msgstr ""
1553
 
1554
+ #: includes/forms/class-wp-job-manager-form-edit-job.php:145
1555
  msgid "Submit changes for approval"
1556
  msgstr ""
1557
 
1558
+ #: includes/forms/class-wp-job-manager-form-edit-job.php:199
1559
  msgid "Your changes have been saved."
1560
  msgstr ""
1561
 
1562
+ #: includes/forms/class-wp-job-manager-form-edit-job.php:205
1563
  msgid "View &rarr;"
1564
  msgstr ""
1565
 
1566
+ #: includes/forms/class-wp-job-manager-form-edit-job.php:207
1567
  msgid ""
1568
  "Your changes have been submitted and your listing will be visible again "
1569
  "once approved."
1574
  msgstr ""
1575
 
1576
  #: includes/forms/class-wp-job-manager-form-submit-job.php:88
1577
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:578
1578
  #: templates/job-preview.php:30
1579
  msgid "Preview"
1580
  msgstr ""
1583
  msgid "Done"
1584
  msgstr ""
1585
 
1586
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:206
1587
  msgid "Job Title"
1588
  msgstr ""
1589
 
1590
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:214
1591
  msgid "Leave this blank if the location is not important"
1592
  msgstr ""
1593
 
1594
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:224
1595
  msgid "Choose job type&hellip;"
1596
  msgstr ""
1597
 
1598
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:239
1599
  msgid "Description"
1600
  msgstr ""
1601
 
1602
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:258
1603
  msgid "Enter the name of the company"
1604
  msgstr ""
1605
 
1606
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:262
1607
  #: templates/content-single-job_listing-company.php:30
1608
  msgid "Website"
1609
  msgstr ""
1610
 
1611
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:266
1612
  msgid "http://"
1613
  msgstr ""
1614
 
1615
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:270
1616
  msgid "Tagline"
1617
  msgstr ""
1618
 
1619
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:273
1620
  msgid "Briefly describe your company"
1621
  msgstr ""
1622
 
1623
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:278
1624
  msgid "Video"
1625
  msgstr ""
1626
 
1627
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:282
1628
  msgid "A link to a video about your company"
1629
  msgstr ""
1630
 
1631
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:286
1632
  msgid "Twitter username"
1633
  msgstr ""
1634
 
1635
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:289
1636
  msgid "@yourcompany"
1637
  msgstr ""
1638
 
1639
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:293
1640
  msgid "Logo"
1641
  msgstr ""
1642
 
1643
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:343
1644
  #. translators: Placeholder %s is the label for the required field.
1645
  msgid "%s is a required field"
1646
  msgstr ""
1647
 
1648
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:354
1649
  #. translators: Placeholder %s is the field label that is did not validate.
1650
  msgid "%s is invalid"
1651
  msgstr ""
1652
 
1653
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:371
1654
  msgid "Invalid attachment provided."
1655
  msgstr ""
1656
 
1657
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:389
1658
+ #: wp-job-manager-functions.php:1304
1659
  #. translators: Placeholder %1$s is field label; %2$s is the file mime type;
1660
  #. %3$s is the allowed mime-types.
1661
  #. translators: %1$s is the file field label; %2$s is the file type; %3$s is
1663
  msgid "\"%1$s\" (filetype %2$s) needs to be one of the following file types: %3$s"
1664
  msgstr ""
1665
 
1666
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:424
1667
  msgid "Please enter a valid application email address"
1668
  msgstr ""
1669
 
1670
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:433
1671
  msgid "Please enter a valid application URL"
1672
  msgstr ""
1673
 
1674
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:443
1675
  msgid "Please enter a valid application email address or URL"
1676
  msgstr ""
1677
 
1678
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:637
1679
  msgid "Please enter a username."
1680
  msgstr ""
1681
 
1682
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:641
1683
  msgid "Please enter a password."
1684
  msgstr ""
1685
 
1686
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:645
1687
  msgid "Please enter your email address."
1688
  msgstr ""
1689
 
1690
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:651
1691
  msgid "Passwords must match."
1692
  msgstr ""
1693
 
1694
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:657
1695
  #. translators: Placeholder %s is the password hint.
1696
  msgid "Invalid Password: %s"
1697
  msgstr ""
1698
 
1699
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:659
1700
  msgid "Password is not valid."
1701
  msgstr ""
1702
 
1703
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:682
1704
  msgid "You must be signed in to post a new listing."
1705
  msgstr ""
1706
 
1707
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:700
1708
  #. translators: placeholder is the URL to the job dashboard page.
1709
  msgid ""
1710
  "Draft was saved. Job listing drafts can be resumed from the <a "
1711
  "href=\"%s\">job dashboard</a>."
1712
  msgstr ""
1713
 
1714
+ #: includes/helper/class-wp-job-manager-helper.php:279
1715
  msgid "Manage License (Requires Attention)"
1716
  msgstr ""
1717
 
1718
+ #: includes/helper/class-wp-job-manager-helper.php:282
1719
  msgid "Manage License"
1720
  msgstr ""
1721
 
1722
+ #: includes/helper/class-wp-job-manager-helper.php:285
1723
  #: includes/helper/views/html-licences.php:75
1724
  msgid "Activate License"
1725
  msgstr ""
1726
 
1727
+ #: includes/helper/class-wp-job-manager-helper.php:494
1728
  msgid ""
1729
  "Please enter a valid license key and email address in order to activate "
1730
  "this plugin's license."
1731
  msgstr ""
1732
 
1733
+ #: includes/helper/class-wp-job-manager-helper.php:526
1734
  msgid "Connection failed to the License Key API server - possible server issue."
1735
  msgstr ""
1736
 
1737
+ #: includes/helper/class-wp-job-manager-helper.php:535
1738
  msgid "Plugin license has been activated."
1739
  msgstr ""
1740
 
1741
+ #: includes/helper/class-wp-job-manager-helper.php:538
1742
  msgid "An unknown error occurred while attempting to activate the license"
1743
  msgstr ""
1744
 
1745
+ #: includes/helper/class-wp-job-manager-helper.php:558
1746
  msgid "license is not active."
1747
  msgstr ""
1748
 
1749
+ #: includes/helper/class-wp-job-manager-helper.php:574
1750
  msgid "Plugin license has been deactivated."
1751
  msgstr ""
1752
 
1922
  msgid "This listing has expired."
1923
  msgstr ""
1924
 
 
 
 
 
 
1925
  #: templates/emails/admin-expiring-job.php:32
1926
+ #. translators: %1$s placeholder is URL to the blog. %2$s placeholder is the
1927
+ #. name of the site.
1928
+ msgid "The following job listing is expiring today from <a href=\"%1$s\">%2$s</a>."
1929
  msgstr ""
1930
 
1931
  #: templates/emails/admin-expiring-job.php:35
1932
+ #. translators: %1$s placeholder is URL to the blog. %2$s placeholder is the
1933
+ #. name of the site.
1934
+ msgid "The following job listing is expiring soon from <a href=\"%1$s\">%2$s</a>."
1935
+ msgstr ""
1936
+
1937
+ #: templates/emails/admin-expiring-job.php:41
1938
+ #. translators: Placeholder is URL to site's WP admin.
1939
  msgid "Visit <a href=\"%s\">WordPress admin</a> to manage the listing."
1940
  msgstr ""
1941
 
1969
  "an administrator in the site's <a href=\"%s\">WordPress admin</a>."
1970
  msgstr ""
1971
 
1972
+ #: templates/emails/employer-expiring-job.php:32
1973
+ msgid "The following job listing is expiring today from <a href=\"%s\">%s</a>."
1974
+ msgstr ""
1975
+
1976
+ #: templates/emails/employer-expiring-job.php:40
1977
+ msgid "The following job listing is expiring soon from <a href=\"%s\">%s</a>."
1978
+ msgstr ""
1979
+
1980
  #: templates/emails/employer-expiring-job.php:48
1981
  msgid "Visit the <a href=\"%s\">job listing dashboard</a> to manage the listing."
1982
  msgstr ""
2022
  msgstr ""
2023
 
2024
  #: templates/form-fields/multiselect-field.php:20
2025
+ #: wp-job-manager-functions.php:1086
2026
  msgid "No results match"
2027
  msgstr ""
2028
 
2029
  #: templates/form-fields/multiselect-field.php:20
2030
+ #: wp-job-manager-functions.php:1087
2031
  msgid "Select Some Options"
2032
  msgstr ""
2033
 
2140
  msgid "%s submitted successfully. Your listing will be visible once approved."
2141
  msgstr ""
2142
 
2143
+ #: wp-job-manager-functions.php:454
2144
  msgid "Reset"
2145
  msgstr ""
2146
 
2147
+ #: wp-job-manager-functions.php:458
2148
  msgid "RSS"
2149
  msgstr ""
2150
 
2151
+ #: wp-job-manager-functions.php:566
2152
  msgid "Invalid email address."
2153
  msgstr ""
2154
 
2155
+ #: wp-job-manager-functions.php:574
2156
  msgid "Your email address isn&#8217;t correct."
2157
  msgstr ""
2158
 
2159
+ #: wp-job-manager-functions.php:578
2160
  msgid "This email is already registered, please choose another one."
2161
  msgstr ""
2162
 
2163
+ #: wp-job-manager-functions.php:892
2164
  msgid "Full Time"
2165
  msgstr ""
2166
 
2167
+ #: wp-job-manager-functions.php:893
2168
  msgid "Part Time"
2169
  msgstr ""
2170
 
2171
+ #: wp-job-manager-functions.php:894
2172
  msgid "Contractor"
2173
  msgstr ""
2174
 
2175
+ #: wp-job-manager-functions.php:895
2176
  msgid "Temporary"
2177
  msgstr ""
2178
 
2179
+ #: wp-job-manager-functions.php:896
2180
  msgid "Intern"
2181
  msgstr ""
2182
 
2183
+ #: wp-job-manager-functions.php:897
2184
  msgid "Volunteer"
2185
  msgstr ""
2186
 
2187
+ #: wp-job-manager-functions.php:898
2188
  msgid "Per Diem"
2189
  msgstr ""
2190
 
2191
+ #: wp-job-manager-functions.php:899
2192
  msgid "Other"
2193
  msgstr ""
2194
 
2195
+ #: wp-job-manager-functions.php:966
2196
  msgid "Passwords must be at least 8 characters long."
2197
  msgstr ""
2198
 
2199
+ #: wp-job-manager-functions.php:1085
2200
  msgid "Choose a category&hellip;"
2201
  msgstr ""
2202
 
2203
+ #: wp-job-manager-functions.php:1307
2204
  #. translators: %s is the list of allowed file types.
2205
  msgid "Uploaded files need to be one of the following file types: %s"
2206
  msgstr ""
2219
  msgid "Username"
2220
  msgstr ""
2221
 
2222
+ #: wp-job-manager-template.php:702
2223
  msgid "Password"
2224
  msgstr ""
2225
 
2226
+ #: wp-job-manager-template.php:712
2227
  msgid "Verify Password"
2228
  msgstr ""
2229
 
2230
+ #: wp-job-manager-template.php:719
2231
  msgid "Your email"
2232
  msgstr ""
2233
 
2234
+ #: wp-job-manager-template.php:720
2235
  msgid "you@yourdomain.com"
2236
  msgstr ""
2237
 
2238
+ #: wp-job-manager-template.php:747
2239
  msgid "Posted on "
2240
  msgstr ""
2241
 
2242
+ #: wp-job-manager-template.php:750 wp-job-manager-template.php:771
2243
  #. translators: Placeholder %s is the relative, human readable time since the
2244
  #. job listing was posted.
2245
  msgid "Posted %s ago"
2246
  msgstr ""
2247
 
2248
+ #: wp-job-manager-template.php:801
2249
  msgid "Anywhere"
2250
  msgstr ""
2251
 
2294
  msgstr ""
2295
 
2296
  #: includes/admin/class-wp-job-manager-admin.php:123
2297
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:490
2298
  #. translators: jQuery date format, see
2299
  #. http:api.jqueryui.com/datepicker/#utility-formatDate
2300
  msgctxt "Date format for jQuery datepicker."
2302
  msgstr ""
2303
 
2304
  #: includes/admin/class-wp-job-manager-permalink-settings.php:108
2305
+ #: includes/class-wp-job-manager-post-types.php:945
2306
  msgctxt "Job permalink - resave permalinks after changing this"
2307
  msgid "job"
2308
  msgstr ""
2309
 
2310
  #: includes/admin/class-wp-job-manager-permalink-settings.php:117
2311
+ #: includes/class-wp-job-manager-post-types.php:946
2312
  msgctxt "Job category slug - resave permalinks after changing this"
2313
  msgid "job-category"
2314
  msgstr ""
2315
 
2316
  #: includes/admin/class-wp-job-manager-permalink-settings.php:126
2317
+ #: includes/class-wp-job-manager-post-types.php:947
2318
  msgctxt "Job type slug - resave permalinks after changing this"
2319
  msgid "job-type"
2320
  msgstr ""
2321
 
2322
+ #: includes/admin/views/html-admin-setup-step-2.php:47
2323
  msgctxt "Default page title (wizard)"
2324
  msgid "Post a Job"
2325
  msgstr ""
2326
 
2327
+ #: includes/admin/views/html-admin-setup-step-2.php:55
2328
  msgctxt "Default page title (wizard)"
2329
  msgid "Job Dashboard"
2330
  msgstr ""
2331
 
2332
+ #: includes/admin/views/html-admin-setup-step-2.php:63
2333
  msgctxt "Default page title (wizard)"
2334
  msgid "Jobs"
2335
  msgstr ""
2336
 
2337
  #: includes/class-wp-job-manager-post-types.php:391
2338
+ #: wp-job-manager-functions.php:329
2339
  msgctxt "post status"
2340
  msgid "Expired"
2341
  msgstr ""
2342
 
2343
  #: includes/class-wp-job-manager-post-types.php:404
2344
+ #: wp-job-manager-functions.php:330
2345
  msgctxt "post status"
2346
  msgid "Preview"
2347
  msgstr ""
2348
 
2349
+ #: wp-job-manager-functions.php:328
2350
  msgctxt "post status"
2351
  msgid "Draft"
2352
  msgstr ""
2353
 
2354
+ #: wp-job-manager-functions.php:331
2355
  msgctxt "post status"
2356
  msgid "Pending approval"
2357
  msgstr ""
2358
 
2359
+ #: wp-job-manager-functions.php:332
2360
  msgctxt "post status"
2361
  msgid "Pending payment"
2362
  msgstr ""
2363
 
2364
+ #: wp-job-manager-functions.php:333
2365
  msgctxt "post status"
2366
  msgid "Active"
2367
  msgstr ""
2368
 
2369
+ #: includes/class-wp-job-manager-post-types.php:929
2370
  msgctxt "Post type archive slug - resave permalinks after changing this"
2371
  msgid "jobs"
2372
  msgstr ""
readme.txt CHANGED
@@ -1,9 +1,10 @@
1
  === WP Job Manager ===
2
  Contributors: mikejolley, automattic, adamkheckler, alexsanford1, annezazu, cena, chaselivingston, csonnek, davor.altman, donnapep, donncha, drawmyface, erania-pinnera, jacobshere, jakeom, jeherve, jenhooks, jgs, jonryan, kraftbj, lamdayap, lschuyler, macmanx, nancythanki, orangesareorange, rachelsquirrel, ryancowles, richardmtl, scarstocea
3
  Tags: job manager, job listing, job board, job management, job lists, job list, job, jobs, company, hiring, employment, employer, employees, candidate, freelance, internship, job listings, positions, board, application, hiring, listing, manager, recruiting, recruitment, talent
4
- Requires at least: 4.7.0
5
  Tested up to: 5.2
6
- Stable tag: 1.33.3
 
7
  License: GPLv3
8
  License URI: http://www.gnu.org/licenses/gpl-3.0.html
9
 
@@ -151,6 +152,11 @@ It then creates a database based on the parameters passed to it.
151
  6. Job listings in admin.
152
 
153
  == Changelog ==
 
 
 
 
 
154
  = 1.33.3 =
155
  * Fix: Upgrade jquery-fileupload to v9.32.0
156
  * Fix: Set frame origin on pages where shortcodes are embedded
1
  === WP Job Manager ===
2
  Contributors: mikejolley, automattic, adamkheckler, alexsanford1, annezazu, cena, chaselivingston, csonnek, davor.altman, donnapep, donncha, drawmyface, erania-pinnera, jacobshere, jakeom, jeherve, jenhooks, jgs, jonryan, kraftbj, lamdayap, lschuyler, macmanx, nancythanki, orangesareorange, rachelsquirrel, ryancowles, richardmtl, scarstocea
3
  Tags: job manager, job listing, job board, job management, job lists, job list, job, jobs, company, hiring, employment, employer, employees, candidate, freelance, internship, job listings, positions, board, application, hiring, listing, manager, recruiting, recruitment, talent
4
+ Requires at least: 4.9
5
  Tested up to: 5.2
6
+ Requires PHP: 5.6
7
+ Stable tag: 1.33.4
8
  License: GPLv3
9
  License URI: http://www.gnu.org/licenses/gpl-3.0.html
10
 
152
  6. Job listings in admin.
153
 
154
  == Changelog ==
155
+ = 1.33.4 =
156
+ * Fix: job-submission.js throws js error expects job_description to be WP Editor
157
+ * Fix: checking typeof undefined should be in quotes (in job_submission.js)
158
+ * Fix: plugin activation issue
159
+
160
  = 1.33.3 =
161
  * Fix: Upgrade jquery-fileupload to v9.32.0
162
  * Fix: Set frame origin on pages where shortcodes are embedded
templates/emails/admin-expiring-job.php CHANGED
@@ -8,7 +8,7 @@
8
  * @author Automattic
9
  * @package wp-job-manager
10
  * @category Template
11
- * @version 1.31.1
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
@@ -24,15 +24,21 @@ $job = $args['job'];
24
  * @var bool
25
  */
26
  $expiring_today = $args['expiring_today'];
 
27
 
28
  echo '<p>';
29
  if ( $expiring_today ) {
30
- printf( esc_html__( 'The following job listing is expiring today from <a href="%s">%s</a>.', 'wp-job-manager' ), esc_url( home_url() ), esc_html( get_bloginfo( 'name' ) ) );
 
31
  } else {
32
- printf( esc_html__( 'The following job listing is expiring soon from <a href="%s">%s</a>.', 'wp-job-manager' ), esc_url( home_url() ), esc_html( get_bloginfo( 'name' ) ) );
 
33
  }
34
- $edit_post_link = admin_url( sprintf( 'post.php?post=%d&amp;action=edit', $job->ID ) );
35
- printf( ' ' . esc_html__( 'Visit <a href="%s">WordPress admin</a> to manage the listing.', 'wp-job-manager' ), esc_url( $edit_post_link ) );
 
 
 
36
  echo '</p>';
37
 
38
  /**
8
  * @author Automattic
9
  * @package wp-job-manager
10
  * @category Template
11
+ * @version 1.34.0
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
24
  * @var bool
25
  */
26
  $expiring_today = $args['expiring_today'];
27
+ $edit_post_link = admin_url( sprintf( 'post.php?post=%d&amp;action=edit', $job->ID ) );
28
 
29
  echo '<p>';
30
  if ( $expiring_today ) {
31
+ // translators: %1$s placeholder is URL to the blog. %2$s placeholder is the name of the site.
32
+ echo wp_kses_post( sprintf( __( 'The following job listing is expiring today from <a href="%1$s">%2$s</a>.', 'wp-job-manager' ), esc_url( home_url() ), esc_html( get_bloginfo( 'name' ) ) ) );
33
  } else {
34
+ // translators: %1$s placeholder is URL to the blog. %2$s placeholder is the name of the site.
35
+ echo wp_kses_post( sprintf( __( 'The following job listing is expiring soon from <a href="%1$s">%2$s</a>.', 'wp-job-manager' ), esc_url( home_url() ), esc_html( get_bloginfo( 'name' ) ) ) );
36
  }
37
+
38
+ echo ' ';
39
+
40
+ // translators: Placeholder is URL to site's WP admin.
41
+ echo wp_kses_post( sprintf( __( 'Visit <a href="%s">WordPress admin</a> to manage the listing.', 'wp-job-manager' ), esc_url( $edit_post_link ) ) );
42
  echo '</p>';
43
 
44
  /**
uninstall.php CHANGED
@@ -1,4 +1,10 @@
1
  <?php
 
 
 
 
 
 
2
  if ( ! defined( 'WP_UNINSTALL_PLUGIN' ) ) {
3
  exit();
4
  }
@@ -13,14 +19,18 @@ if ( ! is_multisite() ) {
13
  if ( $do_deletion ) {
14
  WP_Job_Manager_Data_Cleaner::cleanup_all();
15
  }
16
- } else {
17
- global $wpdb;
 
 
 
 
 
18
 
19
- $blog_ids = $wpdb->get_col( "SELECT blog_id FROM $wpdb->blogs" );
20
  $original_blog_id = get_current_blog_id();
21
 
22
- foreach ( $blog_ids as $blog_id ) {
23
- switch_to_blog( $blog_id );
24
 
25
  // Only do deletion if the setting is true.
26
  $do_deletion = get_option( 'job_manager_delete_data_on_uninstall' );
1
  <?php
2
+ /**
3
+ * Uninstall file for the plugin. Runs when plugin is deleted in WordPress Admin.
4
+ *
5
+ * @package wp-job-manager
6
+ */
7
+
8
  if ( ! defined( 'WP_UNINSTALL_PLUGIN' ) ) {
9
  exit();
10
  }
19
  if ( $do_deletion ) {
20
  WP_Job_Manager_Data_Cleaner::cleanup_all();
21
  }
22
+ } elseif ( function_exists( 'get_sites' ) ) {
23
+ $blog_ids = get_sites(
24
+ array(
25
+ 'fields' => 'ids',
26
+ 'update_site_cache' => false,
27
+ )
28
+ );
29
 
 
30
  $original_blog_id = get_current_blog_id();
31
 
32
+ foreach ( $blog_ids as $current_blog_id ) {
33
+ switch_to_blog( $current_blog_id );
34
 
35
  // Only do deletion if the setting is true.
36
  $do_deletion = get_option( 'job_manager_delete_data_on_uninstall' );
wp-job-manager-functions.php CHANGED
@@ -1,4 +1,12 @@
1
  <?php
 
 
 
 
 
 
 
 
2
  if ( ! function_exists( 'get_job_listings' ) ) :
3
  /**
4
  * Queries job listings with certain criteria and returns them.
@@ -163,12 +171,13 @@ if ( ! function_exists( 'get_job_listings' ) ) :
163
  $cached_query_posts = get_transient( $query_args_hash );
164
  if ( is_string( $cached_query_posts ) ) {
165
  $cached_query_posts = json_decode( $cached_query_posts, false );
166
- if ( $cached_query_posts
167
- && is_object( $cached_query_posts )
168
- && isset( $cached_query_posts->max_num_pages )
169
- && isset( $cached_query_posts->found_posts )
170
- && isset( $cached_query_posts->posts )
171
- && is_array( $cached_query_posts->posts )
 
172
  ) {
173
  $posts = array_map( 'get_post', $cached_query_posts->posts );
174
  $result = new WP_Query();
@@ -231,7 +240,7 @@ if ( ! function_exists( '_wpjm_shuffle_featured_post_results_helper' ) ) :
231
  return 1;
232
  }
233
  }
234
- return rand( -1, 1 );
235
  }
236
  endif;
237
 
@@ -459,14 +468,16 @@ if ( ! function_exists( 'job_manager_get_filtered_links' ) ) :
459
  )
460
  ),
461
  ),
462
- ), $args
 
463
  );
464
 
465
- if ( count( (array) $args['filter_job_types'] ) === count( $types )
466
- && empty( $args['search_keywords'] )
467
- && empty( $args['search_location'] )
468
- && empty( $args['search_categories'] )
469
- && ! apply_filters( 'job_manager_get_listings_custom_filter', false )
 
470
  ) {
471
  unset( $links['reset'] );
472
  }
@@ -507,7 +518,8 @@ if ( ! function_exists( 'wp_job_manager_notify_new_user' ) ) :
507
  global $wp_version;
508
 
509
  if ( version_compare( $wp_version, '4.3.1', '<' ) ) {
510
- wp_new_user_notification( $user_id, $password ); // phpcs:ignore WordPress.WP.DeprecatedParameters.Wp_new_user_notificationParam2Found
 
511
  } else {
512
  $notify = 'admin';
513
  if ( empty( $password ) ) {
@@ -1129,7 +1141,8 @@ function job_manager_dropdown_categories( $args = '' ) {
1129
  $output .= "</select>\n";
1130
 
1131
  if ( $r['echo'] ) {
1132
- echo $output; // WPCS: XSS ok.
 
1133
  }
1134
 
1135
  return $output;
@@ -1430,6 +1443,8 @@ function job_manager_duplicate_listing( $post_id ) {
1430
  /*
1431
  * Duplicate post meta, aside from some reserved fields.
1432
  */
 
 
1433
  $post_meta = $wpdb->get_results( $wpdb->prepare( "SELECT meta_key, meta_value FROM {$wpdb->postmeta} WHERE post_id=%d", $post_id ) );
1434
 
1435
  if ( ! empty( $post_meta ) ) {
1
  <?php
2
+ /**
3
+ * Global WP Job Manager functions.
4
+ *
5
+ * New global functions are discouraged whenever possible.
6
+ *
7
+ * @package wp-job-manager
8
+ */
9
+
10
  if ( ! function_exists( 'get_job_listings' ) ) :
11
  /**
12
  * Queries job listings with certain criteria and returns them.
171
  $cached_query_posts = get_transient( $query_args_hash );
172
  if ( is_string( $cached_query_posts ) ) {
173
  $cached_query_posts = json_decode( $cached_query_posts, false );
174
+ if (
175
+ $cached_query_posts
176
+ && is_object( $cached_query_posts )
177
+ && isset( $cached_query_posts->max_num_pages )
178
+ && isset( $cached_query_posts->found_posts )
179
+ && isset( $cached_query_posts->posts )
180
+ && is_array( $cached_query_posts->posts )
181
  ) {
182
  $posts = array_map( 'get_post', $cached_query_posts->posts );
183
  $result = new WP_Query();
240
  return 1;
241
  }
242
  }
243
+ return wp_rand( -1, 1 );
244
  }
245
  endif;
246
 
468
  )
469
  ),
470
  ),
471
+ ),
472
+ $args
473
  );
474
 
475
+ if (
476
+ count( (array) $args['filter_job_types'] ) === count( $types )
477
+ && empty( $args['search_keywords'] )
478
+ && empty( $args['search_location'] )
479
+ && empty( $args['search_categories'] )
480
+ && ! apply_filters( 'job_manager_get_listings_custom_filter', false )
481
  ) {
482
  unset( $links['reset'] );
483
  }
518
  global $wp_version;
519
 
520
  if ( version_compare( $wp_version, '4.3.1', '<' ) ) {
521
+ // phpcs:ignore WordPress.WP.DeprecatedParameters.Wp_new_user_notificationParam2Found
522
+ wp_new_user_notification( $user_id, $password );
523
  } else {
524
  $notify = 'admin';
525
  if ( empty( $password ) ) {
1141
  $output .= "</select>\n";
1142
 
1143
  if ( $r['echo'] ) {
1144
+ // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1145
+ echo $output;
1146
  }
1147
 
1148
  return $output;
1443
  /*
1444
  * Duplicate post meta, aside from some reserved fields.
1445
  */
1446
+
1447
+ // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Easiest way to retrieve raw meta values without filters.
1448
  $post_meta = $wpdb->get_results( $wpdb->prepare( "SELECT meta_key, meta_value FROM {$wpdb->postmeta} WHERE post_id=%d", $post_id ) );
1449
 
1450
  if ( ! empty( $post_meta ) ) {
wp-job-manager-template.php CHANGED
@@ -21,8 +21,8 @@
21
  */
22
  function get_job_manager_template( $template_name, $args = array(), $template_path = 'job_manager', $default_path = '' ) {
23
  if ( $args && is_array( $args ) ) {
24
- // Please, forgive us.
25
- extract( $args ); // phpcs:ignore WordPress.Functions.DontExtract.extract_extract
26
  }
27
  include locate_job_manager_template( $template_name, $template_path, $default_path );
28
  }
@@ -692,7 +692,8 @@ function wpjm_get_registration_fields() {
692
  'type' => 'text',
693
  'label' => esc_html__( 'Username', 'wp-job-manager' ),
694
  'required' => $account_required,
695
- 'value' => isset( $_POST['create_account_username'] ) ? $_POST['create_account_username'] : '',
 
696
  );
697
  }
698
  if ( ! $use_standard_password_setup_email ) {
@@ -718,7 +719,8 @@ function wpjm_get_registration_fields() {
718
  'label' => esc_html__( 'Your email', 'wp-job-manager' ),
719
  'placeholder' => __( 'you@yourdomain.com', 'wp-job-manager' ),
720
  'required' => $account_required,
721
- 'value' => isset( $_POST['create_account_email'] ) ? $_POST['create_account_email'] : '',
 
722
  );
723
  }
724
 
@@ -788,7 +790,8 @@ function the_job_location( $map_link = true, $post = null ) {
788
  apply_filters(
789
  'the_job_location_map_link',
790
  '<a class="google_map_link" href="' . esc_url( 'http://maps.google.com/maps?q=' . rawurlencode( wp_strip_all_tags( $location ) ) . '&zoom=14&size=512x512&maptype=roadmap&sensor=false' ) . '">' . esc_html( wp_strip_all_tags( $location ) ) . '</a>',
791
- $location, $post
 
792
  )
793
  );
794
  } else {
@@ -875,9 +878,10 @@ function get_the_company_logo( $post = null, $size = 'thumbnail' ) {
875
  function job_manager_get_resized_image( $logo, $size ) {
876
  global $_wp_additional_image_sizes;
877
 
878
- if ( 'full' !== $size
879
- && strstr( $logo, WP_CONTENT_URL )
880
- && ( isset( $_wp_additional_image_sizes[ $size ] ) || in_array( $size, array( 'thumbnail', 'medium', 'large' ), true ) )
 
881
  ) {
882
 
883
  if ( in_array( $size, array( 'thumbnail', 'medium', 'large' ), true ) ) {
@@ -953,7 +957,8 @@ function the_company_video( $post = null ) {
953
  $video_embed = apply_filters( 'the_company_video_embed', $video_embed, $post );
954
 
955
  if ( $video_embed ) {
956
- echo '<div class="company_video">' . $video_embed . '</div>'; // WPCS: XSS ok.
 
957
  }
958
  }
959
 
21
  */
22
  function get_job_manager_template( $template_name, $args = array(), $template_path = 'job_manager', $default_path = '' ) {
23
  if ( $args && is_array( $args ) ) {
24
+ // phpcs:ignore WordPress.PHP.DontExtract.extract_extract -- Please, forgive us.
25
+ extract( $args );
26
  }
27
  include locate_job_manager_template( $template_name, $template_path, $default_path );
28
  }
692
  'type' => 'text',
693
  'label' => esc_html__( 'Username', 'wp-job-manager' ),
694
  'required' => $account_required,
695
+ // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Just used to populate value when validation failed.
696
+ 'value' => isset( $_POST['create_account_username'] ) ? sanitize_text_field( wp_unslash( $_POST['create_account_username'] ) ) : '',
697
  );
698
  }
699
  if ( ! $use_standard_password_setup_email ) {
719
  'label' => esc_html__( 'Your email', 'wp-job-manager' ),
720
  'placeholder' => __( 'you@yourdomain.com', 'wp-job-manager' ),
721
  'required' => $account_required,
722
+ // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Just used to populate value when validation failed.
723
+ 'value' => isset( $_POST['create_account_email'] ) ? sanitize_text_field( wp_unslash( $_POST['create_account_email'] ) ) : '',
724
  );
725
  }
726
 
790
  apply_filters(
791
  'the_job_location_map_link',
792
  '<a class="google_map_link" href="' . esc_url( 'http://maps.google.com/maps?q=' . rawurlencode( wp_strip_all_tags( $location ) ) . '&zoom=14&size=512x512&maptype=roadmap&sensor=false' ) . '">' . esc_html( wp_strip_all_tags( $location ) ) . '</a>',
793
+ $location,
794
+ $post
795
  )
796
  );
797
  } else {
878
  function job_manager_get_resized_image( $logo, $size ) {
879
  global $_wp_additional_image_sizes;
880
 
881
+ if (
882
+ 'full' !== $size
883
+ && strstr( $logo, WP_CONTENT_URL )
884
+ && ( isset( $_wp_additional_image_sizes[ $size ] ) || in_array( $size, array( 'thumbnail', 'medium', 'large' ), true ) )
885
  ) {
886
 
887
  if ( in_array( $size, array( 'thumbnail', 'medium', 'large' ), true ) ) {
957
  $video_embed = apply_filters( 'the_company_video_embed', $video_embed, $post );
958
 
959
  if ( $video_embed ) {
960
+ // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
961
+ echo '<div class="company_video">' . $video_embed . '</div>';
962
  }
963
  }
964
 
wp-job-manager.php CHANGED
@@ -3,11 +3,12 @@
3
  * Plugin Name: WP Job Manager
4
  * Plugin URI: https://wpjobmanager.com/
5
  * Description: Manage job listings from the WordPress admin panel, and allow users to post jobs directly to your site.
6
- * Version: 1.33.3
7
  * Author: Automattic
8
  * Author URI: https://wpjobmanager.com/
9
- * Requires at least: 4.7.0
10
  * Tested up to: 5.2
 
11
  * Text Domain: wp-job-manager
12
  * Domain Path: /languages/
13
  * License: GPL2+
@@ -20,7 +21,7 @@ if ( ! defined( 'ABSPATH' ) ) {
20
  }
21
 
22
  // Define constants.
23
- define( 'JOB_MANAGER_VERSION', '1.33.3' );
24
  define( 'JOB_MANAGER_PLUGIN_DIR', untrailingslashit( plugin_dir_path( __FILE__ ) ) );
25
  define( 'JOB_MANAGER_PLUGIN_URL', untrailingslashit( plugins_url( basename( plugin_dir_path( __FILE__ ) ), basename( __FILE__ ) ) ) );
26
  define( 'JOB_MANAGER_PLUGIN_BASENAME', plugin_basename( __FILE__ ) );
@@ -45,3 +46,10 @@ function WPJM() { // phpcs:ignore WordPress.NamingConventions.ValidFunctionName
45
  }
46
 
47
  $GLOBALS['job_manager'] = WPJM();
 
 
 
 
 
 
 
3
  * Plugin Name: WP Job Manager
4
  * Plugin URI: https://wpjobmanager.com/
5
  * Description: Manage job listings from the WordPress admin panel, and allow users to post jobs directly to your site.
6
+ * Version: 1.33.4
7
  * Author: Automattic
8
  * Author URI: https://wpjobmanager.com/
9
+ * Requires at least: 4.9
10
  * Tested up to: 5.2
11
+ * Requires PHP: 5.6
12
  * Text Domain: wp-job-manager
13
  * Domain Path: /languages/
14
  * License: GPL2+
21
  }
22
 
23
  // Define constants.
24
+ define( 'JOB_MANAGER_VERSION', '1.33.4' );
25
  define( 'JOB_MANAGER_PLUGIN_DIR', untrailingslashit( plugin_dir_path( __FILE__ ) ) );
26
  define( 'JOB_MANAGER_PLUGIN_URL', untrailingslashit( plugins_url( basename( plugin_dir_path( __FILE__ ) ), basename( __FILE__ ) ) ) );
27
  define( 'JOB_MANAGER_PLUGIN_BASENAME', plugin_basename( __FILE__ ) );
46
  }
47
 
48
  $GLOBALS['job_manager'] = WPJM();
49
+
50
+ // Activation - works with symlinks.
51
+ register_activation_hook( basename( dirname( __FILE__ ) ) . '/' . basename( __FILE__ ), array( WPJM(), 'activate' ) );
52
+
53
+ // Cleanup on deactivation.
54
+ register_deactivation_hook( __FILE__, array( WPJM(), 'unschedule_cron_jobs' ) );
55
+ register_deactivation_hook( __FILE__, array( WPJM(), 'usage_tracking_cleanup' ) );