WP Job Manager - Version 1.30.0

Version Description

  • Enhancement: Adds ability to have a reCAPTCHA field to check if job listing author is human. (@jom)
  • Enhancement: Allows for option to make edits to job listings force listing back into pending approval status. (@jom)
  • Enhancement: Adds spinner and disables form when user submits job listing. (@jom)
  • Enhancement: Update the add-ons page of the plugin. (@jom)
  • Enhancement: Added the ability to sort jobs randomly on the Featured Jobs Widget. (@jom)
  • Enhancement: Improved handling of alternative date formats when editing job expiration field in WP admin. (@jom)
  • Enhancement: Added star indicator next to featured listings on [job_dashboard]. (@jom)
  • Enhancement: Opt-in to usage tracking so we can better improve the plugin. (@alexsanford, @donnapep, @jom)
  • Enhancement: Introduced new asset enqueuing strategy that will be turned on in 1.32.0. Requires plugin and theme updates. (@jom; Dev notes: https://github.com/Automattic/WP-Job-Manager/pull/1354)
  • Fix: Use WordPress core checks for image formats to not confuse docx as an image. (@tripflex)
  • Fix: Issue with [jobs] shortcode when categories argument is provided. (@jom)
  • Fix: Issue with double encoding HTML entities in custom text area fields. (@jom)
  • Fix: Updates job-dashboard.php template with colspan fix on no active listings message. (@jom)
  • Fix: Clear job listings cache when deleting a user and their job listings. (@jom)
  • Dev: Adds is_wpjm() and related functions to test if we're on a WPJM related page. (@jom)
  • Dev: Adds job_manager_user_edit_job_listing action that fires after a user edits a job listing. (@jom)
  • Dev: Adds job_manager_enable_job_archive_page filter to enable job archive page. (@jom)
  • Dev: Adds date field for custom job listing form fields. (@alexsandford)
Download this release

Release Info

Developer jakeom
Plugin Icon 128x128 WP Job Manager
Version 1.30.0
Comparing to
See all releases

Code changes from version 1.29.3 to 1.30.0

Files changed (55) hide show
  1. assets/css/admin.css +1 -1
  2. assets/css/admin.less +25 -102
  3. assets/css/frontend.css +1 -1
  4. assets/css/frontend.less +25 -210
  5. assets/css/job-listings.css +1 -0
  6. assets/css/job-listings.less +218 -0
  7. assets/js/admin.js +0 -17
  8. assets/js/admin.min.js +1 -1
  9. assets/js/ajax-filters.js +3 -0
  10. assets/js/ajax-filters.min.js +1 -1
  11. assets/js/datepicker.js +27 -0
  12. assets/js/datepicker.min.js +1 -0
  13. assets/js/job-submission.js +5 -1
  14. assets/js/job-submission.min.js +1 -1
  15. changelog.txt +20 -0
  16. includes/3rd-party/3rd-party.php +7 -5
  17. includes/3rd-party/{all_in_one_seo_pack.php → all-in-one-seo-pack.php} +0 -0
  18. includes/3rd-party/polylang.php +2 -2
  19. includes/3rd-party/rp4wp.php +54 -0
  20. includes/3rd-party/wp-all-import.php +20 -0
  21. includes/3rd-party/yoast.php +2 -2
  22. includes/abstracts/abstract-wp-job-manager-form.php +79 -0
  23. includes/admin/class-wp-job-manager-addons.php +65 -35
  24. includes/admin/class-wp-job-manager-admin.php +9 -6
  25. includes/admin/class-wp-job-manager-cpt.php +3 -3
  26. includes/admin/class-wp-job-manager-settings.php +75 -18
  27. includes/admin/class-wp-job-manager-setup.php +66 -5
  28. includes/admin/class-wp-job-manager-writepanels.php +9 -3
  29. includes/admin/views/html-admin-page-addons.php +70 -0
  30. includes/class-wp-job-manager-cache-helper.php +2 -0
  31. includes/class-wp-job-manager-post-types.php +9 -69
  32. includes/class-wp-job-manager-usage-tracking-data.php +315 -0
  33. includes/class-wp-job-manager-usage-tracking.php +142 -0
  34. includes/class-wp-job-manager-widget.php +11 -0
  35. includes/forms/class-wp-job-manager-form-edit-job.php +90 -15
  36. includes/forms/class-wp-job-manager-form-submit-job.php +51 -5
  37. includes/helper/class-wp-job-manager-helper.php +29 -31
  38. includes/helper/views/html-licence-key-error.php +9 -0
  39. includes/widgets/class-wp-job-manager-widget-featured-jobs.php +29 -5
  40. includes/widgets/class-wp-job-manager-widget-recent-jobs.php +2 -0
  41. languages/wp-job-manager.pot +492 -323
  42. lib/usage-tracking/class-usage-tracking-base.php +572 -0
  43. lib/usage-tracking/tests/support/class-usage-tracking-test-subclass.php +67 -0
  44. lib/usage-tracking/tests/support/wp-die-exception.php +18 -0
  45. lib/usage-tracking/tests/test-class-usage-tracking.php +528 -0
  46. readme.txt +21 -1
  47. templates/form-fields/date-field.php +22 -0
  48. templates/form-fields/recaptcha-field.php +24 -0
  49. templates/form-fields/textarea-field.php +2 -2
  50. templates/form-fields/uploaded-file-html.php +2 -3
  51. templates/job-dashboard.php +6 -4
  52. templates/job-submit.php +2 -1
  53. uninstall.php +4 -1
  54. wp-job-manager-functions.php +176 -2
  55. wp-job-manager.php +87 -7
assets/css/admin.css CHANGED
@@ -1 +1 @@
1
- .clearfix{zoom:1}.clearfix:after,.clearfix:before{content:"";display:table}.clearfix:after{clear:both}@font-face{font-family:job-manager;src:url(../font/job-manager.eot?4963673);src:url(../font/job-manager.eot?4963673#iefix) format('embedded-opentype'),url(../font/job-manager.woff?4963673) format('woff'),url(../font/job-manager.ttf?4963673) format('truetype'),url(../font/job-manager.svg?4963673#job-manager) format('svg');font-weight:400;font-style:normal}@font-face{font-family:jm-logo;src:url(../font/jm-logo/jm.eot?ycsbky);src:url(../font/jm-logo/jm.eot?#iefixycsbky) format('embedded-opentype'),url(../font/jm-logo/jm.woff?ycsbky) format('woff'),url(../font/jm-logo/jm.ttf?ycsbky) format('truetype'),url(../font/jm-logo/jm.svg?ycsbky#icomoon) format('svg');font-weight:400;font-style:normal}.jm-icon{font-family:job-manager!important;font-style:normal;font-weight:400;speak:none;display:inline-block;text-decoration:inherit;width:1em;text-align:center;font-variant:normal;text-transform:none;line-height:1em}.job-manager-settings-wrap .updated{display:none}.job-manager-settings-wrap .job-manager-updated{display:block;margin:1em 0 0}a.wpjm-activate-licence-link,a.wpjm-activate-licence-link:active,a.wpjm-activate-licence-link:hover,a.wpjm-activate-licence-link:link,a.wpjm-activate-licence-link:visited{color:#ff4500}.wpjm-licences{margin-top:10px}.wpjm-licences .licence-row{align-items:center;border:solid 1px #e2e0e2;display:flex;background-color:#fff;flex-wrap:wrap;min-height:82px;margin-bottom:20px;position:relative}.wpjm-licences .plugin-info{font-size:18px;flex-basis:320px;padding:0 20px;margin-right:10px}.wpjm-licences .plugin-info .plugin-author{font-size:12px}.wpjm-licences .plugin-licence{flex:1;flex-basis:40%;padding-bottom:5px}.wpjm-licences .plugin-licence label{white-space:nowrap}.widefat td.column-featured_job,.widefat td.column-filled,.widefat td.column-job_status{width:46px;text-align:left;padding-left:11px}.widefat th.column-featured_job,.widefat th.column-filled,.widefat th.column-job_status{width:1em}.widefat th.column-featured_job span,.widefat th.column-filled span,.widefat th.column-job_status span{display:block;width:1em;height:1em;line-height:1em;padding:1px 0 0 0;overflow:hidden}.widefat th.column-featured_job span:before,.widefat th.column-filled span:before,.widefat th.column-job_status span:before{content:'\e803';font-family:job-manager!important;font-style:normal;font-weight:400;speak:none;display:inline-block;text-decoration:inherit;width:1em;text-align:center;font-variant:normal;text-transform:none;line-height:1em}.widefat th.column-filled span:before{content:'\e807'}.widefat th.column-job_status span:before{content:'\e828'}.widefat .column-job_posted strong{display:block;margin-bottom:.2em}.widefat td.column-job_status span{position:relative;font-size:1em;line-height:1.5em;width:1em;height:0;padding:2em 0 0 0;overflow:hidden;display:block}.widefat td.column-job_status span:before{font-family:job-manager!important;font-style:normal;font-weight:400;speak:none;display:inline-block;text-decoration:inherit;width:1em;text-align:center;font-variant:normal;text-transform:none;line-height:1em;position:absolute;top:0;left:0;line-height:1.5em;vertical-align:middle;color:#999;content:'\e829'}.widefat td.column-job_status .status-trash:before{content:'\e82b';color:#a00}.widefat td.column-job_status .status-pending:before{content:'\e82c';color:#ffba00}.widefat td.column-job_status .status-publish:before{content:'\e82f';color:#73a724}.widefat td.column-job_status .status-expired:before{content:'\e82e';color:#a00}.widefat .column-job_listing_type{text-align:left;width:6em;word-wrap:normal!important}.widefat .column-job_listing_type .job-type{color:#fff;padding:4px;font-size:11px;-webkit-border-radius:2px;border-radius:2px;display:block;background-color:#f08d3c;text-align:center}.widefat .column-job_listing_type .full-time{background-color:#90da36}.widefat .column-job_listing_type .part-time{background-color:#f08d3c}.widefat .column-job_listing_type .temporary{background-color:#d93674}.widefat .column-job_listing_type .freelance{background-color:#39c}.widefat .column-job_listing_type .internship{background-color:#6033cc}.widefat th.column-job_position{width:20%}.widefat td.column-job_position{width:20%;height:34px}.widefat td.column-job_position .job_position{position:relative;padding-right:50px!important}.widefat td.column-job_position a.job_title{font-weight:700}.widefat td.column-job_position img{width:32px;height:32px;position:absolute;right:7px;top:0;-webkit-border-radius:50%;border-radius:50%;box-shadow:0 1px 0 1px rgba(0,0,0,.1);-webkit-box-shadow:0 1px 0 1px rgba(0,0,0,.1);-moz-box-shadow:0 1px 0 1px rgba(0,0,0,.1);border:1px solid #fff}.widefat td.column-job_position .company{margin-top:.2em;display:block;padding-top:2px;color:#bbb}.widefat .column-job_location{width:10%}.widefat .column-job_actions{text-align:right;width:128px}.widefat .column-job_actions strong{display:block;margin-bottom:.2em}.widefat .column-job_actions .actions{padding-top:2px}.widefat .column-job_actions a.button{display:inline-block;margin:0 0 2px 4px;cursor:pointer;padding:0 6px!important;font-size:1em!important;line-height:2em!important;overflow:hidden}.widefat .column-job_actions a.button-icon{width:2em!important;padding:0!important}.widefat .column-job_actions a.button-icon:before{font-family:job-manager!important;font-style:normal;font-weight:400;speak:none;display:inline-block;text-decoration:inherit;width:1em;text-align:center;font-variant:normal;text-transform:none;line-height:1em;float:left;width:2em!important;line-height:2em}.widefat .column-job_actions .icon-view:before{content:'\e805'}.widefat .column-job_actions .icon-edit:before{content:'\e804'}.widefat .column-job_actions .icon-delete:before{content:'\e82b'}.widefat .column-job_actions .icon-approve:before{content:'\e802'}.wp_job_manager_meta_data{zoom:1}.wp_job_manager_meta_data:after,.wp_job_manager_meta_data:before{content:"";display:table}.wp_job_manager_meta_data:after{clear:both}.wp_job_manager_meta_data .form-field{width:50%;line-height:2em;float:left;box-sizing:border-box;padding:0 12px 0 0;margin:0 0 12px;clear:both}.wp_job_manager_meta_data .form-field:nth-child(even){float:right;padding:0 0 0 12px;clear:right}.wp_job_manager_meta_data .form-field:nth-last-child(-n+2){margin-bottom:0;padding-bottom:0;border-bottom:0}.wp_job_manager_meta_data .form-field label{vertical-align:middle;display:block;font-weight:700;margin:0}.wp_job_manager_meta_data .form-field .tips{cursor:help;float:right;font-weight:400;color:#999}.wp_job_manager_meta_data .form-field input{width:100%;margin:1px 0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;vertical-align:middle}.wp_job_manager_meta_data .form-field input.checkbox,.wp_job_manager_meta_data .form-field input.radio{width:auto;margin:4px 2px;display:inline-block}.wp_job_manager_meta_data .form-field .description{display:block;color:#999}.wp_job_manager_meta_data .form-field.form-field-checkbox .description{display:inline}.wp_job_manager_meta_data .form-field .file_url input{width:75%}.wp_job_manager_meta_data .form-field .button{margin-left:4px}.wp_job_manager_meta_data .form-field .file_no_url{-o-animation:flash .3s linear infinite alternate;-webkit-animation:flash .3s linear infinite alternate;-moz-animation:flash .3s linear infinite alternate;animation:flash .3s linear infinite alternate}@-o-keyframes flash{from{background-color:unset}to{background-color:#dc3232}}@-ms-keyframes flash{from{background-color:unset}to{background-color:#dc3232}}@-moz-keyframes flash{from{background-color:unset}to{background-color:#dc3232}}@-webkit-keyframes flash{from{background-color:unset}to{background-color:#dc3232}}@keyframes flash{from{background-color:unset}to{background-color:#dc3232}}#tiptip_holder{display:none;position:absolute;top:0;left:0;z-index:99999}#tiptip_holder.tip_top{padding-bottom:5px}#tiptip_holder.tip_bottom{padding-top:5px}#tiptip_holder.tip_right{padding-left:5px}#tiptip_holder.tip_left{padding-right:5px}#tiptip_content{font-size:11px;color:#fff;padding:4px 8px;background:#464646;border-radius:3px;-webkit-border-radius:3px;-moz-border-radius:3px;box-shadow:1px 1px 3px rgba(0,0,0,.1);-webkit-box-shadow:1px 1px 3px rgba(0,0,0,.1);-moz-box-shadow:1px 1px 3px rgba(0,0,0,.1);text-align:center}#tiptip_content code{background:#999;padding:1px}#tiptip_arrow,#tiptip_arrow_inner{position:absolute;border-color:transparent;border-style:solid;border-width:6px;height:0;width:0}#tiptip_holder.tip_top #tiptip_arrow_inner{margin-top:-7px;margin-left:-6px;border-top-color:#464646}#tiptip_holder.tip_bottom #tiptip_arrow_inner{margin-top:-5px;margin-left:-6px;border-bottom-color:#464646}#tiptip_holder.tip_right #tiptip_arrow_inner{margin-top:-6px;margin-left:-5px;border-right-color:#464646}#tiptip_holder.tip_left #tiptip_arrow_inner{margin-top:-6px;margin-left:-7px;border-left-color:#464646}.wp_job_manager_addons_wrap #job-manager-addons-banner{position:relative;background:#d85677;padding:0 2em 0 5em;color:#fff;margin:10px .25% 20px 0;border-color:rgba(0,0,0,.1);overflow:hidden}.wp_job_manager_addons_wrap #job-manager-addons-banner strong{font-size:1.25em;line-height:.8em;text-shadow:0 2px 0 rgba(0,0,0,.1);font-weight:400;float:left;padding:1.6em 0}.wp_job_manager_addons_wrap #job-manager-addons-banner a.button{color:#fff;text-decoration:none;font-weight:700;float:right;background:#d85677;border:1px solid #fff;line-height:1em;padding:1em;margin:1em 0;text-shadow:0 2px 0 rgba(0,0,0,.1);box-shadow:0 2px 0 rgba(0,0,0,.1);height:auto;position:relative}.wp_job_manager_addons_wrap #job-manager-addons-banner:before{display:inline-block;-webkit-font-smoothing:antialiased;vertical-align:top;font-family:jm-logo;content:"\e600";top:.02em;left:0;position:absolute;text-shadow:0 2px 0 rgba(0,0,0,.1);font-size:5em;font-weight:400;text-align:center;width:1em;height:1em;line-height:1em}.wp_job_manager_addons_wrap .products{overflow:hidden}.wp_job_manager_addons_wrap .products li{display:inline-block;margin:0 1% 10px 0!important;padding:0;vertical-align:top;width:24%;min-width:250px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;border:1px solid #ddd;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.2),inset 0 -1px 0 rgba(0,0,0,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.2),inset 0 -1px 0 rgba(0,0,0,.1);overflow:hidden;position:relative;opacity:.8}.wp_job_manager_addons_wrap .products li:nth-child(4n+0){margin-right:0!important}.wp_job_manager_addons_wrap .products li a{color:inherit;text-decoration:none}.wp_job_manager_addons_wrap .products li img{width:100%;height:auto;display:block;padding:0;margin:0;background:#fff;border-bottom:1px solid rgba(0,0,0,.1)}.wp_job_manager_addons_wrap .products li h2{margin:0!important;padding:10px 0!important;line-height:1;background:rgba(255,255,255,.6);border-bottom:1px solid rgba(0,0,0,.1);color:#000;text-align:center;position:absolute;width:100%;top:0;left:0;font-size:16px;text-shadow:none;display:none}.wp_job_manager_addons_wrap .products li:focus,.wp_job_manager_addons_wrap .products li:hover{opacity:1}.wp_job_manager_addons_wrap .products li:focus h2,.wp_job_manager_addons_wrap .products li:hover h2{display:block}.wp_job_manager_addons_wrap .products li .third_party{display:none}.wp_job_manager_addons_wrap .products li p{padding:20px!important;margin:0!important;border-top:1px solid #f1f1f1}.wp_job_manager_addons_wrap .products li .price{display:none}.rtl .widefat .column-job_actions a.button-icon:before{float:right}.rtl .wp_job_manager_meta_data p{padding:0 20% 0 0}.rtl .wp_job_manager_meta_data label{left:auto;right:0}@media only screen and (max-width:782px){.wpjm-licences .plugin-info{padding:10px}.wpjm-licences .plugin-licence{padding:10px}.widefat .job_position.column-primary{display:table-cell!important}.widefat .toggle-row:before{top:5px}.widefat .column-job_actions{text-align:left}.widefat .column-job_actions a.button-icon:before{float:left}.rtl .widefat .column-job_actions{text-align:right}.rtl .widefat .column-job_actions a.button-icon:before{float:right}.wp_job_manager_meta_data .form-field{width:100%;padding:0}.wp_job_manager_meta_data .form-field:nth-child(even){float:none;padding:0;margin-bottom:12px;clear:both}.wp_job_manager_meta_data .form-field:nth-last-child(-n+2){float:none;padding:0;margin-bottom:12px;clear:both}}
1
+ .clearfix{zoom:1}.clearfix:after,.clearfix:before{content:"";display:table}.clearfix:after{clear:both}@font-face{font-family:job-manager;src:url(../font/job-manager.eot?4963673);src:url(../font/job-manager.eot?4963673#iefix) format('embedded-opentype'),url(../font/job-manager.woff?4963673) format('woff'),url(../font/job-manager.ttf?4963673) format('truetype'),url(../font/job-manager.svg?4963673#job-manager) format('svg');font-weight:400;font-style:normal}@font-face{font-family:jm-logo;src:url(../font/jm-logo/jm.eot?ycsbky);src:url(../font/jm-logo/jm.eot?#iefixycsbky) format('embedded-opentype'),url(../font/jm-logo/jm.woff?ycsbky) format('woff'),url(../font/jm-logo/jm.ttf?ycsbky) format('truetype'),url(../font/jm-logo/jm.svg?ycsbky#icomoon) format('svg');font-weight:400;font-style:normal}.jm-icon{font-family:job-manager!important;font-style:normal;font-weight:400;speak:none;display:inline-block;text-decoration:inherit;width:1em;text-align:center;font-variant:normal;text-transform:none;line-height:1em}.job-manager-settings-wrap .updated{display:none}.job-manager-settings-wrap .job-manager-updated{display:block;margin:1em 0 0}a.wpjm-activate-licence-link,a.wpjm-activate-licence-link:active,a.wpjm-activate-licence-link:hover,a.wpjm-activate-licence-link:link,a.wpjm-activate-licence-link:visited{color:#ff4500}.wpjm-licences{margin-top:10px}.wpjm-licences .licence-row{align-items:center;border:solid 1px #e2e0e2;display:flex;background-color:#fff;flex-wrap:wrap;min-height:82px;margin-bottom:20px;position:relative}.wpjm-licences .plugin-info{font-size:18px;flex-basis:320px;padding:0 20px;margin-right:10px}.wpjm-licences .plugin-info .plugin-author{font-size:12px}.wpjm-licences .plugin-licence{flex:1;flex-basis:40%;padding-bottom:5px}.wpjm-licences .plugin-licence label{white-space:nowrap}.widefat td.column-featured_job,.widefat td.column-filled,.widefat td.column-job_status{width:46px;text-align:left;padding-left:11px}.widefat th.column-featured_job,.widefat th.column-filled,.widefat th.column-job_status{width:1em}.widefat th.column-featured_job span,.widefat th.column-filled span,.widefat th.column-job_status span{display:block;width:1em;height:1em;line-height:1em;padding:1px 0 0 0;overflow:hidden}.widefat th.column-featured_job span:before,.widefat th.column-filled span:before,.widefat th.column-job_status span:before{content:'\e803';font-family:job-manager!important;font-style:normal;font-weight:400;speak:none;display:inline-block;text-decoration:inherit;width:1em;text-align:center;font-variant:normal;text-transform:none;line-height:1em}.widefat th.column-filled span:before{content:'\e807'}.widefat th.column-job_status span:before{content:'\e828'}.widefat .column-job_posted strong{display:block;margin-bottom:.2em}.widefat td.column-job_status span{position:relative;font-size:1em;line-height:1.5em;width:1em;height:0;padding:2em 0 0 0;overflow:hidden;display:block}.widefat td.column-job_status span:before{font-family:job-manager!important;font-style:normal;font-weight:400;speak:none;display:inline-block;text-decoration:inherit;width:1em;text-align:center;font-variant:normal;text-transform:none;line-height:1em;position:absolute;top:0;left:0;line-height:1.5em;vertical-align:middle;color:#999;content:'\e829'}.widefat td.column-job_status .status-trash:before{content:'\e82b';color:#a00}.widefat td.column-job_status .status-pending:before{content:'\e82c';color:#ffba00}.widefat td.column-job_status .status-publish:before{content:'\e82f';color:#73a724}.widefat td.column-job_status .status-expired:before{content:'\e82e';color:#a00}.widefat .column-job_listing_type{text-align:left;width:6em;word-wrap:normal!important}.widefat .column-job_listing_type .job-type{color:#fff;padding:4px;font-size:11px;-webkit-border-radius:2px;border-radius:2px;display:block;background-color:#f08d3c;text-align:center}.widefat .column-job_listing_type .full-time{background-color:#90da36}.widefat .column-job_listing_type .part-time{background-color:#f08d3c}.widefat .column-job_listing_type .temporary{background-color:#d93674}.widefat .column-job_listing_type .freelance{background-color:#39c}.widefat .column-job_listing_type .internship{background-color:#6033cc}.widefat th.column-job_position{width:20%}.widefat td.column-job_position{width:20%;height:34px}.widefat td.column-job_position .job_position{position:relative;padding-right:50px!important}.widefat td.column-job_position a.job_title{font-weight:700}.widefat td.column-job_position img{width:32px;height:32px;position:absolute;right:7px;top:0;-webkit-border-radius:50%;border-radius:50%;box-shadow:0 1px 0 1px rgba(0,0,0,.1);-webkit-box-shadow:0 1px 0 1px rgba(0,0,0,.1);-moz-box-shadow:0 1px 0 1px rgba(0,0,0,.1);border:1px solid #fff}.widefat td.column-job_position .company{margin-top:.2em;display:block;padding-top:2px;color:#bbb}.widefat .column-job_location{width:10%}.widefat .column-job_actions{text-align:right;width:128px}.widefat .column-job_actions strong{display:block;margin-bottom:.2em}.widefat .column-job_actions .actions{padding-top:2px}.widefat .column-job_actions a.button{display:inline-block;margin:0 0 2px 4px;cursor:pointer;padding:0 6px!important;font-size:1em!important;line-height:2em!important;overflow:hidden}.widefat .column-job_actions a.button-icon{width:2em!important;padding:0!important}.widefat .column-job_actions a.button-icon:before{font-family:job-manager!important;font-style:normal;font-weight:400;speak:none;display:inline-block;text-decoration:inherit;width:1em;text-align:center;font-variant:normal;text-transform:none;line-height:1em;float:left;width:2em!important;line-height:2em}.widefat .column-job_actions .icon-view:before{content:'\e805'}.widefat .column-job_actions .icon-edit:before{content:'\e804'}.widefat .column-job_actions .icon-delete:before{content:'\e82b'}.widefat .column-job_actions .icon-approve:before{content:'\e802'}.wp_job_manager_meta_data{zoom:1}.wp_job_manager_meta_data:after,.wp_job_manager_meta_data:before{content:"";display:table}.wp_job_manager_meta_data:after{clear:both}.wp_job_manager_meta_data .form-field{width:50%;line-height:2em;float:left;box-sizing:border-box;padding:0 12px 0 0;margin:0 0 12px;clear:both}.wp_job_manager_meta_data .form-field:nth-child(even){float:right;padding:0 0 0 12px;clear:right}.wp_job_manager_meta_data .form-field:nth-last-child(-n+2){margin-bottom:0;padding-bottom:0;border-bottom:0}.wp_job_manager_meta_data .form-field label{vertical-align:middle;display:block;font-weight:700;margin:0}.wp_job_manager_meta_data .form-field .tips{cursor:help;float:right;font-weight:400;color:#999}.wp_job_manager_meta_data .form-field input{width:100%;margin:1px 0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;vertical-align:middle}.wp_job_manager_meta_data .form-field input.checkbox,.wp_job_manager_meta_data .form-field input.radio{width:auto;margin:4px 2px;display:inline-block}.wp_job_manager_meta_data .form-field .description{display:block;color:#999}.wp_job_manager_meta_data .form-field.form-field-checkbox .description{display:inline}.wp_job_manager_meta_data .form-field .file_url input{width:75%}.wp_job_manager_meta_data .form-field .button{margin-left:4px}.wp_job_manager_meta_data .form-field .file_no_url{-o-animation:flash .3s linear infinite alternate;-webkit-animation:flash .3s linear infinite alternate;-moz-animation:flash .3s linear infinite alternate;animation:flash .3s linear infinite alternate}@-o-keyframes flash{from{background-color:unset}to{background-color:#dc3232}}@-ms-keyframes flash{from{background-color:unset}to{background-color:#dc3232}}@-moz-keyframes flash{from{background-color:unset}to{background-color:#dc3232}}@-webkit-keyframes flash{from{background-color:unset}to{background-color:#dc3232}}@keyframes flash{from{background-color:unset}to{background-color:#dc3232}}#tiptip_holder{display:none;position:absolute;top:0;left:0;z-index:99999}#tiptip_holder.tip_top{padding-bottom:5px}#tiptip_holder.tip_bottom{padding-top:5px}#tiptip_holder.tip_right{padding-left:5px}#tiptip_holder.tip_left{padding-right:5px}#tiptip_content{font-size:11px;color:#fff;padding:4px 8px;background:#464646;border-radius:3px;-webkit-border-radius:3px;-moz-border-radius:3px;box-shadow:1px 1px 3px rgba(0,0,0,.1);-webkit-box-shadow:1px 1px 3px rgba(0,0,0,.1);-moz-box-shadow:1px 1px 3px rgba(0,0,0,.1);text-align:center}#tiptip_content code{background:#999;padding:1px}#tiptip_arrow,#tiptip_arrow_inner{position:absolute;border-color:transparent;border-style:solid;border-width:6px;height:0;width:0}#tiptip_holder.tip_top #tiptip_arrow_inner{margin-top:-7px;margin-left:-6px;border-top-color:#464646}#tiptip_holder.tip_bottom #tiptip_arrow_inner{margin-top:-5px;margin-left:-6px;border-bottom-color:#464646}#tiptip_holder.tip_right #tiptip_arrow_inner{margin-top:-6px;margin-left:-5px;border-right-color:#464646}#tiptip_holder.tip_left #tiptip_arrow_inner{margin-top:-6px;margin-left:-7px;border-left-color:#464646}.wp_job_manager_add_ons_wrap .products{overflow:hidden}.wp_job_manager_add_ons_wrap .products li{float:left;margin:0 1em 1em 0!important;padding:0;vertical-align:top;width:350px}.wp_job_manager_add_ons_wrap .products li a{text-decoration:none;color:inherit;border:1px solid #ddd;display:block;min-height:220px;overflow:hidden;background:#f6f6f6;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.2),inset 0 -1px 0 rgba(0,0,0,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.2),inset 0 -1px 0 rgba(0,0,0,.1)}.wp_job_manager_add_ons_wrap .products li img{display:inline-block;width:auto;max-height:60px;max-width:90px;margin:0 5px 0 0;float:left}.wp_job_manager_add_ons_wrap .products li h2{margin:0!important;padding:20px!important;background:#fff;height:20px;font-size:16px}.wp_job_manager_add_ons_wrap .products li p{padding:20px!important;margin:0!important;border-top:1px solid #f1f1f1}.wp_job_manager_add_ons_wrap .products li .price{display:none}.rtl .widefat .column-job_actions a.button-icon:before{float:right}.rtl .wp_job_manager_meta_data p{padding:0 20% 0 0}.rtl .wp_job_manager_meta_data label{left:auto;right:0}@media only screen and (max-width:782px){.wpjm-licences .plugin-info{padding:10px}.wpjm-licences .plugin-licence{padding:10px}.widefat .job_position.column-primary{display:table-cell!important}.widefat .toggle-row:before{top:5px}.widefat .column-job_actions{text-align:left}.widefat .column-job_actions a.button-icon:before{float:left}.rtl .widefat .column-job_actions{text-align:right}.rtl .widefat .column-job_actions a.button-icon:before{float:right}.wp_job_manager_meta_data .form-field{width:100%;padding:0}.wp_job_manager_meta_data .form-field:nth-child(even){float:none;padding:0;margin-bottom:12px;clear:both}.wp_job_manager_meta_data .form-field:nth-last-child(-n+2){float:none;padding:0;margin-bottom:12px;clear:both}}
assets/css/admin.less CHANGED
@@ -383,122 +383,45 @@ a.wpjm-activate-licence-link:active {
383
  }
384
 
385
  /* Addons */
386
- .wp_job_manager_addons_wrap {
387
- #job-manager-addons-banner {
388
- position: relative;
389
- background: #d85677;
390
- padding: 0 2em 0 5em;
391
- color: #fff;
392
- margin: 10px .25% 20px 0;
393
- border-color: rgba(0,0,0,.1);
394
- overflow: hidden;
395
- strong {
396
- font-size: 1.25em;
397
- line-height: 1/1.25em;
398
- text-shadow: 0 2px 0 rgba(0,0,0,.1);
399
- font-weight: normal;
400
- float: left;
401
- padding: 1/1.25*2em 0;
402
- }
403
- a.button {
404
- color: #fff;
405
- text-decoration: none;
406
- font-weight: bold;
407
- float: right;
408
- background: #d85677;
409
- border: 1px solid #fff;
410
- line-height: 1em;
411
- padding: 1em;
412
- margin: 1em 0;
413
- text-shadow: 0 2px 0 rgba(0,0,0,.1);
414
- box-shadow: 0 2px 0 rgba(0,0,0,.1);
415
- height: auto;
416
- position: relative;
417
- }
418
- &:before {
419
- display: inline-block;
420
- -webkit-font-smoothing: antialiased;
421
- vertical-align: top;
422
- font-family: 'jm-logo';
423
- content: "\e600";
424
- top: .02em;
425
- left: 0;
426
- position: absolute;
427
- text-shadow: 0 2px 0 rgba(0,0,0,0.1);
428
- font-size: 5em;
429
- font-weight: normal;
430
- text-align: center;
431
- width: 1em;
432
- height: 1em;
433
- line-height: 1em;
434
- }
435
- }
436
  .products {
437
  overflow: hidden;
438
  li {
439
- display: inline-block;
440
- margin: 0 1% 10px 0 !important;
441
  padding: 0;
442
  vertical-align: top;
443
- width: 24%;
444
- min-width: 250px;
445
- -webkit-box-sizing: border-box; /* Safari/Chrome, other WebKit */
446
- -moz-box-sizing: border-box; /* Firefox, other Gecko */
447
- box-sizing: border-box; /* Opera/IE 8+ */
448
- border: 1px solid #ddd;
449
- -webkit-box-shadow:
450
- inset 0 1px 0 rgba(255,255,255,0.2),
451
- inset 0 -1px 0 rgba(0,0,0,0.1);
452
- box-shadow:
453
- inset 0 1px 0 rgba(255,255,255,0.2),
454
- inset 0 -1px 0 rgba(0,0,0,0.1);
455
- overflow: hidden;
456
- position: relative;
457
- opacity: 0.8;
458
- &:nth-child(4n+0) {
459
- margin-right: 0 !important;
460
- }
461
  a {
462
- color: inherit;
463
  text-decoration: none;
 
 
 
 
 
 
 
 
464
  }
465
  img {
466
- width: 100%;
467
- height: auto;
468
- display: block;
469
- padding: 0;
470
- margin: 0;
471
- background: #fff;
472
- border-bottom: 1px solid rgba(0,0,0,0.1);
473
  }
474
  h2 {
475
- margin: 0 !important;
476
- padding: 10px 0 !important;
477
- line-height: 1;
478
- background: rgba(255,255,255,0.6);
479
- border-bottom: 1px solid rgba(0,0,0,0.1);
480
- color: #000;
481
- text-align: center;
482
- position: absolute;
483
- width: 100%;
484
- top: 0;
485
- left: 0;
486
  font-size: 16px;
487
- text-shadow: none;
488
- display: none;
489
- }
490
- &:hover, &:focus {
491
- opacity: 1;
492
- h2 {
493
- display: block;
494
- }
495
- }
496
- .third_party {
497
- display: none;
498
  }
499
  p {
500
- padding: 20px !important;
501
- margin: 0 !important;
502
  border-top: 1px solid #f1f1f1;
503
  }
504
  .price {
383
  }
384
 
385
  /* Addons */
386
+ .wp_job_manager_add_ons_wrap {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
387
  .products {
388
  overflow: hidden;
389
  li {
390
+ float: left;
391
+ margin: 0 1em 1em 0!important;
392
  padding: 0;
393
  vertical-align: top;
394
+ width: 350px;
395
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
396
  a {
 
397
  text-decoration: none;
398
+ color: inherit;
399
+ border: 1px solid #ddd;
400
+ display: block;
401
+ min-height: 220px;
402
+ overflow: hidden;
403
+ background: #f6f6f6;
404
+ -webkit-box-shadow: inset 0 1px 0 rgba(255,255,255,.2), inset 0 -1px 0 rgba(0,0,0,.1);
405
+ box-shadow: inset 0 1px 0 rgba(255,255,255,.2), inset 0 -1px 0 rgba(0,0,0,.1);
406
  }
407
  img {
408
+ display: inline-block;
409
+ width: auto;
410
+ max-height: 60px;
411
+ max-width: 90px;
412
+ margin: 0 5px 0 0;
413
+ float: left;
 
414
  }
415
  h2 {
416
+ margin: 0!important;
417
+ padding: 20px!important;
418
+ background: #fff;
419
+ height: 20px;
 
 
 
 
 
 
 
420
  font-size: 16px;
 
 
 
 
 
 
 
 
 
 
 
421
  }
422
  p {
423
+ padding: 20px!important;
424
+ margin: 0!important;
425
  border-top: 1px solid #f1f1f1;
426
  }
427
  .price {
assets/css/frontend.css CHANGED
@@ -1 +1 @@
1
- .clearfix{zoom:1}.clearfix:after,.clearfix:before{content:"";display:table}.clearfix:after{clear:both}@font-face{font-family:job-manager;src:url(../font/job-manager.eot?4963673);src:url(../font/job-manager.eot?4963673#iefix) format('embedded-opentype'),url(../font/job-manager.woff?4963673) format('woff'),url(../font/job-manager.ttf?4963673) format('truetype'),url(../font/job-manager.svg?4963673#job-manager) format('svg');font-weight:400;font-style:normal}@font-face{font-family:jm-logo;src:url(../font/jm-logo/jm.eot?ycsbky);src:url(../font/jm-logo/jm.eot?#iefixycsbky) format('embedded-opentype'),url(../font/jm-logo/jm.woff?ycsbky) format('woff'),url(../font/jm-logo/jm.ttf?ycsbky) format('truetype'),url(../font/jm-logo/jm.svg?ycsbky#icomoon) format('svg');font-weight:400;font-style:normal}.jm-icon{font-family:job-manager!important;font-style:normal;font-weight:400;speak:none;display:inline-block;text-decoration:inherit;width:1em;text-align:center;font-variant:normal;text-transform:none;line-height:1em}.display-icon{display:inline-block;width:16px;height:16px;-webkit-font-smoothing:antialiased;font-family:job-manager!important;text-decoration:none;font-weight:400;font-style:normal;vertical-align:top;font-size:16px;margin:0 2px 0 0}.job-manager-error,.job-manager-info,.job-manager-message{padding:1em 2em 1em 3.5em!important;margin:0 0 2em!important;position:relative;background-color:#fff;color:#666;border-top:3px solid #999;list-style:none outside!important;width:auto;zoom:1;box-shadow:0 1px 1px rgba(0,0,0,.2)}.job-manager-error:after,.job-manager-error:before,.job-manager-info:after,.job-manager-info:before,.job-manager-message:after,.job-manager-message:before{content:"";display:table}.job-manager-error:after,.job-manager-info:after,.job-manager-message:after{clear:both}.job-manager-error:before,.job-manager-info:before,.job-manager-message:before{content:"";font-family:sans-serif;display:inline-block;position:absolute;top:1em;left:1.5em}.job-manager-error li,.job-manager-info li,.job-manager-message li{list-style:none outside!important;padding-left:0!important;margin-left:0!important}.job-manager-error.job-manager-message,.job-manager-info.job-manager-message,.job-manager-message.job-manager-message{border-top-color:#8fae1b}.job-manager-error.job-manager-message:before,.job-manager-info.job-manager-message:before,.job-manager-message.job-manager-message:before{color:#8fae1b;content:"\2713"}.job-manager-error.job-manager-info,.job-manager-info.job-manager-info,.job-manager-message.job-manager-info{border-top-color:#1e85be}.job-manager-error.job-manager-info:before,.job-manager-info.job-manager-info:before,.job-manager-message.job-manager-info:before{color:#1e85be;content:"i";font-family:Times,Georgia,serif;font-style:italic}.job-manager-error.job-manager-error,.job-manager-info.job-manager-error,.job-manager-message.job-manager-error{border-top-color:#b81c23}.job-manager-error.job-manager-error:before,.job-manager-info.job-manager-error:before,.job-manager-message.job-manager-error:before{color:#b81c23;content:"\00d7";font-weight:700}.job-manager-form fieldset{margin:0 0 1em 0;padding:0 0 1em 0;line-height:2em;border:0;border-bottom:1px solid #eee;zoom:1}.job-manager-form fieldset:after,.job-manager-form fieldset:before{content:"";display:table}.job-manager-form fieldset:after{clear:both}.job-manager-form fieldset label{display:block;margin:0;width:29%;float:left;vertical-align:middle}.job-manager-form fieldset label small{opacity:.75;font-size:.83em}.job-manager-form fieldset div.field{width:70%;float:right;vertical-align:middle}.job-manager-form fieldset .wp-editor-container{border:1px solid #ccc;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.job-manager-form fieldset .account-sign-in .button{margin-right:.5em}.job-manager-form fieldset .account-sign-in .button:before{display:inline-block;width:16px;height:16px;-webkit-font-smoothing:antialiased;font-family:job-manager!important;text-decoration:none;font-weight:400;font-style:normal;vertical-align:top;font-size:16px;margin:0 2px 0 0;content:'\e808'}.job-manager-form fieldset abbr.required{color:red;font-weight:700;border:0}.job-manager-form fieldset input.input-text,.job-manager-form fieldset select,.job-manager-form fieldset textarea{margin:0;vertical-align:middle;width:100%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.job-manager-form fieldset small.description{opacity:.75;font-size:.83em;margin:1.2em 0 0 0;display:block;line-height:1.2em}.job-manager-form fieldset .job-manager-uploaded-files{display:table}.job-manager-form fieldset .job-manager-uploaded-files .job-manager-uploaded-file{line-height:2em;font-style:italic;margin-bottom:1em;display:block}.job-manager-form fieldset .job-manager-uploaded-files .job-manager-uploaded-file .job-manager-uploaded-file-preview img{height:64px;margin:0;vertical-align:top}.job-manager-form fieldset .job-manager-uploaded-files .job-manager-uploaded-file .job-manager-uploaded-file-preview a{line-height:64px;display:inline-block;padding:0 0 0 1em}.job-manager-form fieldset .job-manager-uploaded-files .job-manager-uploaded-file .job-manager-uploaded-file-name{display:block}.job-manager-form .submit-job{padding:1em 0}.job-manager-form .job-manager-term-checklist{list-style:none outside;max-height:200px;overflow:auto;margin:0}.job-manager-form .job-manager-term-checklist li{list-style:none outside;margin:0;display:block;float:none}.job-manager-form .job-manager-term-checklist li label{width:auto;float:none}.job-manager-form .job-manager-term-checklist li li{margin:0 0 0 2em}div.job_listings{margin-bottom:1em}div.job_listings ul.job_listings{margin:0}.rp4wp-related-job_listing>ul,ul.job_listings{padding:0;margin:0;border-top:1px solid #eee}.rp4wp-related-job_listing>ul.loading,ul.job_listings.loading{min-height:96px;border-bottom:1px solid #eee;background:url(../images/ajax-loader.gif) no-repeat center 32px}.rp4wp-related-job_listing>ul li.job_listing,.rp4wp-related-job_listing>ul li.no_job_listings_found,ul.job_listings li.job_listing,ul.job_listings li.no_job_listings_found{list-style:none outside;padding:0;margin:0;border-bottom:1px solid #eee}.rp4wp-related-job_listing>ul li.job_listing.job_position_filled a,.rp4wp-related-job_listing>ul li.no_job_listings_found.job_position_filled a,ul.job_listings li.job_listing.job_position_filled a,ul.job_listings li.no_job_listings_found.job_position_filled a{opacity:.25}.rp4wp-related-job_listing>ul li.job_listing.no_job_listings_found,.rp4wp-related-job_listing>ul li.no_job_listings_found.no_job_listings_found,ul.job_listings li.job_listing.no_job_listings_found,ul.job_listings li.no_job_listings_found.no_job_listings_found{padding:1em;border-bottom:1px solid #eee}.rp4wp-related-job_listing>ul li.job_listing a,.rp4wp-related-job_listing>ul li.no_job_listings_found a,ul.job_listings li.job_listing a,ul.job_listings li.no_job_listings_found a{display:block;padding:1em 1em 1em 2em;border:0;overflow:hidden;zoom:1;position:relative;line-height:1.5em;text-decoration:none}.rp4wp-related-job_listing>ul li.job_listing a:focus,.rp4wp-related-job_listing>ul li.job_listing a:hover,.rp4wp-related-job_listing>ul li.no_job_listings_found a:focus,.rp4wp-related-job_listing>ul li.no_job_listings_found a:hover,ul.job_listings li.job_listing a:focus,ul.job_listings li.job_listing a:hover,ul.job_listings li.no_job_listings_found a:focus,ul.job_listings li.no_job_listings_found a:hover{background-color:#fcfcfc}.rp4wp-related-job_listing>ul li.job_listing a img.company_logo,.rp4wp-related-job_listing>ul li.no_job_listings_found a img.company_logo,ul.job_listings li.job_listing a img.company_logo,ul.job_listings li.no_job_listings_found a img.company_logo{width:42px;height:42px;position:absolute;left:1em;float:left;margin-right:1em;vertical-align:middle;box-shadow:none}.rp4wp-related-job_listing>ul li.job_listing a div.location,.rp4wp-related-job_listing>ul li.job_listing a div.position,.rp4wp-related-job_listing>ul li.job_listing a ul.meta,.rp4wp-related-job_listing>ul li.no_job_listings_found a div.location,.rp4wp-related-job_listing>ul li.no_job_listings_found a div.position,.rp4wp-related-job_listing>ul li.no_job_listings_found a ul.meta,ul.job_listings li.job_listing a div.location,ul.job_listings li.job_listing a div.position,ul.job_listings li.job_listing a ul.meta,ul.job_listings li.no_job_listings_found a div.location,ul.job_listings li.no_job_listings_found a div.position,ul.job_listings li.no_job_listings_found a ul.meta{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.rp4wp-related-job_listing>ul li.job_listing a div.position,.rp4wp-related-job_listing>ul li.no_job_listings_found a div.position,ul.job_listings li.job_listing a div.position,ul.job_listings li.no_job_listings_found a div.position{float:left;width:55%;padding:0 0 0 42px;line-height:1.5em}.rp4wp-related-job_listing>ul li.job_listing a div.position h3,.rp4wp-related-job_listing>ul li.no_job_listings_found a div.position h3,ul.job_listings li.job_listing a div.position h3,ul.job_listings li.no_job_listings_found a div.position h3{margin:0;padding:0;line-height:inherit;font-size:inherit}.rp4wp-related-job_listing>ul li.job_listing a div.position .company,.rp4wp-related-job_listing>ul li.no_job_listings_found a div.position .company,ul.job_listings li.job_listing a div.position .company,ul.job_listings li.no_job_listings_found a div.position .company{color:#999}.rp4wp-related-job_listing>ul li.job_listing a div.position .company .tagline,.rp4wp-related-job_listing>ul li.no_job_listings_found a div.position .company .tagline,ul.job_listings li.job_listing a div.position .company .tagline,ul.job_listings li.no_job_listings_found a div.position .company .tagline{margin-left:.5em}.rp4wp-related-job_listing>ul li.job_listing a div.location,.rp4wp-related-job_listing>ul li.no_job_listings_found a div.location,ul.job_listings li.job_listing a div.location,ul.job_listings li.no_job_listings_found a div.location{float:left;text-align:left;width:25%;padding:0 0 0 1em;color:#999;line-height:1.5em}.rp4wp-related-job_listing>ul li.job_listing a .meta,.rp4wp-related-job_listing>ul li.no_job_listings_found a .meta,ul.job_listings li.job_listing a .meta,ul.job_listings li.no_job_listings_found a .meta{float:right;text-align:right;width:20%;padding:0 0 0 1em;margin:0;line-height:1.5em;color:#999;list-style:none outside}.rp4wp-related-job_listing>ul li.job_listing a .meta li,.rp4wp-related-job_listing>ul li.no_job_listings_found a .meta li,ul.job_listings li.job_listing a .meta li,ul.job_listings li.no_job_listings_found a .meta li{list-style:none outside;display:block;margin:0}.rp4wp-related-job_listing>ul li.job_listing a .meta .job-type,.rp4wp-related-job_listing>ul li.no_job_listings_found a .meta .job-type,ul.job_listings li.job_listing a .meta .job-type,ul.job_listings li.no_job_listings_found a .meta .job-type{font-weight:700}.rp4wp-related-job_listing>ul li.job_listing.job_position_featured a,.rp4wp-related-job_listing>ul li.no_job_listings_found.job_position_featured a,ul.job_listings li.job_listing.job_position_featured a,ul.job_listings li.no_job_listings_found.job_position_featured a{background:#fefee5}.rp4wp-related-job_listing>ul li.job_listing.job_position_featured a:focus,.rp4wp-related-job_listing>ul li.job_listing.job_position_featured a:hover,.rp4wp-related-job_listing>ul li.no_job_listings_found.job_position_featured a:focus,.rp4wp-related-job_listing>ul li.no_job_listings_found.job_position_featured a:hover,ul.job_listings li.job_listing.job_position_featured a:focus,ul.job_listings li.job_listing.job_position_featured a:hover,ul.job_listings li.no_job_listings_found.job_position_featured a:focus,ul.job_listings li.no_job_listings_found.job_position_featured a:hover{background-color:#fefed8}.widget ul.job_listings li.job_listing a{padding:1em 0}.widget ul.job_listings li.job_listing .position{float:none;width:auto;padding:0}.widget ul.job_listings li.job_listing ul.meta{float:none;width:auto;padding:0;margin:0;text-align:left}.widget ul.job_listings li.job_listing ul.meta li{float:none;display:inline;padding:0;margin:0 .5em 0 0;font-weight:400}.widget ul.job_listings li.job_listing ul.meta li:after{padding:0 0 0 .5em;content:"\2023"}.widget ul.job_listings li.job_listing ul.meta li:last-child:after{content:''}.job-manager .job-type,.job-types .job-type,.job_listing .job-type{color:#f08d3c}.job-manager .full-time,.job-types .full-time,.job_listing .full-time{color:#90da36}.job-manager .part-time,.job-types .part-time,.job_listing .part-time{color:#f08d3c}.job-manager .temporary,.job-types .temporary,.job_listing .temporary{color:#d93674}.job-manager .freelance,.job-types .freelance,.job_listing .freelance{color:#39c}.job-manager .internship,.job-types .internship,.job_listing .internship{color:#6033cc}.single_job_listing .company{position:relative;border:1px solid #eee;padding:1em;margin:0 0 2em;display:block;clear:both;min-height:3em;box-shadow:0 1px 1px rgba(0,0,0,.1)}.single_job_listing .company img{width:3em;height:3em;position:absolute;left:1em;float:left;vertical-align:middle;box-shadow:none}.single_job_listing .company .name{margin:0 0 0 3em;padding:0 0 0 1em;line-height:1.5em}.single_job_listing .company .name a{float:right;margin-left:1em}.single_job_listing .company .tagline{display:block;margin:0 0 0 42px;padding:0 0 0 1em;line-height:1.5em;font-style:italic;color:#999}.single_job_listing .company .website:before{display:inline-block;width:16px;height:16px;-webkit-font-smoothing:antialiased;font-family:job-manager!important;text-decoration:none;font-weight:400;font-style:normal;vertical-align:top;font-size:16px;margin:0 2px 0 0;content:'\e809'}.single_job_listing .company .company_twitter:before{display:inline-block;width:16px;height:16px;-webkit-font-smoothing:antialiased;font-family:job-manager!important;text-decoration:none;font-weight:400;font-style:normal;vertical-align:top;font-size:16px;margin:0 2px 0 0;content:'\e80a'}.single_job_listing .company .company_video{border-top:1px solid #eee;padding:1em 0 0;margin:1em 0 0 0;position:relative;padding-bottom:56.25%;padding-top:30px;height:0;overflow:hidden}.single_job_listing .company .company_video embed,.single_job_listing .company .company_video iframe,.single_job_listing .company .company_video object{position:absolute;top:0;left:0;width:100%;height:100%;margin:0;display:block}.single_job_listing .meta{list-style:none outside;padding:0;margin:0 0 1.5em;overflow:hidden;zoom:1;clear:both}.single_job_listing .meta li{margin:0 1em 0 0;padding:.5em;float:left;line-height:1em;color:#999}.single_job_listing .meta .job-type{color:#fff;background-color:#f08d3c}.single_job_listing .meta .full-time{background-color:#90da36}.single_job_listing .meta .part-time{background-color:#f08d3c}.single_job_listing .meta .temporary{background-color:#d93674}.single_job_listing .meta .freelance{background-color:#39c}.single_job_listing .meta .internship{background-color:#6033cc}.single_job_listing .meta .listing-expired,.single_job_listing .meta .position-filled{color:#b81c23}.single_job_listing .meta .location:before{display:inline-block;width:16px;height:16px;-webkit-font-smoothing:antialiased;font-family:job-manager!important;text-decoration:none;font-weight:400;font-style:normal;vertical-align:top;font-size:16px;margin:0 2px 0 0;content:'\e81d'}.single_job_listing .meta .date-posted:before{display:inline-block;width:16px;height:16px;-webkit-font-smoothing:antialiased;font-family:job-manager!important;text-decoration:none;font-weight:400;font-style:normal;vertical-align:top;font-size:16px;margin:0 2px 0 0;content:'\e80f'}.single_job_listing .meta .listing-expired:before,.single_job_listing .meta .position-filled:before{display:inline-block;width:16px;height:16px;-webkit-font-smoothing:antialiased;font-family:job-manager!important;text-decoration:none;font-weight:400;font-style:normal;vertical-align:top;font-size:16px;margin:0 2px 0 0;content:'\e80e'}.single_job_listing .job_description{margin:0 0 1.5em}.job-manager-application-wrapper{clear:both;border:1px solid #eee;padding:.75em 1em 0;margin:1em 0;line-height:1.5em;display:block;position:relative;box-shadow:0 1px 1px rgba(0,0,0,.1)}.job-manager-application-wrapper .application,.single_job_listing .application{padding:0;margin:0 0 1em;overflow:hidden}.job-manager-application-wrapper .application .application_button,.job-manager-application-wrapper .application .application_details,.single_job_listing .application .application_button,.single_job_listing .application .application_details{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.job-manager-application-wrapper .application .application_button,.single_job_listing .application .application_button{text-align:center;font-size:1.1em;line-height:1em;display:inline-block;margin:0 .5em 0 0;padding:.90909091em 2em;outline:0}.job-manager-application-wrapper .application .application_details,.single_job_listing .application .application_details{clear:both;border:1px solid #eee;padding:.75em 1em 0;margin:1em 0;line-height:1.5em;display:block;position:relative;box-shadow:0 1px 1px rgba(0,0,0,.1)}.job-manager-application-wrapper .application .application_details p,.single_job_listing .application .application_details p{margin:0 0 .75em}.job-manager-application-wrapper .application .application_details:before,.single_job_listing .application .application_details:before{content:"";position:absolute;margin:-10px 0 0 0;top:0;left:5em;width:0;height:0;border-left:10px solid transparent;border-right:10px solid transparent;border-bottom:10px solid #eee}.job-manager-application-wrapper .application .application_details:after,.single_job_listing .application .application_details:after{content:"";position:absolute;margin:-9px 0 0 1px;left:5em;top:0;width:0;height:0;border-left:9px solid transparent;border-right:9px solid transparent;border-bottom:9px solid #fff}.job_filters{background:#eee;zoom:1}.job_filters:after,.job_filters:before{content:"";display:table}.job_filters:after{clear:both}.job_filters .search_jobs{padding:1em;zoom:1}.job_filters .search_jobs:after,.job_filters .search_jobs:before{content:"";display:table}.job_filters .search_jobs:after{clear:both}.job_filters .search_jobs div{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.job_filters .search_jobs div label{display:none}.job_filters .search_jobs div.filter_first,.job_filters .search_jobs div.search_keywords{float:left;padding-right:.5em;width:50%}.job_filters .search_jobs div.filter_last,.job_filters .search_jobs div.search_location{float:right;padding-left:.5em;width:50%}.job_filters .search_jobs div.filter_wide,.job_filters .search_jobs div.search_categories{padding-top:.5em;clear:both;width:100%}.job_filters .search_jobs div .showing_jobs a{padding:.25em}.job_filters .search_jobs div .showing_jobs a.active{background:#ddd;text-decoration:none}.job_filters .search_jobs input,.job_filters .search_jobs select{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;width:100%}.job_filters .job_types{list-style:none outside;margin:0;padding:0;font-size:.83em;background:#f9f9f9;border-top:1px solid #e5e5e5;zoom:1}.job_filters .job_types:after,.job_filters .job_types:before{content:"";display:table}.job_filters .job_types:after{clear:both}.job_filters .job_types li{margin:0;padding:.5em 1em;float:left;border-right:1px solid #eee}.job_filters .job_types li:last-child{border-right:0}.job_filters .showing_jobs{padding:.5em 1em;display:none;font-size:.83em;background:#f9f9f9;border-top:1px solid #e5e5e5}.job_filters .showing_jobs a{float:right;padding-left:10px;border:0}div.job_listings .job-manager-pagination{text-align:center;display:block;padding:1em 0 1em 0;border-bottom:1px solid #eee;line-height:1}div.job_listings .load_previous{border-top:1px solid #eee}div.job_listings .load_more_jobs+ul.job_listings{border-top:0}div.job_listings .load_more_jobs{text-align:center;display:block;padding:1em 1em 1em 2em;border-bottom:1px solid #eee;font-weight:700}div.job_listings .load_more_jobs.loading{background:url(../images/ajax-loader.gif) no-repeat center}div.job_listings .load_more_jobs.loading strong{visibility:hidden}div.job_listings .load_more_jobs:focus,div.job_listings .load_more_jobs:hover{background-color:#fcfcfc;border-bottom:1px solid #eee}.job_listing_preview{padding:0 1em 1em;border:5px solid #eee}.single-job_listing .entry-header .attachment-post-thumbnail,.single-job_listing .job_listing.has-post-thumbnail .post-thumbnail{display:none}.entry-content .job_listing_preview_title,.job_listing_preview_title{padding:.5em 1em;vertical-align:middle;position:relative;background:#eee}.entry-content .job_listing_preview_title h2,.job_listing_preview_title h2{margin:0;clear:none}.entry-content .job_listing_preview_title .button,.job_listing_preview_title .button{float:right;margin-left:.25em}.job_summary_shortcode{border:1px solid #ccc;-moz-border-radius:4px;-webkit-border-radius:4px;border-radius:4px;text-align:center;position:relative;box-shadow:0 2px 4px rgba(0,0,0,.1),inset 0 1px 0 rgba(255,255,255,.4);-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.job_summary_shortcode.aligncenter{display:block;margin:2em auto 2em}.job_summary_shortcode.alignleft{float:left;margin:0 2em 2em 0}.job_summary_shortcode.alignright{float:right;margin:0 0 2em 2em}.job_summary_shortcode a{text-decoration:none;color:inherit}.job_summary_shortcode img{margin:0;padding:0;display:block;width:100%;-moz-border-radius:0;-webkit-border-radius:0;-moz-border-top-left-radius:3px;-moz-border-top-right-radius:3px;-webkit-border-top-left-radius:3px;-webkit-border-top-right-radius:3px;border-radius:0;border-top-left-radius:3px;border-top-right-radius:3px;box-shadow:inset 0 1px 0 rgba(255,255,255,.4)}.job_summary_shortcode .job_summary_content{padding:0 1em}.job_summary_shortcode .meta{font-style:italic;color:#777}.job_summary_shortcode .job-type{-moz-border-radius:1em;-webkit-border-radius:1em;border-radius:1em;color:#fff;text-shadow:0 1px 0 rgba(255,255,255,.5);box-shadow:0 2px 4px rgba(0,0,0,.1),inset 0 1px 0 rgba(255,255,255,.4);position:absolute;top:0;right:0;padding:.5em;height:1em;width:auto;min-width:1em;font-size:1em;text-align:center;vertical-align:middle;line-height:1em;margin:-.5em -.5em 0 0}.job_summary_shortcode .job-type.full-time{background-color:#90da36}.job_summary_shortcode .job-type.part-time{background-color:#f08d3c}.job_summary_shortcode .job-type.temporary{background-color:#d93674}.job_summary_shortcode .job-type.freelance{background-color:#39c}.job_summary_shortcode .job-type.internship{background-color:#6033cc}#job-manager-job-dashboard .account-sign-in .button{margin-right:.5em}#job-manager-job-dashboard .account-sign-in .button:before{display:inline-block;width:16px;height:16px;-webkit-font-smoothing:antialiased;font-family:job-manager!important;text-decoration:none;font-weight:400;font-style:normal;vertical-align:top;font-size:16px;margin:0 2px 0 0;content:'\e808'}#job-manager-job-dashboard table ul.job-dashboard-actions{margin:0;padding:0;visibility:hidden;font-size:.92em}#job-manager-job-dashboard table ul.job-dashboard-actions li{float:none;display:inline;padding:0;margin:0 .5em 0 0;font-weight:400;list-style:none outside}#job-manager-job-dashboard table ul.job-dashboard-actions li:after{padding:0 0 0 .5em;content:"\2023"}#job-manager-job-dashboard table ul.job-dashboard-actions li:last-child:after{content:''}#job-manager-job-dashboard table ul.job-dashboard-actions li .job-dashboard-action-delete{color:red}#job-manager-job-dashboard table tr:focus ul.job-dashboard-actions,#job-manager-job-dashboard table tr:hover ul.job-dashboard-actions{visibility:visible}#job-manager-job-dashboard table td,#job-manager-job-dashboard table th{padding:.5em 1em .5em 0}#job-manager-job-dashboard table .job_title small{color:#999}#job-manager-job-dashboard table .applications,#job-manager-job-dashboard table .expires,#job-manager-job-dashboard table .filled{text-align:center}#content nav.job-manager-pagination,nav.job-manager-pagination{text-align:center}#content nav.job-manager-pagination ul,nav.job-manager-pagination ul{display:inline-block;white-space:nowrap;padding:0;clear:both;border-left:1px solid #eee;margin:1px}#content nav.job-manager-pagination ul li,nav.job-manager-pagination ul li{border-right:1px solid #eee;border-top:1px solid #eee;border-bottom:1px solid #eee;padding:0;margin:0;float:left;display:inline;overflow:hidden}#content nav.job-manager-pagination ul li a,#content nav.job-manager-pagination ul li span,nav.job-manager-pagination ul li a,nav.job-manager-pagination ul li span{margin:0;text-decoration:none;padding:0;line-height:1em;font-size:1em;font-weight:400;padding:.5em;min-width:1em;display:block;border:0}#content nav.job-manager-pagination ul li a:focus,#content nav.job-manager-pagination ul li a:hover,#content nav.job-manager-pagination ul li span.current,nav.job-manager-pagination ul li a:focus,nav.job-manager-pagination ul li a:hover,nav.job-manager-pagination ul li span.current{background:#eee;color:#888}@media only screen and (max-width:767px){ul.job_listings li.job_listing a,ul.job_listings li.no_job_listings_found a{padding:1em}ul.job_listings li.job_listing a img.company_logo,ul.job_listings li.no_job_listings_found a img.company_logo{visibility:hidden}ul.job_listings li.job_listing a div.position,ul.job_listings li.no_job_listings_found a div.position{float:left;width:60%;padding:0}ul.job_listings li.job_listing a div.location,ul.job_listings li.no_job_listings_found a div.location{float:right;width:40%;line-height:2em;font-size:.75em;padding:0 0 0 1em;text-align:right}ul.job_listings li.job_listing a .meta,ul.job_listings li.no_job_listings_found a .meta{float:right;width:40%;line-height:2em;font-size:.75em}ul.job_listings li.job_listing a .meta li,ul.job_listings li.no_job_listings_found a .meta li{font-size:1em}}.chosen-container{width:100%!important}.twenty-eleven ul.job_listings li.job_listing,.twenty-eleven ul.job_listings li.no_job_listings_found{padding:0!important}.twenty-ten .chosen-choices,.twenty-ten .job_types{margin:0!important}.rtl .job-manager-form label{float:right}.rtl .job-manager-form div.field{float:left}.rtl .entry-content .job_listing_preview_title .button,.rtl .job_listing_preview_title .button{float:left}.rtl .single_job_listing .meta li{float:right;margin:0 0 0 1em}
1
+ .clearfix{zoom:1}.clearfix:after,.clearfix:before{content:"";display:table}.clearfix:after{clear:both}@font-face{font-family:job-manager;src:url(../font/job-manager.eot?4963673);src:url(../font/job-manager.eot?4963673#iefix) format('embedded-opentype'),url(../font/job-manager.woff?4963673) format('woff'),url(../font/job-manager.ttf?4963673) format('truetype'),url(../font/job-manager.svg?4963673#job-manager) format('svg');font-weight:400;font-style:normal}@font-face{font-family:jm-logo;src:url(../font/jm-logo/jm.eot?ycsbky);src:url(../font/jm-logo/jm.eot?#iefixycsbky) format('embedded-opentype'),url(../font/jm-logo/jm.woff?ycsbky) format('woff'),url(../font/jm-logo/jm.ttf?ycsbky) format('truetype'),url(../font/jm-logo/jm.svg?ycsbky#icomoon) format('svg');font-weight:400;font-style:normal}.jm-icon{font-family:job-manager!important;font-style:normal;font-weight:400;speak:none;display:inline-block;text-decoration:inherit;width:1em;text-align:center;font-variant:normal;text-transform:none;line-height:1em}.rp4wp-related-job_listing>ul,ul.job_listings{padding:0;margin:0;border-top:1px solid #eee}.rp4wp-related-job_listing>ul.loading,ul.job_listings.loading{min-height:96px;border-bottom:1px solid #eee;background:url(../images/ajax-loader.gif) no-repeat center 32px}.rp4wp-related-job_listing>ul li.job_listing,.rp4wp-related-job_listing>ul li.no_job_listings_found,ul.job_listings li.job_listing,ul.job_listings li.no_job_listings_found{list-style:none outside;padding:0;margin:0;border-bottom:1px solid #eee}.rp4wp-related-job_listing>ul li.job_listing.job_position_filled a,.rp4wp-related-job_listing>ul li.no_job_listings_found.job_position_filled a,ul.job_listings li.job_listing.job_position_filled a,ul.job_listings li.no_job_listings_found.job_position_filled a{opacity:.25}.rp4wp-related-job_listing>ul li.job_listing.no_job_listings_found,.rp4wp-related-job_listing>ul li.no_job_listings_found.no_job_listings_found,ul.job_listings li.job_listing.no_job_listings_found,ul.job_listings li.no_job_listings_found.no_job_listings_found{padding:1em;border-bottom:1px solid #eee}.rp4wp-related-job_listing>ul li.job_listing a,.rp4wp-related-job_listing>ul li.no_job_listings_found a,ul.job_listings li.job_listing a,ul.job_listings li.no_job_listings_found a{display:block;padding:1em 1em 1em 2em;border:0;overflow:hidden;zoom:1;position:relative;line-height:1.5em;text-decoration:none}.rp4wp-related-job_listing>ul li.job_listing a:focus,.rp4wp-related-job_listing>ul li.job_listing a:hover,.rp4wp-related-job_listing>ul li.no_job_listings_found a:focus,.rp4wp-related-job_listing>ul li.no_job_listings_found a:hover,ul.job_listings li.job_listing a:focus,ul.job_listings li.job_listing a:hover,ul.job_listings li.no_job_listings_found a:focus,ul.job_listings li.no_job_listings_found a:hover{background-color:#fcfcfc}.rp4wp-related-job_listing>ul li.job_listing a img.company_logo,.rp4wp-related-job_listing>ul li.no_job_listings_found a img.company_logo,ul.job_listings li.job_listing a img.company_logo,ul.job_listings li.no_job_listings_found a img.company_logo{width:42px;height:42px;position:absolute;left:1em;float:left;margin-right:1em;vertical-align:middle;box-shadow:none}.rp4wp-related-job_listing>ul li.job_listing a div.location,.rp4wp-related-job_listing>ul li.job_listing a div.position,.rp4wp-related-job_listing>ul li.job_listing a ul.meta,.rp4wp-related-job_listing>ul li.no_job_listings_found a div.location,.rp4wp-related-job_listing>ul li.no_job_listings_found a div.position,.rp4wp-related-job_listing>ul li.no_job_listings_found a ul.meta,ul.job_listings li.job_listing a div.location,ul.job_listings li.job_listing a div.position,ul.job_listings li.job_listing a ul.meta,ul.job_listings li.no_job_listings_found a div.location,ul.job_listings li.no_job_listings_found a div.position,ul.job_listings li.no_job_listings_found a ul.meta{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.rp4wp-related-job_listing>ul li.job_listing a div.position,.rp4wp-related-job_listing>ul li.no_job_listings_found a div.position,ul.job_listings li.job_listing a div.position,ul.job_listings li.no_job_listings_found a div.position{float:left;width:55%;padding:0 0 0 42px;line-height:1.5em}.rp4wp-related-job_listing>ul li.job_listing a div.position h3,.rp4wp-related-job_listing>ul li.no_job_listings_found a div.position h3,ul.job_listings li.job_listing a div.position h3,ul.job_listings li.no_job_listings_found a div.position h3{margin:0;padding:0;line-height:inherit;font-size:inherit}.rp4wp-related-job_listing>ul li.job_listing a div.position .company,.rp4wp-related-job_listing>ul li.no_job_listings_found a div.position .company,ul.job_listings li.job_listing a div.position .company,ul.job_listings li.no_job_listings_found a div.position .company{color:#999}.rp4wp-related-job_listing>ul li.job_listing a div.position .company .tagline,.rp4wp-related-job_listing>ul li.no_job_listings_found a div.position .company .tagline,ul.job_listings li.job_listing a div.position .company .tagline,ul.job_listings li.no_job_listings_found a div.position .company .tagline{margin-left:.5em}.rp4wp-related-job_listing>ul li.job_listing a div.location,.rp4wp-related-job_listing>ul li.no_job_listings_found a div.location,ul.job_listings li.job_listing a div.location,ul.job_listings li.no_job_listings_found a div.location{float:left;text-align:left;width:25%;padding:0 0 0 1em;color:#999;line-height:1.5em}.rp4wp-related-job_listing>ul li.job_listing a .meta,.rp4wp-related-job_listing>ul li.no_job_listings_found a .meta,ul.job_listings li.job_listing a .meta,ul.job_listings li.no_job_listings_found a .meta{float:right;text-align:right;width:20%;padding:0 0 0 1em;margin:0;line-height:1.5em;color:#999;list-style:none outside}.rp4wp-related-job_listing>ul li.job_listing a .meta li,.rp4wp-related-job_listing>ul li.no_job_listings_found a .meta li,ul.job_listings li.job_listing a .meta li,ul.job_listings li.no_job_listings_found a .meta li{list-style:none outside;display:block;margin:0}.rp4wp-related-job_listing>ul li.job_listing a .meta .job-type,.rp4wp-related-job_listing>ul li.no_job_listings_found a .meta .job-type,ul.job_listings li.job_listing a .meta .job-type,ul.job_listings li.no_job_listings_found a .meta .job-type{font-weight:700}.rp4wp-related-job_listing>ul li.job_listing.job_position_featured a,.rp4wp-related-job_listing>ul li.no_job_listings_found.job_position_featured a,ul.job_listings li.job_listing.job_position_featured a,ul.job_listings li.no_job_listings_found.job_position_featured a{background:#fefee5}.rp4wp-related-job_listing>ul li.job_listing.job_position_featured a:focus,.rp4wp-related-job_listing>ul li.job_listing.job_position_featured a:hover,.rp4wp-related-job_listing>ul li.no_job_listings_found.job_position_featured a:focus,.rp4wp-related-job_listing>ul li.no_job_listings_found.job_position_featured a:hover,ul.job_listings li.job_listing.job_position_featured a:focus,ul.job_listings li.job_listing.job_position_featured a:hover,ul.job_listings li.no_job_listings_found.job_position_featured a:focus,ul.job_listings li.no_job_listings_found.job_position_featured a:hover{background-color:#fefed8}.widget ul.job_listings li.job_listing a{padding:1em 0}.widget ul.job_listings li.job_listing .position{float:none;width:auto;padding:0}.widget ul.job_listings li.job_listing ul.meta{float:none;width:auto;padding:0;margin:0;text-align:left}.widget ul.job_listings li.job_listing ul.meta li{float:none;display:inline;padding:0;margin:0 .5em 0 0;font-weight:400}.widget ul.job_listings li.job_listing ul.meta li:after{padding:0 0 0 .5em;content:"\2023"}.widget ul.job_listings li.job_listing ul.meta li:last-child:after{content:''}.job-manager .job-type,.job-types .job-type,.job_listing .job-type{color:#f08d3c}.job-manager .full-time,.job-types .full-time,.job_listing .full-time{color:#90da36}.job-manager .part-time,.job-types .part-time,.job_listing .part-time{color:#f08d3c}.job-manager .temporary,.job-types .temporary,.job_listing .temporary{color:#d93674}.job-manager .freelance,.job-types .freelance,.job_listing .freelance{color:#39c}.job-manager .internship,.job-types .internship,.job_listing .internship{color:#6033cc}@media only screen and (max-width:767px){ul.job_listings li.job_listing a,ul.job_listings li.no_job_listings_found a{padding:1em}ul.job_listings li.job_listing a img.company_logo,ul.job_listings li.no_job_listings_found a img.company_logo{visibility:hidden}ul.job_listings li.job_listing a div.position,ul.job_listings li.no_job_listings_found a div.position{float:left;width:60%;padding:0}ul.job_listings li.job_listing a div.location,ul.job_listings li.no_job_listings_found a div.location{float:right;width:40%;line-height:2em;font-size:.75em;padding:0 0 0 1em;text-align:right}ul.job_listings li.job_listing a .meta,ul.job_listings li.no_job_listings_found a .meta{float:right;width:40%;line-height:2em;font-size:.75em}ul.job_listings li.job_listing a .meta li,ul.job_listings li.no_job_listings_found a .meta li{font-size:1em}}.twenty-eleven ul.job_listings li.job_listing,.twenty-eleven ul.job_listings li.no_job_listings_found{padding:0!important}.display-icon{display:inline-block;width:16px;height:16px;-webkit-font-smoothing:antialiased;font-family:job-manager!important;text-decoration:none;font-weight:400;font-style:normal;vertical-align:top;font-size:16px;margin:0 2px 0 0}.job-manager-error,.job-manager-info,.job-manager-message{padding:1em 2em 1em 3.5em!important;margin:0 0 2em!important;position:relative;background-color:#fff;color:#666;border-top:3px solid #999;list-style:none outside!important;width:auto;zoom:1;box-shadow:0 1px 1px rgba(0,0,0,.2)}.job-manager-error:after,.job-manager-error:before,.job-manager-info:after,.job-manager-info:before,.job-manager-message:after,.job-manager-message:before{content:"";display:table}.job-manager-error:after,.job-manager-info:after,.job-manager-message:after{clear:both}.job-manager-error:before,.job-manager-info:before,.job-manager-message:before{content:"";font-family:sans-serif;display:inline-block;position:absolute;top:1em;left:1.5em}.job-manager-error li,.job-manager-info li,.job-manager-message li{list-style:none outside!important;padding-left:0!important;margin-left:0!important}.job-manager-error.job-manager-message,.job-manager-info.job-manager-message,.job-manager-message.job-manager-message{border-top-color:#8fae1b}.job-manager-error.job-manager-message:before,.job-manager-info.job-manager-message:before,.job-manager-message.job-manager-message:before{color:#8fae1b;content:"\2713"}.job-manager-error.job-manager-info,.job-manager-info.job-manager-info,.job-manager-message.job-manager-info{border-top-color:#1e85be}.job-manager-error.job-manager-info:before,.job-manager-info.job-manager-info:before,.job-manager-message.job-manager-info:before{color:#1e85be;content:"i";font-family:Times,Georgia,serif;font-style:italic}.job-manager-error.job-manager-error,.job-manager-info.job-manager-error,.job-manager-message.job-manager-error{border-top-color:#b81c23}.job-manager-error.job-manager-error:before,.job-manager-info.job-manager-error:before,.job-manager-message.job-manager-error:before{color:#b81c23;content:"\00d7";font-weight:700}.job-manager-form fieldset{margin:0 0 1em 0;padding:0 0 1em 0;line-height:2em;border:0;border-bottom:1px solid #eee;zoom:1}.job-manager-form fieldset:after,.job-manager-form fieldset:before{content:"";display:table}.job-manager-form fieldset:after{clear:both}.job-manager-form fieldset label{display:block;margin:0;width:29%;float:left;vertical-align:middle}.job-manager-form fieldset label small{opacity:.75;font-size:.83em}.job-manager-form fieldset div.field{width:70%;float:right;vertical-align:middle}.job-manager-form fieldset .wp-editor-container{border:1px solid #ccc;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.job-manager-form fieldset .account-sign-in .button{margin-right:.5em}.job-manager-form fieldset .account-sign-in .button:before{display:inline-block;width:16px;height:16px;-webkit-font-smoothing:antialiased;font-family:job-manager!important;text-decoration:none;font-weight:400;font-style:normal;vertical-align:top;font-size:16px;margin:0 2px 0 0;content:'\e808'}.job-manager-form fieldset abbr.required{color:red;font-weight:700;border:0}.job-manager-form fieldset input.input-text,.job-manager-form fieldset select,.job-manager-form fieldset textarea{margin:0;vertical-align:middle;width:100%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.job-manager-form fieldset small.description{opacity:.75;font-size:.83em;margin:1.2em 0 0 0;display:block;line-height:1.2em}.job-manager-form fieldset .job-manager-uploaded-files{display:table}.job-manager-form fieldset .job-manager-uploaded-files .job-manager-uploaded-file{line-height:2em;font-style:italic;margin-bottom:1em;display:block}.job-manager-form fieldset .job-manager-uploaded-files .job-manager-uploaded-file .job-manager-uploaded-file-preview img{height:64px;margin:0;vertical-align:top}.job-manager-form fieldset .job-manager-uploaded-files .job-manager-uploaded-file .job-manager-uploaded-file-preview a{line-height:64px;display:inline-block;padding:0 0 0 1em}.job-manager-form fieldset .job-manager-uploaded-files .job-manager-uploaded-file .job-manager-uploaded-file-name{display:block}.job-manager-form .submit-job{padding:1em 0}.job-manager-form .job-manager-term-checklist{list-style:none outside;max-height:200px;overflow:auto;margin:0}.job-manager-form .job-manager-term-checklist li{list-style:none outside;margin:0;display:block;float:none}.job-manager-form .job-manager-term-checklist li label{width:auto;float:none}.job-manager-form .job-manager-term-checklist li li{margin:0 0 0 2em}.job-manager-form input[type=submit].disabled,.job-manager-form input[type=submit]:disabled{opacity:.5;cursor:not-allowed}.job-manager-form .spinner{background:url(../../../../../wp-includes/images/spinner.gif) no-repeat;background-size:20px 20px;display:inline-block;visibility:hidden;width:20px;height:20px;margin:0;vertical-align:middle}.job-manager-form .spinner.is-active{visibility:visible}div.job_listings{margin-bottom:1em}div.job_listings ul.job_listings{margin:0}.single_job_listing .company{position:relative;border:1px solid #eee;padding:1em;margin:0 0 2em;display:block;clear:both;min-height:3em;box-shadow:0 1px 1px rgba(0,0,0,.1)}.single_job_listing .company img{width:3em;height:3em;position:absolute;left:1em;float:left;vertical-align:middle;box-shadow:none}.single_job_listing .company .name{margin:0 0 0 3em;padding:0 0 0 1em;line-height:1.5em}.single_job_listing .company .name a{float:right;margin-left:1em}.single_job_listing .company .tagline{display:block;margin:0 0 0 42px;padding:0 0 0 1em;line-height:1.5em;font-style:italic;color:#999}.single_job_listing .company .website:before{display:inline-block;width:16px;height:16px;-webkit-font-smoothing:antialiased;font-family:job-manager!important;text-decoration:none;font-weight:400;font-style:normal;vertical-align:top;font-size:16px;margin:0 2px 0 0;content:'\e809'}.single_job_listing .company .company_twitter:before{display:inline-block;width:16px;height:16px;-webkit-font-smoothing:antialiased;font-family:job-manager!important;text-decoration:none;font-weight:400;font-style:normal;vertical-align:top;font-size:16px;margin:0 2px 0 0;content:'\e80a'}.single_job_listing .company .company_video{border-top:1px solid #eee;padding:1em 0 0;margin:1em 0 0 0;position:relative;padding-bottom:56.25%;padding-top:30px;height:0;overflow:hidden}.single_job_listing .company .company_video embed,.single_job_listing .company .company_video iframe,.single_job_listing .company .company_video object{position:absolute;top:0;left:0;width:100%;height:100%;margin:0;display:block}.single_job_listing .meta{list-style:none outside;padding:0;margin:0 0 1.5em;overflow:hidden;zoom:1;clear:both}.single_job_listing .meta li{margin:0 1em 0 0;padding:.5em;float:left;line-height:1em;color:#999}.single_job_listing .meta .job-type{color:#fff;background-color:#f08d3c}.single_job_listing .meta .full-time{background-color:#90da36}.single_job_listing .meta .part-time{background-color:#f08d3c}.single_job_listing .meta .temporary{background-color:#d93674}.single_job_listing .meta .freelance{background-color:#39c}.single_job_listing .meta .internship{background-color:#6033cc}.single_job_listing .meta .listing-expired,.single_job_listing .meta .position-filled{color:#b81c23}.single_job_listing .meta .location:before{display:inline-block;width:16px;height:16px;-webkit-font-smoothing:antialiased;font-family:job-manager!important;text-decoration:none;font-weight:400;font-style:normal;vertical-align:top;font-size:16px;margin:0 2px 0 0;content:'\e81d'}.single_job_listing .meta .date-posted:before{display:inline-block;width:16px;height:16px;-webkit-font-smoothing:antialiased;font-family:job-manager!important;text-decoration:none;font-weight:400;font-style:normal;vertical-align:top;font-size:16px;margin:0 2px 0 0;content:'\e80f'}.single_job_listing .meta .listing-expired:before,.single_job_listing .meta .position-filled:before{display:inline-block;width:16px;height:16px;-webkit-font-smoothing:antialiased;font-family:job-manager!important;text-decoration:none;font-weight:400;font-style:normal;vertical-align:top;font-size:16px;margin:0 2px 0 0;content:'\e80e'}.single_job_listing .job_description{margin:0 0 1.5em}.job-manager-application-wrapper{clear:both;border:1px solid #eee;padding:.75em 1em 0;margin:1em 0;line-height:1.5em;display:block;position:relative;box-shadow:0 1px 1px rgba(0,0,0,.1)}.job-manager-application-wrapper .application,.single_job_listing .application{padding:0;margin:0 0 1em;overflow:hidden}.job-manager-application-wrapper .application .application_button,.job-manager-application-wrapper .application .application_details,.single_job_listing .application .application_button,.single_job_listing .application .application_details{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.job-manager-application-wrapper .application .application_button,.single_job_listing .application .application_button{text-align:center;font-size:1.1em;line-height:1em;display:inline-block;margin:0 .5em 0 0;padding:.90909091em 2em;outline:0}.job-manager-application-wrapper .application .application_details,.single_job_listing .application .application_details{clear:both;border:1px solid #eee;padding:.75em 1em 0;margin:1em 0;line-height:1.5em;display:block;position:relative;box-shadow:0 1px 1px rgba(0,0,0,.1)}.job-manager-application-wrapper .application .application_details p,.single_job_listing .application .application_details p{margin:0 0 .75em}.job-manager-application-wrapper .application .application_details:before,.single_job_listing .application .application_details:before{content:"";position:absolute;margin:-10px 0 0 0;top:0;left:5em;width:0;height:0;border-left:10px solid transparent;border-right:10px solid transparent;border-bottom:10px solid #eee}.job-manager-application-wrapper .application .application_details:after,.single_job_listing .application .application_details:after{content:"";position:absolute;margin:-9px 0 0 1px;left:5em;top:0;width:0;height:0;border-left:9px solid transparent;border-right:9px solid transparent;border-bottom:9px solid #fff}.job_filters{background:#eee;zoom:1}.job_filters:after,.job_filters:before{content:"";display:table}.job_filters:after{clear:both}.job_filters .search_jobs{padding:1em;zoom:1}.job_filters .search_jobs:after,.job_filters .search_jobs:before{content:"";display:table}.job_filters .search_jobs:after{clear:both}.job_filters .search_jobs div{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.job_filters .search_jobs div label{display:none}.job_filters .search_jobs div.filter_first,.job_filters .search_jobs div.search_keywords{float:left;padding-right:.5em;width:50%}.job_filters .search_jobs div.filter_last,.job_filters .search_jobs div.search_location{float:right;padding-left:.5em;width:50%}.job_filters .search_jobs div.filter_wide,.job_filters .search_jobs div.search_categories{padding-top:.5em;clear:both;width:100%}.job_filters .search_jobs div .showing_jobs a{padding:.25em}.job_filters .search_jobs div .showing_jobs a.active{background:#ddd;text-decoration:none}.job_filters .search_jobs input,.job_filters .search_jobs select{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;width:100%}.job_filters .job_types{list-style:none outside;margin:0;padding:0;font-size:.83em;background:#f9f9f9;border-top:1px solid #e5e5e5;zoom:1}.job_filters .job_types:after,.job_filters .job_types:before{content:"";display:table}.job_filters .job_types:after{clear:both}.job_filters .job_types li{margin:0;padding:.5em 1em;float:left;border-right:1px solid #eee}.job_filters .job_types li:last-child{border-right:0}.job_filters .showing_jobs{padding:.5em 1em;display:none;font-size:.83em;background:#f9f9f9;border-top:1px solid #e5e5e5}.job_filters .showing_jobs a{float:right;padding-left:10px;border:0}div.job_listings .job-manager-pagination{text-align:center;display:block;padding:1em 0 1em 0;border-bottom:1px solid #eee;line-height:1}div.job_listings .load_previous{border-top:1px solid #eee}div.job_listings .load_more_jobs+ul.job_listings{border-top:0}div.job_listings .load_more_jobs{text-align:center;display:block;padding:1em 1em 1em 2em;border-bottom:1px solid #eee;font-weight:700}div.job_listings .load_more_jobs.loading{background:url(../images/ajax-loader.gif) no-repeat center}div.job_listings .load_more_jobs.loading strong{visibility:hidden}div.job_listings .load_more_jobs:focus,div.job_listings .load_more_jobs:hover{background-color:#fcfcfc;border-bottom:1px solid #eee}.job_listing_preview{padding:0 1em 1em;border:5px solid #eee}.single-job_listing .entry-header .attachment-post-thumbnail,.single-job_listing .job_listing.has-post-thumbnail .post-thumbnail{display:none}.entry-content .job_listing_preview_title,.job_listing_preview_title{padding:.5em 1em;vertical-align:middle;position:relative;background:#eee}.entry-content .job_listing_preview_title h2,.job_listing_preview_title h2{margin:0;clear:none}.entry-content .job_listing_preview_title .button,.job_listing_preview_title .button{float:right;margin-left:.25em}.job_summary_shortcode{border:1px solid #ccc;-moz-border-radius:4px;-webkit-border-radius:4px;border-radius:4px;text-align:center;position:relative;box-shadow:0 2px 4px rgba(0,0,0,.1),inset 0 1px 0 rgba(255,255,255,.4);-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.job_summary_shortcode.aligncenter{display:block;margin:2em auto 2em}.job_summary_shortcode.alignleft{float:left;margin:0 2em 2em 0}.job_summary_shortcode.alignright{float:right;margin:0 0 2em 2em}.job_summary_shortcode a{text-decoration:none;color:inherit}.job_summary_shortcode img{margin:0;padding:0;display:block;width:100%;-moz-border-radius:0;-webkit-border-radius:0;-moz-border-top-left-radius:3px;-moz-border-top-right-radius:3px;-webkit-border-top-left-radius:3px;-webkit-border-top-right-radius:3px;border-radius:0;border-top-left-radius:3px;border-top-right-radius:3px;box-shadow:inset 0 1px 0 rgba(255,255,255,.4)}.job_summary_shortcode .job_summary_content{padding:0 1em}.job_summary_shortcode .meta{font-style:italic;color:#777}.job_summary_shortcode .job-type{-moz-border-radius:1em;-webkit-border-radius:1em;border-radius:1em;color:#fff;text-shadow:0 1px 0 rgba(255,255,255,.5);box-shadow:0 2px 4px rgba(0,0,0,.1),inset 0 1px 0 rgba(255,255,255,.4);position:absolute;top:0;right:0;padding:.5em;height:1em;width:auto;min-width:1em;font-size:1em;text-align:center;vertical-align:middle;line-height:1em;margin:-.5em -.5em 0 0}.job_summary_shortcode .job-type.full-time{background-color:#90da36}.job_summary_shortcode .job-type.part-time{background-color:#f08d3c}.job_summary_shortcode .job-type.temporary{background-color:#d93674}.job_summary_shortcode .job-type.freelance{background-color:#39c}.job_summary_shortcode .job-type.internship{background-color:#6033cc}#job-manager-job-dashboard .account-sign-in .button{margin-right:.5em}#job-manager-job-dashboard .account-sign-in .button:before{display:inline-block;width:16px;height:16px;-webkit-font-smoothing:antialiased;font-family:job-manager!important;text-decoration:none;font-weight:400;font-style:normal;vertical-align:top;font-size:16px;margin:0 2px 0 0;content:'\e808'}#job-manager-job-dashboard table ul.job-dashboard-actions{margin:0;padding:0;visibility:hidden;font-size:.92em}#job-manager-job-dashboard table ul.job-dashboard-actions li{float:none;display:inline;padding:0;margin:0 .5em 0 0;font-weight:400;list-style:none outside}#job-manager-job-dashboard table ul.job-dashboard-actions li:after{padding:0 0 0 .5em;content:"\2023"}#job-manager-job-dashboard table ul.job-dashboard-actions li:last-child:after{content:''}#job-manager-job-dashboard table ul.job-dashboard-actions li .job-dashboard-action-delete{color:red}#job-manager-job-dashboard table tr:focus ul.job-dashboard-actions,#job-manager-job-dashboard table tr:hover ul.job-dashboard-actions{visibility:visible}#job-manager-job-dashboard table td,#job-manager-job-dashboard table th{padding:.5em 1em .5em 0}#job-manager-job-dashboard table .job_title small{color:#999}#job-manager-job-dashboard table .featured-job-icon:before{content:'\e803';font-family:job-manager!important;font-style:normal;font-weight:400;speak:none;display:inline-block;text-decoration:inherit;width:1em;text-align:center;font-variant:normal;text-transform:none;line-height:1em}#job-manager-job-dashboard table .applications,#job-manager-job-dashboard table .expires,#job-manager-job-dashboard table .filled{text-align:center}#content nav.job-manager-pagination,nav.job-manager-pagination{text-align:center}#content nav.job-manager-pagination ul,nav.job-manager-pagination ul{display:inline-block;white-space:nowrap;padding:0;clear:both;border-left:1px solid #eee;margin:1px}#content nav.job-manager-pagination ul li,nav.job-manager-pagination ul li{border-right:1px solid #eee;border-top:1px solid #eee;border-bottom:1px solid #eee;padding:0;margin:0;float:left;display:inline;overflow:hidden}#content nav.job-manager-pagination ul li a,#content nav.job-manager-pagination ul li span,nav.job-manager-pagination ul li a,nav.job-manager-pagination ul li span{margin:0;text-decoration:none;padding:0;line-height:1em;font-size:1em;font-weight:400;padding:.5em;min-width:1em;display:block;border:0}#content nav.job-manager-pagination ul li a:focus,#content nav.job-manager-pagination ul li a:hover,#content nav.job-manager-pagination ul li span.current,nav.job-manager-pagination ul li a:focus,nav.job-manager-pagination ul li a:hover,nav.job-manager-pagination ul li span.current{background:#eee;color:#888}.chosen-container{width:100%!important}.twenty-ten .chosen-choices,.twenty-ten .job_types{margin:0!important}.rtl .job-manager-form label{float:right}.rtl .job-manager-form div.field{float:left}.rtl .entry-content .job_listing_preview_title .button,.rtl .job_listing_preview_title .button{float:left}.rtl .single_job_listing .meta li{float:right;margin:0 0 0 1em}
assets/css/frontend.less CHANGED
@@ -1,5 +1,6 @@
1
  @import "mixins";
2
  @import "icons";
 
3
 
4
  @primary: #999999; /* Primary colour for buttons (alt) */
5
  @primarytext: desaturate(lighten(@primary,50%),18%); /* Text on primary colour bg */
@@ -190,6 +191,24 @@
190
  }
191
  }
192
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
193
  }
194
  div.job_listings {
195
  margin-bottom: 1em;
@@ -197,172 +216,7 @@ div.job_listings {
197
  margin: 0;
198
  }
199
  }
200
- .rp4wp-related-job_listing > ul,
201
- ul.job_listings {
202
- padding: 0;
203
- margin: 0;
204
- border-top: 1px solid #eee;
205
-
206
- &.loading {
207
- min-height: 96px;
208
- border-bottom: 1px solid #eee;
209
- background: url(../images/ajax-loader.gif) no-repeat center 32px;
210
- }
211
- li.job_listing, li.no_job_listings_found {
212
- list-style: none outside;
213
- padding: 0;
214
- margin: 0;
215
- border-bottom: 1px solid #eee;
216
-
217
- &.job_position_filled {
218
- a {
219
- opacity: 0.25;
220
- }
221
- }
222
- &.no_job_listings_found {
223
- padding: 1em;
224
- border-bottom: 1px solid #eee;
225
- }
226
- a {
227
- display: block;
228
- padding: 1em 1em 1em 2em;
229
- border: 0;
230
- overflow: hidden;
231
- zoom: 1;
232
- position: relative;
233
- line-height: 1.5em;
234
- text-decoration: none;
235
 
236
- &:hover, &:focus {
237
- background-color: #fcfcfc;
238
- }
239
- img.company_logo {
240
- width: 42px;
241
- height: 42px;
242
- position: absolute;
243
- left: 1em;
244
- float: left;
245
- margin-right: 1em;
246
- vertical-align: middle;
247
- box-shadow: none;
248
- }
249
- div.position, div.location, ul.meta {
250
- -webkit-box-sizing: border-box; /* Safari/Chrome, other WebKit */
251
- -moz-box-sizing: border-box; /* Firefox, other Gecko */
252
- box-sizing: border-box; /* Opera/IE 8+ */
253
- }
254
- div.position {
255
- float: left;
256
- width: 55%;
257
- padding: 0 0 0 42px;
258
- line-height: 1.5em;
259
- h3 {
260
- margin: 0;
261
- padding: 0;
262
- line-height: inherit;
263
- font-size: inherit;
264
- }
265
- .company {
266
- color: #999;
267
- .tagline {
268
- margin-left: .5em;
269
- }
270
- }
271
- }
272
- div.location {
273
- float: left;
274
- text-align: left;
275
- width: 25%;
276
- padding: 0 0 0 1em;
277
- color: #999;
278
- line-height: 1.5em;
279
- }
280
- .meta {
281
- float: right;
282
- text-align: right;
283
- width: 20%;
284
- padding: 0 0 0 1em;
285
- margin: 0;
286
- line-height: 1.5em;
287
- color: #999;
288
- list-style: none outside;
289
- li {
290
- list-style: none outside;
291
- display: block;
292
- margin: 0;
293
- }
294
- .job-type {
295
- font-weight: bold;
296
- }
297
- }
298
- }
299
- &.job_position_featured {
300
- a {
301
- background: #fefee5;
302
-
303
- &:hover, &:focus {
304
- background-color: #fefed8;
305
- }
306
- }
307
- }
308
- }
309
- }
310
- .widget {
311
- ul.job_listings {
312
- li.job_listing {
313
- a {
314
- padding: 1em 0;
315
- }
316
- .position {
317
- float: none;
318
- width: auto;
319
- padding: 0;
320
- }
321
- ul.meta {
322
- float: none;
323
- width: auto;
324
- padding: 0;
325
- margin: 0;
326
- text-align: left;
327
- li {
328
- float: none;
329
- display: inline;
330
- padding: 0;
331
- margin: 0 .5em 0 0;
332
- font-weight: normal;
333
-
334
- &:after {
335
- padding: 0 0 0 .5em;
336
- content: "\2023";
337
- }
338
- &:last-child:after {
339
- content: '';
340
- }
341
- }
342
- }
343
- }
344
- }
345
- }
346
- .job-manager, .job_listing, .job-types {
347
- .job-type {
348
- color: @part-time;
349
- }
350
- .full-time {
351
- color: @full-time;
352
- }
353
- .part-time {
354
- color: @part-time;
355
- }
356
- .temporary {
357
- color: @temporary;
358
- }
359
- .freelance {
360
- color: @freelance;
361
- }
362
- .internship {
363
- color: @internship;
364
- }
365
- }
366
  .single_job_listing {
367
  .company {
368
  position: relative;
@@ -832,6 +686,12 @@ div.job_listings {
832
  .job_title small {
833
  color: #999;
834
  }
 
 
 
 
 
 
835
  .filled, .expires, .applications {
836
  text-align: center;
837
  }
@@ -876,57 +736,12 @@ nav.job-manager-pagination, #content nav.job-manager-pagination {
876
  }
877
  }
878
 
879
- /**
880
- * Mobile styles
881
- */
882
- @media only screen and (max-width: 767px) {
883
- ul.job_listings {
884
- li.job_listing, li.no_job_listings_found {
885
- a {
886
- padding: 1em;
887
- img.company_logo {
888
- visibility: hidden;
889
- }
890
- div.position {
891
- float: left;
892
- width: 60%;
893
- padding: 0;
894
- }
895
- div.location {
896
- float: right;
897
- width: 40%;
898
- line-height: 2em;
899
- font-size: .75em;
900
- padding: 0 0 0 1em;
901
- text-align: right;
902
- }
903
- .meta {
904
- float: right;
905
- width: 40%;
906
- line-height: 2em;
907
- font-size: .75em;
908
- li {
909
- font-size: 1em;
910
- }
911
- }
912
- }
913
- }
914
- }
915
- }
916
-
917
  // Chosen fixes
918
  .chosen-container {
919
  width: 100% !important;
920
  }
921
 
922
  // Default theme fixes
923
- .twenty-eleven {
924
- ul.job_listings {
925
- li.job_listing, li.no_job_listings_found {
926
- padding: 0 !important;
927
- }
928
- }
929
- }
930
  .twenty-ten {
931
  .job_types, .chosen-choices {
932
  margin: 0 !important;
1
  @import "mixins";
2
  @import "icons";
3
+ @import "job-listings";
4
 
5
  @primary: #999999; /* Primary colour for buttons (alt) */
6
  @primarytext: desaturate(lighten(@primary,50%),18%); /* Text on primary colour bg */
191
  }
192
  }
193
  }
194
+ input[type=submit]:disabled, input[type=submit].disabled {
195
+ opacity: .5;
196
+ filter: alpha(opacity=50);
197
+ cursor: not-allowed;
198
+ }
199
+ .spinner {
200
+ background: url(../../../../../wp-includes/images/spinner.gif) no-repeat;
201
+ background-size: 20px 20px;
202
+ display: inline-block;
203
+ visibility: hidden;
204
+ width: 20px;
205
+ height: 20px;
206
+ margin: 0;
207
+ vertical-align: middle;
208
+ }
209
+ .spinner.is-active {
210
+ visibility: visible;
211
+ }
212
  }
213
  div.job_listings {
214
  margin-bottom: 1em;
216
  margin: 0;
217
  }
218
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
219
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
220
  .single_job_listing {
221
  .company {
222
  position: relative;
686
  .job_title small {
687
  color: #999;
688
  }
689
+ .featured-job-icon {
690
+ &:before {
691
+ content: '\e803';
692
+ .jm-icon;
693
+ }
694
+ }
695
  .filled, .expires, .applications {
696
  text-align: center;
697
  }
736
  }
737
  }
738
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
739
  // Chosen fixes
740
  .chosen-container {
741
  width: 100% !important;
742
  }
743
 
744
  // Default theme fixes
 
 
 
 
 
 
 
745
  .twenty-ten {
746
  .job_types, .chosen-choices {
747
  margin: 0 !important;
assets/css/job-listings.css ADDED
@@ -0,0 +1 @@
 
1
+ .clearfix{zoom:1}.clearfix:after,.clearfix:before{content:"";display:table}.clearfix:after{clear:both}.rp4wp-related-job_listing>ul,ul.job_listings{padding:0;margin:0;border-top:1px solid #eee}.rp4wp-related-job_listing>ul.loading,ul.job_listings.loading{min-height:96px;border-bottom:1px solid #eee;background:url(../images/ajax-loader.gif) no-repeat center 32px}.rp4wp-related-job_listing>ul li.job_listing,.rp4wp-related-job_listing>ul li.no_job_listings_found,ul.job_listings li.job_listing,ul.job_listings li.no_job_listings_found{list-style:none outside;padding:0;margin:0;border-bottom:1px solid #eee}.rp4wp-related-job_listing>ul li.job_listing.job_position_filled a,.rp4wp-related-job_listing>ul li.no_job_listings_found.job_position_filled a,ul.job_listings li.job_listing.job_position_filled a,ul.job_listings li.no_job_listings_found.job_position_filled a{opacity:.25}.rp4wp-related-job_listing>ul li.job_listing.no_job_listings_found,.rp4wp-related-job_listing>ul li.no_job_listings_found.no_job_listings_found,ul.job_listings li.job_listing.no_job_listings_found,ul.job_listings li.no_job_listings_found.no_job_listings_found{padding:1em;border-bottom:1px solid #eee}.rp4wp-related-job_listing>ul li.job_listing a,.rp4wp-related-job_listing>ul li.no_job_listings_found a,ul.job_listings li.job_listing a,ul.job_listings li.no_job_listings_found a{display:block;padding:1em 1em 1em 2em;border:0;overflow:hidden;zoom:1;position:relative;line-height:1.5em;text-decoration:none}.rp4wp-related-job_listing>ul li.job_listing a:focus,.rp4wp-related-job_listing>ul li.job_listing a:hover,.rp4wp-related-job_listing>ul li.no_job_listings_found a:focus,.rp4wp-related-job_listing>ul li.no_job_listings_found a:hover,ul.job_listings li.job_listing a:focus,ul.job_listings li.job_listing a:hover,ul.job_listings li.no_job_listings_found a:focus,ul.job_listings li.no_job_listings_found a:hover{background-color:#fcfcfc}.rp4wp-related-job_listing>ul li.job_listing a img.company_logo,.rp4wp-related-job_listing>ul li.no_job_listings_found a img.company_logo,ul.job_listings li.job_listing a img.company_logo,ul.job_listings li.no_job_listings_found a img.company_logo{width:42px;height:42px;position:absolute;left:1em;float:left;margin-right:1em;vertical-align:middle;box-shadow:none}.rp4wp-related-job_listing>ul li.job_listing a div.location,.rp4wp-related-job_listing>ul li.job_listing a div.position,.rp4wp-related-job_listing>ul li.job_listing a ul.meta,.rp4wp-related-job_listing>ul li.no_job_listings_found a div.location,.rp4wp-related-job_listing>ul li.no_job_listings_found a div.position,.rp4wp-related-job_listing>ul li.no_job_listings_found a ul.meta,ul.job_listings li.job_listing a div.location,ul.job_listings li.job_listing a div.position,ul.job_listings li.job_listing a ul.meta,ul.job_listings li.no_job_listings_found a div.location,ul.job_listings li.no_job_listings_found a div.position,ul.job_listings li.no_job_listings_found a ul.meta{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.rp4wp-related-job_listing>ul li.job_listing a div.position,.rp4wp-related-job_listing>ul li.no_job_listings_found a div.position,ul.job_listings li.job_listing a div.position,ul.job_listings li.no_job_listings_found a div.position{float:left;width:55%;padding:0 0 0 42px;line-height:1.5em}.rp4wp-related-job_listing>ul li.job_listing a div.position h3,.rp4wp-related-job_listing>ul li.no_job_listings_found a div.position h3,ul.job_listings li.job_listing a div.position h3,ul.job_listings li.no_job_listings_found a div.position h3{margin:0;padding:0;line-height:inherit;font-size:inherit}.rp4wp-related-job_listing>ul li.job_listing a div.position .company,.rp4wp-related-job_listing>ul li.no_job_listings_found a div.position .company,ul.job_listings li.job_listing a div.position .company,ul.job_listings li.no_job_listings_found a div.position .company{color:#999}.rp4wp-related-job_listing>ul li.job_listing a div.position .company .tagline,.rp4wp-related-job_listing>ul li.no_job_listings_found a div.position .company .tagline,ul.job_listings li.job_listing a div.position .company .tagline,ul.job_listings li.no_job_listings_found a div.position .company .tagline{margin-left:.5em}.rp4wp-related-job_listing>ul li.job_listing a div.location,.rp4wp-related-job_listing>ul li.no_job_listings_found a div.location,ul.job_listings li.job_listing a div.location,ul.job_listings li.no_job_listings_found a div.location{float:left;text-align:left;width:25%;padding:0 0 0 1em;color:#999;line-height:1.5em}.rp4wp-related-job_listing>ul li.job_listing a .meta,.rp4wp-related-job_listing>ul li.no_job_listings_found a .meta,ul.job_listings li.job_listing a .meta,ul.job_listings li.no_job_listings_found a .meta{float:right;text-align:right;width:20%;padding:0 0 0 1em;margin:0;line-height:1.5em;color:#999;list-style:none outside}.rp4wp-related-job_listing>ul li.job_listing a .meta li,.rp4wp-related-job_listing>ul li.no_job_listings_found a .meta li,ul.job_listings li.job_listing a .meta li,ul.job_listings li.no_job_listings_found a .meta li{list-style:none outside;display:block;margin:0}.rp4wp-related-job_listing>ul li.job_listing a .meta .job-type,.rp4wp-related-job_listing>ul li.no_job_listings_found a .meta .job-type,ul.job_listings li.job_listing a .meta .job-type,ul.job_listings li.no_job_listings_found a .meta .job-type{font-weight:700}.rp4wp-related-job_listing>ul li.job_listing.job_position_featured a,.rp4wp-related-job_listing>ul li.no_job_listings_found.job_position_featured a,ul.job_listings li.job_listing.job_position_featured a,ul.job_listings li.no_job_listings_found.job_position_featured a{background:#fefee5}.rp4wp-related-job_listing>ul li.job_listing.job_position_featured a:focus,.rp4wp-related-job_listing>ul li.job_listing.job_position_featured a:hover,.rp4wp-related-job_listing>ul li.no_job_listings_found.job_position_featured a:focus,.rp4wp-related-job_listing>ul li.no_job_listings_found.job_position_featured a:hover,ul.job_listings li.job_listing.job_position_featured a:focus,ul.job_listings li.job_listing.job_position_featured a:hover,ul.job_listings li.no_job_listings_found.job_position_featured a:focus,ul.job_listings li.no_job_listings_found.job_position_featured a:hover{background-color:#fefed8}.widget ul.job_listings li.job_listing a{padding:1em 0}.widget ul.job_listings li.job_listing .position{float:none;width:auto;padding:0}.widget ul.job_listings li.job_listing ul.meta{float:none;width:auto;padding:0;margin:0;text-align:left}.widget ul.job_listings li.job_listing ul.meta li{float:none;display:inline;padding:0;margin:0 .5em 0 0;font-weight:400}.widget ul.job_listings li.job_listing ul.meta li:after{padding:0 0 0 .5em;content:"\2023"}.widget ul.job_listings li.job_listing ul.meta li:last-child:after{content:''}.job-manager .job-type,.job-types .job-type,.job_listing .job-type{color:#f08d3c}.job-manager .full-time,.job-types .full-time,.job_listing .full-time{color:#90da36}.job-manager .part-time,.job-types .part-time,.job_listing .part-time{color:#f08d3c}.job-manager .temporary,.job-types .temporary,.job_listing .temporary{color:#d93674}.job-manager .freelance,.job-types .freelance,.job_listing .freelance{color:#39c}.job-manager .internship,.job-types .internship,.job_listing .internship{color:#6033cc}@media only screen and (max-width:767px){ul.job_listings li.job_listing a,ul.job_listings li.no_job_listings_found a{padding:1em}ul.job_listings li.job_listing a img.company_logo,ul.job_listings li.no_job_listings_found a img.company_logo{visibility:hidden}ul.job_listings li.job_listing a div.position,ul.job_listings li.no_job_listings_found a div.position{float:left;width:60%;padding:0}ul.job_listings li.job_listing a div.location,ul.job_listings li.no_job_listings_found a div.location{float:right;width:40%;line-height:2em;font-size:.75em;padding:0 0 0 1em;text-align:right}ul.job_listings li.job_listing a .meta,ul.job_listings li.no_job_listings_found a .meta{float:right;width:40%;line-height:2em;font-size:.75em}ul.job_listings li.job_listing a .meta li,ul.job_listings li.no_job_listings_found a .meta li{font-size:1em}}.twenty-eleven ul.job_listings li.job_listing,.twenty-eleven ul.job_listings li.no_job_listings_found{padding:0!important}
assets/css/job-listings.less ADDED
@@ -0,0 +1,218 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ @import "mixins";
2
+
3
+ .rp4wp-related-job_listing > ul,
4
+ ul.job_listings {
5
+ padding: 0;
6
+ margin: 0;
7
+ border-top: 1px solid #eee;
8
+
9
+ &.loading {
10
+ min-height: 96px;
11
+ border-bottom: 1px solid #eee;
12
+ background: url(../images/ajax-loader.gif) no-repeat center 32px;
13
+ }
14
+ li.job_listing, li.no_job_listings_found {
15
+ list-style: none outside;
16
+ padding: 0;
17
+ margin: 0;
18
+ border-bottom: 1px solid #eee;
19
+
20
+ &.job_position_filled {
21
+ a {
22
+ opacity: 0.25;
23
+ }
24
+ }
25
+ &.no_job_listings_found {
26
+ padding: 1em;
27
+ border-bottom: 1px solid #eee;
28
+ }
29
+ a {
30
+ display: block;
31
+ padding: 1em 1em 1em 2em;
32
+ border: 0;
33
+ overflow: hidden;
34
+ zoom: 1;
35
+ position: relative;
36
+ line-height: 1.5em;
37
+ text-decoration: none;
38
+
39
+ &:hover, &:focus {
40
+ background-color: #fcfcfc;
41
+ }
42
+ img.company_logo {
43
+ width: 42px;
44
+ height: 42px;
45
+ position: absolute;
46
+ left: 1em;
47
+ float: left;
48
+ margin-right: 1em;
49
+ vertical-align: middle;
50
+ box-shadow: none;
51
+ }
52
+ div.position, div.location, ul.meta {
53
+ -webkit-box-sizing: border-box; /* Safari/Chrome, other WebKit */
54
+ -moz-box-sizing: border-box; /* Firefox, other Gecko */
55
+ box-sizing: border-box; /* Opera/IE 8+ */
56
+ }
57
+ div.position {
58
+ float: left;
59
+ width: 55%;
60
+ padding: 0 0 0 42px;
61
+ line-height: 1.5em;
62
+ h3 {
63
+ margin: 0;
64
+ padding: 0;
65
+ line-height: inherit;
66
+ font-size: inherit;
67
+ }
68
+ .company {
69
+ color: #999;
70
+ .tagline {
71
+ margin-left: .5em;
72
+ }
73
+ }
74
+ }
75
+ div.location {
76
+ float: left;
77
+ text-align: left;
78
+ width: 25%;
79
+ padding: 0 0 0 1em;
80
+ color: #999;
81
+ line-height: 1.5em;
82
+ }
83
+ .meta {
84
+ float: right;
85
+ text-align: right;
86
+ width: 20%;
87
+ padding: 0 0 0 1em;
88
+ margin: 0;
89
+ line-height: 1.5em;
90
+ color: #999;
91
+ list-style: none outside;
92
+ li {
93
+ list-style: none outside;
94
+ display: block;
95
+ margin: 0;
96
+ }
97
+ .job-type {
98
+ font-weight: bold;
99
+ }
100
+ }
101
+ }
102
+ &.job_position_featured {
103
+ a {
104
+ background: #fefee5;
105
+
106
+ &:hover, &:focus {
107
+ background-color: #fefed8;
108
+ }
109
+ }
110
+ }
111
+ }
112
+ }
113
+ .widget {
114
+ ul.job_listings {
115
+ li.job_listing {
116
+ a {
117
+ padding: 1em 0;
118
+ }
119
+ .position {
120
+ float: none;
121
+ width: auto;
122
+ padding: 0;
123
+ }
124
+ ul.meta {
125
+ float: none;
126
+ width: auto;
127
+ padding: 0;
128
+ margin: 0;
129
+ text-align: left;
130
+ li {
131
+ float: none;
132
+ display: inline;
133
+ padding: 0;
134
+ margin: 0 .5em 0 0;
135
+ font-weight: normal;
136
+
137
+ &:after {
138
+ padding: 0 0 0 .5em;
139
+ content: "\2023";
140
+ }
141
+ &:last-child:after {
142
+ content: '';
143
+ }
144
+ }
145
+ }
146
+ }
147
+ }
148
+ }
149
+ .job-manager, .job_listing, .job-types {
150
+ .job-type {
151
+ color: @part-time;
152
+ }
153
+ .full-time {
154
+ color: @full-time;
155
+ }
156
+ .part-time {
157
+ color: @part-time;
158
+ }
159
+ .temporary {
160
+ color: @temporary;
161
+ }
162
+ .freelance {
163
+ color: @freelance;
164
+ }
165
+ .internship {
166
+ color: @internship;
167
+ }
168
+ }
169
+
170
+ /**
171
+ * Mobile styles
172
+ */
173
+ @media only screen and (max-width: 767px) {
174
+ ul.job_listings {
175
+ li.job_listing, li.no_job_listings_found {
176
+ a {
177
+ padding: 1em;
178
+ img.company_logo {
179
+ visibility: hidden;
180
+ }
181
+ div.position {
182
+ float: left;
183
+ width: 60%;
184
+ padding: 0;
185
+ }
186
+ div.location {
187
+ float: right;
188
+ width: 40%;
189
+ line-height: 2em;
190
+ font-size: .75em;
191
+ padding: 0 0 0 1em;
192
+ text-align: right;
193
+ }
194
+ .meta {
195
+ float: right;
196
+ width: 40%;
197
+ line-height: 2em;
198
+ font-size: .75em;
199
+ li {
200
+ font-size: 1em;
201
+ }
202
+ }
203
+ }
204
+ }
205
+ }
206
+ }
207
+
208
+
209
+ /**
210
+ * Default theme fixes
211
+ */
212
+ .twenty-eleven {
213
+ ul.job_listings {
214
+ li.job_listing, li.no_job_listings_found {
215
+ padding: 0 !important;
216
+ }
217
+ }
218
+ }
assets/js/admin.js CHANGED
@@ -1,4 +1,3 @@
1
- /* global job_manager_admin */
2
  jQuery(document).ready(function($) {
3
  // Tooltips
4
  $( '.tips, .help_tip' ).tipTip({
@@ -15,22 +14,6 @@ jQuery(document).ready(function($) {
15
  return false;
16
  });
17
 
18
- // Datepicker
19
- $( 'input.job-manager-datepicker, input#_job_expires' ).datepicker({
20
- altFormat : 'yy-mm-dd',
21
- dateFormat : job_manager_admin.date_format,
22
- });
23
-
24
- $( 'input.job-manager-datepicker, input#_job_expires' ).each( function(){
25
- if ( $(this).val() ) {
26
- var dateParts = $(this).val().split("-");
27
- if ( 3 === dateParts.length ) {
28
- var selectedDate = new Date(parseInt(dateParts[0], 10), (parseInt(dateParts[1], 10) - 1), parseInt(dateParts[2], 10));
29
- $(this).datepicker('setDate', selectedDate);
30
- }
31
- }
32
- });
33
-
34
  // Uploading files
35
  var file_frame;
36
  var file_target_input;
 
1
  jQuery(document).ready(function($) {
2
  // Tooltips
3
  $( '.tips, .help_tip' ).tipTip({
14
  return false;
15
  });
16
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
  // Uploading files
18
  var file_frame;
19
  var file_target_input;
assets/js/admin.min.js CHANGED
@@ -1 +1 @@
1
- jQuery(document).ready(function(t){t(".tips, .help_tip").tipTip({attribute:"data-tip",fadeIn:50,fadeOut:50,delay:200}),t("p.form-field-author").on("click","a.change-author",function(){return t(this).closest("p").find(".current-author").hide(),t(this).closest("p").find(".change-author").show(),!1}),t("input.job-manager-datepicker, input#_job_expires").datepicker({altFormat:"yy-mm-dd",dateFormat:job_manager_admin.date_format}),t("input.job-manager-datepicker, input#_job_expires").each(function(){if(t(this).val()){var e=t(this).val().split("-");if(3===e.length){var a=new Date(parseInt(e[0],10),parseInt(e[1],10)-1,parseInt(e[2],10));t(this).datepicker("setDate",a)}}});var e,a,i;t(document).on("click",".wp_job_manager_add_another_file_button",function(e){e.preventDefault();var a=t(this).data("field_name"),i=t(this).data("field_placeholder"),n=t(this).data("uploader_button_text"),o=t(this).data("uploader_button"),l=t(this).data("view_button");t(this).before('<span class="file_url"><input type="text" name="'+a+'[]" placeholder="'+i+'" /><button class="button button-small wp_job_manager_upload_file_button" data-uploader_button_text="'+n+'">'+o+'</button><button class="button button-small wp_job_manager_view_file_button">'+l+"</button></span>")}),t(document).on("click",".wp_job_manager_view_file_button",function(e){e.preventDefault(),i=t(this).closest(".file_url");var n=(a=i.find("input")).val();n.indexOf("://")>-1?window.open(n,"_blank"):(a.addClass("file_no_url"),setTimeout(function(){a.removeClass("file_no_url")},1e3))}),t(document).on("click",".wp_job_manager_upload_file_button",function(n){n.preventDefault(),i=t(this).closest(".file_url"),a=i.find("input"),e?e.open():((e=wp.media.frames.file_frame=wp.media({title:t(this).data("uploader_title"),button:{text:t(this).data("uploader_button_text")},multiple:!1})).on("select",function(){var i=e.state().get("selection").first().toJSON();t(a).val(i.url)}),e.open())})}),jQuery(document).ready(function(t){var e="job_listing_type";t("#"+e+"checklist li :radio, #"+e+"checklist-pop :radio").live("click",function(){var a=t(this),i=a.is(":checked"),n=a.val();t("#"+e+"checklist li :radio, #"+e+"checklist-pop :radio").prop("checked",!1),t("#in-"+e+"-"+n+", #in-popular-"+e+"-"+n).prop("checked",i)})});
1
+ jQuery(document).ready(function(t){t(".tips, .help_tip").tipTip({attribute:"data-tip",fadeIn:50,fadeOut:50,delay:200}),t("p.form-field-author").on("click","a.change-author",function(){return t(this).closest("p").find(".current-author").hide(),t(this).closest("p").find(".change-author").show(),!1});var e,a,i;t(document).on("click",".wp_job_manager_add_another_file_button",function(e){e.preventDefault();var a=t(this).data("field_name"),i=t(this).data("field_placeholder"),n=t(this).data("uploader_button_text"),o=t(this).data("uploader_button"),l=t(this).data("view_button");t(this).before('<span class="file_url"><input type="text" name="'+a+'[]" placeholder="'+i+'" /><button class="button button-small wp_job_manager_upload_file_button" data-uploader_button_text="'+n+'">'+o+'</button><button class="button button-small wp_job_manager_view_file_button">'+l+"</button></span>")}),t(document).on("click",".wp_job_manager_view_file_button",function(e){e.preventDefault(),i=t(this).closest(".file_url");var n=(a=i.find("input")).val();n.indexOf("://")>-1?window.open(n,"_blank"):(a.addClass("file_no_url"),setTimeout(function(){a.removeClass("file_no_url")},1e3))}),t(document).on("click",".wp_job_manager_upload_file_button",function(n){n.preventDefault(),i=t(this).closest(".file_url"),a=i.find("input"),e?e.open():((e=wp.media.frames.file_frame=wp.media({title:t(this).data("uploader_title"),button:{text:t(this).data("uploader_button_text")},multiple:!1})).on("select",function(){var i=e.state().get("selection").first().toJSON();t(a).val(i.url)}),e.open())})}),jQuery(document).ready(function(t){var e="job_listing_type";t("#"+e+"checklist li :radio, #"+e+"checklist-pop :radio").live("click",function(){var a=t(this),i=a.is(":checked"),n=a.val();t("#"+e+"checklist li :radio, #"+e+"checklist-pop :radio").prop("checked",!1),t("#in-"+e+"-"+n+", #in-popular-"+e+"-"+n).prop("checked",i)})});
assets/js/ajax-filters.js CHANGED
@@ -90,6 +90,9 @@ jQuery( document ).ready( function ( $ ) {
90
  location = target.data( 'location' );
91
 
92
  if ( categories ) {
 
 
 
93
  categories = categories.split( ',' );
94
  }
95
 
90
  location = target.data( 'location' );
91
 
92
  if ( categories ) {
93
+ if ( typeof categories !== 'string' ) {
94
+ categories = String( categories );
95
+ }
96
  categories = categories.split( ',' );
97
  }
98
 
assets/js/ajax-filters.min.js CHANGED
@@ -1 +1 @@
1
- jQuery(document).ready(function(e){function a(a,t){if(i){var n=a.find(".job_filters"),s=e(n).serialize(),r=e("div.job_listings").index(a);window.history.replaceState({id:"job_manager_state",page:t,data:s,index:r},"",o+"#s=1")}}var t=[];e(".job_listings").on("update_results",function(a,i,o,n){var s,r,d,l="",_=e(this),g=_.find(".job_filters"),c=_.find(".showing_jobs"),p=_.find(".job_listings"),h=_.data("per_page"),u=_.data("orderby"),f=_.data("order"),b=_.data("featured"),j=_.data("filled"),m=_.data("job_types"),w=_.data("post_status"),v=e("div.job_listings").index(this);if(!(v<0)){if(t[v]&&t[v].abort(),o||(e(p).addClass("loading"),e("li.job_listing, li.no_job_listings_found",p).css("visibility","hidden"),i>1&&!0!==_.data("show_pagination")?e(p).before('<a class="load_more_jobs load_previous" href="#"><strong>'+job_manager_ajax_filters.i18n_load_prev_listings+"</strong></a>"):_.find(".load_previous").remove(),_.find(".load_more_jobs").data("page",i)),!0===_.data("show_filters")){var y=[];e(':input[name="filter_job_type[]"]:checked, :input[name="filter_job_type[]"][type="hidden"], :input[name="filter_job_type"]',g).each(function(){y.push(e(this).val())}),s=g.find(':input[name^="search_categories"]').map(function(){return e(this).val()}).get(),r="",d="";var k=g.find(':input[name="search_keywords"]'),x=g.find(':input[name="search_location"]');k.val()!==k.attr("placeholder")&&(r=k.val()),x.val()!==x.attr("placeholder")&&(d=x.val()),l={lang:job_manager_ajax_filters.lang,search_keywords:r,search_location:d,search_categories:s,filter_job_type:y,filter_post_status:w,per_page:h,orderby:u,order:f,page:i,featured:b,filled:j,show_pagination:_.data("show_pagination"),form_data:g.serialize()}}else s=_.data("categories"),r=_.data("keywords"),d=_.data("location"),s&&(s=s.split(",")),l={lang:job_manager_ajax_filters.lang,search_categories:s,search_keywords:r,search_location:d,filter_post_status:w,filter_job_type:m,per_page:h,orderby:u,order:f,page:i,featured:b,filled:j,show_pagination:_.data("show_pagination")};t[v]=e.ajax({type:"POST",url:job_manager_ajax_filters.ajax_url.toString().replace("%%endpoint%%","get_listings"),data:l,success:function(a){if(a)try{a.showing?e(c).show().html("<span>"+a.showing+"</span>"+a.showing_links):e(c).hide(),a.showing_all?e(c).addClass("wp-job-manager-showing-all"):e(c).removeClass("wp-job-manager-showing-all"),a.html&&(o&&n?e(p).prepend(a.html):o?e(p).append(a.html):e(p).html(a.html)),!0===_.data("show_pagination")?(_.find(".job-manager-pagination").remove(),a.pagination&&_.append(a.pagination)):(!a.found_jobs||a.max_num_pages<=i?e(".load_more_jobs:not(.load_previous)",_).hide():n||e(".load_more_jobs",_).show(),e(".load_more_jobs",_).removeClass("loading"),e("li.job_listing",p).css("visibility","visible")),e(p).removeClass("loading"),_.triggerHandler("updated_results",a)}catch(e){window.console&&window.console.log(e)}},error:function(e,a,t){window.console&&"abort"!==a&&window.console.log(a+": "+t)},statusCode:{404:function(){window.console&&window.console.log("Error 404: Ajax Endpoint cannot be reached. Go to Settings > Permalinks and save to resolve.")}}})}}),e("#search_keywords, #search_location, .job_types :input, #search_categories, .job-manager-filter").change(function(){var t=e(this).closest("div.job_listings");t.triggerHandler("update_results",[1,!1]),a(t,1)}).on("keyup",function(a){13===a.which&&e(this).trigger("change")}),e(".job_filters").on("click",".reset",function(){var t=e(this).closest("div.job_listings"),i=e(this).closest("form");return i.find(':input[name="search_keywords"], :input[name="search_location"], .job-manager-filter').not(':input[type="hidden"]').val("").trigger("chosen:updated"),i.find(':input[name^="search_categories"]').not(':input[type="hidden"]').val("").trigger("chosen:updated"),e(':input[name="filter_job_type[]"]',i).not(':input[type="hidden"]').attr("checked","checked"),t.triggerHandler("reset"),t.triggerHandler("update_results",[1,!1]),a(t,1),!1}),e(document.body).on("click",".load_more_jobs",function(){var t=e(this).closest("div.job_listings"),i=parseInt(e(this).data("page")||1,10),o=!1;return e(this).addClass("loading"),e(this).is(".load_previous")?(o=!0,1===(i-=1)?e(this).remove():e(this).data("page",i)):(i+=1,e(this).data("page",i),a(t,i)),t.triggerHandler("update_results",[i,!0,o]),!1}),e("div.job_listings").on("click",".job-manager-pagination a",function(){var t=e(this).closest("div.job_listings"),i=e(this).data("page");return a(t,i),t.triggerHandler("update_results",[i,!1]),e("body, html").animate({scrollTop:t.offset().top},600),!1}),e.isFunction(e.fn.chosen)&&(1===job_manager_ajax_filters.is_rtl&&e('select[name^="search_categories"]').addClass("chosen-rtl"),e('select[name^="search_categories"]').chosen({search_contains:!0}));var i=!1;window.history&&window.history.pushState&&(i=!0);var o=document.location.href.split("#")[0];e(window).on("load",function(){e(".job_filters").each(function(){var a=e(this).closest("div.job_listings"),t=a.find(".job_filters"),i=1,o=e("div.job_listings").index(a);if(window.history.state&&window.location.hash){var n=window.history.state;n.id&&"job_manager_state"===n.id&&o===n.index&&(i=n.page,t.deserialize(n.data),t.find(':input[name^="search_categories"]').not(':input[type="hidden"]').trigger("chosen:updated"))}a.triggerHandler("update_results",[i,!1])})})});
1
+ jQuery(document).ready(function(e){function a(a,t){if(i){var n=a.find(".job_filters"),s=e(n).serialize(),r=e("div.job_listings").index(a);window.history.replaceState({id:"job_manager_state",page:t,data:s,index:r},"",o+"#s=1")}}var t=[];e(".job_listings").on("update_results",function(a,i,o,n){var s,r,d,l="",_=e(this),g=_.find(".job_filters"),c=_.find(".showing_jobs"),p=_.find(".job_listings"),h=_.data("per_page"),u=_.data("orderby"),f=_.data("order"),b=_.data("featured"),j=_.data("filled"),m=_.data("job_types"),w=_.data("post_status"),v=e("div.job_listings").index(this);if(!(v<0)){if(t[v]&&t[v].abort(),o||(e(p).addClass("loading"),e("li.job_listing, li.no_job_listings_found",p).css("visibility","hidden"),i>1&&!0!==_.data("show_pagination")?e(p).before('<a class="load_more_jobs load_previous" href="#"><strong>'+job_manager_ajax_filters.i18n_load_prev_listings+"</strong></a>"):_.find(".load_previous").remove(),_.find(".load_more_jobs").data("page",i)),!0===_.data("show_filters")){var y=[];e(':input[name="filter_job_type[]"]:checked, :input[name="filter_job_type[]"][type="hidden"], :input[name="filter_job_type"]',g).each(function(){y.push(e(this).val())}),s=g.find(':input[name^="search_categories"]').map(function(){return e(this).val()}).get(),r="",d="";var k=g.find(':input[name="search_keywords"]'),x=g.find(':input[name="search_location"]');k.val()!==k.attr("placeholder")&&(r=k.val()),x.val()!==x.attr("placeholder")&&(d=x.val()),l={lang:job_manager_ajax_filters.lang,search_keywords:r,search_location:d,search_categories:s,filter_job_type:y,filter_post_status:w,per_page:h,orderby:u,order:f,page:i,featured:b,filled:j,show_pagination:_.data("show_pagination"),form_data:g.serialize()}}else s=_.data("categories"),r=_.data("keywords"),d=_.data("location"),s&&("string"!=typeof s&&(s=String(s)),s=s.split(",")),l={lang:job_manager_ajax_filters.lang,search_categories:s,search_keywords:r,search_location:d,filter_post_status:w,filter_job_type:m,per_page:h,orderby:u,order:f,page:i,featured:b,filled:j,show_pagination:_.data("show_pagination")};t[v]=e.ajax({type:"POST",url:job_manager_ajax_filters.ajax_url.toString().replace("%%endpoint%%","get_listings"),data:l,success:function(a){if(a)try{a.showing?e(c).show().html("<span>"+a.showing+"</span>"+a.showing_links):e(c).hide(),a.showing_all?e(c).addClass("wp-job-manager-showing-all"):e(c).removeClass("wp-job-manager-showing-all"),a.html&&(o&&n?e(p).prepend(a.html):o?e(p).append(a.html):e(p).html(a.html)),!0===_.data("show_pagination")?(_.find(".job-manager-pagination").remove(),a.pagination&&_.append(a.pagination)):(!a.found_jobs||a.max_num_pages<=i?e(".load_more_jobs:not(.load_previous)",_).hide():n||e(".load_more_jobs",_).show(),e(".load_more_jobs",_).removeClass("loading"),e("li.job_listing",p).css("visibility","visible")),e(p).removeClass("loading"),_.triggerHandler("updated_results",a)}catch(e){window.console&&window.console.log(e)}},error:function(e,a,t){window.console&&"abort"!==a&&window.console.log(a+": "+t)},statusCode:{404:function(){window.console&&window.console.log("Error 404: Ajax Endpoint cannot be reached. Go to Settings > Permalinks and save to resolve.")}}})}}),e("#search_keywords, #search_location, .job_types :input, #search_categories, .job-manager-filter").change(function(){var t=e(this).closest("div.job_listings");t.triggerHandler("update_results",[1,!1]),a(t,1)}).on("keyup",function(a){13===a.which&&e(this).trigger("change")}),e(".job_filters").on("click",".reset",function(){var t=e(this).closest("div.job_listings"),i=e(this).closest("form");return i.find(':input[name="search_keywords"], :input[name="search_location"], .job-manager-filter').not(':input[type="hidden"]').val("").trigger("chosen:updated"),i.find(':input[name^="search_categories"]').not(':input[type="hidden"]').val("").trigger("chosen:updated"),e(':input[name="filter_job_type[]"]',i).not(':input[type="hidden"]').attr("checked","checked"),t.triggerHandler("reset"),t.triggerHandler("update_results",[1,!1]),a(t,1),!1}),e(document.body).on("click",".load_more_jobs",function(){var t=e(this).closest("div.job_listings"),i=parseInt(e(this).data("page")||1,10),o=!1;return e(this).addClass("loading"),e(this).is(".load_previous")?(o=!0,1===(i-=1)?e(this).remove():e(this).data("page",i)):(i+=1,e(this).data("page",i),a(t,i)),t.triggerHandler("update_results",[i,!0,o]),!1}),e("div.job_listings").on("click",".job-manager-pagination a",function(){var t=e(this).closest("div.job_listings"),i=e(this).data("page");return a(t,i),t.triggerHandler("update_results",[i,!1]),e("body, html").animate({scrollTop:t.offset().top},600),!1}),e.isFunction(e.fn.chosen)&&(1===job_manager_ajax_filters.is_rtl&&e('select[name^="search_categories"]').addClass("chosen-rtl"),e('select[name^="search_categories"]').chosen({search_contains:!0}));var i=!1;window.history&&window.history.pushState&&(i=!0);var o=document.location.href.split("#")[0];e(window).on("load",function(){e(".job_filters").each(function(){var a=e(this).closest("div.job_listings"),t=a.find(".job_filters"),i=1,o=e("div.job_listings").index(a);if(window.history.state&&window.location.hash){var n=window.history.state;n.id&&"job_manager_state"===n.id&&o===n.index&&(i=n.page,t.deserialize(n.data),t.find(':input[name^="search_categories"]').not(':input[type="hidden"]').trigger("chosen:updated"))}a.triggerHandler("update_results",[i,!1])})})});
assets/js/datepicker.js ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* global job_manager_datepicker */
2
+ jQuery(document).ready(function($) {
3
+ var datePickerOptions = {
4
+ altFormat : 'yy-mm-dd',
5
+ };
6
+ if ( typeof job_manager_datepicker !== 'undefined' ) {
7
+ datePickerOptions.dateFormat = job_manager_datepicker.date_format;
8
+ }
9
+
10
+ $( 'input.job-manager-datepicker, input#_job_expires' ).each( function(){
11
+ var $hidden_input = $( '<input />', { type: 'hidden', name: $(this).attr( 'name' ) } ).insertAfter( $( this ) );
12
+ $(this).attr( 'name', $(this).attr( 'name' ) + '-datepicker' );
13
+ $(this).keyup( function() {
14
+ if ( '' === $(this).val() ) {
15
+ $hidden_input.val( '' );
16
+ }
17
+ } );
18
+ $(this).datepicker( $.extend( {}, datePickerOptions, { altField: $hidden_input } ) );
19
+ if ( $(this).val() ) {
20
+ var dateParts = $(this).val().split("-");
21
+ if ( 3 === dateParts.length ) {
22
+ var selectedDate = new Date(parseInt(dateParts[0], 10), (parseInt(dateParts[1], 10) - 1), parseInt(dateParts[2], 10));
23
+ $(this).datepicker('setDate', selectedDate);
24
+ }
25
+ }
26
+ });
27
+ });
assets/js/datepicker.min.js ADDED
@@ -0,0 +1 @@
 
1
+ jQuery(document).ready(function(t){var e={altFormat:"yy-mm-dd"};"undefined"!=typeof job_manager_datepicker&&(e.dateFormat=job_manager_datepicker.date_format),t("input.job-manager-datepicker, input#_job_expires").each(function(){var a=t("<input />",{type:"hidden",name:t(this).attr("name")}).insertAfter(t(this));if(t(this).attr("name",t(this).attr("name")+"-datepicker"),t(this).keyup(function(){""===t(this).val()&&a.val("")}),t(this).datepicker(t.extend({},e,{altField:a})),t(this).val()){var i=t(this).val().split("-");if(3===i.length){var n=new Date(parseInt(i[0],10),parseInt(i[1],10)-1,parseInt(i[2],10));t(this).datepicker("setDate",n)}}})});
assets/js/job-submission.js CHANGED
@@ -3,4 +3,8 @@ jQuery(document).ready(function($) {
3
  $(this).closest( '.job-manager-uploaded-file' ).remove();
4
  return false;
5
  });
6
- });
 
 
 
 
3
  $(this).closest( '.job-manager-uploaded-file' ).remove();
4
  return false;
5
  });
6
+ $('body').on( 'submit', '.job-manager-form:not(.prevent-spinner-behavior)', function() {
7
+ $(this).find( '.spinner' ).addClass( 'is-active' );
8
+ $(this).find( 'input[type=submit]' ).addClass( 'disabled' ).on( 'click', function() { return false; } );
9
+ });
10
+ });
assets/js/job-submission.min.js CHANGED
@@ -1 +1 @@
1
- jQuery(document).ready(function(e){e("body").on("click",".job-manager-remove-uploaded-file",function(){return e(this).closest(".job-manager-uploaded-file").remove(),!1})});
1
+ jQuery(document).ready(function(n){n("body").on("click",".job-manager-remove-uploaded-file",function(){return n(this).closest(".job-manager-uploaded-file").remove(),!1}),n("body").on("submit",".job-manager-form:not(.prevent-spinner-behavior)",function(){n(this).find(".spinner").addClass("is-active"),n(this).find("input[type=submit]").addClass("disabled").on("click",function(){return!1})})});
changelog.txt CHANGED
@@ -1,3 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  = 1.29.3 =
2
  * Fix: When retrieving job listing results, cache only the post results and not all of `WP_Query` (@jom; props slavco)
3
 
1
+ = 1.30.0 =
2
+ * Enhancement: Adds ability to have a reCAPTCHA field to check if job listing author is human. (@jom)
3
+ * Enhancement: Allows for option to make edits to job listings force listing back into pending approval status. (@jom)
4
+ * Enhancement: Adds spinner and disables form when user submits job listing. (@jom)
5
+ * Enhancement: Update the add-ons page of the plugin. (@jom)
6
+ * Enhancement: Added the ability to sort jobs randomly on the Featured Jobs Widget. (@jom)
7
+ * Enhancement: Improved handling of alternative date formats when editing job expiration field in WP admin. (@jom)
8
+ * Enhancement: Added star indicator next to featured listings on `[job_dashboard]`. (@jom)
9
+ * Enhancement: Opt-in to usage tracking so we can better improve the plugin. (@alexsanford, @donnapep, @jom)
10
+ * Enhancement: Introduced new asset enqueuing strategy that will be turned on in 1.32.0. Requires plugin and theme updates. (@jom; Dev notes: https://github.com/Automattic/WP-Job-Manager/pull/1354)
11
+ * Fix: Use WordPress core checks for image formats to not confuse `docx` as an image. (@tripflex)
12
+ * Fix: Issue with `[jobs]` shortcode when `categories` argument is provided. (@jom)
13
+ * Fix: Issue with double encoding HTML entities in custom text area fields. (@jom)
14
+ * Fix: Updates `job-dashboard.php` template with `colspan` fix on no active listings message. (@jom)
15
+ * Fix: Clear job listings cache when deleting a user and their job listings. (@jom)
16
+ * Dev: Adds `is_wpjm()` and related functions to test if we're on a WPJM related page. (@jom)
17
+ * Dev: Adds `job_manager_user_edit_job_listing` action that fires after a user edits a job listing. (@jom)
18
+ * Dev: Adds `job_manager_enable_job_archive_page` filter to enable job archive page. (@jom)
19
+ * Dev: Adds `date` field for custom job listing form fields. (@alexsandford)
20
+
21
  = 1.29.3 =
22
  * Fix: When retrieving job listing results, cache only the post results and not all of `WP_Query` (@jom; props slavco)
23
 
includes/3rd-party/3rd-party.php CHANGED
@@ -2,8 +2,10 @@
2
  /**
3
  * Load 3rd party compatibility tweaks.
4
  */
5
- require_once( JOB_MANAGER_PLUGIN_DIR . '/includes/3rd-party/jetpack.php' );
6
- require_once( JOB_MANAGER_PLUGIN_DIR . '/includes/3rd-party/wpml.php' );
7
- require_once( JOB_MANAGER_PLUGIN_DIR . '/includes/3rd-party/polylang.php' );
8
- require_once( JOB_MANAGER_PLUGIN_DIR . '/includes/3rd-party/yoast.php' );
9
- require_once( JOB_MANAGER_PLUGIN_DIR . '/includes/3rd-party/all_in_one_seo_pack.php' );
 
 
2
  /**
3
  * Load 3rd party compatibility tweaks.
4
  */
5
+ require_once JOB_MANAGER_PLUGIN_DIR . '/includes/3rd-party/jetpack.php';
6
+ require_once JOB_MANAGER_PLUGIN_DIR . '/includes/3rd-party/wpml.php';
7
+ require_once JOB_MANAGER_PLUGIN_DIR . '/includes/3rd-party/polylang.php';
8
+ require_once JOB_MANAGER_PLUGIN_DIR . '/includes/3rd-party/yoast.php';
9
+ require_once JOB_MANAGER_PLUGIN_DIR . '/includes/3rd-party/all-in-one-seo-pack.php';
10
+ require_once JOB_MANAGER_PLUGIN_DIR . '/includes/3rd-party/rp4wp.php';
11
+ require_once JOB_MANAGER_PLUGIN_DIR . '/includes/3rd-party/wp-all-import.php';
includes/3rd-party/{all_in_one_seo_pack.php → all-in-one-seo-pack.php} RENAMED
File without changes
includes/3rd-party/polylang.php CHANGED
@@ -41,8 +41,8 @@ function polylang_wpjm_query_language( $query_args ) {
41
  */
42
  function polylang_wpjm_get_job_listings_lang( $lang ) {
43
  if ( function_exists( 'pll_current_language' )
44
- && function_exists( 'pll_is_translated_post_type' )
45
- && pll_is_translated_post_type( 'job_listing' ) ) {
46
  return pll_current_language();
47
  }
48
  return $lang;
41
  */
42
  function polylang_wpjm_get_job_listings_lang( $lang ) {
43
  if ( function_exists( 'pll_current_language' )
44
+ && function_exists( 'pll_is_translated_post_type' )
45
+ && pll_is_translated_post_type( 'job_listing' ) ) {
46
  return pll_current_language();
47
  }
48
  return $lang;
includes/3rd-party/rp4wp.php ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Adds additional compatibility with Related Post for WordPress.
4
+ */
5
+
6
+ add_filter( 'rp4wp_get_template', 'wpjm_rp4wp_template', 10, 3 );
7
+ add_filter( 'rp4wp_related_meta_fields', 'wpjm_rp4wp_related_meta_fields', 10, 3 );
8
+ add_filter( 'rp4wp_related_meta_fields_weight', 'wpjm_rp4wp_related_meta_fields_weight', 10, 3 );
9
+
10
+ /**
11
+ * Replaces RP4WP template with the template from Job Manager.
12
+ *
13
+ * @param string $located
14
+ * @param string $template_name
15
+ * @param array $args
16
+ * @return string
17
+ */
18
+ function wpjm_rp4wp_template( $located, $template_name, $args ) {
19
+ if ( 'related-post-default.php' === $template_name && 'job_listing' === $args['related_post']->post_type ) {
20
+ return JOB_MANAGER_PLUGIN_DIR . '/templates/content-job_listing.php';
21
+ }
22
+ return $located;
23
+ }
24
+
25
+ /**
26
+ * Adds meta fields for RP4WP to relate jobs by.
27
+ *
28
+ * @param array $meta_fields
29
+ * @param int $post_id
30
+ * @param WP_Post $post
31
+ * @return array
32
+ */
33
+ function wpjm_rp4wp_related_meta_fields( $meta_fields, $post_id, $post ) {
34
+ if ( 'job_listing' === $post->post_type ) {
35
+ $meta_fields[] = '_company_name';
36
+ $meta_fields[] = '_job_location';
37
+ }
38
+ return $meta_fields;
39
+ }
40
+
41
+ /**
42
+ * Adds meta fields for RP4WP to relate jobs by.
43
+ *
44
+ * @param int $weight
45
+ * @param WP_Post $post
46
+ * @param string $meta_field
47
+ * @return int
48
+ */
49
+ function wpjm_rp4wp_related_meta_fields_weight( $weight, $post, $meta_field ) {
50
+ if ( 'job_listing' === $post->post_type ) {
51
+ $weight = 100;
52
+ }
53
+ return $weight;
54
+ }
includes/3rd-party/wp-all-import.php ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Adds additional compatibility with WP All Import.
4
+ */
5
+
6
+ add_action( 'pmxi_saved_post', 'wpjm_pmxi_saved_post', 10, 1 );
7
+
8
+ /**
9
+ * After importing via WP All Import, adds default meta data.
10
+ *
11
+ * @param int $post_id
12
+ */
13
+ function wpjm_pmxi_saved_post( $post_id ) {
14
+ if ( 'job_listing' === get_post_type( $post_id ) ) {
15
+ WP_Job_Manager_Post_Types::instance()->maybe_add_default_meta_data( $post_id );
16
+ if ( ! WP_Job_Manager_Geocode::has_location_data( $post_id ) && ( $location = get_post_meta( $post_id, '_job_location', true ) ) ) {
17
+ WP_Job_Manager_Geocode::generate_location_data( $post_id, $location );
18
+ }
19
+ }
20
+ }
includes/3rd-party/yoast.php CHANGED
@@ -1,10 +1,10 @@
1
  <?php
2
  /**
3
  * Adds additional compatibility with Yoast SEO.
 
 
4
  */
5
 
6
- // Yoast SEO will by default include the `job_listing` post type because it is flagged as public.
7
-
8
  /**
9
  * Skip filled job listings.
10
  *
1
  <?php
2
  /**
3
  * Adds additional compatibility with Yoast SEO.
4
+ *
5
+ * Yoast SEO will by default include the `job_listing` post type because it is flagged as public.
6
  */
7
 
 
 
8
  /**
9
  * Skip filled job listings.
10
  *
includes/abstracts/abstract-wp-job-manager-form.php CHANGED
@@ -109,6 +109,7 @@ abstract class WP_Job_Manager_Form {
109
  * @param array $atts Attributes to use in the view handler.
110
  */
111
  public function output( $atts = array() ) {
 
112
  $step_key = $this->get_step_key( $this->step );
113
  $this->show_errors();
114
 
@@ -249,6 +250,84 @@ abstract class WP_Job_Manager_Form {
249
  $this->fields = array();
250
  }
251
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
252
  /**
253
  * Gets post data for fields.
254
  *
109
  * @param array $atts Attributes to use in the view handler.
110
  */
111
  public function output( $atts = array() ) {
112
+ $this->enqueue_scripts();
113
  $step_key = $this->get_step_key( $this->step );
114
  $this->show_errors();
115
 
250
  $this->fields = array();
251
  }
252
 
253
+ /**
254
+ * Enqueue the scripts for the form.
255
+ */
256
+ public function enqueue_scripts() {
257
+ if ( $this->use_recaptcha_field() ) {
258
+ wp_enqueue_script( 'recaptcha', 'https://www.google.com/recaptcha/api.js' );
259
+ }
260
+ }
261
+
262
+ /**
263
+ * Checks whether reCAPTCHA has been set up and is available.
264
+ *
265
+ * @return bool
266
+ */
267
+ public function is_recaptcha_available() {
268
+ $site_key = get_option( 'job_manager_recaptcha_site_key' );
269
+ $secret_key = get_option( 'job_manager_recaptcha_secret_key' );
270
+ $is_recaptcha_available = ! empty( $site_key ) && ! empty( $secret_key );
271
+
272
+ /**
273
+ * Filter whether reCAPTCHA should be available for this form.
274
+ *
275
+ * @since 1.30.0
276
+ *
277
+ * @param bool $is_recaptcha_available
278
+ */
279
+ return apply_filters( 'job_manager_is_recaptcha_available', $is_recaptcha_available );
280
+ }
281
+
282
+ /**
283
+ * Show reCAPTCHA field on the form.
284
+ *
285
+ * @return bool
286
+ */
287
+ public function use_recaptcha_field() {
288
+ return false;
289
+ }
290
+
291
+ /**
292
+ * Output the reCAPTCHA field.
293
+ */
294
+ public function display_recaptcha_field() {
295
+ $field = array();
296
+ $field['label'] = get_option( 'job_manager_recaptcha_label' );
297
+ $field['required'] = true;
298
+ $field['site_key'] = get_option( 'job_manager_recaptcha_site_key' );
299
+ get_job_manager_template( 'form-fields/recaptcha-field.php', array( 'key' => 'recaptcha', 'field' => $field ) );
300
+ }
301
+
302
+ /**
303
+ * Validate a reCAPTCHA field.
304
+ *
305
+ * @param bool $success
306
+ *
307
+ * @return bool|WP_Error
308
+ */
309
+ public function validate_recaptcha_field( $success ) {
310
+ $recaptcha_field_label = get_option( 'job_manager_recaptcha_label' );
311
+ if ( empty( $_POST['g-recaptcha-response'] ) ) {
312
+ return new WP_Error( 'validation-error', sprintf( __( '"%s" check failed. Please try again.', 'wp-job-manager' ), $recaptcha_field_label ) );
313
+ }
314
+
315
+ $response = wp_remote_get( add_query_arg( array(
316
+ 'secret' => get_option( 'job_manager_recaptcha_secret_key' ),
317
+ 'response' => isset( $_POST['g-recaptcha-response'] ) ? $_POST['g-recaptcha-response'] : '',
318
+ 'remoteip' => isset( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ? $_SERVER['HTTP_X_FORWARDED_FOR'] : $_SERVER['REMOTE_ADDR']
319
+ ), 'https://www.google.com/recaptcha/api/siteverify' ) );
320
+
321
+ if ( is_wp_error( $response )
322
+ || empty( $response['body'] )
323
+ || ! ( $json = json_decode( $response['body'] ) )
324
+ || ! $json->success ) {
325
+ return new WP_Error( 'validation-error', sprintf( __( '"%s" check failed. Please try again.', 'wp-job-manager' ), $recaptcha_field_label ) );
326
+ }
327
+
328
+ return $success;
329
+ }
330
+
331
  /**
332
  * Gets post data for fields.
333
  *
includes/admin/class-wp-job-manager-addons.php CHANGED
@@ -14,6 +14,7 @@ if ( ! class_exists( 'WP_Job_Manager_Addons' ) ) :
14
  * @since 1.1.0
15
  */
16
  class WP_Job_Manager_Addons {
 
17
 
18
  /**
19
  * The single instance of the class.
@@ -38,47 +39,74 @@ class WP_Job_Manager_Addons {
38
  }
39
 
40
  /**
41
- * Handles output of the reports page in admin.
 
 
 
 
 
 
42
  */
43
- public function output() {
44
-
45
- if ( false === ( $addons = get_transient( 'wp_job_manager_addons_html' ) ) ) {
46
-
47
- $raw_addons = wp_remote_get(
48
- 'https://wpjobmanager.com/add-ons/',
49
- array(
50
- 'timeout' => 10,
51
- 'redirection' => 5,
52
- 'sslverify' => false
53
- )
54
- );
55
-
56
- if ( ! is_wp_error( $raw_addons ) ) {
57
-
58
- $raw_addons = wp_remote_retrieve_body( $raw_addons );
59
-
60
- // Get Products
61
- $dom = new DOMDocument();
62
- libxml_use_internal_errors(true);
63
- $dom->loadHTML( $raw_addons );
64
 
65
- $xpath = new DOMXPath( $dom );
66
- $tags = $xpath->query('//ul[@class="products"]');
67
- foreach ( $tags as $tag ) {
68
- $addons = $tag->ownerDocument->saveXML( $tag );
69
- break;
 
 
 
 
 
 
 
 
 
 
70
  }
 
 
 
 
71
 
72
- $addons = wp_kses_post( $addons );
73
-
74
- if ( $addons ) {
75
- set_transient( 'wp_job_manager_addons_html', $addons, 60*60*24*7 ); // Cached for a week
 
 
 
 
 
 
 
 
 
 
 
 
 
76
  }
77
  }
78
  }
 
 
79
 
 
 
 
 
80
  ?>
81
- <div class="wrap wp_job_manager wp_job_manager_addons_wrap">
82
  <nav class="nav-tab-wrapper woo-nav-tab-wrapper">
83
  <a href="<?php echo esc_url( admin_url( 'edit.php?post_type=job_listing&page=job-manager-addons' ) ); ?>" class="nav-tab<?php if ( ! isset( $_GET['section'] ) || 'helper' !== $_GET['section'] ) { echo ' nav-tab-active'; } ?>"><?php _e( 'WP Job Manager Add-ons', 'wp-job-manager' ); ?></a>
84
  <?php if ( current_user_can( 'update_plugins' ) ) : ?>
@@ -89,9 +117,11 @@ class WP_Job_Manager_Addons {
89
  if ( isset( $_GET['section'] ) && 'helper' === $_GET['section'] ) {
90
  do_action( 'job_manager_helper_output' );
91
  } else {
92
- echo '<h1 class="screen-reader-text">' . __( 'WP Job Manager Add-ons', 'wp-job-manager' ) . '</h1>';
93
- echo '<div id="job-manager-addons-banner" class="notice updated below-h2"><strong>' . __( 'Do you need multiple add-ons?', 'wp-job-manager' ) . '</strong> <a href="https://wpjobmanager.com/add-ons/bundle/" class="button">' . __( 'Check out the core add-on bundle &rarr;', 'wp-job-manager' ) . '</a></div>';
94
- echo $addons;
 
 
95
  }
96
  ?>
97
  </div>
14
  * @since 1.1.0
15
  */
16
  class WP_Job_Manager_Addons {
17
+ const WPJM_COM_PRODUCTS_API_BASE_URL = 'https://wpjobmanager.com/wp-json/wpjmcom-products/1.0';
18
 
19
  /**
20
  * The single instance of the class.
39
  }
40
 
41
  /**
42
+ * Call API to get WPJM add-ons
43
+ *
44
+ * @since 1.30.0
45
+ *
46
+ * @param string $category
47
+ *
48
+ * @return array of add-ons
49
  */
50
+ private function get_add_ons( $category = null ) {
51
+ $raw_add_ons = wp_remote_get(
52
+ add_query_arg( array( array( 'category' => $category ) ), self::WPJM_COM_PRODUCTS_API_BASE_URL . '/search' )
53
+ );
54
+ if ( ! is_wp_error( $raw_add_ons ) ) {
55
+ $add_ons = json_decode( wp_remote_retrieve_body( $raw_add_ons ) )->products;
56
+ }
57
+ return $add_ons;
58
+ }
 
 
 
 
 
 
 
 
 
 
 
 
59
 
60
+ /**
61
+ * Get categories for the add-ons screen
62
+ *
63
+ * @since 1.30.0
64
+ *
65
+ * @return array of objects
66
+ */
67
+ private function get_categories() {
68
+ $add_on_categories = get_transient( 'jm_wpjmcom_add_on_categories' );
69
+ if ( false === ( $add_on_categories ) ) {
70
+ $raw_categories = wp_safe_remote_get( self::WPJM_COM_PRODUCTS_API_BASE_URL . '/categories' );
71
+ if ( ! is_wp_error( $raw_categories ) ) {
72
+ $add_on_categories = json_decode( wp_remote_retrieve_body( $raw_categories ) );
73
+ if ( $add_on_categories ) {
74
+ set_transient( 'jm_wpjmcom_add_on_categories', $add_on_categories, WEEK_IN_SECONDS );
75
  }
76
+ }
77
+ }
78
+ return apply_filters( 'job_manager_add_on_categories', $add_on_categories );
79
+ }
80
 
81
+ /**
82
+ * Get messages for the add-ons screen
83
+ *
84
+ * @since 1.30.0
85
+ *
86
+ * @return array of objects
87
+ */
88
+ private function get_messages() {
89
+ $add_on_messages = get_transient( 'jm_wpjmcom_add_on_messages' );
90
+ if ( false === ( $add_on_messages ) ) {
91
+ $raw_messages = wp_safe_remote_get(
92
+ add_query_arg( array( 'version' => JOB_MANAGER_VERSION, 'lang' => get_locale() ), self::WPJM_COM_PRODUCTS_API_BASE_URL . '/messages' )
93
+ );
94
+ if ( ! is_wp_error( $raw_messages ) ) {
95
+ $add_on_messages = json_decode( wp_remote_retrieve_body( $raw_messages ) );
96
+ if ( $add_on_messages ) {
97
+ set_transient( 'jm_wpjmcom_add_on_messages', $add_on_messages, WEEK_IN_SECONDS );
98
  }
99
  }
100
  }
101
+ return apply_filters( 'job_manager_add_on_messages', $add_on_messages );
102
+ }
103
 
104
+ /**
105
+ * Handles output of the reports page in admin.
106
+ */
107
+ public function output() {
108
  ?>
109
+ <div class="wrap wp_job_manager wp_job_manager_add_ons_wrap">
110
  <nav class="nav-tab-wrapper woo-nav-tab-wrapper">
111
  <a href="<?php echo esc_url( admin_url( 'edit.php?post_type=job_listing&page=job-manager-addons' ) ); ?>" class="nav-tab<?php if ( ! isset( $_GET['section'] ) || 'helper' !== $_GET['section'] ) { echo ' nav-tab-active'; } ?>"><?php _e( 'WP Job Manager Add-ons', 'wp-job-manager' ); ?></a>
112
  <?php if ( current_user_can( 'update_plugins' ) ) : ?>
117
  if ( isset( $_GET['section'] ) && 'helper' === $_GET['section'] ) {
118
  do_action( 'job_manager_helper_output' );
119
  } else {
120
+ $category = isset( $_GET['category'] ) ? sanitize_text_field( $_GET['category'] ) : null;
121
+ $messages = $this->get_messages();
122
+ $categories = $this->get_categories();
123
+ $add_ons = $this->get_add_ons( $category );
124
+ include_once( dirname( __FILE__ ) . '/views/html-admin-page-addons.php' );
125
  }
126
  ?>
127
  </div>
includes/admin/class-wp-job-manager-admin.php CHANGED
@@ -92,12 +92,15 @@ class WP_Job_Manager_Admin {
92
  wp_enqueue_style( 'jquery-ui-style', '//code.jquery.com/ui/' . $jquery_version . '/themes/smoothness/jquery-ui.css', array(), $jquery_version );
93
  wp_enqueue_style( 'job_manager_admin_css', JOB_MANAGER_PLUGIN_URL . '/assets/css/admin.css', array(), JOB_MANAGER_VERSION );
94
  wp_register_script( 'jquery-tiptip', JOB_MANAGER_PLUGIN_URL. '/assets/js/jquery-tiptip/jquery.tipTip.min.js', array( 'jquery' ), JOB_MANAGER_VERSION, true );
95
- wp_enqueue_script( 'job_manager_admin_js', JOB_MANAGER_PLUGIN_URL. '/assets/js/admin.min.js', array( 'jquery', 'jquery-tiptip', 'jquery-ui-datepicker' ), JOB_MANAGER_VERSION, true );
96
-
97
- wp_localize_script( 'job_manager_admin_js', 'job_manager_admin', array(
98
- /* translators: jQuery date format, see http://api.jqueryui.com/datepicker/#utility-formatDate */
99
- 'date_format' => _x( 'yy-mm-dd', 'Date format for jQuery datepicker.', 'wp-job-manager' )
100
- ) );
 
 
 
101
  }
102
 
103
  wp_enqueue_style( 'job_manager_admin_menu_css', JOB_MANAGER_PLUGIN_URL . '/assets/css/menu.css', array(), JOB_MANAGER_VERSION );
92
  wp_enqueue_style( 'jquery-ui-style', '//code.jquery.com/ui/' . $jquery_version . '/themes/smoothness/jquery-ui.css', array(), $jquery_version );
93
  wp_enqueue_style( 'job_manager_admin_css', JOB_MANAGER_PLUGIN_URL . '/assets/css/admin.css', array(), JOB_MANAGER_VERSION );
94
  wp_register_script( 'jquery-tiptip', JOB_MANAGER_PLUGIN_URL. '/assets/js/jquery-tiptip/jquery.tipTip.min.js', array( 'jquery' ), JOB_MANAGER_VERSION, true );
95
+ wp_enqueue_script( 'job_manager_datepicker_js', JOB_MANAGER_PLUGIN_URL. '/assets/js/datepicker.min.js', array( 'jquery', 'jquery-ui-datepicker' ), JOB_MANAGER_VERSION, true );
96
+ wp_enqueue_script( 'job_manager_admin_js', JOB_MANAGER_PLUGIN_URL. '/assets/js/admin.min.js', array( 'jquery', 'jquery-tiptip' ), JOB_MANAGER_VERSION, true );
97
+
98
+ if ( ! function_exists( 'wp_localize_jquery_ui_datepicker' ) || ! has_action( 'admin_enqueue_scripts', 'wp_localize_jquery_ui_datepicker' ) ) {
99
+ wp_localize_script( 'job_manager_datepicker_js', 'job_manager_datepicker', array(
100
+ /* translators: jQuery date format, see http://api.jqueryui.com/datepicker/#utility-formatDate */
101
+ 'date_format' => _x( 'yy-mm-dd', 'Date format for jQuery datepicker.', 'wp-job-manager' )
102
+ ) );
103
+ }
104
  }
105
 
106
  wp_enqueue_style( 'job_manager_admin_menu_css', JOB_MANAGER_PLUGIN_URL . '/assets/css/menu.css', array(), JOB_MANAGER_VERSION );
includes/admin/class-wp-job-manager-cpt.php CHANGED
@@ -335,7 +335,7 @@ class WP_Job_Manager_CPT {
335
  7 => sprintf( __( '%s saved.', 'wp-job-manager' ), $wp_post_types['job_listing']->labels->singular_name ),
336
  8 => sprintf( __( '%s submitted. <a target="_blank" href="%s">Preview</a>', 'wp-job-manager' ), $wp_post_types['job_listing']->labels->singular_name, esc_url( add_query_arg( 'preview', 'true', get_permalink($post_ID) ) ) ),
337
  9 => sprintf( __( '%s scheduled for: <strong>%1$s</strong>. <a target="_blank" href="%2$s">Preview</a>', 'wp-job-manager' ), $wp_post_types['job_listing']->labels->singular_name,
338
- date_i18n( __( 'M j, Y @ G:i', 'wp-job-manager' ), strtotime( $post->post_date ) ), esc_url( get_permalink( $post_ID ) ) ),
339
  10 => sprintf( __( '%s draft updated. <a target="_blank" href="%s">Preview</a>', 'wp-job-manager' ), $wp_post_types['job_listing']->labels->singular_name, esc_url( add_query_arg( 'preview', 'true', get_permalink( $post_ID ) ) ) ),
340
  );
341
 
@@ -457,12 +457,12 @@ class WP_Job_Manager_CPT {
457
  if ( is_position_featured( $post ) ) echo '&#10004;'; else echo '&ndash;';
458
  break;
459
  case "job_posted" :
460
- echo '<strong>' . date_i18n( __( 'M j, Y', 'wp-job-manager' ), strtotime( $post->post_date ) ) . '</strong><span>';
461
  echo ( empty( $post->post_author ) ? __( 'by a guest', 'wp-job-manager' ) : sprintf( __( 'by %s', 'wp-job-manager' ), '<a href="' . esc_url( add_query_arg( 'author', $post->post_author ) ) . '">' . get_the_author() . '</a>' ) ) . '</span>';
462
  break;
463
  case "job_expires" :
464
  if ( $post->_job_expires )
465
- echo '<strong>' . date_i18n( __( 'M j, Y', 'wp-job-manager' ), strtotime( $post->_job_expires ) ) . '</strong>';
466
  else
467
  echo '&ndash;';
468
  break;
335
  7 => sprintf( __( '%s saved.', 'wp-job-manager' ), $wp_post_types['job_listing']->labels->singular_name ),
336
  8 => sprintf( __( '%s submitted. <a target="_blank" href="%s">Preview</a>', 'wp-job-manager' ), $wp_post_types['job_listing']->labels->singular_name, esc_url( add_query_arg( 'preview', 'true', get_permalink($post_ID) ) ) ),
337
  9 => sprintf( __( '%s scheduled for: <strong>%1$s</strong>. <a target="_blank" href="%2$s">Preview</a>', 'wp-job-manager' ), $wp_post_types['job_listing']->labels->singular_name,
338
+ date_i18n( get_option( 'date_format' ) . ' @ '. get_option( 'time_format' ), strtotime( $post->post_date ) ), esc_url( get_permalink( $post_ID ) ) ),
339
  10 => sprintf( __( '%s draft updated. <a target="_blank" href="%s">Preview</a>', 'wp-job-manager' ), $wp_post_types['job_listing']->labels->singular_name, esc_url( add_query_arg( 'preview', 'true', get_permalink( $post_ID ) ) ) ),
340
  );
341
 
457
  if ( is_position_featured( $post ) ) echo '&#10004;'; else echo '&ndash;';
458
  break;
459
  case "job_posted" :
460
+ echo '<strong>' . date_i18n( get_option( 'date_format' ), strtotime( $post->post_date ) ) . '</strong><span>';
461
  echo ( empty( $post->post_author ) ? __( 'by a guest', 'wp-job-manager' ) : sprintf( __( 'by %s', 'wp-job-manager' ), '<a href="' . esc_url( add_query_arg( 'author', $post->post_author ) ) . '">' . get_the_author() . '</a>' ) ) . '</span>';
462
  break;
463
  case "job_expires" :
464
  if ( $post->_job_expires )
465
+ echo '<strong>' . date_i18n( get_option( 'date_format' ), strtotime( $post->_job_expires ) ) . '</strong>';
466
  else
467
  echo '&ndash;';
468
  break;
includes/admin/class-wp-job-manager-settings.php CHANGED
@@ -78,6 +78,29 @@ class WP_Job_Manager_Settings {
78
 
79
  $this->settings = apply_filters( 'job_manager_settings',
80
  array(
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
81
  'job_listings' => array(
82
  __( 'Job Listings', 'wp-job-manager' ),
83
  array(
@@ -163,24 +186,6 @@ class WP_Job_Manager_Settings {
163
  'type' => 'checkbox',
164
  'attributes' => array()
165
  ),
166
- array(
167
- 'name' => 'job_manager_date_format',
168
- 'std' => 'relative',
169
- 'label' => __( 'Date Format', 'wp-job-manager' ),
170
- 'desc' => __( 'Choose how you want the published date for jobs to be displayed on the front-end.', 'wp-job-manager' ),
171
- 'type' => 'radio',
172
- 'options' => array(
173
- 'relative' => __( 'Relative to the current date (e.g., 1 day, 1 week, 1 month ago)', 'wp-job-manager' ),
174
- 'default' => __( 'Default date format as defined in Settings', 'wp-job-manager' ),
175
- )
176
- ),
177
- array(
178
- 'name' => 'job_manager_google_maps_api_key',
179
- 'std' => '',
180
- 'label' => __( 'Google Maps API Key', 'wp-job-manager' ),
181
- 'desc' => sprintf( __( 'Google requires an API key to retrieve location information for job listings. Acquire an API key from the <a href="%s">Google Maps API developer site</a>.', 'wp-job-manager' ), 'https://developers.google.com/maps/documentation/geocoding/get-api-key' ),
182
- 'attributes' => array()
183
- ),
184
  ),
185
  ),
186
  'job_submission' => array(
@@ -248,6 +253,20 @@ class WP_Job_Manager_Settings {
248
  'type' => 'checkbox',
249
  'attributes' => array()
250
  ),
 
 
 
 
 
 
 
 
 
 
 
 
 
 
251
  array(
252
  'name' => 'job_manager_submission_duration',
253
  'std' => '30',
@@ -267,6 +286,44 @@ class WP_Job_Manager_Settings {
267
  'url' => __( 'Website URLs only', 'wp-job-manager' ),
268
  )
269
  ),
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
270
  )
271
  ),
272
  'job_pages' => array(
78
 
79
  $this->settings = apply_filters( 'job_manager_settings',
80
  array(
81
+ 'general' => array(
82
+ __( 'General', 'wp-job-manager' ),
83
+ array(
84
+ array(
85
+ 'name' => 'job_manager_date_format',
86
+ 'std' => 'relative',
87
+ 'label' => __( 'Date Format', 'wp-job-manager' ),
88
+ 'desc' => __( 'Choose how you want the published date for jobs to be displayed on the front-end.', 'wp-job-manager' ),
89
+ 'type' => 'radio',
90
+ 'options' => array(
91
+ 'relative' => __( 'Relative to the current date (e.g., 1 day, 1 week, 1 month ago)', 'wp-job-manager' ),
92
+ 'default' => __( 'Default date format as defined in Settings', 'wp-job-manager' ),
93
+ )
94
+ ),
95
+ array(
96
+ 'name' => 'job_manager_google_maps_api_key',
97
+ 'std' => '',
98
+ 'label' => __( 'Google Maps API Key', 'wp-job-manager' ),
99
+ 'desc' => sprintf( __( 'Google requires an API key to retrieve location information for job listings. Acquire an API key from the <a href="%s">Google Maps API developer site</a>.', 'wp-job-manager' ), 'https://developers.google.com/maps/documentation/geocoding/get-api-key' ),
100
+ 'attributes' => array()
101
+ ),
102
+ ),
103
+ ),
104
  'job_listings' => array(
105
  __( 'Job Listings', 'wp-job-manager' ),
106
  array(
186
  'type' => 'checkbox',
187
  'attributes' => array()
188
  ),
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
189
  ),
190
  ),
191
  'job_submission' => array(
253
  'type' => 'checkbox',
254
  'attributes' => array()
255
  ),
256
+ array(
257
+ 'name' => 'job_manager_user_edit_published_submissions',
258
+ 'std' => 'yes',
259
+ 'label' => __( 'Allow Published Edits', 'wp-job-manager' ),
260
+ 'cb_label' => __( 'Allow editing of published listings', 'wp-job-manager' ),
261
+ 'desc' => __( 'Choose whether published job listings can be edited and if edits require admin approval. When moderation is required, the original job listings will be unpublished while edits await admin approval.', 'wp-job-manager' ),
262
+ 'type' => 'radio',
263
+ 'options' => array(
264
+ 'no' => __( 'Users cannot edit', 'wp-job-manager' ),
265
+ 'yes' => __( 'Users can edit without admin approval', 'wp-job-manager' ),
266
+ 'yes_moderated' => __( 'Users can edit, but edits require admin approval', 'wp-job-manager' ),
267
+ ),
268
+ 'attributes' => array()
269
+ ),
270
  array(
271
  'name' => 'job_manager_submission_duration',
272
  'std' => '30',
286
  'url' => __( 'Website URLs only', 'wp-job-manager' ),
287
  )
288
  ),
289
+ ),
290
+ ),
291
+ 'recaptcha' => array(
292
+ __( 'reCAPTCHA', 'wp-job-manager' ),
293
+ array(
294
+ array(
295
+ 'name' => 'job_manager_recaptcha_label',
296
+ 'std' => __( 'Are you human?', 'wp-job-manager' ),
297
+ 'placeholder' => '',
298
+ 'label' => __( 'Field Label', 'wp-job-manager' ),
299
+ 'desc' => __( 'The label used for the reCAPTCHA field on forms.', 'wp-job-manager' ),
300
+ 'attributes' => array()
301
+ ),
302
+ array(
303
+ 'name' => 'job_manager_recaptcha_site_key',
304
+ 'std' => '',
305
+ 'placeholder' => '',
306
+ 'label' => __( 'Site Key', 'wp-job-manager' ),
307
+ 'desc' => sprintf( __( 'You can retrieve your site key from <a href="%s">Google\'s reCAPTCHA admin dashboard</a>.', 'wp-job-manager' ), 'https://www.google.com/recaptcha/admin#list' ),
308
+ 'attributes' => array()
309
+ ),
310
+ array(
311
+ 'name' => 'job_manager_recaptcha_secret_key',
312
+ 'std' => '',
313
+ 'placeholder' => '',
314
+ 'label' => __( 'Secret Key', 'wp-job-manager' ),
315
+ 'desc' => sprintf( __( 'You can retrieve your secret key from <a href="%s">Google\'s reCAPTCHA admin dashboard</a>.', 'wp-job-manager' ), 'https://www.google.com/recaptcha/admin#list' ),
316
+ 'attributes' => array()
317
+ ),
318
+ array(
319
+ 'name' => 'job_manager_enable_recaptcha_job_submission',
320
+ 'std' => '0',
321
+ 'label' => __( 'Job Submission Form', 'wp-job-manager' ),
322
+ 'cb_label' => __( 'Display a reCAPTCHA field on job submission form.', 'wp-job-manager' ),
323
+ 'desc' => sprintf( __( 'This will help prevent bots from submitting job listings. You must have entered a valid site key and secret key above.', 'wp-job-manager' ), 'https://www.google.com/recaptcha/admin#list' ),
324
+ 'type' => 'checkbox',
325
+ 'attributes' => array()
326
+ ),
327
  )
328
  ),
329
  'job_pages' => array(
includes/admin/class-wp-job-manager-setup.php CHANGED
@@ -48,7 +48,7 @@ class WP_Job_Manager_Setup {
48
  * Adds setup link to admin dashboard menu briefly so the page callback is registered.
49
  */
50
  public function admin_menu() {
51
- add_dashboard_page( __( 'Setup', 'wp-job-manager' ), __( 'Setup', 'wp-job-manager' ), 'manage_options', 'job-manager-setup', array( $this, 'output' ) );
52
  }
53
 
54
  /**
@@ -119,6 +119,61 @@ class WP_Job_Manager_Setup {
119
  }
120
  }
121
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
122
  /**
123
  * Displays setup page.
124
  */
@@ -161,10 +216,16 @@ class WP_Job_Manager_Setup {
161
  <p><?php _e( 'This setup wizard will walk you through the process of creating pages for job submissions, management, and listings.', 'wp-job-manager' ); ?></p>
162
  <p><?php printf( __( 'If you\'d prefer to skip this and set up your pages manually, our %sdocumentation%s will walk you through each step.', 'wp-job-manager' ), '<a href="https://wpjobmanager.com/documentation/">', '</a>' ); ?></p>
163
 
164
- <p class="submit">
165
- <a href="<?php echo esc_url( add_query_arg( 'step', 2 ) ); ?>" class="button button-primary"><?php _e( 'Start setup', 'wp-job-manager' ); ?></a>
166
- <a href="<?php echo esc_url( add_query_arg( 'skip-job-manager-setup', 1, admin_url( 'index.php?page=job-manager-setup&step=3' ) ) ); ?>" class="button"><?php _e( 'Skip setup. I will set up the plugin manually.', 'wp-job-manager' ); ?></a>
167
- </p>
 
 
 
 
 
 
168
 
169
  <?php endif; ?>
170
  <?php if ( 2 === $step ) : ?>
48
  * Adds setup link to admin dashboard menu briefly so the page callback is registered.
49
  */
50
  public function admin_menu() {
51
+ add_dashboard_page( __( 'Setup', 'wp-job-manager' ), __( 'Setup', 'wp-job-manager' ), 'manage_options', 'job-manager-setup', array( $this, 'setup_page' ) );
52
  }
53
 
54
  /**
119
  }
120
  }
121
 
122
+ /**
123
+ * Handle request to the setup page.
124
+ */
125
+ public function setup_page() {
126
+ $usage_tracking = WP_Job_Manager_Usage_Tracking::get_instance();
127
+
128
+ if ( 'POST' === $_SERVER['REQUEST_METHOD'] ) {
129
+ $enable = isset( $_POST['job_manager_usage_tracking_enabled'] )
130
+ && '1' === $_POST['job_manager_usage_tracking_enabled'];
131
+
132
+ $nonce = isset( $_POST['nonce'] ) ? $_POST['nonce'] : null;
133
+ $valid_nonce = wp_verify_nonce( $nonce, 'enable-usage-tracking' );
134
+
135
+ if ( $valid_nonce ) {
136
+ $usage_tracking->set_tracking_enabled( $enable );
137
+ $usage_tracking->hide_tracking_opt_in();
138
+ }
139
+ }
140
+
141
+ $this->output();
142
+ }
143
+
144
+ /**
145
+ * Usage tracking opt in text for setup page.
146
+ */
147
+ private function opt_in_text() {
148
+ return WP_Job_Manager_Usage_Tracking::get_instance()->opt_in_checkbox_text();
149
+ }
150
+
151
+ /**
152
+ * Output opt-in checkbox if usage tracking isn't already enabled.
153
+ */
154
+ private function maybe_output_opt_in_checkbox() {
155
+ // Only show the checkbox if we aren't already opted in.
156
+ $usage_tracking = WP_Job_Manager_Usage_Tracking::get_instance();
157
+ if ( ! $usage_tracking->get_tracking_enabled() ) {
158
+ ?>
159
+ <p>
160
+ <label>
161
+ <input
162
+ type="checkbox"
163
+ name="job_manager_usage_tracking_enabled"
164
+ value="1" />
165
+ <?php
166
+ echo wp_kses(
167
+ $this->opt_in_text(),
168
+ $usage_tracking->opt_in_dialog_text_allowed_html()
169
+ );
170
+ ?>
171
+ </label>
172
+ </p>
173
+ <?php
174
+ }
175
+ }
176
+
177
  /**
178
  * Displays setup page.
179
  */
216
  <p><?php _e( 'This setup wizard will walk you through the process of creating pages for job submissions, management, and listings.', 'wp-job-manager' ); ?></p>
217
  <p><?php printf( __( 'If you\'d prefer to skip this and set up your pages manually, our %sdocumentation%s will walk you through each step.', 'wp-job-manager' ), '<a href="https://wpjobmanager.com/documentation/">', '</a>' ); ?></p>
218
 
219
+ <form method="post" action="<?php echo esc_url( add_query_arg( 'step', 2 ) ); ?>">
220
+ <input type="hidden" name="nonce" value="<?php echo esc_attr( wp_create_nonce( 'enable-usage-tracking' ) ); ?>" />
221
+
222
+ <?php $this->maybe_output_opt_in_checkbox(); ?>
223
+
224
+ <p class="submit">
225
+ <input type="submit" value="<?php esc_html_e( 'Start setup', 'wp-job-manager' ); ?>" class="button button-primary" />
226
+ <a href="<?php echo esc_url( add_query_arg( 'skip-job-manager-setup', 1, admin_url( 'index.php?page=job-manager-setup&step=3' ) ) ); ?>" class="button"><?php esc_html_e( 'Skip setup. I will set up the plugin manually.', 'wp-job-manager' ); ?></a>
227
+ </p>
228
+ </form>
229
 
230
  <?php endif; ?>
231
  <?php if ( 2 === $step ) : ?>
includes/admin/class-wp-job-manager-writepanels.php CHANGED
@@ -109,8 +109,7 @@ class WP_Job_Manager_Writepanels {
109
  'label' => __( 'Listing Expiry Date', 'wp-job-manager' ),
110
  'priority' => 11,
111
  'classes' => array( 'job-manager-datepicker' ),
112
- /* translators: date format placeholder, see https://secure.php.net/date */
113
- 'placeholder' => ! empty( $job_expires ) ? _x( 'yyyy-mm-dd', 'Date format placeholder.', 'wp-job-manager' ) : calculate_job_expiry( $post->ID ),
114
  'value' => ! empty( $job_expires ) ? date( 'Y-m-d', strtotime( $job_expires ) ) : '',
115
  );
116
  }
@@ -533,7 +532,7 @@ class WP_Job_Manager_Writepanels {
533
  * @param int|WP_Post $post
534
  */
535
  public function job_listing_data( $post ) {
536
- global $post, $thepostid;
537
 
538
  $thepostid = $post->ID;
539
 
@@ -553,6 +552,13 @@ class WP_Job_Manager_Writepanels {
553
  }
554
  }
555
 
 
 
 
 
 
 
 
556
  do_action( 'job_manager_job_listing_data_end', $thepostid );
557
 
558
  echo '</div>';
109
  'label' => __( 'Listing Expiry Date', 'wp-job-manager' ),
110
  'priority' => 11,
111
  'classes' => array( 'job-manager-datepicker' ),
112
+ 'placeholder' => ! empty( $job_expires ) ? null : date_i18n( get_option( 'date_format' ), strtotime( calculate_job_expiry( $post->ID ) ) ),
 
113
  'value' => ! empty( $job_expires ) ? date( 'Y-m-d', strtotime( $job_expires ) ) : '',
114
  );
115
  }
532
  * @param int|WP_Post $post
533
  */
534
  public function job_listing_data( $post ) {
535
+ global $post, $thepostid, $wp_post_types;
536
 
537
  $thepostid = $post->ID;
538
 
552
  }
553
  }
554
 
555
+ $user_edited_date = get_post_meta( $post->ID, '_job_edited', true );
556
+ if ( $user_edited_date ) {
557
+ echo '<p class="form-field">';
558
+ echo '<em>' . sprintf( __( '%s was last modified by the user on %s.', 'wp-job-manager' ), $wp_post_types['job_listing']->labels->singular_name, date_i18n( get_option( 'date_format' ), $user_edited_date ) ) . '</em>';
559
+ echo '</p>';
560
+ }
561
+
562
  do_action( 'job_manager_job_listing_data_end', $thepostid );
563
 
564
  echo '</div>';
includes/admin/views/html-admin-page-addons.php ADDED
@@ -0,0 +1,70 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ echo '<h1 class="screen-reader-text">' . __( 'WP Job Manager Add-ons', 'wp-job-manager' ) . '</h1>';
3
+ if ( ! empty( $messages ) ) {
4
+ foreach ( $messages as $message ) {
5
+ if ( empty( $message->message ) ) {
6
+ continue;
7
+ }
8
+ $type = 'info';
9
+ if ( isset( $message->type )
10
+ && in_array( $message->type, array( 'info', 'success', 'warning', 'error' ) ) ) {
11
+ $type = $message->type;
12
+ }
13
+ $action_label = isset( $message->action_label ) ? esc_attr( $message->action_label ) : __( 'More Information &rarr;', 'wp-job-manager' );
14
+ $action_url = isset( $message->action_url ) ? esc_url( $message->action_url, array( 'http', 'https' ) ) : false;
15
+ $action_target = isset( $message->action_target ) && 'self' === $message->action_target ? '_self' : '_blank';
16
+ $action_str = '';
17
+ if ( $action_url ) {
18
+ $action_str = ' <a href="' . $action_url . '" target="' . $action_target . '" class="button">' . $action_label . '</a>';
19
+ }
20
+
21
+ echo '<div class="notice notice-' . $type . ' below-h2"><p><strong>' . esc_html( $message->message ) . '</strong>' . $action_str . '</p></div>';
22
+ }
23
+ }
24
+ if ( ! empty( $categories ) ) {
25
+ $current_category = isset( $_GET['category'] ) ? $_GET['category'] : '_all';
26
+ echo '<ul class="subsubsub">';
27
+ foreach ( $categories as $category ) {
28
+ ?>
29
+ <li>
30
+ <a class="<?php echo $current_category === $category->slug ? 'current' : ''; ?>"
31
+ href="<?php echo admin_url( 'edit.php?post_type=job_listing&page=job-manager-addons&category=' . esc_attr( $category->slug ) ); ?>">
32
+ <?php echo esc_html( $category->label ); ?>
33
+ </a>
34
+ </li>
35
+ <?php
36
+ }
37
+ echo '</ul>';
38
+ }
39
+
40
+ echo '<br class="clear" />';
41
+
42
+ if ( empty( $add_ons ) ) {
43
+ echo '<div class="notice notice-warning below-h2"><p><strong>' . __( 'No add-ons were found.', 'wp-job-manager' ) . '</strong></p></div>';
44
+ } else {
45
+ echo '<ul class="products">';
46
+ foreach ( $add_ons as $add_on ) {
47
+ $url = add_query_arg( array(
48
+ 'utm_source' => 'product',
49
+ 'utm_medium' => 'addonpage',
50
+ 'utm_campaign' => 'wpjmplugin',
51
+ 'utm_content' => 'listing',
52
+ ), $add_on->link );
53
+ ?>
54
+ <li class="product">
55
+ <a href="<?php echo esc_url( $url, array( 'http', 'https' ) ); ?>">
56
+ <?php if ( ! empty( $add_on->image ) ) : ?>
57
+ <img src="<?php echo esc_url( $add_on->image ); ?>" />
58
+ <?php endif; ?>
59
+ <h2><?php echo esc_html( $add_on->title ); ?></h2>
60
+ <p><?php echo esc_html( $add_on->excerpt ); ?>
61
+ <?php if ( ! empty( $add_on->price ) ) : ?>
62
+ <span class="price"><?php echo esc_html( $add_on->price ); ?></span>
63
+ <?php endif; ?>
64
+ </p>
65
+ </a>
66
+ </li>
67
+ <?php
68
+ }
69
+ echo '</ul>';
70
+ }
includes/class-wp-job-manager-cache-helper.php CHANGED
@@ -17,6 +17,8 @@ class WP_Job_Manager_Cache_Helper {
17
  */
18
  public static function init() {
19
  add_action( 'save_post', array( __CLASS__, 'flush_get_job_listings_cache' ) );
 
 
20
  add_action( 'job_manager_my_job_do_action', array( __CLASS__, 'job_manager_my_job_do_action' ) );
21
  add_action( 'set_object_terms', array( __CLASS__, 'set_term' ), 10, 4 );
22
  add_action( 'edited_term', array( __CLASS__, 'edited_term' ), 10, 3 );
17
  */
18
  public static function init() {
19
  add_action( 'save_post', array( __CLASS__, 'flush_get_job_listings_cache' ) );
20
+ add_action( 'delete_post', array( __CLASS__, 'flush_get_job_listings_cache' ) );
21
+ add_action( 'trash_post', array( __CLASS__, 'flush_get_job_listings_cache' ) );
22
  add_action( 'job_manager_my_job_do_action', array( __CLASS__, 'job_manager_my_job_do_action' ) );
23
  add_action( 'set_object_terms', array( __CLASS__, 'set_term' ), 10, 4 );
24
  add_action( 'edited_term', array( __CLASS__, 'edited_term' ), 10, 3 );
includes/class-wp-job-manager-post-types.php CHANGED
@@ -68,14 +68,6 @@ class WP_Job_Manager_Post_Types {
68
 
69
  add_action( 'parse_query', array( $this, 'add_feed_query_args' ) );
70
 
71
- // WP ALL Import
72
- add_action( 'pmxi_saved_post', array( $this, 'pmxi_saved_post' ), 10, 1 );
73
-
74
- // RP4WP
75
- add_filter( 'rp4wp_get_template', array( $this, 'rp4wp_template' ), 10, 3 );
76
- add_filter( 'rp4wp_related_meta_fields', array( $this, 'rp4wp_related_meta_fields' ), 10, 3 );
77
- add_filter( 'rp4wp_related_meta_fields_weight', array( $this, 'rp4wp_related_meta_fields_weight' ), 10, 3 );
78
-
79
  // Single job content
80
  $this->job_content_filter( true );
81
  }
@@ -197,7 +189,14 @@ class WP_Job_Manager_Post_Types {
197
  $singular = __( 'Job', 'wp-job-manager' );
198
  $plural = __( 'Jobs', 'wp-job-manager' );
199
 
200
- if ( current_theme_supports( 'job-manager-templates' ) ) {
 
 
 
 
 
 
 
201
  $has_archive = _x( 'jobs', 'Post type archive slug - resave permalinks after changing this', 'wp-job-manager' );
202
  } else {
203
  $has_archive = false;
@@ -777,67 +776,8 @@ class WP_Job_Manager_Post_Types {
777
 
778
  $structured_data = wpjm_get_job_listing_structured_data();
779
  if ( ! empty( $structured_data ) ) {
 
780
  echo '<script type="application/ld+json">' . wp_json_encode( $structured_data ) . '</script>';
781
  }
782
  }
783
-
784
- /**
785
- * After importing via WP All Import, adds default meta data.
786
- *
787
- * @param int $post_id
788
- */
789
- public function pmxi_saved_post( $post_id ) {
790
- if ( 'job_listing' === get_post_type( $post_id ) ) {
791
- $this->maybe_add_default_meta_data( $post_id );
792
- if ( ! WP_Job_Manager_Geocode::has_location_data( $post_id ) && ( $location = get_post_meta( $post_id, '_job_location', true ) ) ) {
793
- WP_Job_Manager_Geocode::generate_location_data( $post_id, $location );
794
- }
795
- }
796
- }
797
-
798
- /**
799
- * Replaces RP4WP template with the template from Job Manager.
800
- *
801
- * @param string $located
802
- * @param string $template_name
803
- * @param array $args
804
- * @return string
805
- */
806
- public function rp4wp_template( $located, $template_name, $args ) {
807
- if ( 'related-post-default.php' === $template_name && 'job_listing' === $args['related_post']->post_type ) {
808
- return JOB_MANAGER_PLUGIN_DIR . '/templates/content-job_listing.php';
809
- }
810
- return $located;
811
- }
812
-
813
- /**
814
- * Adds meta fields for RP4WP to relate jobs by.
815
- *
816
- * @param array $meta_fields
817
- * @param int $post_id
818
- * @param WP_Post $post
819
- * @return array
820
- */
821
- public function rp4wp_related_meta_fields( $meta_fields, $post_id, $post ) {
822
- if ( 'job_listing' === $post->post_type ) {
823
- $meta_fields[] = '_company_name';
824
- $meta_fields[] = '_job_location';
825
- }
826
- return $meta_fields;
827
- }
828
-
829
- /**
830
- * Adds meta fields for RP4WP to relate jobs by.
831
- *
832
- * @param int $weight
833
- * @param WP_Post $post
834
- * @param string $meta_field
835
- * @return int
836
- */
837
- public function rp4wp_related_meta_fields_weight( $weight, $post, $meta_field ) {
838
- if ( 'job_listing' === $post->post_type ) {
839
- $weight = 100;
840
- }
841
- return $weight;
842
- }
843
  }
68
 
69
  add_action( 'parse_query', array( $this, 'add_feed_query_args' ) );
70
 
 
 
 
 
 
 
 
 
71
  // Single job content
72
  $this->job_content_filter( true );
73
  }
189
  $singular = __( 'Job', 'wp-job-manager' );
190
  $plural = __( 'Jobs', 'wp-job-manager' );
191
 
192
+ /**
193
+ * Set whether to add archive page support when registering the job listing post type.
194
+ *
195
+ * @since 1.30.0
196
+ *
197
+ * @param bool $enable_job_archive_page
198
+ */
199
+ if ( apply_filters( 'job_manager_enable_job_archive_page', current_theme_supports( 'job-manager-templates' ) ) ) {
200
  $has_archive = _x( 'jobs', 'Post type archive slug - resave permalinks after changing this', 'wp-job-manager' );
201
  } else {
202
  $has_archive = false;
776
 
777
  $structured_data = wpjm_get_job_listing_structured_data();
778
  if ( ! empty( $structured_data ) ) {
779
+ echo '<!-- WP Job Manager Structured Data -->' . "\r\n";
780
  echo '<script type="application/ld+json">' . wp_json_encode( $structured_data ) . '</script>';
781
  }
782
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
783
  }
includes/class-wp-job-manager-usage-tracking-data.php ADDED
@@ -0,0 +1,315 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Usage tracking data
4
+ *
5
+ * @package Usage Tracking
6
+ **/
7
+
8
+ if ( ! defined( 'ABSPATH' ) ) {
9
+ exit;
10
+ }
11
+
12
+ /**
13
+ * Supplies the usage tracking data for logging.
14
+ *
15
+ * @package Usage Tracking
16
+ * @since 1.30.0
17
+ */
18
+ class WP_Job_Manager_Usage_Tracking_Data {
19
+ /**
20
+ * Get the usage tracking data to send.
21
+ *
22
+ * @since 1.30.0
23
+ *
24
+ * @return array Usage data.
25
+ **/
26
+ public static function get_usage_data() {
27
+ $categories = 0;
28
+ $count_posts = wp_count_posts( 'job_listing' );
29
+
30
+ if ( taxonomy_exists( 'job_listing_category' ) ) {
31
+ $categories = wp_count_terms( 'job_listing_category', array( 'hide_empty' => false ) );
32
+ }
33
+
34
+ return array(
35
+ 'employers' => self::get_employer_count(),
36
+ 'job_categories' => $categories,
37
+ 'job_categories_desc' => self::get_job_category_has_description_count(),
38
+ 'job_types' => wp_count_terms( 'job_listing_type', array( 'hide_empty' => false ) ),
39
+ 'job_types_desc' => self::get_job_type_has_description_count(),
40
+ 'job_types_emp_type' => self::get_job_type_has_employment_type_count(),
41
+ 'jobs_type' => self::get_job_type_count(),
42
+ 'jobs_logo' => self::get_company_logo_count(),
43
+ 'jobs_status_expired' => isset( $count_posts->expired ) ? $count_posts->expired : 0,
44
+ 'jobs_status_pending' => $count_posts->pending,
45
+ 'jobs_status_pending_payment' => isset( $count_posts->pending_payment ) ? $count_posts->pending_payment : 0,
46
+ 'jobs_status_preview' => isset( $count_posts->preview ) ? $count_posts->preview : 0,
47
+ 'jobs_status_publish' => $count_posts->publish,
48
+ 'jobs_location' => self::get_jobs_count_with_meta( '_job_location' ),
49
+ 'jobs_app_contact' => self::get_jobs_count_with_meta( '_application' ),
50
+ 'jobs_company_name' => self::get_jobs_count_with_meta( '_company_name' ),
51
+ 'jobs_company_site' => self::get_jobs_count_with_meta( '_company_website' ),
52
+ 'jobs_company_tagline' => self::get_jobs_count_with_meta( '_company_tagline' ),
53
+ 'jobs_company_twitter' => self::get_jobs_count_with_meta( '_company_twitter' ),
54
+ 'jobs_company_video' => self::get_jobs_count_with_meta( '_company_video' ),
55
+ 'jobs_expiry' => self::get_jobs_count_with_meta( '_job_expires' ),
56
+ 'jobs_featured' => self::get_jobs_count_with_checked_meta( '_featured' ),
57
+ 'jobs_filled' => self::get_jobs_count_with_checked_meta( '_filled' ),
58
+ 'jobs_freelance' => self::get_jobs_by_type_count( 'freelance' ),
59
+ 'jobs_full_time' => self::get_jobs_by_type_count( 'full-time' ),
60
+ 'jobs_intern' => self::get_jobs_by_type_count( 'internship' ),
61
+ 'jobs_location' => self::get_jobs_count_with_meta( '_job_location' ),
62
+ 'jobs_logo' => self::get_company_logo_count(),
63
+ 'jobs_part_time' => self::get_jobs_by_type_count( 'part-time' ),
64
+ 'jobs_status_expired' => isset( $count_posts->expired ) ? $count_posts->expired : 0,
65
+ 'jobs_status_pending' => $count_posts->pending,
66
+ 'jobs_status_pending_payment' => isset( $count_posts->pending_payment ) ? $count_posts->pending_payment : 0,
67
+ 'jobs_status_preview' => isset( $count_posts->preview ) ? $count_posts->preview : 0,
68
+ 'jobs_status_publish' => $count_posts->publish,
69
+ 'jobs_temp' => self::get_jobs_by_type_count( 'temporary' ),
70
+ 'jobs_type' => self::get_job_type_count(),
71
+ 'jobs_by_guests' => self::get_jobs_by_guests(),
72
+ );
73
+ }
74
+
75
+ /**
76
+ * Get the total number of users with the "employer" role.
77
+ *
78
+ * @return int the number of "employers".
79
+ */
80
+ private static function get_employer_count() {
81
+ $employer_query = new WP_User_Query(
82
+ array(
83
+ 'fields' => 'ID',
84
+ 'role' => 'employer',
85
+ )
86
+ );
87
+
88
+ return $employer_query->total_users;
89
+ }
90
+
91
+ /**
92
+ * Get the number of job categories that have a description.
93
+ *
94
+ * @since 1.30.0
95
+ *
96
+ * @return int Number of job categories with a description.
97
+ **/
98
+ private static function get_job_category_has_description_count() {
99
+ if ( ! taxonomy_exists( 'job_listing_category' ) ) {
100
+ return 0;
101
+ }
102
+
103
+ $count = 0;
104
+ $terms = get_terms(
105
+ 'job_listing_category', array(
106
+ 'hide_empty' => false,
107
+ )
108
+ );
109
+
110
+ foreach ( $terms as $term ) {
111
+ $description = isset( $term->description ) ? trim( $term->description ) : '';
112
+
113
+ if ( ! empty( $description ) ) {
114
+ $count++;
115
+ }
116
+ }
117
+
118
+ return $count;
119
+ }
120
+
121
+ /**
122
+ * Get the number of job types that have a description.
123
+ *
124
+ * @since 1.30.0
125
+ *
126
+ * @return int Number of job types with a description.
127
+ **/
128
+ private static function get_job_type_has_description_count() {
129
+ $count = 0;
130
+ $terms = get_terms(
131
+ 'job_listing_type', array(
132
+ 'hide_empty' => false,
133
+ )
134
+ );
135
+
136
+ foreach ( $terms as $term ) {
137
+ $description = isset( $term->description ) ? trim( $term->description ) : '';
138
+
139
+ if ( ! empty( $description ) ) {
140
+ $count++;
141
+ }
142
+ }
143
+
144
+ return $count;
145
+ }
146
+
147
+ /**
148
+ * Get the number of job types that have Employment Type set.
149
+ *
150
+ * @since 1.30.0
151
+ *
152
+ * @return int Number of job types with an employment type.
153
+ **/
154
+ private static function get_job_type_has_employment_type_count() {
155
+ $count = 0;
156
+ $terms = get_terms(
157
+ array(
158
+ 'taxonomy' => 'job_listing_type',
159
+ 'hide_empty' => false,
160
+ )
161
+ );
162
+
163
+ foreach ( $terms as $term ) {
164
+ $employment_type = get_term_meta( $term->term_id, 'employment_type', true );
165
+
166
+ if ( ! empty( $employment_type ) ) {
167
+ $count++;
168
+ }
169
+ }
170
+
171
+ return $count;
172
+ }
173
+
174
+ /**
175
+ * Get the total number of published or expired jobs for a particular job type.
176
+ *
177
+ * @since 1.30.0
178
+ *
179
+ * @param string $job_type Job type to search for.
180
+ *
181
+ * @return array Number of published or expired jobs for a particular job type.
182
+ **/
183
+ private static function get_jobs_by_type_count( $job_type ) {
184
+ $query = new WP_Query(
185
+ array(
186
+ 'post_type' => 'job_listing',
187
+ 'post_status' => array( 'expired', 'publish' ),
188
+ 'fields' => 'ids',
189
+ 'tax_query' => array(
190
+ array(
191
+ 'field' => 'slug',
192
+ 'taxonomy' => 'job_listing_type',
193
+ 'terms' => $job_type,
194
+ ),
195
+ ),
196
+ )
197
+ );
198
+
199
+ return $query->found_posts;
200
+ }
201
+
202
+ /**
203
+ * Get the number of job listings that have a company logo.
204
+ *
205
+ * @since 1.30.0
206
+ *
207
+ * @return int Number of job listings with a company logo.
208
+ */
209
+ private static function get_company_logo_count() {
210
+ $query = new WP_Query(
211
+ array(
212
+ 'post_type' => 'job_listing',
213
+ 'post_status' => array( 'expired', 'publish' ),
214
+ 'fields' => 'ids',
215
+ 'meta_query' => array(
216
+ array(
217
+ 'key' => '_thumbnail_id',
218
+ 'compare' => 'EXISTS',
219
+ ),
220
+ ),
221
+ )
222
+ );
223
+
224
+ return $query->found_posts;
225
+ }
226
+
227
+ /**
228
+ * Get the total number of job listings that have one or more job types selected.
229
+ *
230
+ * @since 1.30.0
231
+ *
232
+ * @return array Number of job listings associated with at least one job type.
233
+ **/
234
+ private static function get_job_type_count() {
235
+ $query = new WP_Query(
236
+ array(
237
+ 'post_type' => 'job_listing',
238
+ 'post_status' => array( 'expired', 'publish' ),
239
+ 'fields' => 'ids',
240
+ 'tax_query' => array(
241
+ array(
242
+ 'taxonomy' => 'job_listing_type',
243
+ 'operator' => 'EXISTS',
244
+ ),
245
+ ),
246
+ )
247
+ );
248
+
249
+ return $query->found_posts;
250
+ }
251
+
252
+ /**
253
+ * Get the number of job listings where the given meta value is non-empty.
254
+ *
255
+ * @param string $meta_key the key for the meta value to check.
256
+ *
257
+ * @return int the number of job listings.
258
+ */
259
+ private static function get_jobs_count_with_meta( $meta_key ) {
260
+ $query = new WP_Query( array(
261
+ 'post_type' => 'job_listing',
262
+ 'post_status' => array( 'publish', 'expired' ),
263
+ 'fields' => 'ids',
264
+ 'meta_query' => array(
265
+ array(
266
+ 'key' => $meta_key,
267
+ 'value' => '[^[:space:]]',
268
+ 'compare' => 'REGEXP',
269
+ ),
270
+ ),
271
+ ) );
272
+
273
+ return $query->found_posts;
274
+ }
275
+
276
+ /**
277
+ * Get the number of job listings where the given checkbox meta value is
278
+ * checked.
279
+ *
280
+ * @param string $meta_key the key for the meta value to check.
281
+ *
282
+ * @return int the number of job listings.
283
+ */
284
+ private static function get_jobs_count_with_checked_meta( $meta_key ) {
285
+ $query = new WP_Query( array(
286
+ 'post_type' => 'job_listing',
287
+ 'post_status' => array( 'publish', 'expired' ),
288
+ 'fields' => 'ids',
289
+ 'meta_query' => array(
290
+ array(
291
+ 'key' => $meta_key,
292
+ 'value' => '1',
293
+ ),
294
+ ),
295
+ ) );
296
+
297
+ return $query->found_posts;
298
+ }
299
+
300
+ /**
301
+ * Get the number of job listings posted by guests.
302
+ *
303
+ * @return int the number of job listings.
304
+ */
305
+ private static function get_jobs_by_guests() {
306
+ $query = new WP_Query( array(
307
+ 'post_type' => 'job_listing',
308
+ 'post_status' => array( 'publish', 'expired' ),
309
+ 'fields' => 'ids',
310
+ 'author__in' => array( 0 ),
311
+ ) );
312
+
313
+ return $query->found_posts;
314
+ }
315
+ }
includes/class-wp-job-manager-usage-tracking.php ADDED
@@ -0,0 +1,142 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ if ( ! defined( 'ABSPATH' ) ) {
4
+ exit;
5
+ }
6
+
7
+ include dirname( __FILE__ ) . '/../lib/usage-tracking/class-usage-tracking-base.php';
8
+
9
+ /**
10
+ * WPJM Usage Tracking subclass.
11
+ **/
12
+ class WP_Job_Manager_Usage_Tracking extends WP_Job_Manager_Usage_Tracking_Base {
13
+
14
+ const WPJM_SETTING_NAME = 'job_manager_usage_tracking_enabled';
15
+
16
+ const WPJM_TRACKING_INFO_URL = 'https://wpjobmanager.com/document/what-data-does-wpjm-track';
17
+
18
+ protected function __construct() {
19
+ parent::__construct();
20
+
21
+ // Add filter for settings.
22
+ add_filter( 'job_manager_settings', array( $this, 'add_setting_field' ) );
23
+
24
+ // In the setup wizard, do not display the normal opt-in dialog.
25
+ if ( isset( $_GET['page'] ) && 'job-manager-setup' === $_GET['page'] ) {
26
+ remove_action( 'admin_notices', array( $this, 'maybe_display_tracking_opt_in' ) );
27
+ }
28
+ }
29
+
30
+ /*
31
+ * Implementation for abstract functions.
32
+ */
33
+
34
+ public static function get_instance() {
35
+ return self::get_instance_for_subclass( get_class() );
36
+ }
37
+
38
+ protected function get_prefix() {
39
+ return 'job_manager';
40
+ }
41
+
42
+ protected function get_event_prefix() {
43
+ return 'wpjm';
44
+ }
45
+
46
+ protected function get_text_domain() {
47
+ return 'wp-job-manager';
48
+ }
49
+
50
+ public function get_tracking_enabled() {
51
+ return get_option( self::WPJM_SETTING_NAME ) || false;
52
+ }
53
+
54
+ public function set_tracking_enabled( $enable ) {
55
+ update_option( self::WPJM_SETTING_NAME, $enable );
56
+ }
57
+
58
+ protected function current_user_can_manage_tracking() {
59
+ return current_user_can( 'manage_options' );
60
+ }
61
+
62
+ protected function opt_in_dialog_text() {
63
+ return sprintf( __( "We'd love if you helped us make WP Job Manager better by allowing us to collect
64
+ <a href=\"%s\" target=\"_blank\">usage tracking data</a>.
65
+ No sensitive information is collected, and you can opt out at any time.",
66
+ 'wp-job-manager' ), self::WPJM_TRACKING_INFO_URL );
67
+ }
68
+
69
+ protected function do_track_plugin( $plugin_slug ) {
70
+ if ( 1 === preg_match( '/^wp-job-manager/', $plugin_slug ) ) {
71
+ return true;
72
+ }
73
+ $third_party_plugins = array(
74
+ 'all-in-one-seo-pack',
75
+ 'polylang',
76
+ 'jetpack',
77
+ 'wordpress-seo', // Yoast.
78
+ 'sitepress-multilingual-cms', // WPML.
79
+ 'bibblio-related-posts', // Related Posts for WordPress.
80
+ );
81
+ if ( in_array( $plugin_slug, $third_party_plugins, true ) ) {
82
+ return true;
83
+ }
84
+ return false;
85
+ }
86
+
87
+
88
+ /*
89
+ * Public functions.
90
+ */
91
+
92
+ public function hide_tracking_opt_in() {
93
+ parent::hide_tracking_opt_in();
94
+ }
95
+
96
+ public function opt_in_dialog_text_allowed_html() {
97
+ return parent::opt_in_dialog_text_allowed_html();
98
+ }
99
+
100
+ public function opt_in_checkbox_text() {
101
+ return sprintf(
102
+
103
+ /*
104
+ * translators: the href tag contains the URL for the page
105
+ * telling users what data WPJM tracks.
106
+ */
107
+ __(
108
+ 'Help us make WP Job Manager better by allowing us to collect
109
+ <a href="%s" target="_blank">usage tracking data</a>.
110
+ No sensitive information is collected.', 'wp-job-manager'
111
+ ), self::WPJM_TRACKING_INFO_URL
112
+ );
113
+ }
114
+
115
+
116
+ /*
117
+ * Hooks.
118
+ */
119
+
120
+ public function add_setting_field( $fields ) {
121
+ $fields['general'][1][] = array(
122
+ 'name' => self::WPJM_SETTING_NAME,
123
+ 'std' => '0',
124
+ 'type' => 'checkbox',
125
+ 'desc' => '',
126
+ 'label' => __( 'Enable usage tracking', 'wp-job-manager' ),
127
+ 'cb_label' => $this->opt_in_checkbox_text(),
128
+ );
129
+
130
+ return $fields;
131
+ }
132
+
133
+
134
+ /*
135
+ * Helpers.
136
+ */
137
+
138
+ public function clear_options() {
139
+ delete_option( self::WPJM_SETTING_NAME );
140
+ delete_option( $this->hide_tracking_opt_in_option_name );
141
+ }
142
+ }
includes/class-wp-job-manager-widget.php CHANGED
@@ -167,6 +167,17 @@ class WP_Job_Manager_Widget extends WP_Widget {
167
  </p>
168
  <?php
169
  break;
 
 
 
 
 
 
 
 
 
 
 
170
  }
171
  }
172
  }
167
  </p>
168
  <?php
169
  break;
170
+ case 'select' :
171
+ ?>
172
+ <p>
173
+ <label for="<?php echo $this->get_field_id( $key ); ?>"><?php echo $setting['label']; ?></label>
174
+ <select class="widefat" id="<?php echo esc_attr( $this->get_field_id( $key ) ); ?>" name="<?php echo $this->get_field_name( $key ); ?>">
175
+ <?php foreach ( $setting['options'] as $key => $label ) : ?>
176
+ <option value="<?php echo esc_attr( $key ); ?>" <?php selected( $value, $key ); ?>><?php echo esc_html( $label ); ?></option>
177
+ <?php endforeach; ?></select>
178
+ </p>
179
+ <?php
180
+ break;
181
  }
182
  }
183
  }
includes/forms/class-wp-job-manager-form-edit-job.php CHANGED
@@ -18,6 +18,16 @@ class WP_Job_Manager_Form_Edit_Job extends WP_Job_Manager_Form_Submit_Job {
18
  */
19
  public $form_name = 'edit-job';
20
 
 
 
 
 
 
 
 
 
 
 
21
  /**
22
  * Instance
23
  *
@@ -40,11 +50,22 @@ class WP_Job_Manager_Form_Edit_Job extends WP_Job_Manager_Form_Submit_Job {
40
  * Constructor
41
  */
42
  public function __construct() {
 
43
  $this->job_id = ! empty( $_REQUEST['job_id'] ) ? absint( $_REQUEST[ 'job_id' ] ) : 0;
44
 
45
  if ( ! job_manager_user_can_edit_job( $this->job_id ) ) {
46
  $this->job_id = 0;
47
  }
 
 
 
 
 
 
 
 
 
 
48
  }
49
 
50
  /**
@@ -53,7 +74,12 @@ class WP_Job_Manager_Form_Edit_Job extends WP_Job_Manager_Form_Submit_Job {
53
  * @param array $atts
54
  */
55
  public function output( $atts = array() ) {
56
- $this->submit_handler();
 
 
 
 
 
57
  $this->submit();
58
  }
59
 
@@ -63,7 +89,7 @@ class WP_Job_Manager_Form_Edit_Job extends WP_Job_Manager_Form_Submit_Job {
63
  public function submit() {
64
  $job = get_post( $this->job_id );
65
 
66
- if ( empty( $this->job_id ) || ( $job->post_status !== 'publish' && ! job_manager_user_can_edit_pending_submissions() ) ) {
67
  echo wpautop( __( 'Invalid listing', 'wp-job-manager' ) );
68
  return;
69
  }
@@ -94,7 +120,15 @@ class WP_Job_Manager_Form_Edit_Job extends WP_Job_Manager_Form_Submit_Job {
94
 
95
  $this->fields = apply_filters( 'submit_job_form_fields_get_job_data', $this->fields, $job );
96
 
97
- wp_enqueue_script( 'wp-job-manager-job-submission' );
 
 
 
 
 
 
 
 
98
 
99
  get_job_manager_template( 'job-submit.php', array(
100
  'form' => $this->form_name,
@@ -103,8 +137,8 @@ class WP_Job_Manager_Form_Edit_Job extends WP_Job_Manager_Form_Submit_Job {
103
  'job_fields' => $this->get_fields( 'job' ),
104
  'company_fields' => $this->get_fields( 'company' ),
105
  'step' => $this->get_step(),
106
- 'submit_button_text' => __( 'Save changes', 'wp-job-manager' )
107
- ) );
108
  }
109
 
110
  /**
@@ -125,23 +159,64 @@ class WP_Job_Manager_Form_Edit_Job extends WP_Job_Manager_Form_Submit_Job {
125
  throw new Exception( $return->get_error_message() );
126
  }
127
 
 
 
 
 
 
 
128
  // Update the job
129
- $this->save_job( $values['job']['job_title'], $values['job']['job_description'], '', $values, false );
130
  $this->update_job_data( $values );
131
 
132
  // Successful
133
- switch ( get_post_status( $this->job_id ) ) {
134
- case 'publish' :
135
- echo '<div class="job-manager-message">' . __( 'Your changes have been saved.', 'wp-job-manager' ) . ' <a href="' . get_permalink( $this->job_id ) . '">' . __( 'View &rarr;', 'wp-job-manager' ) . '</a>' . '</div>';
136
- break;
137
- default :
138
- echo '<div class="job-manager-message">' . __( 'Your changes have been saved.', 'wp-job-manager' ) . '</div>';
139
- break;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
140
  }
141
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
142
  } catch ( Exception $e ) {
143
- echo '<div class="job-manager-error">' . $e->getMessage() . '</div>';
144
- return;
145
  }
146
  }
147
  }
18
  */
19
  public $form_name = 'edit-job';
20
 
21
+ /**
22
+ * @var bool|string
23
+ */
24
+ private $save_message = false;
25
+
26
+ /**
27
+ * @var bool|string
28
+ */
29
+ private $save_error = false;
30
+
31
  /**
32
  * Instance
33
  *
50
  * Constructor
51
  */
52
  public function __construct() {
53
+ add_action( 'wp', array( $this, 'submit_handler' ) );
54
  $this->job_id = ! empty( $_REQUEST['job_id'] ) ? absint( $_REQUEST[ 'job_id' ] ) : 0;
55
 
56
  if ( ! job_manager_user_can_edit_job( $this->job_id ) ) {
57
  $this->job_id = 0;
58
  }
59
+
60
+ if ( ! empty( $this->job_id ) ) {
61
+ $post_status = get_post_status( $this->job_id );
62
+ if (
63
+ ( 'publish' === $post_status && ! wpjm_user_can_edit_published_submissions() )
64
+ || ( 'publish' !== $post_status && ! job_manager_user_can_edit_pending_submissions() )
65
+ ) {
66
+ $this->job_id = 0;
67
+ }
68
+ }
69
  }
70
 
71
  /**
74
  * @param array $atts
75
  */
76
  public function output( $atts = array() ) {
77
+ if ( ! empty( $this->save_message ) ) {
78
+ echo '<div class="job-manager-message">' . $this->save_message . '</div>';
79
+ }
80
+ if ( ! empty( $this->save_error ) ) {
81
+ echo '<div class="job-manager-error">' . $this->save_error . '</div>';
82
+ }
83
  $this->submit();
84
  }
85
 
89
  public function submit() {
90
  $job = get_post( $this->job_id );
91
 
92
+ if ( empty( $this->job_id ) ) {
93
  echo wpautop( __( 'Invalid listing', 'wp-job-manager' ) );
94
  return;
95
  }
120
 
121
  $this->fields = apply_filters( 'submit_job_form_fields_get_job_data', $this->fields, $job );
122
 
123
+ $this->enqueue_job_form_assets();
124
+
125
+ $save_button_text = __( 'Save changes', 'wp-job-manager' );
126
+ if ( 'publish' === get_post_status( $this->job_id )
127
+ && wpjm_published_submission_edits_require_moderation() ) {
128
+ $save_button_text = __( 'Submit changes for approval', 'wp-job-manager' );
129
+ }
130
+
131
+ $save_button_text = apply_filters( 'update_job_form_submit_button_text', $save_button_text );
132
 
133
  get_job_manager_template( 'job-submit.php', array(
134
  'form' => $this->form_name,
137
  'job_fields' => $this->get_fields( 'job' ),
138
  'company_fields' => $this->get_fields( 'company' ),
139
  'step' => $this->get_step(),
140
+ 'submit_button_text' => $save_button_text,
141
+ ) );
142
  }
143
 
144
  /**
159
  throw new Exception( $return->get_error_message() );
160
  }
161
 
162
+ $save_post_status = '';
163
+ if ( wpjm_published_submission_edits_require_moderation() ) {
164
+ $save_post_status = 'pending';
165
+ }
166
+ $original_post_status = get_post_status( $this->job_id );
167
+
168
  // Update the job
169
+ $this->save_job( $values['job']['job_title'], $values['job']['job_description'], $save_post_status, $values, false );
170
  $this->update_job_data( $values );
171
 
172
  // Successful
173
+ $save_message = __( 'Your changes have been saved.', 'wp-job-manager' );
174
+ $post_status = get_post_status( $this->job_id );
175
+
176
+ update_post_meta( $this->job_id, '_job_edited', time() );
177
+
178
+ if ( 'publish' === $post_status ) {
179
+ $save_message = $save_message . ' <a href="' . get_permalink( $this->job_id ) . '">' . __( 'View &rarr;', 'wp-job-manager' ) . '</a>';
180
+ } elseif ( 'publish' === $original_post_status && 'pending' === $post_status ) {
181
+ $save_message = __( 'Your changes have been submitted and your listing will be visible again once approved.', 'wp-job-manager' );
182
+
183
+ /**
184
+ * Resets the job expiration date when a user submits their job listing edit for approval.
185
+ * Defaults to `false`.
186
+ *
187
+ * @since 1.29.0
188
+ *
189
+ * @param bool $reset_expiration If true, reset expiration date.
190
+ */
191
+ if ( apply_filters( 'job_manager_reset_listing_expiration_on_user_edit', false ) ) {
192
+ delete_post_meta( $this->job_id, '_job_expires' );
193
+ }
194
  }
195
 
196
+ /**
197
+ * Fire action after the user edits a job listing.
198
+ *
199
+ * @since 1.30.0
200
+ *
201
+ * @param int $job_id Job ID.
202
+ * @param string $save_message Save message to filter.
203
+ * @param array $values Submitted values for job listing.
204
+ */
205
+ do_action( 'job_manager_user_edit_job_listing', $this->job_id, $save_message, $values );
206
+
207
+ /**
208
+ * Change the message that appears when a user edits a job listing.
209
+ *
210
+ * @since 1.29.0
211
+ *
212
+ * @param string $save_message Save message to filter.
213
+ * @param int $job_id Job ID.
214
+ * @param array $values Submitted values for job listing.
215
+ */
216
+ $this->save_message = apply_filters( 'job_manager_update_job_listings_message', $save_message, $this->job_id, $values );
217
+
218
  } catch ( Exception $e ) {
219
+ $this->save_error = $e->getMessage();
 
220
  }
221
  }
222
  }
includes/forms/class-wp-job-manager-form-submit-job.php CHANGED
@@ -57,6 +57,10 @@ class WP_Job_Manager_Form_Submit_Job extends WP_Job_Manager_Form {
57
  */
58
  public function __construct() {
59
  add_action( 'wp', array( $this, 'process' ) );
 
 
 
 
60
 
61
  $this->steps = (array) apply_filters( 'submit_job_steps', array(
62
  'submit' => array(
@@ -238,6 +242,7 @@ class WP_Job_Manager_Form_Submit_Job extends WP_Job_Manager_Form {
238
  'company_video' => array(
239
  'label' => __( 'Video', 'wp-job-manager' ),
240
  'type' => 'text',
 
241
  'required' => false,
242
  'placeholder' => __( 'A link to a video about your company', 'wp-job-manager' ),
243
  'priority' => 4
@@ -275,6 +280,18 @@ class WP_Job_Manager_Form_Submit_Job extends WP_Job_Manager_Form {
275
  }
276
  }
277
 
 
 
 
 
 
 
 
 
 
 
 
 
278
  /**
279
  * Validates the posted fields.
280
  *
@@ -329,7 +346,7 @@ class WP_Job_Manager_Form_Submit_Job extends WP_Job_Manager_Form {
329
  if ( ! is_email( $values['job']['application'] ) ) {
330
  throw new Exception( __( 'Please enter a valid application email address', 'wp-job-manager' ) );
331
  }
332
- break;
333
  case 'url' :
334
  // Prefix http if needed
335
  if ( ! strstr( $values['job']['application'], 'http:' ) && ! strstr( $values['job']['application'], 'https:' ) ) {
@@ -338,7 +355,7 @@ class WP_Job_Manager_Form_Submit_Job extends WP_Job_Manager_Form {
338
  if ( ! filter_var( $values['job']['application'], FILTER_VALIDATE_URL ) ) {
339
  throw new Exception( __( 'Please enter a valid application URL', 'wp-job-manager' ) );
340
  }
341
- break;
342
  default :
343
  if ( ! is_email( $values['job']['application'] ) ) {
344
  // Prefix http if needed
@@ -349,13 +366,43 @@ class WP_Job_Manager_Form_Submit_Job extends WP_Job_Manager_Form {
349
  throw new Exception( __( 'Please enter a valid application email address or URL', 'wp-job-manager' ) );
350
  }
351
  }
352
- break;
353
  }
354
  }
355
 
356
  return apply_filters( 'submit_job_form_validate_fields', true, $this->fields, $values );
357
  }
358
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
359
  /**
360
  * Returns an array of the job types indexed by slug. (Unused)
361
  *
@@ -426,8 +473,7 @@ class WP_Job_Manager_Form_Submit_Job extends WP_Job_Manager_Form {
426
  $this->fields = apply_filters( 'submit_job_form_fields_get_user_data', $this->fields, get_current_user_id() );
427
  }
428
 
429
- wp_enqueue_script( 'wp-job-manager-job-submission' );
430
-
431
  get_job_manager_template( 'job-submit.php', array(
432
  'form' => $this->form_name,
433
  'job_id' => $this->get_job_id(),
57
  */
58
  public function __construct() {
59
  add_action( 'wp', array( $this, 'process' ) );
60
+ if ( $this->use_recaptcha_field() ) {
61
+ add_action( 'submit_job_form_end', array( $this, 'display_recaptcha_field' ) );
62
+ add_action( 'submit_job_form_validate_fields', array( $this, 'validate_recaptcha_field' ) );
63
+ }
64
 
65
  $this->steps = (array) apply_filters( 'submit_job_steps', array(
66
  'submit' => array(
242
  'company_video' => array(
243
  'label' => __( 'Video', 'wp-job-manager' ),
244
  'type' => 'text',
245
+ 'sanitizer' => 'url',
246
  'required' => false,
247
  'placeholder' => __( 'A link to a video about your company', 'wp-job-manager' ),
248
  'priority' => 4
280
  }
281
  }
282
 
283
+ /**
284
+ * Use reCAPTCHA field on the form?
285
+ *
286
+ * @return bool
287
+ */
288
+ public function use_recaptcha_field() {
289
+ if ( ! $this->is_recaptcha_available() ) {
290
+ return false;
291
+ }
292
+ return 1 === absint( get_option( 'job_manager_enable_recaptcha_job_submission' ) );
293
+ }
294
+
295
  /**
296
  * Validates the posted fields.
297
  *
346
  if ( ! is_email( $values['job']['application'] ) ) {
347
  throw new Exception( __( 'Please enter a valid application email address', 'wp-job-manager' ) );
348
  }
349
+ break;
350
  case 'url' :
351
  // Prefix http if needed
352
  if ( ! strstr( $values['job']['application'], 'http:' ) && ! strstr( $values['job']['application'], 'https:' ) ) {
355
  if ( ! filter_var( $values['job']['application'], FILTER_VALIDATE_URL ) ) {
356
  throw new Exception( __( 'Please enter a valid application URL', 'wp-job-manager' ) );
357
  }
358
+ break;
359
  default :
360
  if ( ! is_email( $values['job']['application'] ) ) {
361
  // Prefix http if needed
366
  throw new Exception( __( 'Please enter a valid application email address or URL', 'wp-job-manager' ) );
367
  }
368
  }
369
+ break;
370
  }
371
  }
372
 
373
  return apply_filters( 'submit_job_form_validate_fields', true, $this->fields, $values );
374
  }
375
 
376
+ /**
377
+ * Enqueues scripts and styles for editing and posting a job listing.
378
+ */
379
+ protected function enqueue_job_form_assets() {
380
+ wp_enqueue_script( 'wp-job-manager-job-submission' );
381
+ wp_enqueue_style( 'wp-job-manager-job-submission', JOB_MANAGER_PLUGIN_URL . '/assets/css/job-submission.css', array(), JOB_MANAGER_VERSION );
382
+
383
+ // Register datepicker JS. It will be enqueued if needed when a date
384
+ // field is rendered.
385
+ wp_register_script( 'wp-job-manager-datepicker', JOB_MANAGER_PLUGIN_URL. '/assets/js/datepicker.min.js', array( 'jquery', 'jquery-ui-datepicker' ), JOB_MANAGER_VERSION, true );
386
+
387
+ // Localize scripts after the fields are rendered.
388
+ add_action( 'submit_job_form_end', array( $this, 'localize_job_form_scripts' ) );
389
+ }
390
+
391
+ /**
392
+ * Localize frontend scripts that have been enqueued. This should be called
393
+ * after the fields are rendered, in case some of them enqueue new scripts.
394
+ */
395
+ public function localize_job_form_scripts() {
396
+ if ( function_exists( 'wp_localize_jquery_ui_datepicker' ) ) {
397
+ wp_localize_jquery_ui_datepicker();
398
+ } else {
399
+ wp_localize_script( 'wp-job-manager-datepicker', 'job_manager_datepicker', array(
400
+ /* translators: jQuery date format, see http://api.jqueryui.com/datepicker/#utility-formatDate */
401
+ 'date_format' => _x( 'yy-mm-dd', 'Date format for jQuery datepicker.', 'wp-job-manager' )
402
+ ) );
403
+ }
404
+ }
405
+
406
  /**
407
  * Returns an array of the job types indexed by slug. (Unused)
408
  *
473
  $this->fields = apply_filters( 'submit_job_form_fields_get_user_data', $this->fields, get_current_user_id() );
474
  }
475
 
476
+ $this->enqueue_job_form_assets();
 
477
  get_job_manager_template( 'job-submit.php', array(
478
  'form' => $this->form_name,
479
  'job_id' => $this->get_job_id(),
includes/helper/class-wp-job-manager-helper.php CHANGED
@@ -167,9 +167,7 @@ class WP_Job_Manager_Helper {
167
  'email' => $licence['email'],
168
  ) );
169
 
170
- if ( isset( $response['errors'] ) ) {
171
- $this->handle_api_errors( $product_slug, $response['errors'] );
172
- }
173
 
174
  // Set version variables
175
  if ( ! empty( $response ) ) {
@@ -252,7 +250,12 @@ class WP_Job_Manager_Helper {
252
  $licence = $this->get_plugin_licence( $product_slug );
253
  $css_class = '';
254
  if ( $licence && ! empty( $licence['licence_key'] ) ) {
255
- $manage_licence_label = __( 'Manage License', 'wp-job-manager' );
 
 
 
 
 
256
  } else {
257
  $manage_licence_label = __( 'Activate License', 'wp-job-manager' );
258
  $css_class = 'wpjm-activate-licence-link';
@@ -279,9 +282,7 @@ class WP_Job_Manager_Helper {
279
  $args['api_product_id'] = $product_slug;
280
 
281
  $response = $this->api->plugin_information( $args );
282
- if ( isset( $response['errors'] ) ) {
283
- $this->handle_api_errors( $product_slug, $response['errors'] );
284
- }
285
 
286
  return $response;
287
  }
@@ -411,10 +412,18 @@ class WP_Job_Manager_Helper {
411
  * Outputs unset license key notices.
412
  */
413
  public function licence_error_notices() {
 
 
 
 
414
  foreach( $this->get_installed_plugins() as $product_slug => $plugin_data ) {
415
  $licence = $this->get_plugin_licence( $product_slug );
416
- if ( empty( $licence['licence_key'] ) && ! WP_Job_Manager_Helper_Options::get( $product_slug, 'hide_key_notice' ) ) {
417
- include( 'views/html-licence-key-notice.php' );
 
 
 
 
418
  }
419
  }
420
  }
@@ -508,37 +517,26 @@ class WP_Job_Manager_Helper {
508
  * Handle errors from the API.
509
  *
510
  * @param string $product_slug
511
- * @param array $errors
512
  */
513
- private function handle_api_errors( $product_slug, $errors ) {
514
  $plugin_products = $this->get_installed_plugins();
515
  if ( ! isset( $plugin_products[ $product_slug ] ) ) {
516
  return;
517
  }
 
 
 
 
 
 
 
 
 
518
  if ( ! empty( $errors['no_activation'] ) ) {
519
  $this->deactivate_licence( $product_slug );
520
- $this->add_licence_error( $product_slug, $errors['no_activation'] );
521
- } elseif ( ! empty( $errors['expired_key'] ) ) {
522
- $this->deactivate_licence( $product_slug );
523
- $this->add_licence_error( $product_slug, $errors['expired_key'] );
524
  }
525
- }
526
 
527
- /**
528
- * Add an error message for a licence.
529
- *
530
- * @param string $product_slug
531
- * @param string $message Your error message
532
- * @param string $type Type of error message
533
- */
534
- private function add_licence_error( $product_slug, $message, $type = '' ) {
535
- $licence = $this->get_plugin_licence( $product_slug );
536
- $errors = ! empty( $licence['errors'] ) ? $licence['errors'] : array();
537
- if ( $type ) {
538
- $errors[ $type ] = $message;
539
- } else {
540
- $errors[] = $message;
541
- }
542
  WP_Job_Manager_Helper_Options::update( $product_slug, 'errors', $errors );
543
  }
544
 
167
  'email' => $licence['email'],
168
  ) );
169
 
170
+ $this->handle_api_errors( $product_slug, $response );
 
 
171
 
172
  // Set version variables
173
  if ( ! empty( $response ) ) {
250
  $licence = $this->get_plugin_licence( $product_slug );
251
  $css_class = '';
252
  if ( $licence && ! empty( $licence['licence_key'] ) ) {
253
+ if ( ! empty( $licence['errors'] ) ) {
254
+ $manage_licence_label = __( 'Manage License (Requires Attention)', 'wp-job-manager' );
255
+ $css_class = 'wpjm-activate-licence-link';
256
+ } else {
257
+ $manage_licence_label = __( 'Manage License', 'wp-job-manager' );
258
+ }
259
  } else {
260
  $manage_licence_label = __( 'Activate License', 'wp-job-manager' );
261
  $css_class = 'wpjm-activate-licence-link';
282
  $args['api_product_id'] = $product_slug;
283
 
284
  $response = $this->api->plugin_information( $args );
285
+ $this->handle_api_errors( $product_slug, $response );
 
 
286
 
287
  return $response;
288
  }
412
  * Outputs unset license key notices.
413
  */
414
  public function licence_error_notices() {
415
+ $screen = get_current_screen();
416
+ if ( null === $screen || in_array( $screen->id, array( 'job_listing_page_job-manager-addons' ) ) ) {
417
+ return;
418
+ }
419
  foreach( $this->get_installed_plugins() as $product_slug => $plugin_data ) {
420
  $licence = $this->get_plugin_licence( $product_slug );
421
+ if ( ! WP_Job_Manager_Helper_Options::get( $product_slug, 'hide_key_notice' ) ) {
422
+ if ( empty( $licence[ 'licence_key' ] ) ) {
423
+ include( 'views/html-licence-key-notice.php' );
424
+ } elseif ( ! empty( $licence[ 'errors' ] ) ) {
425
+ include( 'views/html-licence-key-error.php' );
426
+ }
427
  }
428
  }
429
  }
517
  * Handle errors from the API.
518
  *
519
  * @param string $product_slug
520
+ * @param array $response
521
  */
522
+ private function handle_api_errors( $product_slug, $response ) {
523
  $plugin_products = $this->get_installed_plugins();
524
  if ( ! isset( $plugin_products[ $product_slug ] ) ) {
525
  return;
526
  }
527
+
528
+ $errors = ! empty( $response['errors'] ) ? $response['errors'] : array();
529
+ $allowed_errors = array( 'no_activation', 'expired_key', 'expiring_soon' );
530
+ $ignored_errors = array_diff( array_keys( $errors ), $allowed_errors );
531
+
532
+ foreach ( $ignored_errors as $key ) {
533
+ unset( $errors[ $key ] );
534
+ }
535
+
536
  if ( ! empty( $errors['no_activation'] ) ) {
537
  $this->deactivate_licence( $product_slug );
 
 
 
 
538
  }
 
539
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
540
  WP_Job_Manager_Helper_Options::update( $product_slug, 'errors', $errors );
541
  }
542
 
includes/helper/views/html-licence-key-error.php ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ if ( ! defined( 'ABSPATH' ) ) {
3
+ exit; // Exit if accessed directly
4
+ }
5
+ ?>
6
+ <div class="error">
7
+ <p class="wpjm-updater-dismiss" style="float:right;"><a href="<?php echo esc_url( add_query_arg( 'dismiss-wpjm-licence-notice', $product_slug ) ); ?>"><?php _e( 'Hide notice' ); ?></a></p>
8
+ <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>
9
+ </div>
includes/widgets/class-wp-job-manager-widget-featured-jobs.php CHANGED
@@ -35,6 +35,26 @@ class WP_Job_Manager_Widget_Featured_Jobs extends WP_Job_Manager_Widget {
35
  'std' => 10,
36
  'label' => __( 'Number of listings to show', 'wp-job-manager' ),
37
  ),
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38
  );
39
  $this->register();
40
  }
@@ -47,6 +67,8 @@ class WP_Job_Manager_Widget_Featured_Jobs extends WP_Job_Manager_Widget {
47
  * @param array $instance
48
  */
49
  public function widget( $args, $instance ) {
 
 
50
  if ( $this->get_cached_widget( $args ) ) {
51
  return;
52
  }
@@ -55,12 +77,14 @@ class WP_Job_Manager_Widget_Featured_Jobs extends WP_Job_Manager_Widget {
55
 
56
  extract( $args );
57
  $titleInstance = isset( $instance['title'] ) ? esc_attr( $instance['title'] ) : '';
58
- $number = isset( $instance['number'] ) ? absint( $instance['number'] ) : '';
59
- $title = apply_filters( 'widget_title', $titleInstance, $instance, $this->id_base );
60
- $jobs = get_job_listings( array(
 
 
61
  'posts_per_page' => $number,
62
- 'orderby' => 'date',
63
- 'order' => 'DESC',
64
  'featured' => true,
65
  ) );
66
 
35
  'std' => 10,
36
  'label' => __( 'Number of listings to show', 'wp-job-manager' ),
37
  ),
38
+ 'orderby' => array(
39
+ 'type' => 'select',
40
+ 'std' => 'date',
41
+ 'label' => __( 'Sort By', 'wp-job-manager' ),
42
+ 'options' => array(
43
+ 'date' => __( 'Date', 'wp-job-manager' ),
44
+ 'title' => __( 'Title', 'wp-job-manager' ),
45
+ 'author' => __( 'Author', 'wp-job-manager' ),
46
+ 'rand_featured' => __( 'Random', 'wp-job-manager' ),
47
+ ),
48
+ ),
49
+ 'order' => array(
50
+ 'type' => 'select',
51
+ 'std' => 'DESC',
52
+ 'label' => __( 'Sort Direction', 'wp-job-manager' ),
53
+ 'options' => array(
54
+ 'ASC' => __( 'Ascending', 'wp-job-manager' ),
55
+ 'DESC' => __( 'Descending', 'wp-job-manager' ),
56
+ ),
57
+ ),
58
  );
59
  $this->register();
60
  }
67
  * @param array $instance
68
  */
69
  public function widget( $args, $instance ) {
70
+ wp_enqueue_style( 'wp-job-manager-job-listings' );
71
+
72
  if ( $this->get_cached_widget( $args ) ) {
73
  return;
74
  }
77
 
78
  extract( $args );
79
  $titleInstance = isset( $instance['title'] ) ? esc_attr( $instance['title'] ) : '';
80
+ $number = isset( $instance['number'] ) ? absint( $instance['number'] ) : '';
81
+ $orderby = isset( $instance['orderby'] ) ? esc_attr( $instance['orderby'] ) : 'date';
82
+ $order = isset( $instance['order'] ) ? esc_attr( $instance['order'] ) : 'DESC';
83
+ $title = apply_filters( 'widget_title', $titleInstance, $instance, $this->id_base );
84
+ $jobs = get_job_listings( array(
85
  'posts_per_page' => $number,
86
+ 'orderby' => $orderby,
87
+ 'order' => $order,
88
  'featured' => true,
89
  ) );
90
 
includes/widgets/class-wp-job-manager-widget-recent-jobs.php CHANGED
@@ -57,6 +57,8 @@ class WP_Job_Manager_Widget_Recent_Jobs extends WP_Job_Manager_Widget {
57
  * @param array $instance
58
  */
59
  public function widget( $args, $instance ) {
 
 
60
  if ( $this->get_cached_widget( $args ) ) {
61
  return;
62
  }
57
  * @param array $instance
58
  */
59
  public function widget( $args, $instance ) {
60
+ wp_enqueue_style( 'wp-job-manager-job-listings' );
61
+
62
  if ( $this->get_cached_widget( $args ) ) {
63
  return;
64
  }
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.29.3\n"
6
  "Report-Msgid-Bugs-To: https://github.com/Automattic/WP-Job-Manager/issues\n"
7
- "POT-Creation-Date: 2018-01-29 21:58:28+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,27 @@ msgstr ""
13
  "Language-Team: LANGUAGE <EMAIL@ADDRESS>\n"
14
  "X-Generator: grunt-wp-i18n 0.5.4\n"
15
 
16
- #: includes/admin/class-wp-job-manager-addons.php:83
17
- #: includes/admin/class-wp-job-manager-addons.php:92
18
- #: includes/admin/class-wp-job-manager-admin.php:113
 
 
 
 
 
19
  msgid "WP Job Manager Add-ons"
20
  msgstr ""
21
 
22
- #: includes/admin/class-wp-job-manager-addons.php:85
23
  #: includes/helper/views/html-licences.php:6
24
  msgid "Licenses"
25
  msgstr ""
26
 
27
- #: includes/admin/class-wp-job-manager-addons.php:93
28
- msgid "Do you need multiple add-ons?"
29
- msgstr ""
30
-
31
- #: includes/admin/class-wp-job-manager-addons.php:93
32
- msgid "Check out the core add-on bundle &rarr;"
33
- msgstr ""
34
-
35
- #: includes/admin/class-wp-job-manager-admin.php:110
36
  msgid "Settings"
37
  msgstr ""
38
 
39
- #: includes/admin/class-wp-job-manager-admin.php:113
40
  msgid "Add-ons"
41
  msgstr ""
42
 
@@ -119,10 +116,6 @@ msgid ""
119
  "href=\"%2$s\">Preview</a>"
120
  msgstr ""
121
 
122
- #: includes/admin/class-wp-job-manager-cpt.php:338
123
- msgid "M j, Y @ G:i"
124
- msgstr ""
125
-
126
  #: includes/admin/class-wp-job-manager-cpt.php:339
127
  msgid "%s draft updated. <a target=\"_blank\" href=\"%s\">Preview</a>"
128
  msgstr ""
@@ -133,7 +126,7 @@ msgstr ""
133
 
134
  #: includes/admin/class-wp-job-manager-cpt.php:360
135
  #: includes/admin/class-wp-job-manager-writepanels.php:55
136
- #: includes/forms/class-wp-job-manager-form-submit-job.php:174
137
  #: includes/widgets/class-wp-job-manager-widget-recent-jobs.php:38
138
  #: templates/job-filters.php:35 templates/job-filters.php:36
139
  msgid "Location"
@@ -152,7 +145,7 @@ msgid "Expires"
152
  msgstr ""
153
 
154
  #: includes/admin/class-wp-job-manager-cpt.php:364
155
- #: includes/admin/class-wp-job-manager-settings.php:122
156
  msgid "Categories"
157
  msgstr ""
158
 
@@ -173,11 +166,6 @@ msgstr ""
173
  msgid "ID: %d"
174
  msgstr ""
175
 
176
- #: includes/admin/class-wp-job-manager-cpt.php:460
177
- #: includes/admin/class-wp-job-manager-cpt.php:465
178
- msgid "M j, Y"
179
- msgstr ""
180
-
181
  #: includes/admin/class-wp-job-manager-cpt.php:461
182
  msgid "by a guest"
183
  msgstr ""
@@ -191,20 +179,20 @@ msgid "Approve"
191
  msgstr ""
192
 
193
  #: includes/admin/class-wp-job-manager-cpt.php:487
194
- #: includes/admin/class-wp-job-manager-writepanels.php:258
195
- #: includes/admin/class-wp-job-manager-writepanels.php:261
196
- #: includes/admin/class-wp-job-manager-writepanels.php:264
197
  msgid "View"
198
  msgstr ""
199
 
200
  #: includes/admin/class-wp-job-manager-cpt.php:494
201
- #: includes/class-wp-job-manager-post-types.php:222
202
- #: templates/job-dashboard.php:50 templates/job-dashboard.php:68
203
  msgid "Edit"
204
  msgstr ""
205
 
206
  #: includes/admin/class-wp-job-manager-cpt.php:501
207
- #: templates/job-dashboard.php:73
208
  msgid "Delete"
209
  msgstr ""
210
 
@@ -221,338 +209,419 @@ msgid "Job type base"
221
  msgstr ""
222
 
223
  #: includes/admin/class-wp-job-manager-settings.php:82
224
- #: includes/class-wp-job-manager-post-types.php:218
225
- #: includes/class-wp-job-manager-post-types.php:294
226
- msgid "Job Listings"
 
 
227
  msgstr ""
228
 
229
  #: includes/admin/class-wp-job-manager-settings.php:88
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
230
  msgid "Listings Per Page"
231
  msgstr ""
232
 
233
- #: includes/admin/class-wp-job-manager-settings.php:89
234
  msgid "Number of job listings to display per page."
235
  msgstr ""
236
 
237
- #: includes/admin/class-wp-job-manager-settings.php:95
238
  msgid "Filled Positions"
239
  msgstr ""
240
 
241
- #: includes/admin/class-wp-job-manager-settings.php:96
242
  msgid "Hide filled positions"
243
  msgstr ""
244
 
245
- #: includes/admin/class-wp-job-manager-settings.php:97
246
  msgid "Filled positions will not display in your archives."
247
  msgstr ""
248
 
249
- #: includes/admin/class-wp-job-manager-settings.php:104
250
  msgid "Hide Expired Listings"
251
  msgstr ""
252
 
253
- #: includes/admin/class-wp-job-manager-settings.php:105
254
  msgid "Hide expired listings in job archives/search"
255
  msgstr ""
256
 
257
- #: includes/admin/class-wp-job-manager-settings.php:106
258
  msgid "Expired job listings will not be searchable."
259
  msgstr ""
260
 
261
- #: includes/admin/class-wp-job-manager-settings.php:113
262
  msgid "Hide Expired Listings Content"
263
  msgstr ""
264
 
265
- #: includes/admin/class-wp-job-manager-settings.php:114
266
  msgid "Hide content in expired single job listings"
267
  msgstr ""
268
 
269
- #: includes/admin/class-wp-job-manager-settings.php:115
270
  msgid ""
271
  "Your site will display the titles of expired listings, but not the content "
272
  "of the listings. Otherwise, expired listings display their full content "
273
  "minus the application area."
274
  msgstr ""
275
 
276
- #: includes/admin/class-wp-job-manager-settings.php:123
277
  msgid "Enable listing categories"
278
  msgstr ""
279
 
280
- #: includes/admin/class-wp-job-manager-settings.php:124
281
  msgid ""
282
  "This lets users select from a list of categories when submitting a job. "
283
  "Note: an admin has to create categories before site users can select them."
284
  msgstr ""
285
 
286
- #: includes/admin/class-wp-job-manager-settings.php:131
287
  msgid "Multi-select Categories"
288
  msgstr ""
289
 
290
- #: includes/admin/class-wp-job-manager-settings.php:132
291
  msgid "Default to category multiselect"
292
  msgstr ""
293
 
294
- #: includes/admin/class-wp-job-manager-settings.php:133
295
  msgid ""
296
  "The category selection box will default to allowing multiple selections on "
297
  "the [jobs] shortcode. Without this, users will only be able to select a "
298
  "single category when submitting jobs."
299
  msgstr ""
300
 
301
- #: includes/admin/class-wp-job-manager-settings.php:140
302
  msgid "Category Filter Type"
303
  msgstr ""
304
 
305
- #: includes/admin/class-wp-job-manager-settings.php:141
306
  msgid ""
307
  "Determines the logic used to display jobs when selecting multiple "
308
  "categories."
309
  msgstr ""
310
 
311
- #: includes/admin/class-wp-job-manager-settings.php:144
312
  msgid "Jobs will be shown if within ANY selected category"
313
  msgstr ""
314
 
315
- #: includes/admin/class-wp-job-manager-settings.php:145
316
  msgid "Jobs will be shown if within ALL selected categories"
317
  msgstr ""
318
 
319
- #: includes/admin/class-wp-job-manager-settings.php:151
320
  msgid "Types"
321
  msgstr ""
322
 
323
- #: includes/admin/class-wp-job-manager-settings.php:152
324
  msgid "Enable listing types"
325
  msgstr ""
326
 
327
- #: includes/admin/class-wp-job-manager-settings.php:153
328
  msgid ""
329
  "This lets users select from a list of types when submitting a job. Note: an "
330
  "admin has to create types before site users can select them."
331
  msgstr ""
332
 
333
- #: includes/admin/class-wp-job-manager-settings.php:160
334
  msgid "Multi-select Listing Types"
335
  msgstr ""
336
 
337
- #: includes/admin/class-wp-job-manager-settings.php:161
338
  msgid "Allow multiple types for listings"
339
  msgstr ""
340
 
341
- #: includes/admin/class-wp-job-manager-settings.php:162
342
  msgid ""
343
  "This allows users to select more than one type when submitting a job. The "
344
  "metabox on the post editor and the selection box on the front-end job "
345
  "submission form will both reflect this."
346
  msgstr ""
347
 
348
- #: includes/admin/class-wp-job-manager-settings.php:169
349
- msgid "Date Format"
350
- msgstr ""
351
-
352
- #: includes/admin/class-wp-job-manager-settings.php:170
353
- msgid ""
354
- "Choose how you want the published date for jobs to be displayed on the "
355
- "front-end."
356
- msgstr ""
357
-
358
- #: includes/admin/class-wp-job-manager-settings.php:173
359
- msgid "Relative to the current date (e.g., 1 day, 1 week, 1 month ago)"
360
- msgstr ""
361
-
362
- #: includes/admin/class-wp-job-manager-settings.php:174
363
- msgid "Default date format as defined in Settings"
364
- msgstr ""
365
-
366
- #: includes/admin/class-wp-job-manager-settings.php:180
367
- msgid "Google Maps API Key"
368
- msgstr ""
369
-
370
- #: includes/admin/class-wp-job-manager-settings.php:181
371
- msgid ""
372
- "Google requires an API key to retrieve location information for job "
373
- "listings. Acquire an API key from the <a href=\"%s\">Google Maps API "
374
- "developer site</a>."
375
- msgstr ""
376
-
377
- #: includes/admin/class-wp-job-manager-settings.php:187
378
  msgid "Job Submission"
379
  msgstr ""
380
 
381
- #: includes/admin/class-wp-job-manager-settings.php:192
382
  msgid "Account Required"
383
  msgstr ""
384
 
385
- #: includes/admin/class-wp-job-manager-settings.php:193
386
  msgid "Require an account to submit listings"
387
  msgstr ""
388
 
389
- #: includes/admin/class-wp-job-manager-settings.php:194
390
  msgid "Limits job listing submissions to registered, logged-in users."
391
  msgstr ""
392
 
393
- #: includes/admin/class-wp-job-manager-settings.php:201
394
  msgid "Account Creation"
395
  msgstr ""
396
 
397
- #: includes/admin/class-wp-job-manager-settings.php:202
398
  msgid "Enable account creation during submission"
399
  msgstr ""
400
 
401
- #: includes/admin/class-wp-job-manager-settings.php:203
402
  msgid ""
403
  "Includes account creation on the listing submission form, to allow "
404
  "non-registered users to create an account and submit a job listing "
405
  "simultaneously."
406
  msgstr ""
407
 
408
- #: includes/admin/class-wp-job-manager-settings.php:210
409
  msgid "Account Username"
410
  msgstr ""
411
 
412
- #: includes/admin/class-wp-job-manager-settings.php:211
413
  msgid "Generate usernames from email addresses"
414
  msgstr ""
415
 
416
- #: includes/admin/class-wp-job-manager-settings.php:212
417
  msgid ""
418
  "Automatically generates usernames for new accounts from the registrant's "
419
  "email address. If this is not enabled, a \"username\" field will display "
420
  "instead."
421
  msgstr ""
422
 
423
- #: includes/admin/class-wp-job-manager-settings.php:219
424
  msgid "Account Password"
425
  msgstr ""
426
 
427
- #: includes/admin/class-wp-job-manager-settings.php:220
428
  msgid "Email new users a link to set a password"
429
  msgstr ""
430
 
431
- #: includes/admin/class-wp-job-manager-settings.php:221
432
  msgid ""
433
  "Sends an email to the user with their username and a link to set their "
434
  "password. If this is not enabled, a \"password\" field will display "
435
  "instead, and their email address won't be verified."
436
  msgstr ""
437
 
438
- #: includes/admin/class-wp-job-manager-settings.php:228
439
  msgid "Account Role"
440
  msgstr ""
441
 
442
- #: includes/admin/class-wp-job-manager-settings.php:229
443
  msgid ""
444
  "Any new accounts created during submission will have this role. If you "
445
  "haven't enabled account creation during submission in the options above, "
446
  "your own method of assigning roles will apply."
447
  msgstr ""
448
 
449
- #: includes/admin/class-wp-job-manager-settings.php:236
450
  msgid "Moderate New Listings"
451
  msgstr ""
452
 
453
- #: includes/admin/class-wp-job-manager-settings.php:237
454
  msgid "Require admin approval of all new listing submissions"
455
  msgstr ""
456
 
457
- #: includes/admin/class-wp-job-manager-settings.php:238
458
  msgid ""
459
  "Sets all new submissions to \"pending.\" They will not appear on your site "
460
  "until an admin approves them."
461
  msgstr ""
462
 
463
- #: includes/admin/class-wp-job-manager-settings.php:245
464
  msgid "Allow Pending Edits"
465
  msgstr ""
466
 
467
- #: includes/admin/class-wp-job-manager-settings.php:246
468
  msgid "Allow editing of pending listings"
469
  msgstr ""
470
 
471
- #: includes/admin/class-wp-job-manager-settings.php:247
472
  msgid ""
473
  "Users can continue to edit pending listings until they are approved by an "
474
  "admin."
475
  msgstr ""
476
 
477
- #: includes/admin/class-wp-job-manager-settings.php:254
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
478
  msgid "Listing Duration"
479
  msgstr ""
480
 
481
- #: includes/admin/class-wp-job-manager-settings.php:255
482
  msgid ""
483
  "Listings will display for the set number of days, then expire. Leave this "
484
  "field blank if you don't want listings to have an expiration date."
485
  msgstr ""
486
 
487
- #: includes/admin/class-wp-job-manager-settings.php:261
488
  msgid "Application Method"
489
  msgstr ""
490
 
491
- #: includes/admin/class-wp-job-manager-settings.php:262
492
  msgid ""
493
  "Choose the application method job listers will need to provide. Specify URL "
494
  "or email address only, or allow listers to choose which they prefer."
495
  msgstr ""
496
 
497
- #: includes/admin/class-wp-job-manager-settings.php:265
498
  msgid "Email address or website URL"
499
  msgstr ""
500
 
501
- #: includes/admin/class-wp-job-manager-settings.php:266
502
  msgid "Email addresses only"
503
  msgstr ""
504
 
505
- #: includes/admin/class-wp-job-manager-settings.php:267
506
  msgid "Website URLs only"
507
  msgstr ""
508
 
509
- #: includes/admin/class-wp-job-manager-settings.php:273
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
510
  msgid "Pages"
511
  msgstr ""
512
 
513
- #: includes/admin/class-wp-job-manager-settings.php:278
514
  msgid "Submit Job Form Page"
515
  msgstr ""
516
 
517
- #: includes/admin/class-wp-job-manager-settings.php:279
518
  msgid ""
519
  "Select the page where you've used the [submit_job_form] shortcode. This "
520
  "lets the plugin know the location of the form."
521
  msgstr ""
522
 
523
- #: includes/admin/class-wp-job-manager-settings.php:285
524
  msgid "Job Dashboard Page"
525
  msgstr ""
526
 
527
- #: includes/admin/class-wp-job-manager-settings.php:286
528
  msgid ""
529
  "Select the page where you've used the [job_dashboard] shortcode. This lets "
530
  "the plugin know the location of the dashboard."
531
  msgstr ""
532
 
533
- #: includes/admin/class-wp-job-manager-settings.php:292
534
  msgid "Job Listings Page"
535
  msgstr ""
536
 
537
- #: includes/admin/class-wp-job-manager-settings.php:293
538
  msgid ""
539
  "Select the page where you've used the [jobs] shortcode. This lets the "
540
  "plugin know the location of the job listings page."
541
  msgstr ""
542
 
543
- #: includes/admin/class-wp-job-manager-settings.php:339
544
  msgid "Settings successfully saved"
545
  msgstr ""
546
 
547
- #: includes/admin/class-wp-job-manager-settings.php:415
548
  msgid "--no page--"
549
  msgstr ""
550
 
551
- #: includes/admin/class-wp-job-manager-settings.php:420
552
  msgid "Select a page&hellip;"
553
  msgstr ""
554
 
555
- #: includes/admin/class-wp-job-manager-settings.php:466
556
  msgid "Save Changes"
557
  msgstr ""
558
 
@@ -560,64 +629,64 @@ msgstr ""
560
  msgid "Setup"
561
  msgstr ""
562
 
563
- #: includes/admin/class-wp-job-manager-setup.php:148
564
  msgid "WP Job Manager Setup"
565
  msgstr ""
566
 
567
- #: includes/admin/class-wp-job-manager-setup.php:151
568
  msgid "1. Introduction"
569
  msgstr ""
570
 
571
- #: includes/admin/class-wp-job-manager-setup.php:152
572
  msgid "2. Page Setup"
573
  msgstr ""
574
 
575
- #: includes/admin/class-wp-job-manager-setup.php:153
576
  msgid "3. Done"
577
  msgstr ""
578
 
579
- #: includes/admin/class-wp-job-manager-setup.php:158
580
  msgid "Welcome to the Setup Wizard!"
581
  msgstr ""
582
 
583
- #: includes/admin/class-wp-job-manager-setup.php:160
584
  msgid ""
585
  "Thanks for installing <em>WP Job Manager</em>! Let's get your site ready to "
586
  "accept job listings."
587
  msgstr ""
588
 
589
- #: includes/admin/class-wp-job-manager-setup.php:161
590
  msgid ""
591
  "This setup wizard will walk you through the process of creating pages for "
592
  "job submissions, management, and listings."
593
  msgstr ""
594
 
595
- #: includes/admin/class-wp-job-manager-setup.php:162
596
  msgid ""
597
  "If you'd prefer to skip this and set up your pages manually, our "
598
  "%sdocumentation%s will walk you through each step."
599
  msgstr ""
600
 
601
- #: includes/admin/class-wp-job-manager-setup.php:165
602
  msgid "Start setup"
603
  msgstr ""
604
 
605
- #: includes/admin/class-wp-job-manager-setup.php:166
606
  msgid "Skip setup. I will set up the plugin manually."
607
  msgstr ""
608
 
609
- #: includes/admin/class-wp-job-manager-setup.php:172
610
  msgid "Page Setup"
611
  msgstr ""
612
 
613
- #: includes/admin/class-wp-job-manager-setup.php:174
614
  msgid ""
615
  "With WP Job Manager, employers and applicants can post, manage, and browse "
616
  "job listings right on your website. Tell us which of these common pages "
617
  "you'd like your site to have and we'll create and configure them for you."
618
  msgstr ""
619
 
620
- #: includes/admin/class-wp-job-manager-setup.php:175
621
  msgid ""
622
  "(These pages are created using %1$sshortcodes%2$s, which we take care of in "
623
  "this step. If you'd like to build these pages yourself or want to add one "
@@ -626,19 +695,19 @@ msgid ""
626
  "instructions.)"
627
  msgstr ""
628
 
629
- #: includes/admin/class-wp-job-manager-setup.php:183
630
  msgid "Page Title"
631
  msgstr ""
632
 
633
- #: includes/admin/class-wp-job-manager-setup.php:184
634
  msgid "Page Description"
635
  msgstr ""
636
 
637
- #: includes/admin/class-wp-job-manager-setup.php:185
638
  msgid "Content Shortcode"
639
  msgstr ""
640
 
641
- #: includes/admin/class-wp-job-manager-setup.php:193
642
  msgid ""
643
  "Creates a page that allows employers to post new jobs directly from a page "
644
  "on your website, instead of requiring them to log in to an admin area. If "
@@ -646,7 +715,7 @@ msgid ""
646
  "the admin dashboard only -- you can uncheck this setting."
647
  msgstr ""
648
 
649
- #: includes/admin/class-wp-job-manager-setup.php:201
650
  msgid ""
651
  "Creates a page that allows employers to manage their job listings directly "
652
  "from a page on your website, instead of requiring them to log in to an "
@@ -654,66 +723,66 @@ msgid ""
654
  "only, you can uncheck this setting."
655
  msgstr ""
656
 
657
- #: includes/admin/class-wp-job-manager-setup.php:208
658
  msgid "Creates a page where visitors can browse, search, and filter job listings."
659
  msgstr ""
660
 
661
- #: includes/admin/class-wp-job-manager-setup.php:216
662
  msgid "Skip this step"
663
  msgstr ""
664
 
665
- #: includes/admin/class-wp-job-manager-setup.php:226
666
  msgid "You're ready to start using WP Job Manager!"
667
  msgstr ""
668
 
669
- #: includes/admin/class-wp-job-manager-setup.php:228
670
  msgid "Wondering what to do now? Here are some of the most common next steps:"
671
  msgstr ""
672
 
673
- #: includes/admin/class-wp-job-manager-setup.php:231
674
  msgid "Tweak your settings"
675
  msgstr ""
676
 
677
- #: includes/admin/class-wp-job-manager-setup.php:232
678
  msgid "Add a job using the admin dashboard"
679
  msgstr ""
680
 
681
- #: includes/admin/class-wp-job-manager-setup.php:235
682
  msgid "View submitted job listings"
683
  msgstr ""
684
 
685
- #: includes/admin/class-wp-job-manager-setup.php:237
686
  msgid "Add job listings to a page using the [jobs] shortcode"
687
  msgstr ""
688
 
689
- #: includes/admin/class-wp-job-manager-setup.php:241
690
  msgid "Add a job via the front-end"
691
  msgstr ""
692
 
693
- #: includes/admin/class-wp-job-manager-setup.php:243
694
  msgid "Learn to use the front-end job submission board"
695
  msgstr ""
696
 
697
- #: includes/admin/class-wp-job-manager-setup.php:247
698
  msgid "View the job dashboard"
699
  msgstr ""
700
 
701
- #: includes/admin/class-wp-job-manager-setup.php:249
702
  msgid "Learn to use the front-end job dashboard"
703
  msgstr ""
704
 
705
- #: includes/admin/class-wp-job-manager-setup.php:253
706
  msgid ""
707
  "If you need help, you can find more detail in our %1$ssupport "
708
  "documentation%2$s or post your question on the %3$sWP Job Manager support "
709
  "forums%2$s. Happy hiring!"
710
  msgstr ""
711
 
712
- #: includes/admin/class-wp-job-manager-setup.php:256
713
  msgid "Support WP Job Manager's Ongoing Development"
714
  msgstr ""
715
 
716
- #: includes/admin/class-wp-job-manager-setup.php:257
717
  msgid ""
718
  "There are lots of ways you can support open source software projects like "
719
  "this one: contributing code, fixing a bug, assisting with non-English "
@@ -721,19 +790,19 @@ msgid ""
721
  "spread the word. We appreciate your support!"
722
  msgstr ""
723
 
724
- #: includes/admin/class-wp-job-manager-setup.php:259
725
  msgid "Leave a positive review"
726
  msgstr ""
727
 
728
- #: includes/admin/class-wp-job-manager-setup.php:260
729
  msgid "Contribute a localization"
730
  msgstr ""
731
 
732
- #: includes/admin/class-wp-job-manager-setup.php:261
733
  msgid "Contribute code or report a bug"
734
  msgstr ""
735
 
736
- #: includes/admin/class-wp-job-manager-setup.php:262
737
  msgid "Help other users on the forums"
738
  msgstr ""
739
 
@@ -745,7 +814,7 @@ msgid "Employment Type"
745
  msgstr ""
746
 
747
  #: includes/admin/class-wp-job-manager-writepanels.php:56
748
- #: includes/forms/class-wp-job-manager-form-submit-job.php:178
749
  msgid "e.g. \"London\""
750
  msgstr ""
751
 
@@ -827,47 +896,59 @@ msgstr ""
827
  msgid "Listing Expiry Date"
828
  msgstr ""
829
 
830
- #: includes/admin/class-wp-job-manager-writepanels.php:119
831
  #: includes/rest-api/class-wp-job-manager-models-job-listings-custom-fields.php:75
832
  msgid "Posted by"
833
  msgstr ""
834
 
835
- #: includes/admin/class-wp-job-manager-writepanels.php:161
836
  msgid "%s Data"
837
  msgstr ""
838
 
839
- #: includes/admin/class-wp-job-manager-writepanels.php:201
840
  msgid "Most Used"
841
  msgstr ""
842
 
843
- #: includes/admin/class-wp-job-manager-writepanels.php:258
844
- #: includes/admin/class-wp-job-manager-writepanels.php:261
845
- #: includes/admin/class-wp-job-manager-writepanels.php:264
846
  msgid "Use file"
847
  msgstr ""
848
 
849
- #: includes/admin/class-wp-job-manager-writepanels.php:258
850
- #: includes/admin/class-wp-job-manager-writepanels.php:261
851
- #: includes/admin/class-wp-job-manager-writepanels.php:264
852
  msgid "Upload"
853
  msgstr ""
854
 
855
- #: includes/admin/class-wp-job-manager-writepanels.php:264
856
  msgid "Add file"
857
  msgstr ""
858
 
859
- #: includes/admin/class-wp-job-manager-writepanels.php:490
860
  msgid "Guest User"
861
  msgstr ""
862
 
863
- #: includes/admin/class-wp-job-manager-writepanels.php:492
864
  msgid "Change"
865
  msgstr ""
866
 
867
- #: includes/admin/class-wp-job-manager-writepanels.php:496
868
  msgid "Enter the ID of the user, or leave blank if submitted by a guest."
869
  msgstr ""
870
 
 
 
 
 
 
 
 
 
 
 
 
 
871
  #: includes/class-wp-job-manager-ajax.php:170
872
  msgid "Search completed. Found %d matching record."
873
  msgid_plural "Search completed. Found %d matching records."
@@ -896,128 +977,128 @@ msgstr ""
896
  msgid "Employer"
897
  msgstr ""
898
 
899
- #: includes/class-wp-job-manager-post-types.php:98
900
- #: includes/forms/class-wp-job-manager-form-submit-job.php:191
901
  msgid "Job category"
902
  msgstr ""
903
 
904
- #: includes/class-wp-job-manager-post-types.php:99
905
  msgid "Job categories"
906
  msgstr ""
907
 
908
- #: includes/class-wp-job-manager-post-types.php:123
909
- #: includes/class-wp-job-manager-post-types.php:171
910
- #: includes/class-wp-job-manager-post-types.php:227
911
  msgid "Search %s"
912
  msgstr ""
913
 
914
- #: includes/class-wp-job-manager-post-types.php:124
915
- #: includes/class-wp-job-manager-post-types.php:172
916
- #: includes/class-wp-job-manager-post-types.php:219
917
  msgid "All %s"
918
  msgstr ""
919
 
920
- #: includes/class-wp-job-manager-post-types.php:125
921
- #: includes/class-wp-job-manager-post-types.php:173
922
- #: includes/class-wp-job-manager-post-types.php:230
923
  msgid "Parent %s"
924
  msgstr ""
925
 
926
- #: includes/class-wp-job-manager-post-types.php:126
927
- #: includes/class-wp-job-manager-post-types.php:174
928
  msgid "Parent %s:"
929
  msgstr ""
930
 
931
- #: includes/class-wp-job-manager-post-types.php:127
932
- #: includes/class-wp-job-manager-post-types.php:175
933
- #: includes/class-wp-job-manager-post-types.php:223
934
  msgid "Edit %s"
935
  msgstr ""
936
 
937
- #: includes/class-wp-job-manager-post-types.php:128
938
- #: includes/class-wp-job-manager-post-types.php:176
939
  msgid "Update %s"
940
  msgstr ""
941
 
942
- #: includes/class-wp-job-manager-post-types.php:129
943
- #: includes/class-wp-job-manager-post-types.php:177
944
  msgid "Add New %s"
945
  msgstr ""
946
 
947
- #: includes/class-wp-job-manager-post-types.php:130
948
- #: includes/class-wp-job-manager-post-types.php:178
949
  msgid "New %s Name"
950
  msgstr ""
951
 
952
- #: includes/class-wp-job-manager-post-types.php:147
953
- #: includes/forms/class-wp-job-manager-form-submit-job.php:182
954
  msgid "Job type"
955
  msgstr ""
956
 
957
- #: includes/class-wp-job-manager-post-types.php:148
958
  msgid "Job types"
959
  msgstr ""
960
 
961
- #: includes/class-wp-job-manager-post-types.php:197
962
  msgid "Job"
963
  msgstr ""
964
 
965
- #: includes/class-wp-job-manager-post-types.php:198
966
  msgid "Jobs"
967
  msgstr ""
968
 
969
- #: includes/class-wp-job-manager-post-types.php:220
970
  msgid "Add New"
971
  msgstr ""
972
 
973
- #: includes/class-wp-job-manager-post-types.php:221
974
  msgid "Add %s"
975
  msgstr ""
976
 
977
- #: includes/class-wp-job-manager-post-types.php:224
978
  msgid "New %s"
979
  msgstr ""
980
 
 
981
  #: includes/class-wp-job-manager-post-types.php:225
982
- #: includes/class-wp-job-manager-post-types.php:226
983
  msgid "View %s"
984
  msgstr ""
985
 
986
- #: includes/class-wp-job-manager-post-types.php:228
987
  msgid "No %s found"
988
  msgstr ""
989
 
990
- #: includes/class-wp-job-manager-post-types.php:229
991
  msgid "No %s found in trash"
992
  msgstr ""
993
 
994
- #: includes/class-wp-job-manager-post-types.php:231
995
  msgid "Company Logo"
996
  msgstr ""
997
 
998
- #: includes/class-wp-job-manager-post-types.php:232
999
  msgid "Set company logo"
1000
  msgstr ""
1001
 
1002
- #: includes/class-wp-job-manager-post-types.php:233
1003
  msgid "Remove company logo"
1004
  msgstr ""
1005
 
1006
- #: includes/class-wp-job-manager-post-types.php:234
1007
  msgid "Use as company logo"
1008
  msgstr ""
1009
 
1010
- #: includes/class-wp-job-manager-post-types.php:236
1011
  msgid "This is where you can create and manage %s."
1012
  msgstr ""
1013
 
1014
- #: includes/class-wp-job-manager-post-types.php:267
1015
  msgid "Expired <span class=\"count\">(%s)</span>"
1016
  msgid_plural "Expired <span class=\"count\">(%s)</span>"
1017
  msgstr[0] ""
1018
  msgstr[1] ""
1019
 
1020
- #: includes/class-wp-job-manager-post-types.php:275
1021
  msgid "Preview <span class=\"count\">(%s)</span>"
1022
  msgid_plural "Preview <span class=\"count\">(%s)</span>"
1023
  msgstr[0] ""
@@ -1054,6 +1135,7 @@ msgstr ""
1054
 
1055
  #: includes/class-wp-job-manager-shortcodes.php:217
1056
  #: includes/widgets/class-wp-job-manager-widget-featured-jobs.php:28
 
1057
  #: includes/widgets/class-wp-job-manager-widget-recent-jobs.php:28
1058
  msgid "Title"
1059
  msgstr ""
@@ -1071,208 +1153,244 @@ msgstr ""
1071
  msgid "Load more listings"
1072
  msgstr ""
1073
 
1074
- #: includes/forms/class-wp-job-manager-form-edit-job.php:67
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1075
  msgid "Invalid listing"
1076
  msgstr ""
1077
 
1078
- #: includes/forms/class-wp-job-manager-form-edit-job.php:106
1079
  msgid "Save changes"
1080
  msgstr ""
1081
 
1082
- #: includes/forms/class-wp-job-manager-form-edit-job.php:135
1083
- #: includes/forms/class-wp-job-manager-form-edit-job.php:138
 
 
 
1084
  msgid "Your changes have been saved."
1085
  msgstr ""
1086
 
1087
- #: includes/forms/class-wp-job-manager-form-edit-job.php:135
1088
  msgid "View &rarr;"
1089
  msgstr ""
1090
 
1091
- #: includes/forms/class-wp-job-manager-form-submit-job.php:63
 
 
 
 
 
 
1092
  msgid "Submit Details"
1093
  msgstr ""
1094
 
1095
- #: includes/forms/class-wp-job-manager-form-submit-job.php:69
1096
- #: includes/forms/class-wp-job-manager-form-submit-job.php:439
1097
  #: templates/job-preview.php:22
1098
  msgid "Preview"
1099
  msgstr ""
1100
 
1101
- #: includes/forms/class-wp-job-manager-form-submit-job.php:75
1102
  msgid "Done"
1103
  msgstr ""
1104
 
1105
- #: includes/forms/class-wp-job-manager-form-submit-job.php:143
1106
  msgid "Application email"
1107
  msgstr ""
1108
 
1109
- #: includes/forms/class-wp-job-manager-form-submit-job.php:144
1110
  #: wp-job-manager-template.php:646
1111
  msgid "you@yourdomain.com"
1112
  msgstr ""
1113
 
1114
- #: includes/forms/class-wp-job-manager-form-submit-job.php:148
1115
  msgid "Application URL"
1116
  msgstr ""
1117
 
1118
- #: includes/forms/class-wp-job-manager-form-submit-job.php:149
1119
- #: includes/forms/class-wp-job-manager-form-submit-job.php:227
1120
  msgid "http://"
1121
  msgstr ""
1122
 
1123
- #: includes/forms/class-wp-job-manager-form-submit-job.php:153
1124
  msgid "Application email/URL"
1125
  msgstr ""
1126
 
1127
- #: includes/forms/class-wp-job-manager-form-submit-job.php:154
1128
  msgid "Enter an email address or website URL"
1129
  msgstr ""
1130
 
1131
- #: includes/forms/class-wp-job-manager-form-submit-job.php:167
1132
  msgid "Job Title"
1133
  msgstr ""
1134
 
1135
- #: includes/forms/class-wp-job-manager-form-submit-job.php:175
1136
  msgid "Leave this blank if the location is not important"
1137
  msgstr ""
1138
 
1139
- #: includes/forms/class-wp-job-manager-form-submit-job.php:185
1140
  msgid "Choose job type&hellip;"
1141
  msgstr ""
1142
 
1143
- #: includes/forms/class-wp-job-manager-form-submit-job.php:200
1144
  msgid "Description"
1145
  msgstr ""
1146
 
1147
- #: includes/forms/class-wp-job-manager-form-submit-job.php:216
1148
  msgid "Company name"
1149
  msgstr ""
1150
 
1151
- #: includes/forms/class-wp-job-manager-form-submit-job.php:219
1152
  msgid "Enter the name of the company"
1153
  msgstr ""
1154
 
1155
- #: includes/forms/class-wp-job-manager-form-submit-job.php:223
1156
  #: templates/content-single-job_listing-company.php:30
1157
  msgid "Website"
1158
  msgstr ""
1159
 
1160
- #: includes/forms/class-wp-job-manager-form-submit-job.php:231
1161
  msgid "Tagline"
1162
  msgstr ""
1163
 
1164
- #: includes/forms/class-wp-job-manager-form-submit-job.php:234
1165
  msgid "Briefly describe your company"
1166
  msgstr ""
1167
 
1168
- #: includes/forms/class-wp-job-manager-form-submit-job.php:239
1169
  msgid "Video"
1170
  msgstr ""
1171
 
1172
- #: includes/forms/class-wp-job-manager-form-submit-job.php:242
1173
  msgid "A link to a video about your company"
1174
  msgstr ""
1175
 
1176
- #: includes/forms/class-wp-job-manager-form-submit-job.php:246
1177
  msgid "Twitter username"
1178
  msgstr ""
1179
 
1180
- #: includes/forms/class-wp-job-manager-form-submit-job.php:249
1181
  msgid "@yourcompany"
1182
  msgstr ""
1183
 
1184
- #: includes/forms/class-wp-job-manager-form-submit-job.php:253
1185
  msgid "Logo"
1186
  msgstr ""
1187
 
1188
- #: includes/forms/class-wp-job-manager-form-submit-job.php:289
1189
  msgid "%s is a required field"
1190
  msgstr ""
1191
 
1192
- #: includes/forms/class-wp-job-manager-form-submit-job.php:299
1193
  msgid "%s is invalid"
1194
  msgstr ""
1195
 
1196
- #: includes/forms/class-wp-job-manager-form-submit-job.php:315
1197
- #: wp-job-manager-functions.php:1061
1198
  msgid "\"%s\" (filetype %s) needs to be one of the following file types: %s"
1199
  msgstr ""
1200
 
1201
- #: includes/forms/class-wp-job-manager-form-submit-job.php:330
1202
  msgid "Please enter a valid application email address"
1203
  msgstr ""
1204
 
1205
- #: includes/forms/class-wp-job-manager-form-submit-job.php:339
1206
  msgid "Please enter a valid application URL"
1207
  msgstr ""
1208
 
1209
- #: includes/forms/class-wp-job-manager-form-submit-job.php:349
1210
  msgid "Please enter a valid application email address or URL"
1211
  msgstr ""
1212
 
1213
- #: includes/forms/class-wp-job-manager-form-submit-job.php:470
1214
  msgid "Please enter a username."
1215
  msgstr ""
1216
 
1217
- #: includes/forms/class-wp-job-manager-form-submit-job.php:474
1218
  msgid "Please enter a password."
1219
  msgstr ""
1220
 
1221
- #: includes/forms/class-wp-job-manager-form-submit-job.php:478
1222
  msgid "Please enter your email address."
1223
  msgstr ""
1224
 
1225
- #: includes/forms/class-wp-job-manager-form-submit-job.php:484
1226
  msgid "Passwords must match."
1227
  msgstr ""
1228
 
1229
- #: includes/forms/class-wp-job-manager-form-submit-job.php:489
1230
  msgid "Invalid Password: %s"
1231
  msgstr ""
1232
 
1233
- #: includes/forms/class-wp-job-manager-form-submit-job.php:491
1234
  msgid "Password is not valid."
1235
  msgstr ""
1236
 
1237
- #: includes/forms/class-wp-job-manager-form-submit-job.php:512
1238
  msgid "You must be signed in to post a new listing."
1239
  msgstr ""
1240
 
1241
- #: includes/helper/class-wp-job-manager-helper.php:255
1242
- msgid "Manage License"
1243
  msgstr ""
1244
 
1245
  #: includes/helper/class-wp-job-manager-helper.php:257
 
 
 
 
1246
  #: includes/helper/views/html-licences.php:69
1247
  msgid "Activate License"
1248
  msgstr ""
1249
 
1250
- #: includes/helper/class-wp-job-manager-helper.php:440
1251
  msgid ""
1252
  "Please enter a valid license key and email address in order to activate "
1253
  "this plugin's license."
1254
  msgstr ""
1255
 
1256
- #: includes/helper/class-wp-job-manager-helper.php:468
1257
  msgid "Connection failed to the License Key API server - possible server issue."
1258
  msgstr ""
1259
 
1260
- #: includes/helper/class-wp-job-manager-helper.php:476
1261
  msgid "Plugin license has been activated."
1262
  msgstr ""
1263
 
1264
- #: includes/helper/class-wp-job-manager-helper.php:478
1265
  msgid "An unknown error occurred while attempting to activate the license"
1266
  msgstr ""
1267
 
1268
- #: includes/helper/class-wp-job-manager-helper.php:490
1269
  msgid "license is not active."
1270
  msgstr ""
1271
 
1272
- #: includes/helper/class-wp-job-manager-helper.php:504
1273
  msgid "Plugin license has been deactivated."
1274
  msgstr ""
1275
 
 
1276
  #: includes/helper/views/html-licence-key-notice.php:7
1277
  msgid "Hide notice"
1278
  msgstr ""
@@ -1321,6 +1439,34 @@ msgstr ""
1321
  msgid "Number of listings to show"
1322
  msgstr ""
1323
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1324
  #: includes/widgets/class-wp-job-manager-widget-recent-jobs.php:21
1325
  msgid ""
1326
  "Display a list of recent listings on your site, optionally matching a "
@@ -1336,6 +1482,30 @@ msgstr ""
1336
  msgid "Keyword"
1337
  msgstr ""
1338
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1339
  #: lib/wpjm_rest/class-wp-job-manager-rest-model.php:214
1340
  #. translators: %s is usually a field name.
1341
  msgid "%s cannot be empty"
@@ -1417,17 +1587,17 @@ msgid "Maximum file size: %s."
1417
  msgstr ""
1418
 
1419
  #: templates/form-fields/multiselect-field.php:20
1420
- #: wp-job-manager-functions.php:849
1421
  msgid "No results match"
1422
  msgstr ""
1423
 
1424
  #: templates/form-fields/multiselect-field.php:20
1425
- #: wp-job-manager-functions.php:850
1426
  msgid "Select Some Options"
1427
  msgstr ""
1428
 
1429
- #: templates/form-fields/uploaded-file-html.php:29
1430
- #: templates/form-fields/uploaded-file-html.php:31
1431
  msgid "remove"
1432
  msgstr ""
1433
 
@@ -1457,19 +1627,23 @@ msgstr ""
1457
  msgid "You do not have any active listings."
1458
  msgstr ""
1459
 
1460
- #: templates/job-dashboard.php:53
1461
- msgid "Mark not filled"
1462
  msgstr ""
1463
 
1464
  #: templates/job-dashboard.php:55
 
 
 
 
1465
  msgid "Mark filled"
1466
  msgstr ""
1467
 
1468
- #: templates/job-dashboard.php:58
1469
  msgid "Duplicate"
1470
  msgstr ""
1471
 
1472
- #: templates/job-dashboard.php:62
1473
  msgid "Relist"
1474
  msgstr ""
1475
 
@@ -1519,67 +1693,67 @@ msgstr ""
1519
  msgid "%s submitted successfully. Your listing will be visible once approved."
1520
  msgstr ""
1521
 
1522
- #: wp-job-manager-functions.php:420
1523
  msgid "Reset"
1524
  msgstr ""
1525
 
1526
- #: wp-job-manager-functions.php:424
1527
  msgid "RSS"
1528
  msgstr ""
1529
 
1530
- #: wp-job-manager-functions.php:519
1531
  msgid "Invalid email address."
1532
  msgstr ""
1533
 
1534
- #: wp-job-manager-functions.php:527
1535
  msgid "Your email address isn&#8217;t correct."
1536
  msgstr ""
1537
 
1538
- #: wp-job-manager-functions.php:531
1539
  msgid "This email is already registered, please choose another one."
1540
  msgstr ""
1541
 
1542
- #: wp-job-manager-functions.php:692
1543
  msgid "Full Time"
1544
  msgstr ""
1545
 
1546
- #: wp-job-manager-functions.php:693
1547
  msgid "Part Time"
1548
  msgstr ""
1549
 
1550
- #: wp-job-manager-functions.php:694
1551
  msgid "Contractor"
1552
  msgstr ""
1553
 
1554
- #: wp-job-manager-functions.php:695
1555
  msgid "Temporary"
1556
  msgstr ""
1557
 
1558
- #: wp-job-manager-functions.php:696
1559
  msgid "Intern"
1560
  msgstr ""
1561
 
1562
- #: wp-job-manager-functions.php:697
1563
  msgid "Volunteer"
1564
  msgstr ""
1565
 
1566
- #: wp-job-manager-functions.php:698
1567
  msgid "Per Diem"
1568
  msgstr ""
1569
 
1570
- #: wp-job-manager-functions.php:699
1571
  msgid "Other"
1572
  msgstr ""
1573
 
1574
- #: wp-job-manager-functions.php:766
1575
  msgid "Passwords must be at least 8 characters long."
1576
  msgstr ""
1577
 
1578
- #: wp-job-manager-functions.php:848
1579
  msgid "Choose a category&hellip;"
1580
  msgstr ""
1581
 
1582
- #: wp-job-manager-functions.php:1063
1583
  msgid "Uploaded files need to be one of the following file types: %s"
1584
  msgstr ""
1585
 
@@ -1619,15 +1793,15 @@ msgstr ""
1619
  msgid "Anywhere"
1620
  msgstr ""
1621
 
1622
- #: wp-job-manager.php:212
1623
  msgid "Load previous listings"
1624
  msgstr ""
1625
 
1626
- #: wp-job-manager.php:263
1627
  msgid "Invalid file type. Accepted types:"
1628
  msgstr ""
1629
 
1630
- #: wp-job-manager.php:274
1631
  msgid "Are you sure you want to delete this listing?"
1632
  msgstr ""
1633
 
@@ -1649,7 +1823,8 @@ msgstr ""
1649
  msgid "Automattic"
1650
  msgstr ""
1651
 
1652
- #: includes/admin/class-wp-job-manager-admin.php:99
 
1653
  #. translators: jQuery date format, see
1654
  #. http:api.jqueryui.com/datepicker/#utility-formatDate
1655
  msgctxt "Date format for jQuery datepicker."
@@ -1657,77 +1832,71 @@ msgid "yy-mm-dd"
1657
  msgstr ""
1658
 
1659
  #: includes/admin/class-wp-job-manager-permalink-settings.php:81
1660
- #: includes/class-wp-job-manager-post-types.php:641
1661
  msgctxt "Job permalink - resave permalinks after changing this"
1662
  msgid "job"
1663
  msgstr ""
1664
 
1665
  #: includes/admin/class-wp-job-manager-permalink-settings.php:90
1666
- #: includes/class-wp-job-manager-post-types.php:642
1667
  msgctxt "Job category slug - resave permalinks after changing this"
1668
  msgid "job-category"
1669
  msgstr ""
1670
 
1671
  #: includes/admin/class-wp-job-manager-permalink-settings.php:99
1672
- #: includes/class-wp-job-manager-post-types.php:643
1673
  msgctxt "Job type slug - resave permalinks after changing this"
1674
  msgid "job-type"
1675
  msgstr ""
1676
 
1677
- #: includes/admin/class-wp-job-manager-setup.php:191
1678
  msgctxt "Default page title (wizard)"
1679
  msgid "Post a Job"
1680
  msgstr ""
1681
 
1682
- #: includes/admin/class-wp-job-manager-setup.php:199
1683
  msgctxt "Default page title (wizard)"
1684
  msgid "Job Dashboard"
1685
  msgstr ""
1686
 
1687
- #: includes/admin/class-wp-job-manager-setup.php:207
1688
  msgctxt "Default page title (wizard)"
1689
  msgid "Jobs"
1690
  msgstr ""
1691
 
1692
- #: includes/admin/class-wp-job-manager-writepanels.php:113
1693
- #. translators: date format placeholder, see https:secure.php.net/date
1694
- msgctxt "Date format placeholder."
1695
- msgid "yyyy-mm-dd"
1696
- msgstr ""
1697
-
1698
- #: includes/class-wp-job-manager-post-types.php:201
1699
  msgctxt "Post type archive slug - resave permalinks after changing this"
1700
  msgid "jobs"
1701
  msgstr ""
1702
 
1703
- #: includes/class-wp-job-manager-post-types.php:261
1704
- #: wp-job-manager-functions.php:315
1705
  msgctxt "post status"
1706
  msgid "Expired"
1707
  msgstr ""
1708
 
1709
- #: includes/class-wp-job-manager-post-types.php:270
1710
- #: wp-job-manager-functions.php:316
1711
  msgctxt "post status"
1712
  msgid "Preview"
1713
  msgstr ""
1714
 
1715
- #: wp-job-manager-functions.php:314
1716
  msgctxt "post status"
1717
  msgid "Draft"
1718
  msgstr ""
1719
 
1720
- #: wp-job-manager-functions.php:317
1721
  msgctxt "post status"
1722
  msgid "Pending approval"
1723
  msgstr ""
1724
 
1725
- #: wp-job-manager-functions.php:318
1726
  msgctxt "post status"
1727
  msgid "Pending payment"
1728
  msgstr ""
1729
 
1730
- #: wp-job-manager-functions.php:319
1731
  msgctxt "post status"
1732
  msgid "Active"
1733
- msgstr ""
2
  # This file is distributed under the GPL2+.
3
  msgid ""
4
  msgstr ""
5
+ "Project-Id-Version: WP Job Manager 1.30.0\n"
6
  "Report-Msgid-Bugs-To: https://github.com/Automattic/WP-Job-Manager/issues\n"
7
+ "POT-Creation-Date: 2018-02-23 13:04:57+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 0.5.4\n"
15
 
16
+ #: includes/abstracts/abstract-wp-job-manager-form.php:312
17
+ #: includes/abstracts/abstract-wp-job-manager-form.php:325
18
+ msgid "\"%s\" check failed. Please try again."
19
+ msgstr ""
20
+
21
+ #: includes/admin/class-wp-job-manager-addons.php:111
22
+ #: includes/admin/class-wp-job-manager-admin.php:116
23
+ #: includes/admin/views/html-admin-page-addons.php:2
24
  msgid "WP Job Manager Add-ons"
25
  msgstr ""
26
 
27
+ #: includes/admin/class-wp-job-manager-addons.php:113
28
  #: includes/helper/views/html-licences.php:6
29
  msgid "Licenses"
30
  msgstr ""
31
 
32
+ #: includes/admin/class-wp-job-manager-admin.php:113
 
 
 
 
 
 
 
 
33
  msgid "Settings"
34
  msgstr ""
35
 
36
+ #: includes/admin/class-wp-job-manager-admin.php:116
37
  msgid "Add-ons"
38
  msgstr ""
39
 
116
  "href=\"%2$s\">Preview</a>"
117
  msgstr ""
118
 
 
 
 
 
119
  #: includes/admin/class-wp-job-manager-cpt.php:339
120
  msgid "%s draft updated. <a target=\"_blank\" href=\"%s\">Preview</a>"
121
  msgstr ""
126
 
127
  #: includes/admin/class-wp-job-manager-cpt.php:360
128
  #: includes/admin/class-wp-job-manager-writepanels.php:55
129
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:178
130
  #: includes/widgets/class-wp-job-manager-widget-recent-jobs.php:38
131
  #: templates/job-filters.php:35 templates/job-filters.php:36
132
  msgid "Location"
145
  msgstr ""
146
 
147
  #: includes/admin/class-wp-job-manager-cpt.php:364
148
+ #: includes/admin/class-wp-job-manager-settings.php:145
149
  msgid "Categories"
150
  msgstr ""
151
 
166
  msgid "ID: %d"
167
  msgstr ""
168
 
 
 
 
 
 
169
  #: includes/admin/class-wp-job-manager-cpt.php:461
170
  msgid "by a guest"
171
  msgstr ""
179
  msgstr ""
180
 
181
  #: includes/admin/class-wp-job-manager-cpt.php:487
182
+ #: includes/admin/class-wp-job-manager-writepanels.php:257
183
+ #: includes/admin/class-wp-job-manager-writepanels.php:260
184
+ #: includes/admin/class-wp-job-manager-writepanels.php:263
185
  msgid "View"
186
  msgstr ""
187
 
188
  #: includes/admin/class-wp-job-manager-cpt.php:494
189
+ #: includes/class-wp-job-manager-post-types.php:221
190
+ #: templates/job-dashboard.php:52 templates/job-dashboard.php:70
191
  msgid "Edit"
192
  msgstr ""
193
 
194
  #: includes/admin/class-wp-job-manager-cpt.php:501
195
+ #: templates/job-dashboard.php:75
196
  msgid "Delete"
197
  msgstr ""
198
 
209
  msgstr ""
210
 
211
  #: includes/admin/class-wp-job-manager-settings.php:82
212
+ msgid "General"
213
+ msgstr ""
214
+
215
+ #: includes/admin/class-wp-job-manager-settings.php:87
216
+ msgid "Date Format"
217
  msgstr ""
218
 
219
  #: includes/admin/class-wp-job-manager-settings.php:88
220
+ msgid ""
221
+ "Choose how you want the published date for jobs to be displayed on the "
222
+ "front-end."
223
+ msgstr ""
224
+
225
+ #: includes/admin/class-wp-job-manager-settings.php:91
226
+ msgid "Relative to the current date (e.g., 1 day, 1 week, 1 month ago)"
227
+ msgstr ""
228
+
229
+ #: includes/admin/class-wp-job-manager-settings.php:92
230
+ msgid "Default date format as defined in Settings"
231
+ msgstr ""
232
+
233
+ #: includes/admin/class-wp-job-manager-settings.php:98
234
+ msgid "Google Maps API Key"
235
+ msgstr ""
236
+
237
+ #: includes/admin/class-wp-job-manager-settings.php:99
238
+ msgid ""
239
+ "Google requires an API key to retrieve location information for job "
240
+ "listings. Acquire an API key from the <a href=\"%s\">Google Maps API "
241
+ "developer site</a>."
242
+ msgstr ""
243
+
244
+ #: includes/admin/class-wp-job-manager-settings.php:105
245
+ #: includes/class-wp-job-manager-post-types.php:217
246
+ #: includes/class-wp-job-manager-post-types.php:293
247
+ msgid "Job Listings"
248
+ msgstr ""
249
+
250
+ #: includes/admin/class-wp-job-manager-settings.php:111
251
  msgid "Listings Per Page"
252
  msgstr ""
253
 
254
+ #: includes/admin/class-wp-job-manager-settings.php:112
255
  msgid "Number of job listings to display per page."
256
  msgstr ""
257
 
258
+ #: includes/admin/class-wp-job-manager-settings.php:118
259
  msgid "Filled Positions"
260
  msgstr ""
261
 
262
+ #: includes/admin/class-wp-job-manager-settings.php:119
263
  msgid "Hide filled positions"
264
  msgstr ""
265
 
266
+ #: includes/admin/class-wp-job-manager-settings.php:120
267
  msgid "Filled positions will not display in your archives."
268
  msgstr ""
269
 
270
+ #: includes/admin/class-wp-job-manager-settings.php:127
271
  msgid "Hide Expired Listings"
272
  msgstr ""
273
 
274
+ #: includes/admin/class-wp-job-manager-settings.php:128
275
  msgid "Hide expired listings in job archives/search"
276
  msgstr ""
277
 
278
+ #: includes/admin/class-wp-job-manager-settings.php:129
279
  msgid "Expired job listings will not be searchable."
280
  msgstr ""
281
 
282
+ #: includes/admin/class-wp-job-manager-settings.php:136
283
  msgid "Hide Expired Listings Content"
284
  msgstr ""
285
 
286
+ #: includes/admin/class-wp-job-manager-settings.php:137
287
  msgid "Hide content in expired single job listings"
288
  msgstr ""
289
 
290
+ #: includes/admin/class-wp-job-manager-settings.php:138
291
  msgid ""
292
  "Your site will display the titles of expired listings, but not the content "
293
  "of the listings. Otherwise, expired listings display their full content "
294
  "minus the application area."
295
  msgstr ""
296
 
297
+ #: includes/admin/class-wp-job-manager-settings.php:146
298
  msgid "Enable listing categories"
299
  msgstr ""
300
 
301
+ #: includes/admin/class-wp-job-manager-settings.php:147
302
  msgid ""
303
  "This lets users select from a list of categories when submitting a job. "
304
  "Note: an admin has to create categories before site users can select them."
305
  msgstr ""
306
 
307
+ #: includes/admin/class-wp-job-manager-settings.php:154
308
  msgid "Multi-select Categories"
309
  msgstr ""
310
 
311
+ #: includes/admin/class-wp-job-manager-settings.php:155
312
  msgid "Default to category multiselect"
313
  msgstr ""
314
 
315
+ #: includes/admin/class-wp-job-manager-settings.php:156
316
  msgid ""
317
  "The category selection box will default to allowing multiple selections on "
318
  "the [jobs] shortcode. Without this, users will only be able to select a "
319
  "single category when submitting jobs."
320
  msgstr ""
321
 
322
+ #: includes/admin/class-wp-job-manager-settings.php:163
323
  msgid "Category Filter Type"
324
  msgstr ""
325
 
326
+ #: includes/admin/class-wp-job-manager-settings.php:164
327
  msgid ""
328
  "Determines the logic used to display jobs when selecting multiple "
329
  "categories."
330
  msgstr ""
331
 
332
+ #: includes/admin/class-wp-job-manager-settings.php:167
333
  msgid "Jobs will be shown if within ANY selected category"
334
  msgstr ""
335
 
336
+ #: includes/admin/class-wp-job-manager-settings.php:168
337
  msgid "Jobs will be shown if within ALL selected categories"
338
  msgstr ""
339
 
340
+ #: includes/admin/class-wp-job-manager-settings.php:174
341
  msgid "Types"
342
  msgstr ""
343
 
344
+ #: includes/admin/class-wp-job-manager-settings.php:175
345
  msgid "Enable listing types"
346
  msgstr ""
347
 
348
+ #: includes/admin/class-wp-job-manager-settings.php:176
349
  msgid ""
350
  "This lets users select from a list of types when submitting a job. Note: an "
351
  "admin has to create types before site users can select them."
352
  msgstr ""
353
 
354
+ #: includes/admin/class-wp-job-manager-settings.php:183
355
  msgid "Multi-select Listing Types"
356
  msgstr ""
357
 
358
+ #: includes/admin/class-wp-job-manager-settings.php:184
359
  msgid "Allow multiple types for listings"
360
  msgstr ""
361
 
362
+ #: includes/admin/class-wp-job-manager-settings.php:185
363
  msgid ""
364
  "This allows users to select more than one type when submitting a job. The "
365
  "metabox on the post editor and the selection box on the front-end job "
366
  "submission form will both reflect this."
367
  msgstr ""
368
 
369
+ #: includes/admin/class-wp-job-manager-settings.php:192
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
370
  msgid "Job Submission"
371
  msgstr ""
372
 
373
+ #: includes/admin/class-wp-job-manager-settings.php:197
374
  msgid "Account Required"
375
  msgstr ""
376
 
377
+ #: includes/admin/class-wp-job-manager-settings.php:198
378
  msgid "Require an account to submit listings"
379
  msgstr ""
380
 
381
+ #: includes/admin/class-wp-job-manager-settings.php:199
382
  msgid "Limits job listing submissions to registered, logged-in users."
383
  msgstr ""
384
 
385
+ #: includes/admin/class-wp-job-manager-settings.php:206
386
  msgid "Account Creation"
387
  msgstr ""
388
 
389
+ #: includes/admin/class-wp-job-manager-settings.php:207
390
  msgid "Enable account creation during submission"
391
  msgstr ""
392
 
393
+ #: includes/admin/class-wp-job-manager-settings.php:208
394
  msgid ""
395
  "Includes account creation on the listing submission form, to allow "
396
  "non-registered users to create an account and submit a job listing "
397
  "simultaneously."
398
  msgstr ""
399
 
400
+ #: includes/admin/class-wp-job-manager-settings.php:215
401
  msgid "Account Username"
402
  msgstr ""
403
 
404
+ #: includes/admin/class-wp-job-manager-settings.php:216
405
  msgid "Generate usernames from email addresses"
406
  msgstr ""
407
 
408
+ #: includes/admin/class-wp-job-manager-settings.php:217
409
  msgid ""
410
  "Automatically generates usernames for new accounts from the registrant's "
411
  "email address. If this is not enabled, a \"username\" field will display "
412
  "instead."
413
  msgstr ""
414
 
415
+ #: includes/admin/class-wp-job-manager-settings.php:224
416
  msgid "Account Password"
417
  msgstr ""
418
 
419
+ #: includes/admin/class-wp-job-manager-settings.php:225
420
  msgid "Email new users a link to set a password"
421
  msgstr ""
422
 
423
+ #: includes/admin/class-wp-job-manager-settings.php:226
424
  msgid ""
425
  "Sends an email to the user with their username and a link to set their "
426
  "password. If this is not enabled, a \"password\" field will display "
427
  "instead, and their email address won't be verified."
428
  msgstr ""
429
 
430
+ #: includes/admin/class-wp-job-manager-settings.php:233
431
  msgid "Account Role"
432
  msgstr ""
433
 
434
+ #: includes/admin/class-wp-job-manager-settings.php:234
435
  msgid ""
436
  "Any new accounts created during submission will have this role. If you "
437
  "haven't enabled account creation during submission in the options above, "
438
  "your own method of assigning roles will apply."
439
  msgstr ""
440
 
441
+ #: includes/admin/class-wp-job-manager-settings.php:241
442
  msgid "Moderate New Listings"
443
  msgstr ""
444
 
445
+ #: includes/admin/class-wp-job-manager-settings.php:242
446
  msgid "Require admin approval of all new listing submissions"
447
  msgstr ""
448
 
449
+ #: includes/admin/class-wp-job-manager-settings.php:243
450
  msgid ""
451
  "Sets all new submissions to \"pending.\" They will not appear on your site "
452
  "until an admin approves them."
453
  msgstr ""
454
 
455
+ #: includes/admin/class-wp-job-manager-settings.php:250
456
  msgid "Allow Pending Edits"
457
  msgstr ""
458
 
459
+ #: includes/admin/class-wp-job-manager-settings.php:251
460
  msgid "Allow editing of pending listings"
461
  msgstr ""
462
 
463
+ #: includes/admin/class-wp-job-manager-settings.php:252
464
  msgid ""
465
  "Users can continue to edit pending listings until they are approved by an "
466
  "admin."
467
  msgstr ""
468
 
469
+ #: includes/admin/class-wp-job-manager-settings.php:259
470
+ msgid "Allow Published Edits"
471
+ msgstr ""
472
+
473
+ #: includes/admin/class-wp-job-manager-settings.php:260
474
+ msgid "Allow editing of published listings"
475
+ msgstr ""
476
+
477
+ #: includes/admin/class-wp-job-manager-settings.php:261
478
+ msgid ""
479
+ "Choose whether published job listings can be edited and if edits require "
480
+ "admin approval. When moderation is required, the original job listings will "
481
+ "be unpublished while edits await admin approval."
482
+ msgstr ""
483
+
484
+ #: includes/admin/class-wp-job-manager-settings.php:264
485
+ msgid "Users cannot edit"
486
+ msgstr ""
487
+
488
+ #: includes/admin/class-wp-job-manager-settings.php:265
489
+ msgid "Users can edit without admin approval"
490
+ msgstr ""
491
+
492
+ #: includes/admin/class-wp-job-manager-settings.php:266
493
+ msgid "Users can edit, but edits require admin approval"
494
+ msgstr ""
495
+
496
+ #: includes/admin/class-wp-job-manager-settings.php:273
497
  msgid "Listing Duration"
498
  msgstr ""
499
 
500
+ #: includes/admin/class-wp-job-manager-settings.php:274
501
  msgid ""
502
  "Listings will display for the set number of days, then expire. Leave this "
503
  "field blank if you don't want listings to have an expiration date."
504
  msgstr ""
505
 
506
+ #: includes/admin/class-wp-job-manager-settings.php:280
507
  msgid "Application Method"
508
  msgstr ""
509
 
510
+ #: includes/admin/class-wp-job-manager-settings.php:281
511
  msgid ""
512
  "Choose the application method job listers will need to provide. Specify URL "
513
  "or email address only, or allow listers to choose which they prefer."
514
  msgstr ""
515
 
516
+ #: includes/admin/class-wp-job-manager-settings.php:284
517
  msgid "Email address or website URL"
518
  msgstr ""
519
 
520
+ #: includes/admin/class-wp-job-manager-settings.php:285
521
  msgid "Email addresses only"
522
  msgstr ""
523
 
524
+ #: includes/admin/class-wp-job-manager-settings.php:286
525
  msgid "Website URLs only"
526
  msgstr ""
527
 
528
+ #: includes/admin/class-wp-job-manager-settings.php:292
529
+ msgid "reCAPTCHA"
530
+ msgstr ""
531
+
532
+ #: includes/admin/class-wp-job-manager-settings.php:296
533
+ msgid "Are you human?"
534
+ msgstr ""
535
+
536
+ #: includes/admin/class-wp-job-manager-settings.php:298
537
+ msgid "Field Label"
538
+ msgstr ""
539
+
540
+ #: includes/admin/class-wp-job-manager-settings.php:299
541
+ msgid "The label used for the reCAPTCHA field on forms."
542
+ msgstr ""
543
+
544
+ #: includes/admin/class-wp-job-manager-settings.php:306
545
+ msgid "Site Key"
546
+ msgstr ""
547
+
548
+ #: includes/admin/class-wp-job-manager-settings.php:307
549
+ msgid ""
550
+ "You can retrieve your site key from <a href=\"%s\">Google's reCAPTCHA admin "
551
+ "dashboard</a>."
552
+ msgstr ""
553
+
554
+ #: includes/admin/class-wp-job-manager-settings.php:314
555
+ msgid "Secret Key"
556
+ msgstr ""
557
+
558
+ #: includes/admin/class-wp-job-manager-settings.php:315
559
+ msgid ""
560
+ "You can retrieve your secret key from <a href=\"%s\">Google's reCAPTCHA "
561
+ "admin dashboard</a>."
562
+ msgstr ""
563
+
564
+ #: includes/admin/class-wp-job-manager-settings.php:321
565
+ msgid "Job Submission Form"
566
+ msgstr ""
567
+
568
+ #: includes/admin/class-wp-job-manager-settings.php:322
569
+ msgid "Display a reCAPTCHA field on job submission form."
570
+ msgstr ""
571
+
572
+ #: includes/admin/class-wp-job-manager-settings.php:323
573
+ msgid ""
574
+ "This will help prevent bots from submitting job listings. You must have "
575
+ "entered a valid site key and secret key above."
576
+ msgstr ""
577
+
578
+ #: includes/admin/class-wp-job-manager-settings.php:330
579
  msgid "Pages"
580
  msgstr ""
581
 
582
+ #: includes/admin/class-wp-job-manager-settings.php:335
583
  msgid "Submit Job Form Page"
584
  msgstr ""
585
 
586
+ #: includes/admin/class-wp-job-manager-settings.php:336
587
  msgid ""
588
  "Select the page where you've used the [submit_job_form] shortcode. This "
589
  "lets the plugin know the location of the form."
590
  msgstr ""
591
 
592
+ #: includes/admin/class-wp-job-manager-settings.php:342
593
  msgid "Job Dashboard Page"
594
  msgstr ""
595
 
596
+ #: includes/admin/class-wp-job-manager-settings.php:343
597
  msgid ""
598
  "Select the page where you've used the [job_dashboard] shortcode. This lets "
599
  "the plugin know the location of the dashboard."
600
  msgstr ""
601
 
602
+ #: includes/admin/class-wp-job-manager-settings.php:349
603
  msgid "Job Listings Page"
604
  msgstr ""
605
 
606
+ #: includes/admin/class-wp-job-manager-settings.php:350
607
  msgid ""
608
  "Select the page where you've used the [jobs] shortcode. This lets the "
609
  "plugin know the location of the job listings page."
610
  msgstr ""
611
 
612
+ #: includes/admin/class-wp-job-manager-settings.php:396
613
  msgid "Settings successfully saved"
614
  msgstr ""
615
 
616
+ #: includes/admin/class-wp-job-manager-settings.php:472
617
  msgid "--no page--"
618
  msgstr ""
619
 
620
+ #: includes/admin/class-wp-job-manager-settings.php:477
621
  msgid "Select a page&hellip;"
622
  msgstr ""
623
 
624
+ #: includes/admin/class-wp-job-manager-settings.php:523
625
  msgid "Save Changes"
626
  msgstr ""
627
 
629
  msgid "Setup"
630
  msgstr ""
631
 
632
+ #: includes/admin/class-wp-job-manager-setup.php:203
633
  msgid "WP Job Manager Setup"
634
  msgstr ""
635
 
636
+ #: includes/admin/class-wp-job-manager-setup.php:206
637
  msgid "1. Introduction"
638
  msgstr ""
639
 
640
+ #: includes/admin/class-wp-job-manager-setup.php:207
641
  msgid "2. Page Setup"
642
  msgstr ""
643
 
644
+ #: includes/admin/class-wp-job-manager-setup.php:208
645
  msgid "3. Done"
646
  msgstr ""
647
 
648
+ #: includes/admin/class-wp-job-manager-setup.php:213
649
  msgid "Welcome to the Setup Wizard!"
650
  msgstr ""
651
 
652
+ #: includes/admin/class-wp-job-manager-setup.php:215
653
  msgid ""
654
  "Thanks for installing <em>WP Job Manager</em>! Let's get your site ready to "
655
  "accept job listings."
656
  msgstr ""
657
 
658
+ #: includes/admin/class-wp-job-manager-setup.php:216
659
  msgid ""
660
  "This setup wizard will walk you through the process of creating pages for "
661
  "job submissions, management, and listings."
662
  msgstr ""
663
 
664
+ #: includes/admin/class-wp-job-manager-setup.php:217
665
  msgid ""
666
  "If you'd prefer to skip this and set up your pages manually, our "
667
  "%sdocumentation%s will walk you through each step."
668
  msgstr ""
669
 
670
+ #: includes/admin/class-wp-job-manager-setup.php:225
671
  msgid "Start setup"
672
  msgstr ""
673
 
674
+ #: includes/admin/class-wp-job-manager-setup.php:226
675
  msgid "Skip setup. I will set up the plugin manually."
676
  msgstr ""
677
 
678
+ #: includes/admin/class-wp-job-manager-setup.php:233
679
  msgid "Page Setup"
680
  msgstr ""
681
 
682
+ #: includes/admin/class-wp-job-manager-setup.php:235
683
  msgid ""
684
  "With WP Job Manager, employers and applicants can post, manage, and browse "
685
  "job listings right on your website. Tell us which of these common pages "
686
  "you'd like your site to have and we'll create and configure them for you."
687
  msgstr ""
688
 
689
+ #: includes/admin/class-wp-job-manager-setup.php:236
690
  msgid ""
691
  "(These pages are created using %1$sshortcodes%2$s, which we take care of in "
692
  "this step. If you'd like to build these pages yourself or want to add one "
695
  "instructions.)"
696
  msgstr ""
697
 
698
+ #: includes/admin/class-wp-job-manager-setup.php:244
699
  msgid "Page Title"
700
  msgstr ""
701
 
702
+ #: includes/admin/class-wp-job-manager-setup.php:245
703
  msgid "Page Description"
704
  msgstr ""
705
 
706
+ #: includes/admin/class-wp-job-manager-setup.php:246
707
  msgid "Content Shortcode"
708
  msgstr ""
709
 
710
+ #: includes/admin/class-wp-job-manager-setup.php:254
711
  msgid ""
712
  "Creates a page that allows employers to post new jobs directly from a page "
713
  "on your website, instead of requiring them to log in to an admin area. If "
715
  "the admin dashboard only -- you can uncheck this setting."
716
  msgstr ""
717
 
718
+ #: includes/admin/class-wp-job-manager-setup.php:262
719
  msgid ""
720
  "Creates a page that allows employers to manage their job listings directly "
721
  "from a page on your website, instead of requiring them to log in to an "
723
  "only, you can uncheck this setting."
724
  msgstr ""
725
 
726
+ #: includes/admin/class-wp-job-manager-setup.php:269
727
  msgid "Creates a page where visitors can browse, search, and filter job listings."
728
  msgstr ""
729
 
730
+ #: includes/admin/class-wp-job-manager-setup.php:277
731
  msgid "Skip this step"
732
  msgstr ""
733
 
734
+ #: includes/admin/class-wp-job-manager-setup.php:287
735
  msgid "You're ready to start using WP Job Manager!"
736
  msgstr ""
737
 
738
+ #: includes/admin/class-wp-job-manager-setup.php:289
739
  msgid "Wondering what to do now? Here are some of the most common next steps:"
740
  msgstr ""
741
 
742
+ #: includes/admin/class-wp-job-manager-setup.php:292
743
  msgid "Tweak your settings"
744
  msgstr ""
745
 
746
+ #: includes/admin/class-wp-job-manager-setup.php:293
747
  msgid "Add a job using the admin dashboard"
748
  msgstr ""
749
 
750
+ #: includes/admin/class-wp-job-manager-setup.php:296
751
  msgid "View submitted job listings"
752
  msgstr ""
753
 
754
+ #: includes/admin/class-wp-job-manager-setup.php:298
755
  msgid "Add job listings to a page using the [jobs] shortcode"
756
  msgstr ""
757
 
758
+ #: includes/admin/class-wp-job-manager-setup.php:302
759
  msgid "Add a job via the front-end"
760
  msgstr ""
761
 
762
+ #: includes/admin/class-wp-job-manager-setup.php:304
763
  msgid "Learn to use the front-end job submission board"
764
  msgstr ""
765
 
766
+ #: includes/admin/class-wp-job-manager-setup.php:308
767
  msgid "View the job dashboard"
768
  msgstr ""
769
 
770
+ #: includes/admin/class-wp-job-manager-setup.php:310
771
  msgid "Learn to use the front-end job dashboard"
772
  msgstr ""
773
 
774
+ #: includes/admin/class-wp-job-manager-setup.php:314
775
  msgid ""
776
  "If you need help, you can find more detail in our %1$ssupport "
777
  "documentation%2$s or post your question on the %3$sWP Job Manager support "
778
  "forums%2$s. Happy hiring!"
779
  msgstr ""
780
 
781
+ #: includes/admin/class-wp-job-manager-setup.php:317
782
  msgid "Support WP Job Manager's Ongoing Development"
783
  msgstr ""
784
 
785
+ #: includes/admin/class-wp-job-manager-setup.php:318
786
  msgid ""
787
  "There are lots of ways you can support open source software projects like "
788
  "this one: contributing code, fixing a bug, assisting with non-English "
790
  "spread the word. We appreciate your support!"
791
  msgstr ""
792
 
793
+ #: includes/admin/class-wp-job-manager-setup.php:320
794
  msgid "Leave a positive review"
795
  msgstr ""
796
 
797
+ #: includes/admin/class-wp-job-manager-setup.php:321
798
  msgid "Contribute a localization"
799
  msgstr ""
800
 
801
+ #: includes/admin/class-wp-job-manager-setup.php:322
802
  msgid "Contribute code or report a bug"
803
  msgstr ""
804
 
805
+ #: includes/admin/class-wp-job-manager-setup.php:323
806
  msgid "Help other users on the forums"
807
  msgstr ""
808
 
814
  msgstr ""
815
 
816
  #: includes/admin/class-wp-job-manager-writepanels.php:56
817
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:182
818
  msgid "e.g. \"London\""
819
  msgstr ""
820
 
896
  msgid "Listing Expiry Date"
897
  msgstr ""
898
 
899
+ #: includes/admin/class-wp-job-manager-writepanels.php:118
900
  #: includes/rest-api/class-wp-job-manager-models-job-listings-custom-fields.php:75
901
  msgid "Posted by"
902
  msgstr ""
903
 
904
+ #: includes/admin/class-wp-job-manager-writepanels.php:160
905
  msgid "%s Data"
906
  msgstr ""
907
 
908
+ #: includes/admin/class-wp-job-manager-writepanels.php:200
909
  msgid "Most Used"
910
  msgstr ""
911
 
912
+ #: includes/admin/class-wp-job-manager-writepanels.php:257
913
+ #: includes/admin/class-wp-job-manager-writepanels.php:260
914
+ #: includes/admin/class-wp-job-manager-writepanels.php:263
915
  msgid "Use file"
916
  msgstr ""
917
 
918
+ #: includes/admin/class-wp-job-manager-writepanels.php:257
919
+ #: includes/admin/class-wp-job-manager-writepanels.php:260
920
+ #: includes/admin/class-wp-job-manager-writepanels.php:263
921
  msgid "Upload"
922
  msgstr ""
923
 
924
+ #: includes/admin/class-wp-job-manager-writepanels.php:263
925
  msgid "Add file"
926
  msgstr ""
927
 
928
+ #: includes/admin/class-wp-job-manager-writepanels.php:489
929
  msgid "Guest User"
930
  msgstr ""
931
 
932
+ #: includes/admin/class-wp-job-manager-writepanels.php:491
933
  msgid "Change"
934
  msgstr ""
935
 
936
+ #: includes/admin/class-wp-job-manager-writepanels.php:495
937
  msgid "Enter the ID of the user, or leave blank if submitted by a guest."
938
  msgstr ""
939
 
940
+ #: includes/admin/class-wp-job-manager-writepanels.php:558
941
+ msgid "%s was last modified by the user on %s."
942
+ msgstr ""
943
+
944
+ #: includes/admin/views/html-admin-page-addons.php:13
945
+ msgid "More Information &rarr;"
946
+ msgstr ""
947
+
948
+ #: includes/admin/views/html-admin-page-addons.php:43
949
+ msgid "No add-ons were found."
950
+ msgstr ""
951
+
952
  #: includes/class-wp-job-manager-ajax.php:170
953
  msgid "Search completed. Found %d matching record."
954
  msgid_plural "Search completed. Found %d matching records."
977
  msgid "Employer"
978
  msgstr ""
979
 
980
+ #: includes/class-wp-job-manager-post-types.php:90
981
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:195
982
  msgid "Job category"
983
  msgstr ""
984
 
985
+ #: includes/class-wp-job-manager-post-types.php:91
986
  msgid "Job categories"
987
  msgstr ""
988
 
989
+ #: includes/class-wp-job-manager-post-types.php:115
990
+ #: includes/class-wp-job-manager-post-types.php:163
991
+ #: includes/class-wp-job-manager-post-types.php:226
992
  msgid "Search %s"
993
  msgstr ""
994
 
995
+ #: includes/class-wp-job-manager-post-types.php:116
996
+ #: includes/class-wp-job-manager-post-types.php:164
997
+ #: includes/class-wp-job-manager-post-types.php:218
998
  msgid "All %s"
999
  msgstr ""
1000
 
1001
+ #: includes/class-wp-job-manager-post-types.php:117
1002
+ #: includes/class-wp-job-manager-post-types.php:165
1003
+ #: includes/class-wp-job-manager-post-types.php:229
1004
  msgid "Parent %s"
1005
  msgstr ""
1006
 
1007
+ #: includes/class-wp-job-manager-post-types.php:118
1008
+ #: includes/class-wp-job-manager-post-types.php:166
1009
  msgid "Parent %s:"
1010
  msgstr ""
1011
 
1012
+ #: includes/class-wp-job-manager-post-types.php:119
1013
+ #: includes/class-wp-job-manager-post-types.php:167
1014
+ #: includes/class-wp-job-manager-post-types.php:222
1015
  msgid "Edit %s"
1016
  msgstr ""
1017
 
1018
+ #: includes/class-wp-job-manager-post-types.php:120
1019
+ #: includes/class-wp-job-manager-post-types.php:168
1020
  msgid "Update %s"
1021
  msgstr ""
1022
 
1023
+ #: includes/class-wp-job-manager-post-types.php:121
1024
+ #: includes/class-wp-job-manager-post-types.php:169
1025
  msgid "Add New %s"
1026
  msgstr ""
1027
 
1028
+ #: includes/class-wp-job-manager-post-types.php:122
1029
+ #: includes/class-wp-job-manager-post-types.php:170
1030
  msgid "New %s Name"
1031
  msgstr ""
1032
 
1033
+ #: includes/class-wp-job-manager-post-types.php:139
1034
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:186
1035
  msgid "Job type"
1036
  msgstr ""
1037
 
1038
+ #: includes/class-wp-job-manager-post-types.php:140
1039
  msgid "Job types"
1040
  msgstr ""
1041
 
1042
+ #: includes/class-wp-job-manager-post-types.php:189
1043
  msgid "Job"
1044
  msgstr ""
1045
 
1046
+ #: includes/class-wp-job-manager-post-types.php:190
1047
  msgid "Jobs"
1048
  msgstr ""
1049
 
1050
+ #: includes/class-wp-job-manager-post-types.php:219
1051
  msgid "Add New"
1052
  msgstr ""
1053
 
1054
+ #: includes/class-wp-job-manager-post-types.php:220
1055
  msgid "Add %s"
1056
  msgstr ""
1057
 
1058
+ #: includes/class-wp-job-manager-post-types.php:223
1059
  msgid "New %s"
1060
  msgstr ""
1061
 
1062
+ #: includes/class-wp-job-manager-post-types.php:224
1063
  #: includes/class-wp-job-manager-post-types.php:225
 
1064
  msgid "View %s"
1065
  msgstr ""
1066
 
1067
+ #: includes/class-wp-job-manager-post-types.php:227
1068
  msgid "No %s found"
1069
  msgstr ""
1070
 
1071
+ #: includes/class-wp-job-manager-post-types.php:228
1072
  msgid "No %s found in trash"
1073
  msgstr ""
1074
 
1075
+ #: includes/class-wp-job-manager-post-types.php:230
1076
  msgid "Company Logo"
1077
  msgstr ""
1078
 
1079
+ #: includes/class-wp-job-manager-post-types.php:231
1080
  msgid "Set company logo"
1081
  msgstr ""
1082
 
1083
+ #: includes/class-wp-job-manager-post-types.php:232
1084
  msgid "Remove company logo"
1085
  msgstr ""
1086
 
1087
+ #: includes/class-wp-job-manager-post-types.php:233
1088
  msgid "Use as company logo"
1089
  msgstr ""
1090
 
1091
+ #: includes/class-wp-job-manager-post-types.php:235
1092
  msgid "This is where you can create and manage %s."
1093
  msgstr ""
1094
 
1095
+ #: includes/class-wp-job-manager-post-types.php:266
1096
  msgid "Expired <span class=\"count\">(%s)</span>"
1097
  msgid_plural "Expired <span class=\"count\">(%s)</span>"
1098
  msgstr[0] ""
1099
  msgstr[1] ""
1100
 
1101
+ #: includes/class-wp-job-manager-post-types.php:274
1102
  msgid "Preview <span class=\"count\">(%s)</span>"
1103
  msgid_plural "Preview <span class=\"count\">(%s)</span>"
1104
  msgstr[0] ""
1135
 
1136
  #: includes/class-wp-job-manager-shortcodes.php:217
1137
  #: includes/widgets/class-wp-job-manager-widget-featured-jobs.php:28
1138
+ #: includes/widgets/class-wp-job-manager-widget-featured-jobs.php:44
1139
  #: includes/widgets/class-wp-job-manager-widget-recent-jobs.php:28
1140
  msgid "Title"
1141
  msgstr ""
1153
  msgid "Load more listings"
1154
  msgstr ""
1155
 
1156
+ #: includes/class-wp-job-manager-usage-tracking.php:63
1157
+ msgid ""
1158
+ "We'd love if you helped us make WP Job Manager better by allowing us to "
1159
+ "collect\n"
1160
+ "\t\t\t<a href=\"%s\" target=\"_blank\">usage tracking data</a>.\n"
1161
+ "\t\t\tNo sensitive information is collected, and you can opt out at any "
1162
+ "time."
1163
+ msgstr ""
1164
+
1165
+ #: includes/class-wp-job-manager-usage-tracking.php:107
1166
+ #. translators: the href tag contains the URL for the page telling users what
1167
+ #. data WPJM tracks.
1168
+ msgid ""
1169
+ "Help us make WP Job Manager better by allowing us to collect\n"
1170
+ "\t\t\t\t<a href=\"%s\" target=\"_blank\">usage tracking data</a>.\n"
1171
+ "\t\t\t\tNo sensitive information is collected."
1172
+ msgstr ""
1173
+
1174
+ #: includes/class-wp-job-manager-usage-tracking.php:126
1175
+ msgid "Enable usage tracking"
1176
+ msgstr ""
1177
+
1178
+ #: includes/forms/class-wp-job-manager-form-edit-job.php:93
1179
  msgid "Invalid listing"
1180
  msgstr ""
1181
 
1182
+ #: includes/forms/class-wp-job-manager-form-edit-job.php:125
1183
  msgid "Save changes"
1184
  msgstr ""
1185
 
1186
+ #: includes/forms/class-wp-job-manager-form-edit-job.php:128
1187
+ msgid "Submit changes for approval"
1188
+ msgstr ""
1189
+
1190
+ #: includes/forms/class-wp-job-manager-form-edit-job.php:173
1191
  msgid "Your changes have been saved."
1192
  msgstr ""
1193
 
1194
+ #: includes/forms/class-wp-job-manager-form-edit-job.php:179
1195
  msgid "View &rarr;"
1196
  msgstr ""
1197
 
1198
+ #: includes/forms/class-wp-job-manager-form-edit-job.php:181
1199
+ msgid ""
1200
+ "Your changes have been submitted and your listing will be visible again "
1201
+ "once approved."
1202
+ msgstr ""
1203
+
1204
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:67
1205
  msgid "Submit Details"
1206
  msgstr ""
1207
 
1208
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:73
1209
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:485
1210
  #: templates/job-preview.php:22
1211
  msgid "Preview"
1212
  msgstr ""
1213
 
1214
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:79
1215
  msgid "Done"
1216
  msgstr ""
1217
 
1218
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:147
1219
  msgid "Application email"
1220
  msgstr ""
1221
 
1222
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:148
1223
  #: wp-job-manager-template.php:646
1224
  msgid "you@yourdomain.com"
1225
  msgstr ""
1226
 
1227
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:152
1228
  msgid "Application URL"
1229
  msgstr ""
1230
 
1231
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:153
1232
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:231
1233
  msgid "http://"
1234
  msgstr ""
1235
 
1236
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:157
1237
  msgid "Application email/URL"
1238
  msgstr ""
1239
 
1240
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:158
1241
  msgid "Enter an email address or website URL"
1242
  msgstr ""
1243
 
1244
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:171
1245
  msgid "Job Title"
1246
  msgstr ""
1247
 
1248
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:179
1249
  msgid "Leave this blank if the location is not important"
1250
  msgstr ""
1251
 
1252
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:189
1253
  msgid "Choose job type&hellip;"
1254
  msgstr ""
1255
 
1256
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:204
1257
  msgid "Description"
1258
  msgstr ""
1259
 
1260
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:220
1261
  msgid "Company name"
1262
  msgstr ""
1263
 
1264
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:223
1265
  msgid "Enter the name of the company"
1266
  msgstr ""
1267
 
1268
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:227
1269
  #: templates/content-single-job_listing-company.php:30
1270
  msgid "Website"
1271
  msgstr ""
1272
 
1273
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:235
1274
  msgid "Tagline"
1275
  msgstr ""
1276
 
1277
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:238
1278
  msgid "Briefly describe your company"
1279
  msgstr ""
1280
 
1281
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:243
1282
  msgid "Video"
1283
  msgstr ""
1284
 
1285
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:247
1286
  msgid "A link to a video about your company"
1287
  msgstr ""
1288
 
1289
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:251
1290
  msgid "Twitter username"
1291
  msgstr ""
1292
 
1293
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:254
1294
  msgid "@yourcompany"
1295
  msgstr ""
1296
 
1297
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:258
1298
  msgid "Logo"
1299
  msgstr ""
1300
 
1301
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:306
1302
  msgid "%s is a required field"
1303
  msgstr ""
1304
 
1305
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:316
1306
  msgid "%s is invalid"
1307
  msgstr ""
1308
 
1309
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:332
1310
+ #: wp-job-manager-functions.php:1235
1311
  msgid "\"%s\" (filetype %s) needs to be one of the following file types: %s"
1312
  msgstr ""
1313
 
1314
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:347
1315
  msgid "Please enter a valid application email address"
1316
  msgstr ""
1317
 
1318
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:356
1319
  msgid "Please enter a valid application URL"
1320
  msgstr ""
1321
 
1322
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:366
1323
  msgid "Please enter a valid application email address or URL"
1324
  msgstr ""
1325
 
1326
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:516
1327
  msgid "Please enter a username."
1328
  msgstr ""
1329
 
1330
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:520
1331
  msgid "Please enter a password."
1332
  msgstr ""
1333
 
1334
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:524
1335
  msgid "Please enter your email address."
1336
  msgstr ""
1337
 
1338
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:530
1339
  msgid "Passwords must match."
1340
  msgstr ""
1341
 
1342
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:535
1343
  msgid "Invalid Password: %s"
1344
  msgstr ""
1345
 
1346
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:537
1347
  msgid "Password is not valid."
1348
  msgstr ""
1349
 
1350
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:558
1351
  msgid "You must be signed in to post a new listing."
1352
  msgstr ""
1353
 
1354
+ #: includes/helper/class-wp-job-manager-helper.php:254
1355
+ msgid "Manage License (Requires Attention)"
1356
  msgstr ""
1357
 
1358
  #: includes/helper/class-wp-job-manager-helper.php:257
1359
+ msgid "Manage License"
1360
+ msgstr ""
1361
+
1362
+ #: includes/helper/class-wp-job-manager-helper.php:260
1363
  #: includes/helper/views/html-licences.php:69
1364
  msgid "Activate License"
1365
  msgstr ""
1366
 
1367
+ #: includes/helper/class-wp-job-manager-helper.php:449
1368
  msgid ""
1369
  "Please enter a valid license key and email address in order to activate "
1370
  "this plugin's license."
1371
  msgstr ""
1372
 
1373
+ #: includes/helper/class-wp-job-manager-helper.php:477
1374
  msgid "Connection failed to the License Key API server - possible server issue."
1375
  msgstr ""
1376
 
1377
+ #: includes/helper/class-wp-job-manager-helper.php:485
1378
  msgid "Plugin license has been activated."
1379
  msgstr ""
1380
 
1381
+ #: includes/helper/class-wp-job-manager-helper.php:487
1382
  msgid "An unknown error occurred while attempting to activate the license"
1383
  msgstr ""
1384
 
1385
+ #: includes/helper/class-wp-job-manager-helper.php:499
1386
  msgid "license is not active."
1387
  msgstr ""
1388
 
1389
+ #: includes/helper/class-wp-job-manager-helper.php:513
1390
  msgid "Plugin license has been deactivated."
1391
  msgstr ""
1392
 
1393
+ #: includes/helper/views/html-licence-key-error.php:7
1394
  #: includes/helper/views/html-licence-key-notice.php:7
1395
  msgid "Hide notice"
1396
  msgstr ""
1439
  msgid "Number of listings to show"
1440
  msgstr ""
1441
 
1442
+ #: includes/widgets/class-wp-job-manager-widget-featured-jobs.php:41
1443
+ msgid "Sort By"
1444
+ msgstr ""
1445
+
1446
+ #: includes/widgets/class-wp-job-manager-widget-featured-jobs.php:43
1447
+ msgid "Date"
1448
+ msgstr ""
1449
+
1450
+ #: includes/widgets/class-wp-job-manager-widget-featured-jobs.php:45
1451
+ msgid "Author"
1452
+ msgstr ""
1453
+
1454
+ #: includes/widgets/class-wp-job-manager-widget-featured-jobs.php:46
1455
+ msgid "Random"
1456
+ msgstr ""
1457
+
1458
+ #: includes/widgets/class-wp-job-manager-widget-featured-jobs.php:52
1459
+ msgid "Sort Direction"
1460
+ msgstr ""
1461
+
1462
+ #: includes/widgets/class-wp-job-manager-widget-featured-jobs.php:54
1463
+ msgid "Ascending"
1464
+ msgstr ""
1465
+
1466
+ #: includes/widgets/class-wp-job-manager-widget-featured-jobs.php:55
1467
+ msgid "Descending"
1468
+ msgstr ""
1469
+
1470
  #: includes/widgets/class-wp-job-manager-widget-recent-jobs.php:21
1471
  msgid ""
1472
  "Display a list of recent listings on your site, optionally matching a "
1482
  msgid "Keyword"
1483
  msgstr ""
1484
 
1485
+ #: lib/usage-tracking/class-usage-tracking-base.php:327
1486
+ msgid "Every Two Weeks"
1487
+ msgstr ""
1488
+
1489
+ #: lib/usage-tracking/class-usage-tracking-base.php:466
1490
+ msgid "Enable Usage Tracking"
1491
+ msgstr ""
1492
+
1493
+ #: lib/usage-tracking/class-usage-tracking-base.php:469
1494
+ msgid "Disable Usage Tracking"
1495
+ msgstr ""
1496
+
1497
+ #: lib/usage-tracking/class-usage-tracking-base.php:475
1498
+ msgid "Usage data enabled. Thank you!"
1499
+ msgstr ""
1500
+
1501
+ #: lib/usage-tracking/class-usage-tracking-base.php:478
1502
+ msgid "Disabled usage tracking."
1503
+ msgstr ""
1504
+
1505
+ #: lib/usage-tracking/class-usage-tracking-base.php:481
1506
+ msgid "Something went wrong. Please try again later."
1507
+ msgstr ""
1508
+
1509
  #: lib/wpjm_rest/class-wp-job-manager-rest-model.php:214
1510
  #. translators: %s is usually a field name.
1511
  msgid "%s cannot be empty"
1587
  msgstr ""
1588
 
1589
  #: templates/form-fields/multiselect-field.php:20
1590
+ #: wp-job-manager-functions.php:1023
1591
  msgid "No results match"
1592
  msgstr ""
1593
 
1594
  #: templates/form-fields/multiselect-field.php:20
1595
+ #: wp-job-manager-functions.php:1024
1596
  msgid "Select Some Options"
1597
  msgstr ""
1598
 
1599
+ #: templates/form-fields/uploaded-file-html.php:28
1600
+ #: templates/form-fields/uploaded-file-html.php:30
1601
  msgid "remove"
1602
  msgstr ""
1603
 
1627
  msgid "You do not have any active listings."
1628
  msgstr ""
1629
 
1630
+ #: templates/job-dashboard.php:44
1631
+ msgid "Featured Job"
1632
  msgstr ""
1633
 
1634
  #: templates/job-dashboard.php:55
1635
+ msgid "Mark not filled"
1636
+ msgstr ""
1637
+
1638
+ #: templates/job-dashboard.php:57
1639
  msgid "Mark filled"
1640
  msgstr ""
1641
 
1642
+ #: templates/job-dashboard.php:60
1643
  msgid "Duplicate"
1644
  msgstr ""
1645
 
1646
+ #: templates/job-dashboard.php:64
1647
  msgid "Relist"
1648
  msgstr ""
1649
 
1693
  msgid "%s submitted successfully. Your listing will be visible once approved."
1694
  msgstr ""
1695
 
1696
+ #: wp-job-manager-functions.php:421
1697
  msgid "Reset"
1698
  msgstr ""
1699
 
1700
+ #: wp-job-manager-functions.php:425
1701
  msgid "RSS"
1702
  msgstr ""
1703
 
1704
+ #: wp-job-manager-functions.php:520
1705
  msgid "Invalid email address."
1706
  msgstr ""
1707
 
1708
+ #: wp-job-manager-functions.php:528
1709
  msgid "Your email address isn&#8217;t correct."
1710
  msgstr ""
1711
 
1712
+ #: wp-job-manager-functions.php:532
1713
  msgid "This email is already registered, please choose another one."
1714
  msgstr ""
1715
 
1716
+ #: wp-job-manager-functions.php:830
1717
  msgid "Full Time"
1718
  msgstr ""
1719
 
1720
+ #: wp-job-manager-functions.php:831
1721
  msgid "Part Time"
1722
  msgstr ""
1723
 
1724
+ #: wp-job-manager-functions.php:832
1725
  msgid "Contractor"
1726
  msgstr ""
1727
 
1728
+ #: wp-job-manager-functions.php:833
1729
  msgid "Temporary"
1730
  msgstr ""
1731
 
1732
+ #: wp-job-manager-functions.php:834
1733
  msgid "Intern"
1734
  msgstr ""
1735
 
1736
+ #: wp-job-manager-functions.php:835
1737
  msgid "Volunteer"
1738
  msgstr ""
1739
 
1740
+ #: wp-job-manager-functions.php:836
1741
  msgid "Per Diem"
1742
  msgstr ""
1743
 
1744
+ #: wp-job-manager-functions.php:837
1745
  msgid "Other"
1746
  msgstr ""
1747
 
1748
+ #: wp-job-manager-functions.php:904
1749
  msgid "Passwords must be at least 8 characters long."
1750
  msgstr ""
1751
 
1752
+ #: wp-job-manager-functions.php:1022
1753
  msgid "Choose a category&hellip;"
1754
  msgstr ""
1755
 
1756
+ #: wp-job-manager-functions.php:1237
1757
  msgid "Uploaded files need to be one of the following file types: %s"
1758
  msgstr ""
1759
 
1793
  msgid "Anywhere"
1794
  msgstr ""
1795
 
1796
+ #: wp-job-manager.php:268
1797
  msgid "Load previous listings"
1798
  msgstr ""
1799
 
1800
+ #: wp-job-manager.php:331
1801
  msgid "Invalid file type. Accepted types:"
1802
  msgstr ""
1803
 
1804
+ #: wp-job-manager.php:342
1805
  msgid "Are you sure you want to delete this listing?"
1806
  msgstr ""
1807
 
1823
  msgid "Automattic"
1824
  msgstr ""
1825
 
1826
+ #: includes/admin/class-wp-job-manager-admin.php:101
1827
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:401
1828
  #. translators: jQuery date format, see
1829
  #. http:api.jqueryui.com/datepicker/#utility-formatDate
1830
  msgctxt "Date format for jQuery datepicker."
1832
  msgstr ""
1833
 
1834
  #: includes/admin/class-wp-job-manager-permalink-settings.php:81
1835
+ #: includes/class-wp-job-manager-post-types.php:640
1836
  msgctxt "Job permalink - resave permalinks after changing this"
1837
  msgid "job"
1838
  msgstr ""
1839
 
1840
  #: includes/admin/class-wp-job-manager-permalink-settings.php:90
1841
+ #: includes/class-wp-job-manager-post-types.php:641
1842
  msgctxt "Job category slug - resave permalinks after changing this"
1843
  msgid "job-category"
1844
  msgstr ""
1845
 
1846
  #: includes/admin/class-wp-job-manager-permalink-settings.php:99
1847
+ #: includes/class-wp-job-manager-post-types.php:642
1848
  msgctxt "Job type slug - resave permalinks after changing this"
1849
  msgid "job-type"
1850
  msgstr ""
1851
 
1852
+ #: includes/admin/class-wp-job-manager-setup.php:252
1853
  msgctxt "Default page title (wizard)"
1854
  msgid "Post a Job"
1855
  msgstr ""
1856
 
1857
+ #: includes/admin/class-wp-job-manager-setup.php:260
1858
  msgctxt "Default page title (wizard)"
1859
  msgid "Job Dashboard"
1860
  msgstr ""
1861
 
1862
+ #: includes/admin/class-wp-job-manager-setup.php:268
1863
  msgctxt "Default page title (wizard)"
1864
  msgid "Jobs"
1865
  msgstr ""
1866
 
1867
+ #: includes/class-wp-job-manager-post-types.php:200
 
 
 
 
 
 
1868
  msgctxt "Post type archive slug - resave permalinks after changing this"
1869
  msgid "jobs"
1870
  msgstr ""
1871
 
1872
+ #: includes/class-wp-job-manager-post-types.php:260
1873
+ #: wp-job-manager-functions.php:316
1874
  msgctxt "post status"
1875
  msgid "Expired"
1876
  msgstr ""
1877
 
1878
+ #: includes/class-wp-job-manager-post-types.php:269
1879
+ #: wp-job-manager-functions.php:317
1880
  msgctxt "post status"
1881
  msgid "Preview"
1882
  msgstr ""
1883
 
1884
+ #: wp-job-manager-functions.php:315
1885
  msgctxt "post status"
1886
  msgid "Draft"
1887
  msgstr ""
1888
 
1889
+ #: wp-job-manager-functions.php:318
1890
  msgctxt "post status"
1891
  msgid "Pending approval"
1892
  msgstr ""
1893
 
1894
+ #: wp-job-manager-functions.php:319
1895
  msgctxt "post status"
1896
  msgid "Pending payment"
1897
  msgstr ""
1898
 
1899
+ #: wp-job-manager-functions.php:320
1900
  msgctxt "post status"
1901
  msgid "Active"
1902
+ msgstr ""
lib/usage-tracking/class-usage-tracking-base.php ADDED
@@ -0,0 +1,572 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Reusable Usage Tracking library. For sending plugin usage data and events to
4
+ * Tracks.
5
+ **/
6
+
7
+ if ( ! defined( 'ABSPATH' ) ) {
8
+ exit;
9
+ }
10
+
11
+ /**
12
+ * Usage Tracking class. Please update the prefix to something unique to your
13
+ * plugin.
14
+ */
15
+ abstract class WP_Job_Manager_Usage_Tracking_Base {
16
+ const PLUGIN_PREFIX = 'plugin_';
17
+
18
+ /*
19
+ * Instance variables.
20
+ */
21
+
22
+ /**
23
+ * The name of the option for hiding the Usage Tracking opt-in dialog.
24
+ *
25
+ * @var string
26
+ **/
27
+ protected $hide_tracking_opt_in_option_name;
28
+
29
+ /**
30
+ * The name of the cron job action for regularly logging usage data.
31
+ *
32
+ * @var string
33
+ **/
34
+ private $job_name;
35
+
36
+ /**
37
+ * Callback function for the usage tracking job.
38
+ *
39
+ * @var array
40
+ **/
41
+ private $callback;
42
+
43
+
44
+ /*
45
+ * Class variables.
46
+ */
47
+
48
+ /**
49
+ * Subclass instances.
50
+ *
51
+ * @var array
52
+ **/
53
+ private static $instances = array();
54
+
55
+
56
+ /*
57
+ * Abstract methods.
58
+ */
59
+
60
+ /**
61
+ * Gets the singleton instance of this class. Subclasses should implement
62
+ * this as follows:
63
+ *
64
+ * ```
65
+ * public static function get_instance() {
66
+ * return self::get_instance_for_subclass( get_class() );
67
+ * }
68
+ * ```
69
+ */
70
+ abstract public static function get_instance();
71
+
72
+ /**
73
+ * Get prefix for actions and strings. Should be unique to this plugin.
74
+ *
75
+ * @return string The prefix string
76
+ **/
77
+ abstract protected function get_prefix();
78
+
79
+ /**
80
+ * Get the text domain used by this plugin. This class will add some
81
+ * strings to be translated.
82
+ *
83
+ * @return string The text domain string
84
+ **/
85
+ abstract protected function get_text_domain();
86
+
87
+ /**
88
+ * Determine whether usage tracking is enabled.
89
+ *
90
+ * @return bool true if usage tracking is enabled, false otherwise.
91
+ **/
92
+ abstract protected function get_tracking_enabled();
93
+
94
+ /**
95
+ * Set whether usage tracking is enabled.
96
+ *
97
+ * @param bool $enable true if usage tracking should be enabled, false if
98
+ * it should be disabled.
99
+ **/
100
+ abstract protected function set_tracking_enabled( $enable );
101
+
102
+ /**
103
+ * Determine whether current user can manage the tracking options.
104
+ *
105
+ * @return bool true if the current user is allowed to manage the tracking
106
+ * options, false otherwise.
107
+ **/
108
+ abstract protected function current_user_can_manage_tracking();
109
+
110
+ /**
111
+ * Get the text to display in the opt-in dialog for users to enable
112
+ * tracking. This text should include a link to a page indicating what data
113
+ * is being tracked.
114
+ *
115
+ * @return string the text to display in the opt-in dialog.
116
+ **/
117
+ abstract protected function opt_in_dialog_text();
118
+
119
+ /**
120
+ * Checks if we should send an activated plugin's installed version in the
121
+ * `system_log` event.
122
+ *
123
+ * @param string $plugin_slug the plugin slug to check.
124
+ *
125
+ * @return bool true if we send the version, false if not.
126
+ */
127
+ abstract protected function do_track_plugin( $plugin_slug );
128
+
129
+
130
+ /*
131
+ * Initialization.
132
+ */
133
+
134
+ /**
135
+ * Subclasses may override this to add plugin-specific initialization code.
136
+ * However, this constructor must be called by the subclass in order to
137
+ * properly initialize the Usage Tracking system.
138
+ *
139
+ * This class is meant to be a singleton, and assumes that the subclass is
140
+ * implemented as such. If multiple instances are instantiated, the results
141
+ * are undefined.
142
+ **/
143
+ protected function __construct() {
144
+ // Init instance vars.
145
+ $this->hide_tracking_opt_in_option_name = $this->get_prefix() . '_usage_tracking_opt_in_hide';
146
+ $this->job_name = $this->get_prefix() . '_usage_tracking_send_usage_data';
147
+
148
+ // Set up the opt-in dialog.
149
+ add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_script_deps' ) );
150
+ add_action( 'admin_footer', array( $this, 'output_opt_in_js' ) );
151
+ add_action( 'admin_notices', array( $this, 'maybe_display_tracking_opt_in' ) );
152
+ add_action( 'wp_ajax_' . $this->get_prefix() . '_handle_tracking_opt_in', array( $this, 'handle_tracking_opt_in' ) );
153
+
154
+ // Set up schedule and action needed for cron job.
155
+ add_filter( 'cron_schedules', array( $this, 'add_usage_tracking_two_week_schedule' ) );
156
+ add_action( $this->job_name, array( $this, 'send_usage_data' ) );
157
+ }
158
+
159
+ /**
160
+ * Create (if necessary) and return the singleton instance for the given
161
+ * subclass.
162
+ *
163
+ * @param string $subclass the name of the subclass.
164
+ */
165
+ protected static function get_instance_for_subclass( $subclass ) {
166
+ if ( ! isset( self::$instances[ $subclass ] ) ) {
167
+ self::$instances[ $subclass ] = new $subclass();
168
+ }
169
+ return self::$instances[ $subclass ];
170
+ }
171
+
172
+
173
+ /*
174
+ * Public methods.
175
+ */
176
+
177
+ /**
178
+ * Set the Usage Data Callback. This callback should return an array of
179
+ * data to be logged periodically to Tracks.
180
+ *
181
+ * @param callable $callback the callback returning the usage data to be logged.
182
+ **/
183
+ public function set_callback( $callback ) {
184
+ $this->callback = $callback;
185
+ }
186
+
187
+ /**
188
+ * Send an event to Tracks if tracking is enabled.
189
+ *
190
+ * @param string $event The event name. The prefix string will be
191
+ * automatically prepended to this, so please supply this string without a
192
+ * prefix.
193
+ * @param array $properties Event Properties.
194
+ * @param null|int $event_timestamp When the event occurred.
195
+ *
196
+ * @return null|WP_Error
197
+ **/
198
+ public function send_event( $event, $properties = array(), $event_timestamp = null ) {
199
+
200
+ // Only continue if tracking is enabled.
201
+ if ( ! $this->is_tracking_enabled() ) {
202
+ return false;
203
+ }
204
+
205
+ $pixel = 'http://pixel.wp.com/t.gif';
206
+ $event_name = $this->get_event_prefix() . '_' . $event;
207
+ $user = wp_get_current_user();
208
+
209
+ if ( null === $event_timestamp ) {
210
+ $event_timestamp = time();
211
+ }
212
+
213
+ $properties['admin_email'] = get_option( 'admin_email' );
214
+ $properties['_ut'] = $this->get_event_prefix() . ':site_url';
215
+ // Use site URL as the userid to enable usage tracking at the site level.
216
+ // Note that we would likely want to use site URL + user ID for userid if we were
217
+ // to ever add event tracking at the user level.
218
+ $properties['_ui'] = site_url();
219
+ $properties['_ul'] = $user->user_login;
220
+ $properties['_en'] = $event_name;
221
+ $properties['_ts'] = $event_timestamp . '000';
222
+ $properties['_rt'] = round( microtime( true ) * 1000 ); // log time.
223
+ $p = array();
224
+
225
+ foreach ( $properties as $key => $value ) {
226
+ $p[] = rawurlencode( $key ) . '=' . rawurlencode( $value );
227
+ }
228
+
229
+ $pixel .= '?' . implode( '&', $p ) . '&_=_'; // EOF marker.
230
+ $response = wp_remote_get(
231
+ $pixel, array(
232
+ 'blocking' => true,
233
+ 'timeout' => 1,
234
+ 'redirection' => 2,
235
+ 'httpversion' => '1.1',
236
+ 'user-agent' => $this->get_event_prefix() . '_usage_tracking',
237
+ )
238
+ );
239
+
240
+ if ( is_wp_error( $response ) ) {
241
+ return $response;
242
+ }
243
+
244
+ $code = isset( $response['response']['code'] ) ? $response['response']['code'] : 0;
245
+
246
+ if ( 200 !== $code ) {
247
+ return new WP_Error( 'request_failed', 'HTTP Request failed', $code );
248
+ }
249
+
250
+ return true;
251
+ }
252
+
253
+ /**
254
+ * Set up a regular cron job to send usage data. The job will only send
255
+ * the data if tracking is enabled, so it is safe to call this function,
256
+ * and schedule the job, before the user opts into tracking.
257
+ **/
258
+ public function schedule_tracking_task() {
259
+ if ( ! wp_next_scheduled( $this->job_name ) ) {
260
+ wp_schedule_event( time(), $this->get_prefix() . '_usage_tracking_two_weeks', $this->job_name );
261
+ }
262
+ }
263
+
264
+ /**
265
+ * Unschedule the job scheduled by schedule_tracking_task if any is
266
+ * scheduled. This should be called on plugin deactivation.
267
+ **/
268
+ public function unschedule_tracking_task() {
269
+ if ( wp_next_scheduled( $this->job_name ) ) {
270
+ wp_clear_scheduled_hook( $this->job_name );
271
+ }
272
+ }
273
+
274
+ /**
275
+ * Check if tracking is enabled.
276
+ *
277
+ * @return bool true if tracking is enabled, false otherwise
278
+ **/
279
+ public function is_tracking_enabled() {
280
+ // Defer to the plugin-specific function.
281
+ return $this->get_tracking_enabled();
282
+ }
283
+
284
+ /**
285
+ * Call the usage data callback and send the usage data to Tracks. Only
286
+ * sends data if tracking is enabled.
287
+ **/
288
+ public function send_usage_data() {
289
+ if ( ! self::is_tracking_enabled() || ! is_callable( $this->callback ) ) {
290
+ return;
291
+ }
292
+
293
+ $usage_data = call_user_func( $this->callback );
294
+
295
+ if ( ! is_array( $usage_data ) ) {
296
+ return;
297
+ }
298
+
299
+ self::send_event( 'system_log', $this->get_system_data() );
300
+ self::send_event( 'stats_log', $usage_data );
301
+ }
302
+
303
+
304
+ /**
305
+ * Internal methods.
306
+ */
307
+
308
+ /**
309
+ * Get the prefix for the event-related values. By default, this is the
310
+ * same prefix used everywhere else, but plugins may override this if
311
+ * needed.
312
+ */
313
+ protected function get_event_prefix() {
314
+ return $this->get_prefix();
315
+ }
316
+
317
+ /**
318
+ * Add two week schedule to use for cron job. Should not be called
319
+ * externally.
320
+ *
321
+ * @param array $schedules the existing cron schedules.
322
+ **/
323
+ public function add_usage_tracking_two_week_schedule( $schedules ) {
324
+ $day_in_seconds = 86400;
325
+ $schedules[ $this->get_prefix() . '_usage_tracking_two_weeks' ] = array(
326
+ 'interval' => 15 * $day_in_seconds,
327
+ 'display' => esc_html__( 'Every Two Weeks', $this->get_text_domain() ),
328
+ );
329
+
330
+ return $schedules;
331
+ }
332
+
333
+ /**
334
+ * Collect system data to track.
335
+ *
336
+ * @return array
337
+ */
338
+ public function get_system_data() {
339
+ global $wp_version;
340
+
341
+ /**
342
+ * Current active theme.
343
+ *
344
+ * @var WP_Theme $theme
345
+ */
346
+ $theme = wp_get_theme();
347
+
348
+ $system_data = array();
349
+ $system_data['wp_version'] = $wp_version;
350
+ $system_data['php_version'] = PHP_VERSION;
351
+ $system_data['locale'] = get_locale();
352
+ $system_data['multisite'] = is_multisite() ? 1 : 0;
353
+ $system_data['active_theme'] = $theme['Name'];
354
+ $system_data['active_theme_version'] = $theme['Version'];
355
+
356
+ $plugin_data = $this->get_plugin_data();
357
+ foreach ( $plugin_data as $plugin_name => $plugin_version ) {
358
+ if ( $this->do_track_plugin( $plugin_name ) ) {
359
+ $plugin_friendly_name = preg_replace( '/[^a-z0-9]/', '_', $plugin_name );
360
+ $plugin_key = self::PLUGIN_PREFIX . $plugin_friendly_name;
361
+ $system_data[ $plugin_key ] = $plugin_version;
362
+ }
363
+ }
364
+
365
+ return $system_data;
366
+ }
367
+
368
+ /**
369
+ * Gets a list of activated plugins.
370
+ *
371
+ * @return array List of plugins. Index is friendly name, value is version.
372
+ */
373
+ protected function get_plugin_data() {
374
+ $plugins = array();
375
+ foreach ( $this->get_plugins() as $plugin_basename => $plugin ) {
376
+ $plugin_name = $this->get_plugin_name( $plugin_basename );
377
+ $plugins[ $plugin_name ] = $plugin['Version'];
378
+ }
379
+ return $plugins;
380
+ }
381
+
382
+ /**
383
+ * Partial wrapper for for `get_plugins()` function. Filters out non-active plugins.
384
+ *
385
+ * @return array Key is the plugin file path and the value is an array of the plugin data.
386
+ */
387
+ protected function get_plugins() {
388
+ if ( ! function_exists( 'get_plugins' ) ) {
389
+ include_once ABSPATH . 'wp-admin/includes/plugin.php';
390
+ }
391
+ $plugins = get_plugins();
392
+ foreach ( $plugins as $plugin_basename => $plugin_data ) {
393
+ if ( ! is_plugin_active( $plugin_basename ) ) {
394
+ unset( $plugins[ $plugin_basename ] );
395
+ }
396
+ }
397
+ return $plugins;
398
+ }
399
+
400
+ /**
401
+ * Returns a friendly slug for a plugin.
402
+ *
403
+ * @param string $basename Plugin basename.
404
+ *
405
+ * @return string
406
+ */
407
+ private function get_plugin_name( $basename ) {
408
+ $basename = strtolower( $basename );
409
+ if ( false === strpos( $basename, '/' ) ) {
410
+ return basename( $basename, '.php' );
411
+ }
412
+ return dirname( $basename );
413
+ }
414
+
415
+ /**
416
+ * Hide the opt-in for enabling usage tracking.
417
+ **/
418
+ protected function hide_tracking_opt_in() {
419
+ update_option( $this->hide_tracking_opt_in_option_name, true );
420
+ }
421
+
422
+ /**
423
+ * Determine whether the opt-in for enabling usage tracking is hidden.
424
+ *
425
+ * @return bool true if the opt-in is hidden, false otherwise.
426
+ **/
427
+ protected function is_opt_in_hidden() {
428
+ return (bool) get_option( $this->hide_tracking_opt_in_option_name );
429
+ }
430
+
431
+ /**
432
+ * Allowed html tags, used by wp_kses, for the translated opt-in dialog
433
+ * text.
434
+ *
435
+ * @return array the html tags.
436
+ **/
437
+ protected function opt_in_dialog_text_allowed_html() {
438
+ return array(
439
+ 'a' => array(
440
+ 'href' => array(),
441
+ 'title' => array(),
442
+ 'target' => array(),
443
+ ),
444
+ 'em' => array(),
445
+ 'strong' => array(),
446
+ );
447
+ }
448
+
449
+ /**
450
+ * If needed, display opt-in dialog to enable tracking. Should not be
451
+ * called externally.
452
+ **/
453
+ public function maybe_display_tracking_opt_in() {
454
+ $opt_in_hidden = $this->is_opt_in_hidden();
455
+ $user_tracking_enabled = $this->is_tracking_enabled();
456
+ $can_manage_tracking = $this->current_user_can_manage_tracking();
457
+
458
+ if ( ! $user_tracking_enabled && ! $opt_in_hidden && $can_manage_tracking ) { ?>
459
+ <div id="<?php echo esc_attr( $this->get_prefix() ); ?>-usage-tracking-notice" class="notice notice-info"
460
+ data-nonce="<?php echo esc_attr( wp_create_nonce( 'tracking-opt-in' ) ); ?>">
461
+ <p>
462
+ <?php echo wp_kses( $this->opt_in_dialog_text(), $this->opt_in_dialog_text_allowed_html() ); ?>
463
+ </p>
464
+ <p>
465
+ <button class="button button-primary" data-enable-tracking="yes">
466
+ <?php esc_html_e( 'Enable Usage Tracking', $this->get_text_domain() ); ?>
467
+ </button>
468
+ <button class="button" data-enable-tracking="no">
469
+ <?php esc_html_e( 'Disable Usage Tracking', $this->get_text_domain() ); ?>
470
+ </button>
471
+ <span id="progress" class="spinner alignleft"></span>
472
+ </p>
473
+ </div>
474
+ <div id="<?php echo esc_attr( $this->get_prefix() ); ?>-usage-tracking-enable-success" class="notice notice-success hidden">
475
+ <p><?php esc_html_e( 'Usage data enabled. Thank you!', $this->get_text_domain() ); ?></p>
476
+ </div>
477
+ <div id="<?php echo esc_attr( $this->get_prefix() ); ?>-usage-tracking-disable-success" class="notice notice-success hidden">
478
+ <p><?php esc_html_e( 'Disabled usage tracking.', $this->get_text_domain() ); ?></p>
479
+ </div>
480
+ <div id="<?php echo esc_attr( $this->get_prefix() ); ?>-usage-tracking-failure" class="notice notice-error hidden">
481
+ <p><?php esc_html_e( 'Something went wrong. Please try again later.', $this->get_text_domain() ); ?></p>
482
+ </div>
483
+ <?php
484
+ }
485
+ }
486
+
487
+ /**
488
+ * Handle ajax request from the opt-in dialog. Should not be called
489
+ * externally.
490
+ **/
491
+ public function handle_tracking_opt_in() {
492
+ check_ajax_referer( 'tracking-opt-in', 'nonce' );
493
+
494
+ if ( ! $this->current_user_can_manage_tracking() ) {
495
+ wp_die( '', '', 403 );
496
+ }
497
+
498
+ $enable_tracking = isset( $_POST['enable_tracking'] ) && '1' === $_POST['enable_tracking'];
499
+ $this->set_tracking_enabled( $enable_tracking );
500
+ $this->hide_tracking_opt_in();
501
+ $this->send_usage_data();
502
+ wp_die();
503
+ }
504
+
505
+ /**
506
+ * Ensure that jQuery has been enqueued since the opt-in dialog JS depends
507
+ * on it. Should not be called externally.
508
+ **/
509
+ public function enqueue_script_deps() {
510
+ // Ensure jQuery is loaded.
511
+ wp_enqueue_script(
512
+ $this->get_prefix() . '_usage-tracking-notice', '',
513
+ array( 'jquery' ), null, true
514
+ );
515
+ }
516
+
517
+ /**
518
+ * Output the JS code to handle the opt-in dialog. Should not be called
519
+ * externally.
520
+ **/
521
+ public function output_opt_in_js() {
522
+ ?>
523
+ <script type="text/javascript">
524
+ (function( prefix ) {
525
+ jQuery( document ).ready( function() {
526
+ function displayProgressIndicator() {
527
+ jQuery( '#' + prefix + '-usage-tracking-notice #progress' ).addClass( 'is-active' );
528
+ }
529
+
530
+ function displaySuccess( enabledTracking ) {
531
+ if ( enabledTracking ) {
532
+ jQuery( '#' + prefix + '-usage-tracking-enable-success' ).show();
533
+ } else {
534
+ jQuery( '#' + prefix + '-usage-tracking-disable-success' ).show();
535
+ }
536
+ jQuery( '#' + prefix + '-usage-tracking-notice' ).hide();
537
+ }
538
+
539
+ function displayError() {
540
+ jQuery( '#' + prefix + '-usage-tracking-failure' ).show();
541
+ jQuery( '#' + prefix + '-usage-tracking-notice' ).hide();
542
+ }
543
+
544
+ // Handle button clicks
545
+ jQuery( '#' + prefix + '-usage-tracking-notice button' ).click( function( event ) {
546
+ event.preventDefault();
547
+
548
+ var enableTracking = jQuery( this ).data( 'enable-tracking' ) == 'yes';
549
+ var nonce = jQuery( '#' + prefix + '-usage-tracking-notice' ).data( 'nonce' );
550
+
551
+ displayProgressIndicator();
552
+
553
+ jQuery.ajax( {
554
+ type: 'POST',
555
+ url: ajaxurl,
556
+ data: {
557
+ action: prefix + '_handle_tracking_opt_in',
558
+ enable_tracking: enableTracking ? 1 : 0,
559
+ nonce: nonce,
560
+ },
561
+ success: function() {
562
+ displaySuccess( enableTracking );
563
+ },
564
+ error: displayError,
565
+ } );
566
+ });
567
+ });
568
+ })( "<?php echo esc_js( $this->get_prefix() ); ?>" );
569
+ </script>
570
+ <?php
571
+ }
572
+ }
lib/usage-tracking/tests/support/class-usage-tracking-test-subclass.php ADDED
@@ -0,0 +1,67 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ require_once dirname( __FILE__ ) . '/../../class-usage-tracking-base.php';
4
+
5
+ /**
6
+ * Usage Tracking subclass for testing. Please update the superclass name to
7
+ * match the one used by your plugin (usage-tracking/class-usage-tracking-base.php).
8
+ */
9
+ class Usage_Tracking_Test_Subclass extends WP_Job_Manager_Usage_Tracking_Base {
10
+
11
+ const TRACKING_ENABLED_OPTION_NAME = 'testing-usage-tracking-enabled';
12
+
13
+ public static function get_instance() {
14
+ return self::get_instance_for_subclass( get_class() );
15
+ }
16
+
17
+ public function get_prefix() {
18
+ return 'testing';
19
+ }
20
+
21
+ public function get_text_domain() {
22
+ return 'text-domain';
23
+ }
24
+
25
+ public function get_tracking_enabled() {
26
+ return get_option( self::TRACKING_ENABLED_OPTION_NAME ) || false;
27
+ }
28
+
29
+ public function set_tracking_enabled( $enable ) {
30
+ update_option( self::TRACKING_ENABLED_OPTION_NAME, $enable );
31
+ }
32
+
33
+ public function current_user_can_manage_tracking() {
34
+ return current_user_can( 'manage_usage_tracking' );
35
+ }
36
+
37
+ public function opt_in_dialog_text() {
38
+ return 'Please enable Usage Tracking!';
39
+ }
40
+
41
+ public function do_track_plugin( $plugin_slug ) {
42
+ if ( in_array( $plugin_slug, array( 'hello', 'test', 'my-favorite-plugin' ), true ) ) {
43
+ return true;
44
+ }
45
+ return false;
46
+ }
47
+
48
+ protected function get_plugins() {
49
+ return array(
50
+ 'Hello.php' => array(
51
+ 'Version' => '1.0.0',
52
+ ),
53
+ 'jetpack/jetpack.php' => array(
54
+ 'Version' => '1.1.1',
55
+ ),
56
+ 'test-dev/test.php' => array(
57
+ 'Version' => '1.1.1',
58
+ ),
59
+ 'test/test.php' => array(
60
+ 'Version' => '1.0.0',
61
+ ),
62
+ 'my-favorite-plugin/my-favorite-plugin.php' => array(
63
+ 'Version' => '1.0.0',
64
+ ),
65
+ );
66
+ }
67
+ }
lib/usage-tracking/tests/support/wp-die-exception.php ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class WP_Die_Exception extends Exception {
4
+ private $wp_die_args = null;
5
+
6
+ public function set_wp_die_args( $message, $title, $args ) {
7
+ $this->wp_die_args = array(
8
+ 'message' => $message,
9
+ 'title' => $title,
10
+ 'args' => $args,
11
+ );
12
+ }
13
+
14
+ public function get_wp_die_args() {
15
+ return $this->wp_die_args;
16
+ }
17
+ }
18
+
lib/usage-tracking/tests/test-class-usage-tracking.php ADDED
@@ -0,0 +1,528 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ include dirname( __FILE__ ) . '/support/class-usage-tracking-test-subclass.php';
4
+ include dirname( __FILE__ ) . '/support/wp-die-exception.php';
5
+
6
+ // Ensure instance is set up before PHPUnit starts removing hooks.
7
+ Usage_Tracking_Test_Subclass::get_instance();
8
+
9
+ /**
10
+ * Usage Tracking tests. Please update the prefix to something unique to your
11
+ * plugin.
12
+ *
13
+ * @group usage-tracking
14
+ */
15
+ class WP_Job_Manager_Usage_Tracking_Test extends WP_UnitTestCase {
16
+ private $event_counts = array();
17
+ private $track_http_request = array();
18
+
19
+ public function setUp() {
20
+ parent::setUp();
21
+ // Update the class name here to match the Usage Tracking class.
22
+ $this->usage_tracking = Usage_Tracking_Test_Subclass::get_instance();
23
+ $this->usage_tracking->set_callback( array( $this, 'basicDataCallback' ) );
24
+ }
25
+
26
+ /**
27
+ * Ensure cron job action is set up.
28
+ *
29
+ * @covers {Prefix}_Usage_Tracking::hook
30
+ */
31
+ public function testCronJobActionAdded() {
32
+ $this->assertTrue( !! has_action( $this->usage_tracking->get_prefix() . '_usage_tracking_send_usage_data', array( $this->usage_tracking, 'send_usage_data' ) ) );
33
+ }
34
+
35
+ /**
36
+ * Ensure scheduling function works properly.
37
+ *
38
+ * @covers {Prefix}_Usage_Tracking::schedule_tracking_task
39
+ */
40
+ public function testScheduleTrackingTask() {
41
+ // Make sure it's cleared initially
42
+ wp_clear_scheduled_hook( $this->usage_tracking->get_prefix() . '_usage_tracking_send_usage_data' );
43
+
44
+ // Record how many times the event is scheduled
45
+ $this->event_counts['schedule_event'] = 0;
46
+ add_filter( 'schedule_event', array( $this, 'countScheduleEvent' ) );
47
+
48
+ // Should successfully schedule the task
49
+ $this->assertFalse( wp_get_schedule( $this->usage_tracking->get_prefix() . '_usage_tracking_send_usage_data' ), 'Not scheduled initial' );
50
+ $this->usage_tracking->schedule_tracking_task();
51
+ $this->assertNotFalse( wp_get_schedule( $this->usage_tracking->get_prefix() . '_usage_tracking_send_usage_data' ), 'Schedules a job' );
52
+ $this->assertEquals( 1, $this->event_counts['schedule_event'], 'Schedules only one job' );
53
+
54
+ // Should not duplicate when called again
55
+ $this->usage_tracking->schedule_tracking_task();
56
+ $this->assertEquals( 1, $this->event_counts['schedule_event'], 'Does not schedule an additional job' );
57
+ }
58
+
59
+ /* Test ajax request cases */
60
+
61
+ /**
62
+ * Ensure ajax hook is set up properly.
63
+ *
64
+ * @covers {Prefix}_Usage_Tracking::hook
65
+ */
66
+ public function testAjaxRequestSetup() {
67
+ $this->assertTrue( !! has_action( 'wp_ajax_' . $this->usage_tracking->get_prefix() . '_handle_tracking_opt_in', array( $this->usage_tracking, 'handle_tracking_opt_in' ) ) );
68
+ }
69
+
70
+ /**
71
+ * Ensure tracking is enabled through ajax request.
72
+ *
73
+ * @covers {Prefix}_Usage_Tracking::_handle_tracking_opt_in
74
+ */
75
+ public function testAjaxRequestEnableTracking() {
76
+ $this->setupAjaxRequest();
77
+ $_POST['enable_tracking'] = '1';
78
+
79
+ $this->assertFalse( !! $this->usage_tracking->is_tracking_enabled(), 'Usage tracking initially disabled' );
80
+ $this->assertFalse( !! get_option( $this->usage_tracking->get_prefix() . '_usage_tracking_opt_in_hide' ), 'Dialog initially shown' );
81
+
82
+ try {
83
+ $this->usage_tracking->handle_tracking_opt_in();
84
+ } catch ( WP_Die_Exception $e ) {
85
+ $wp_die_args = $e->get_wp_die_args();
86
+ $this->assertEquals( array(), $wp_die_args['args'], 'wp_die call has no non-success status' );
87
+ }
88
+
89
+ $this->assertTrue( $this->usage_tracking->is_tracking_enabled(), 'Usage tracking enabled' );
90
+ $this->assertTrue( get_option( $this->usage_tracking->get_prefix() . '_usage_tracking_opt_in_hide' ), 'Dialog hidden' );
91
+ }
92
+
93
+ /**
94
+ * Ensure usage data is sent when tracking is enabled.
95
+ *
96
+ * @covers {Prefix}_Usage_Tracking::_handle_tracking_opt_in
97
+ */
98
+ public function testAjaxRequestEnableTrackingSendsData() {
99
+ $this->setupAjaxRequest();
100
+ $_POST['enable_tracking'] = '1';
101
+
102
+ // Count the number of network requests
103
+ $this->event_counts['http_request'] = 0;
104
+ add_filter( 'pre_http_request', array( $this, 'countHttpRequest' ) );
105
+
106
+ try {
107
+ $this->usage_tracking->handle_tracking_opt_in();
108
+ } catch ( WP_Die_Exception $e ) {
109
+ $wp_die_args = $e->get_wp_die_args();
110
+ $this->assertEquals( array(), $wp_die_args['args'], 'wp_die call has no non-success status' );
111
+ }
112
+
113
+ $this->assertEquals( 2, $this->event_counts['http_request'], 'Data was sent on usage tracking enable' );
114
+ }
115
+
116
+ /**
117
+ * Ensure tracking is disabled through ajax request.
118
+ *
119
+ * @covers {Prefix}_Usage_Tracking::_handle_tracking_opt_in
120
+ */
121
+ public function testAjaxRequestDisableTracking() {
122
+ $this->setupAjaxRequest();
123
+ $_POST['enable_tracking'] = '0';
124
+
125
+ $this->assertFalse( !! $this->usage_tracking->is_tracking_enabled(), 'Usage tracking initially disabled' );
126
+ $this->assertFalse( !! get_option( $this->usage_tracking->get_prefix() . '_usage_tracking_opt_in_hide' ), 'Dialog initially shown' );
127
+
128
+ try {
129
+ $this->usage_tracking->handle_tracking_opt_in();
130
+ } catch ( WP_Die_Exception $e ) {
131
+ $wp_die_args = $e->get_wp_die_args();
132
+ $this->assertEquals( array(), $wp_die_args['args'], 'wp_die call has no non-success status' );
133
+ }
134
+
135
+ $this->assertFalse( !! $this->usage_tracking->is_tracking_enabled(), 'Usage tracking disabled' );
136
+ $this->assertTrue( get_option( $this->usage_tracking->get_prefix() . '_usage_tracking_opt_in_hide' ), 'Dialog hidden' );
137
+ }
138
+
139
+ /**
140
+ * Ensure ajax request fails on nonce failure and does not update option.
141
+ *
142
+ * @covers {Prefix}_Usage_Tracking::_handle_tracking_opt_in
143
+ */
144
+ public function testAjaxRequestFailedNonce() {
145
+ $this->setupAjaxRequest();
146
+ $_REQUEST['nonce'] = 'invalid_nonce_1234';
147
+
148
+ $this->assertFalse( !! $this->usage_tracking->is_tracking_enabled(), 'Usage tracking initially disabled' );
149
+ $this->assertFalse( !! get_option( $this->usage_tracking->get_prefix() . '_usage_tracking_opt_in_hide' ), 'Dialog initially shown' );
150
+
151
+ try {
152
+ $this->usage_tracking->handle_tracking_opt_in();
153
+ } catch ( WP_Die_Exception $e ) {
154
+ $wp_die_args = $e->get_wp_die_args();
155
+ $this->assertEquals( 403, $wp_die_args['args']['response'], 'wp_die called has "Forbidden" status' );
156
+ }
157
+
158
+ $this->assertFalse( !! $this->usage_tracking->is_tracking_enabled(), 'Usage tracking disabled' );
159
+ $this->assertFalse( !! get_option( $this->usage_tracking->get_prefix() . '_usage_tracking_opt_in_hide' ), 'Dialog not hidden' );
160
+ }
161
+
162
+ /**
163
+ * Ensure ajax request fails on authorization failure and does not update option.
164
+ *
165
+ * @covers {Prefix}_Usage_Tracking::_handle_tracking_opt_in
166
+ */
167
+ public function testAjaxRequestFailedAuth() {
168
+ $this->setupAjaxRequest();
169
+
170
+ // Current user cannot enable tracking
171
+ $this->allowCurrentUserToEnableTracking( false );
172
+
173
+ $this->assertFalse( !! $this->usage_tracking->is_tracking_enabled(), 'Usage tracking initially disabled' );
174
+ $this->assertFalse( !! get_option( $this->usage_tracking->get_prefix() . '_usage_tracking_opt_in_hide' ), 'Dialog initially shown' );
175
+
176
+ try {
177
+ $this->usage_tracking->handle_tracking_opt_in();
178
+ } catch ( WP_Die_Exception $e ) {
179
+ $wp_die_args = $e->get_wp_die_args();
180
+ $this->assertEquals( 403, $wp_die_args['args']['response'], 'wp_die called has "Forbidden" status' );
181
+ }
182
+
183
+ $this->assertFalse( !! $this->usage_tracking->is_tracking_enabled(), 'Usage tracking disabled' );
184
+ $this->assertFalse( !! get_option( $this->usage_tracking->get_prefix() . '_usage_tracking_opt_in_hide' ), 'Dialog not hidden' );
185
+ }
186
+
187
+ /* END test ajax request cases */
188
+
189
+ /**
190
+ * Ensure that a request is made to the correct URL with the given
191
+ * properties and the default properties.
192
+ *
193
+ * @covers {Prefix}_Usage_Tracking::send_event
194
+ */
195
+ public function testSendEvent() {
196
+ $event = 'my_event';
197
+ $properties = array(
198
+ 'button_clicked' => 'my_button',
199
+ );
200
+ $timestamp = '1234';
201
+
202
+ // Enable tracking
203
+ $this->usage_tracking->set_tracking_enabled( true );
204
+
205
+ // Capture the network request, save the request URL and arguments, and
206
+ // simulate a WP_Error
207
+ $this->track_http_request['request_params'] = null;
208
+ $this->track_http_request['request_url'] = null;
209
+ add_filter( 'pre_http_request', array( $this, 'trackHttpRequest' ), 10, 3 );
210
+
211
+ $this->usage_tracking->send_event( 'my_event', $properties, $timestamp );
212
+
213
+ $parsed_url = parse_url( $this->track_http_request['request_url'] );
214
+
215
+ $this->assertEquals( 'pixel.wp.com', $parsed_url['host'], 'Host' );
216
+ $this->assertEquals( '/t.gif', $parsed_url['path'], 'Path' );
217
+
218
+ $query = array();
219
+ parse_str( $parsed_url['query'], $query );
220
+
221
+ // Older versions (for PHP 5.2) of PHPUnit do not have this method
222
+ if ( method_exists( $this, 'assertArraySubset' ) ) {
223
+ $this->assertArraySubset(
224
+ array(
225
+ 'button_clicked' => 'my_button',
226
+ 'admin_email' => 'admin@example.org',
227
+ '_ut' => $this->usage_tracking->get_prefix() . ':site_url',
228
+ '_ui' => 'http://example.org',
229
+ '_ul' => '',
230
+ '_en' => $this->usage_tracking->get_prefix() . '_my_event',
231
+ '_ts' => '1234000',
232
+ '_' => '_',
233
+ ), $query, 'Query parameters'
234
+ );
235
+ }
236
+ }
237
+
238
+ /**
239
+ * Ensure that the request is not made if tracking is not enabled, unless
240
+ * $force is true.
241
+ *
242
+ * @covers {Prefix}_Usage_Tracking::send_event
243
+ */
244
+ public function testSendEventWithTrackingDisabled() {
245
+ $event = 'my_event';
246
+ $properties = array(
247
+ 'button_clicked' => 'my_button',
248
+ );
249
+ $timestamp = '1234';
250
+
251
+ // Disable tracking
252
+ $this->usage_tracking->set_tracking_enabled( false );
253
+
254
+ // Count network requests
255
+ $this->event_counts['http_request'] = 0;
256
+ add_filter( 'pre_http_request', array( $this, 'countHttpRequest' ) );
257
+
258
+ $this->usage_tracking->send_event( 'my_event', $properties, $timestamp );
259
+ $this->assertEquals( 0, $this->event_counts['http_request'], 'No request when disabled' );
260
+ }
261
+
262
+ /**
263
+ * Ensure that the request is only sent when the setting is enabled.
264
+ *
265
+ * @covers {Prefix}_Usage_Tracking::maybe_send_usage_data
266
+ */
267
+ public function testSendUsageData() {
268
+ // Count the number of network requests
269
+ $this->event_counts['http_request'] = 0;
270
+ add_filter( 'pre_http_request', array( $this, 'countHttpRequest' ) );
271
+
272
+ // Setting is not set, ensure the request is not sent.
273
+ $this->usage_tracking->send_usage_data();
274
+ $this->assertEquals( 0, $this->event_counts['http_request'], 'Request not sent when Usage Tracking disabled' );
275
+
276
+ // Set the setting and ensure request is sent.
277
+ $this->usage_tracking->set_tracking_enabled( true );
278
+
279
+ $this->usage_tracking->send_usage_data();
280
+ $this->assertEquals( 2, $this->event_counts['http_request'], 'Request sent when Usage Tracking enabled' );
281
+ }
282
+
283
+ /* Tests for tracking opt in dialog */
284
+
285
+ /**
286
+ * When setting is not set, dialog is not hidden, and user has capability,
287
+ * we should see the dialog and Enable Usage Tracking button.
288
+ *
289
+ * @covers {Prefix}_Usage_Tracking::_maybe_display_tracking_opt_in
290
+ */
291
+ public function testDisplayTrackingOptIn() {
292
+ $this->setupOptInDialog();
293
+
294
+ $this->expectOutputRegex( '/Enable Usage Tracking/' );
295
+ $this->usage_tracking->maybe_display_tracking_opt_in();
296
+ }
297
+
298
+ /**
299
+ * When setting is already set, dialog should not appear.
300
+ *
301
+ * @covers {Prefix}_Usage_Tracking::_maybe_display_tracking_opt_in
302
+ */
303
+ public function testDoNotDisplayTrackingOptInWhenSettingEnabled() {
304
+ $this->setupOptInDialog();
305
+ $this->usage_tracking->set_tracking_enabled( true );
306
+
307
+ $this->expectOutputString( '' );
308
+ $this->usage_tracking->maybe_display_tracking_opt_in();
309
+ }
310
+
311
+ /**
312
+ * When option is set to hide the dialog, it should not appear.
313
+ *
314
+ * @covers {Prefix}_Usage_Tracking::_maybe_display_tracking_opt_in
315
+ */
316
+ public function testDoNotDisplayTrackingOptInWhenDialogHidden() {
317
+ $this->setupOptInDialog();
318
+ update_option( $this->usage_tracking->get_prefix() . '_usage_tracking_opt_in_hide', true );
319
+
320
+ $this->expectOutputString( '' );
321
+ $this->usage_tracking->maybe_display_tracking_opt_in();
322
+ }
323
+
324
+ /**
325
+ * When user does not have permission to manage usage tracking, dialog
326
+ * should not appear.
327
+ *
328
+ * @covers {Prefix}_Usage_Tracking::_maybe_display_tracking_opt_in
329
+ */
330
+ public function testDoNotDisplayTrackingOptInWhenUserNotAuthorized() {
331
+ $this->setupOptInDialog();
332
+ $this->allowCurrentUserToEnableTracking( false );
333
+
334
+ $this->expectOutputString( '' );
335
+ $this->usage_tracking->maybe_display_tracking_opt_in();
336
+ }
337
+
338
+ /* END tests for tracking opt in dialog */
339
+
340
+ /* Tests for system data */
341
+
342
+ /**
343
+ * Tests the basic structure for collected system data.
344
+ *
345
+ * @covers {Prefix}_Usage_Tracking::get_system_data
346
+ * @group track-system-data
347
+ */
348
+ public function testSystemDataStructure() {
349
+ global $wp_version;
350
+
351
+ $system_data = $this->usage_tracking->get_system_data();
352
+
353
+ $this->assertInternalType( 'array', $system_data, 'System data must be returned as an array' );
354
+
355
+ $this->assertArrayHasKey( 'wp_version', $system_data, '`wp_version` key must exist in system data' );
356
+ $this->assertEquals( $wp_version, $system_data['wp_version'], '`wp_version` does not match expected value' );
357
+
358
+ $this->assertArrayHasKey( 'php_version', $system_data, '`php_version` key must exist in system data' );
359
+ $this->assertEquals( PHP_VERSION, $system_data['php_version'], '`php_version` does not match expected value' );
360
+
361
+ $this->assertArrayHasKey( 'locale', $system_data, '`locale` key must exist in system data' );
362
+ $this->assertEquals( get_locale(), $system_data['locale'], '`locale` does not match expected value' );
363
+
364
+ $this->assertArrayHasKey( 'multisite', $system_data, '`multisite` key must exist in system data' );
365
+ $this->assertEquals( is_multisite(), $system_data['multisite'], '`multisite` does not match expected value' );
366
+
367
+ /**
368
+ * Current active theme.
369
+ *
370
+ * @var WP_Theme $theme
371
+ */
372
+ $theme = wp_get_theme();
373
+
374
+ $this->assertArrayHasKey( 'active_theme', $system_data, '`active_theme` key must exist in system data' );
375
+ $this->assertEquals( $theme['Name'], $system_data['active_theme'], '`active_theme` does not match expected value' );
376
+
377
+ $this->assertArrayHasKey( 'active_theme_version', $system_data, '`active_theme_version` key must exist in system data' );
378
+ $this->assertEquals( $theme['Version'], $system_data['active_theme_version'], '`active_theme_version` does not match expected value' );
379
+
380
+ $this->assertArrayHasKey( 'plugin_my_favorite_plugin', $system_data, '`plugin_my_favorite_plugin` key must exist in system data' );
381
+ $this->assertEquals( '1.0.0', $system_data['plugin_my_favorite_plugin'], '`plugin_my_favorite_plugin` does not match expected value' );
382
+
383
+ $this->assertArrayHasKey( 'plugin_hello', $system_data, '`plugin_hello` key must exist in system data' );
384
+ $this->assertEquals( '1.0.0', $system_data['plugin_my_favorite_plugin'], '`plugin_hello` does not match expected value' );
385
+
386
+ $this->assertArrayHasKey( 'plugin_test', $system_data, '`plugin_test` key must exist in system data' );
387
+ $this->assertEquals( '1.0.0', $system_data['plugin_test'], '`plugin_test` does not match expected value' );
388
+
389
+ $this->assertArrayNotHasKey( 'plugin_jetpack', $system_data, '`plugin_jetpack` key must NOT exist in system data' );
390
+ $this->assertArrayNotHasKey( 'plugin_test_dev', $system_data, '`plugin_test_dev` key must NOT exist in system data' );
391
+
392
+ $plugin_prefix_count = 0;
393
+ foreach ( $system_data as $key => $value ) {
394
+ if ( 1 === preg_match( '/^plugin_/', $key ) ) {
395
+ $plugin_prefix_count++;
396
+ }
397
+ }
398
+
399
+ $this->assertEquals( 3, $plugin_prefix_count );
400
+ }
401
+
402
+ /* END tests for system data */
403
+
404
+ /****** Helper methods ******/
405
+
406
+ /**
407
+ * Helper method for ajax request.
408
+ */
409
+ private function setupAjaxRequest() {
410
+ // Simulate an ajax request
411
+ add_filter( 'wp_doing_ajax', '__return_true' );
412
+
413
+ // Set up nonce
414
+ $_REQUEST['nonce'] = wp_create_nonce( 'tracking-opt-in' );
415
+
416
+ // Ensure current user can enable tracking
417
+ $this->allowCurrentUserToEnableTracking();
418
+
419
+ // When wp_die is called, save the args and throw an exception to stop
420
+ // execution.
421
+ add_filter( 'wp_die_ajax_handler', array( $this, 'ajaxDieHandler' ) );
422
+ }
423
+
424
+ /**
425
+ * Helper method to set up tracking opt-in dialog.
426
+ */
427
+ private function setupOptInDialog() {
428
+ // Ensure current user can enable tracking
429
+ $this->allowCurrentUserToEnableTracking();
430
+
431
+ // Ensure setting is not set
432
+ $this->usage_tracking->set_tracking_enabled( false );
433
+ }
434
+
435
+ /**
436
+ * Update the capaility for the current user to be able to enable or
437
+ * disable tracking.
438
+ *
439
+ * @param bool $allow true if the current user should be allowed to update
440
+ * the tracking setting, false otherwise. Default: true
441
+ **/
442
+ private function allowCurrentUserToEnableTracking( $allow = true ) {
443
+ $user = wp_get_current_user();
444
+
445
+ if ( $allow ) {
446
+ $user->add_cap( 'manage_usage_tracking' );
447
+ } else {
448
+ $user->remove_cap( 'manage_usage_tracking' );
449
+ }
450
+ }
451
+
452
+ /**
453
+ * Callback helpers.
454
+ */
455
+
456
+ /**
457
+ * Basic callback for usage data.
458
+ *
459
+ * @return array
460
+ */
461
+ public function basicDataCallback() {
462
+ return array( 'testing' => true );
463
+ }
464
+
465
+ /**
466
+ * Sets the die handler for ajax request.
467
+ *
468
+ * @return array
469
+ */
470
+ public function ajaxDieHandler() {
471
+ return array( $this, 'ajaxDieHandlerCallback' );
472
+ }
473
+
474
+ /**
475
+ * Error handler for ajax requests.
476
+ *
477
+ * @param string $message
478
+ * @param string $title
479
+ * @param array $args
480
+ *
481
+ * @throws WP_Die_Exception
482
+ */
483
+ public function ajaxDieHandlerCallback( $message, $title, $args ) {
484
+ $e = new WP_Die_Exception( 'wp_die called' );
485
+ $e->set_wp_die_args( $message, $title, $args );
486
+ throw $e;
487
+ }
488
+
489
+ /**
490
+ * Count the number of times an event is scheduled.
491
+ *
492
+ * @param object $event
493
+ *
494
+ * @return object
495
+ */
496
+ public function countScheduleEvent( $event ) {
497
+ $prefix = $this->usage_tracking->get_prefix();
498
+ if ( $event->hook === $prefix . '_usage_tracking_send_usage_data' ) {
499
+ $this->event_counts['schedule_event']++;
500
+ }
501
+ return $event;
502
+ }
503
+
504
+ /**
505
+ * Count the number of HTTP requests.
506
+ *
507
+ * @return WP_Error
508
+ */
509
+ public function countHttpRequest() {
510
+ $this->event_counts['http_request']++;
511
+ return new WP_Error();
512
+ }
513
+
514
+ /**
515
+ * Track HTTP request params and URL.
516
+ *
517
+ * @param string $preempt
518
+ * @param array $r
519
+ * @param string $url
520
+ *
521
+ * @return WP_Error
522
+ */
523
+ public function trackHttpRequest( $preempt, $r, $url ) {
524
+ $this->track_http_request['request_params'] = $r;
525
+ $this->track_http_request['request_url'] = $url;
526
+ return new WP_Error();
527
+ }
528
+ }
readme.txt CHANGED
@@ -3,7 +3,7 @@ Contributors: mikejolley, automattic, adamkheckler, annezazu, cena, chaselivings
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.3.1
5
  Tested up to: 4.9
6
- Stable tag: 1.29.3
7
  License: GPLv3
8
  License URI: http://www.gnu.org/licenses/gpl-3.0.html
9
 
@@ -141,6 +141,26 @@ You can view (and contribute) translations via the [translate.wordpress.org](htt
141
 
142
  == Changelog ==
143
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
144
  = 1.29.3 =
145
  * Fix: When retrieving job listing results, cache only the post results and not all of `WP_Query` (@jom; props slavco)
146
 
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.3.1
5
  Tested up to: 4.9
6
+ Stable tag: 1.30.0
7
  License: GPLv3
8
  License URI: http://www.gnu.org/licenses/gpl-3.0.html
9
 
141
 
142
  == Changelog ==
143
 
144
+ = 1.30.0 =
145
+ * Enhancement: Adds ability to have a reCAPTCHA field to check if job listing author is human. (@jom)
146
+ * Enhancement: Allows for option to make edits to job listings force listing back into pending approval status. (@jom)
147
+ * Enhancement: Adds spinner and disables form when user submits job listing. (@jom)
148
+ * Enhancement: Update the add-ons page of the plugin. (@jom)
149
+ * Enhancement: Added the ability to sort jobs randomly on the Featured Jobs Widget. (@jom)
150
+ * Enhancement: Improved handling of alternative date formats when editing job expiration field in WP admin. (@jom)
151
+ * Enhancement: Added star indicator next to featured listings on `[job_dashboard]`. (@jom)
152
+ * Enhancement: Opt-in to usage tracking so we can better improve the plugin. (@alexsanford, @donnapep, @jom)
153
+ * Enhancement: Introduced new asset enqueuing strategy that will be turned on in 1.32.0. Requires plugin and theme updates. (@jom; Dev notes: https://github.com/Automattic/WP-Job-Manager/pull/1354)
154
+ * Fix: Use WordPress core checks for image formats to not confuse `docx` as an image. (@tripflex)
155
+ * Fix: Issue with `[jobs]` shortcode when `categories` argument is provided. (@jom)
156
+ * Fix: Issue with double encoding HTML entities in custom text area fields. (@jom)
157
+ * Fix: Updates `job-dashboard.php` template with `colspan` fix on no active listings message. (@jom)
158
+ * Fix: Clear job listings cache when deleting a user and their job listings. (@jom)
159
+ * Dev: Adds `is_wpjm()` and related functions to test if we're on a WPJM related page. (@jom)
160
+ * Dev: Adds `job_manager_user_edit_job_listing` action that fires after a user edits a job listing. (@jom)
161
+ * Dev: Adds `job_manager_enable_job_archive_page` filter to enable job archive page. (@jom)
162
+ * Dev: Adds `date` field for custom job listing form fields. (@alexsandford)
163
+
164
  = 1.29.3 =
165
  * Fix: When retrieving job listing results, cache only the post results and not all of `WP_Query` (@jom; props slavco)
166
 
templates/form-fields/date-field.php ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Shows a datepicker field on job listing forms.
4
+ *
5
+ * This template can be overridden by copying it to yourtheme/job_manager/form-fields/date-field.php.
6
+ *
7
+ * @see https://wpjobmanager.com/document/template-overrides/
8
+ * @author Automattic
9
+ * @package WP Job Manager
10
+ * @category Template
11
+ * @version 1.30.0
12
+ */
13
+
14
+ if ( ! defined( 'ABSPATH' ) ) {
15
+ exit; // Exit if accessed directly
16
+ }
17
+
18
+ wp_enqueue_script( 'wp-job-manager-datepicker' );
19
+
20
+ ?>
21
+ <input type="text" class="input-date job-manager-datepicker" name="<?php echo esc_attr( isset( $field['name'] ) ? $field['name'] : $key ); ?>"<?php if ( isset( $field['autocomplete'] ) && false === $field['autocomplete'] ) { echo ' autocomplete="off"'; } ?> id="<?php echo esc_attr( $key ); ?>" placeholder="<?php echo empty( $field['placeholder'] ) ? '' : esc_attr( $field['placeholder'] ); ?>" value="<?php echo isset( $field['value'] ) ? esc_attr( $field['value'] ) : ''; ?>" <?php if ( ! empty( $field['required'] ) ) echo 'required'; ?> />
22
+ <?php if ( ! empty( $field['description'] ) ) : ?><small class="description"><?php echo $field['description']; ?></small><?php endif; ?>
templates/form-fields/recaptcha-field.php ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Shows the `recaptcha` form field on job listing forms.
4
+ *
5
+ * This template can be overridden by copying it to yourtheme/job_manager/form-fields/recaptcha-field.php.
6
+ *
7
+ * @see https://wpjobmanager.com/document/template-overrides/
8
+ * @author Automattic
9
+ * @package WP Job Manager
10
+ * @category Template
11
+ * @version 1.30.0
12
+ */
13
+
14
+ if ( ! defined( 'ABSPATH' ) ) {
15
+ exit; // Exit if accessed directly
16
+ }
17
+ ?>
18
+ <fieldset class="fieldset-<?php echo esc_attr( $key ); ?>">
19
+ <label for="<?php echo esc_attr( $key ); ?>"><?php echo $field['label']; ?></label>
20
+ <div class="field <?php echo $field['required'] ? 'required-field' : ''; ?>">
21
+ <div class="g-recaptcha" data-sitekey="<?php echo $field['site_key'] ?>"></div>
22
+ <?php if ( ! empty( $field['description'] ) ) : ?><small class="description"><?php echo $field['description']; ?></small><?php endif; ?>
23
+ </div>
24
+ </fieldset>
templates/form-fields/textarea-field.php CHANGED
@@ -8,12 +8,12 @@
8
  * @author Automattic
9
  * @package WP Job Manager
10
  * @category Template
11
- * @version 1.29.0
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
15
  exit; // Exit if accessed directly
16
  }
17
  ?>
18
- <textarea cols="20" rows="3" class="input-text" name="<?php echo esc_attr( isset( $field['name'] ) ? $field['name'] : $key ); ?>" id="<?php echo esc_attr( $key ); ?>" placeholder="<?php echo empty( $field['placeholder'] ) ? '' : esc_attr( $field['placeholder'] ); ?>" maxlength="<?php echo ! empty( $field['maxlength'] ) ? $field['maxlength'] : ''; ?>" <?php if ( ! empty( $field['required'] ) ) echo 'required'; ?>><?php echo isset( $field['value'] ) ? esc_textarea( $field['value'] ) : ''; ?></textarea>
19
  <?php if ( ! empty( $field['description'] ) ) : ?><small class="description"><?php echo $field['description']; ?></small><?php endif; ?>
8
  * @author Automattic
9
  * @package WP Job Manager
10
  * @category Template
11
+ * @version 1.30.0
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
15
  exit; // Exit if accessed directly
16
  }
17
  ?>
18
+ <textarea cols="20" rows="3" class="input-text" name="<?php echo esc_attr( isset( $field['name'] ) ? $field['name'] : $key ); ?>" id="<?php echo esc_attr( $key ); ?>" placeholder="<?php echo empty( $field['placeholder'] ) ? '' : esc_attr( $field['placeholder'] ); ?>" maxlength="<?php echo ! empty( $field['maxlength'] ) ? $field['maxlength'] : ''; ?>" <?php if ( ! empty( $field['required'] ) ) echo 'required'; ?>><?php echo isset( $field['value'] ) ? esc_textarea( html_entity_decode( $field['value'] ) ) : ''; ?></textarea>
19
  <?php if ( ! empty( $field['description'] ) ) : ?><small class="description"><?php echo $field['description']; ?></small><?php endif; ?>
templates/form-fields/uploaded-file-html.php CHANGED
@@ -8,7 +8,7 @@
8
  * @author Automattic
9
  * @package WP Job Manager
10
  * @category Template
11
- * @version 1.24.0
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
@@ -24,8 +24,7 @@ if ( ! defined( 'ABSPATH' ) ) {
24
  $image_src = $value;
25
  }
26
  $extension = ! empty( $extension ) ? $extension : substr( strrchr( $image_src, '.' ), 1 );
27
-
28
- if ( 3 !== strlen( $extension ) || in_array( $extension, array( 'jpg', 'gif', 'png', 'jpeg', 'jpe' ) ) ) : ?>
29
  <span class="job-manager-uploaded-file-preview"><img src="<?php echo esc_url( $image_src ); ?>" /> <a class="job-manager-remove-uploaded-file" href="#">[<?php _e( 'remove', 'wp-job-manager' ); ?>]</a></span>
30
  <?php else : ?>
31
  <span class="job-manager-uploaded-file-name"><code><?php echo esc_html( basename( $image_src ) ); ?></code> <a class="job-manager-remove-uploaded-file" href="#">[<?php _e( 'remove', 'wp-job-manager' ); ?>]</a></span>
8
  * @author Automattic
9
  * @package WP Job Manager
10
  * @category Template
11
+ * @version 1.30.0
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
24
  $image_src = $value;
25
  }
26
  $extension = ! empty( $extension ) ? $extension : substr( strrchr( $image_src, '.' ), 1 );
27
+ if ( 'image' === wp_ext2type( $extension ) ) : ?>
 
28
  <span class="job-manager-uploaded-file-preview"><img src="<?php echo esc_url( $image_src ); ?>" /> <a class="job-manager-remove-uploaded-file" href="#">[<?php _e( 'remove', 'wp-job-manager' ); ?>]</a></span>
29
  <?php else : ?>
30
  <span class="job-manager-uploaded-file-name"><code><?php echo esc_html( basename( $image_src ) ); ?></code> <a class="job-manager-remove-uploaded-file" href="#">[<?php _e( 'remove', 'wp-job-manager' ); ?>]</a></span>
templates/job-dashboard.php CHANGED
@@ -8,7 +8,7 @@
8
  * @author Automattic
9
  * @package WP Job Manager
10
  * @category Template
11
- * @version 1.27.0
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
@@ -28,7 +28,7 @@ if ( ! defined( 'ABSPATH' ) ) {
28
  <tbody>
29
  <?php if ( ! $jobs ) : ?>
30
  <tr>
31
- <td colspan="6"><?php _e( 'You do not have any active listings.', 'wp-job-manager' ); ?></td>
32
  </tr>
33
  <?php else : ?>
34
  <?php foreach ( $jobs as $job ) : ?>
@@ -41,14 +41,16 @@ if ( ! defined( 'ABSPATH' ) ) {
41
  <?php else : ?>
42
  <?php wpjm_the_job_title( $job ); ?> <small>(<?php the_job_status( $job ); ?>)</small>
43
  <?php endif; ?>
 
44
  <ul class="job-dashboard-actions">
45
  <?php
46
  $actions = array();
47
 
48
  switch ( $job->post_status ) {
49
  case 'publish' :
50
- $actions['edit'] = array( 'label' => __( 'Edit', 'wp-job-manager' ), 'nonce' => false );
51
-
 
52
  if ( is_position_filled( $job ) ) {
53
  $actions['mark_not_filled'] = array( 'label' => __( 'Mark not filled', 'wp-job-manager' ), 'nonce' => true );
54
  } else {
8
  * @author Automattic
9
  * @package WP Job Manager
10
  * @category Template
11
+ * @version 1.30.0
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
28
  <tbody>
29
  <?php if ( ! $jobs ) : ?>
30
  <tr>
31
+ <td colspan="<?php echo count( $job_dashboard_columns ); ?>"><?php _e( 'You do not have any active listings.', 'wp-job-manager' ); ?></td>
32
  </tr>
33
  <?php else : ?>
34
  <?php foreach ( $jobs as $job ) : ?>
41
  <?php else : ?>
42
  <?php wpjm_the_job_title( $job ); ?> <small>(<?php the_job_status( $job ); ?>)</small>
43
  <?php endif; ?>
44
+ <?php echo is_position_featured( $job ) ? '<span class="featured-job-icon" title="' . esc_attr__( 'Featured Job', 'wp-job-manager' ) . '"></span>' : ''; ?>
45
  <ul class="job-dashboard-actions">
46
  <?php
47
  $actions = array();
48
 
49
  switch ( $job->post_status ) {
50
  case 'publish' :
51
+ if ( wpjm_user_can_edit_published_submissions() ) {
52
+ $actions[ 'edit' ] = array( 'label' => __( 'Edit', 'wp-job-manager' ), 'nonce' => false );
53
+ }
54
  if ( is_position_filled( $job ) ) {
55
  $actions['mark_not_filled'] = array( 'label' => __( 'Mark not filled', 'wp-job-manager' ), 'nonce' => true );
56
  } else {
templates/job-submit.php CHANGED
@@ -8,7 +8,7 @@
8
  * @author Automattic
9
  * @package WP Job Manager
10
  * @category Template
11
- * @version 1.27.0
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
@@ -74,6 +74,7 @@ global $job_manager;
74
  <input type="hidden" name="job_id" value="<?php echo esc_attr( $job_id ); ?>" />
75
  <input type="hidden" name="step" value="<?php echo esc_attr( $step ); ?>" />
76
  <input type="submit" name="submit_job" class="button" value="<?php echo esc_attr( $submit_button_text ); ?>" />
 
77
  </p>
78
 
79
  <?php else : ?>
8
  * @author Automattic
9
  * @package WP Job Manager
10
  * @category Template
11
+ * @version 1.30.0
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
74
  <input type="hidden" name="job_id" value="<?php echo esc_attr( $job_id ); ?>" />
75
  <input type="hidden" name="step" value="<?php echo esc_attr( $step ); ?>" />
76
  <input type="submit" name="submit_job" class="button" value="<?php echo esc_attr( $submit_button_text ); ?>" />
77
+ <span class="spinner" style="background-image: url(<?php echo includes_url( 'images/spinner.gif' ); ?>);"></span>
78
  </p>
79
 
80
  <?php else : ?>
uninstall.php CHANGED
@@ -35,4 +35,7 @@ $options = array(
35
 
36
  foreach ( $options as $option ) {
37
  delete_option( $option );
38
- }
 
 
 
35
 
36
  foreach ( $options as $option ) {
37
  delete_option( $option );
38
+ }
39
+
40
+ include dirname( __FILE__ ) . '/includes/class-wp-job-manager-usage-tracking.php';
41
+ WP_Job_Manager_Usage_Tracking::get_instance()->clear_options();
wp-job-manager-functions.php CHANGED
@@ -114,7 +114,8 @@ function get_job_listings( $args = array() ) {
114
  if ( 'featured' === $args['orderby'] ) {
115
  $query_args['orderby'] = array(
116
  'menu_order' => 'ASC',
117
- 'date' => 'DESC'
 
118
  );
119
  }
120
 
@@ -156,7 +157,7 @@ function get_job_listings( $args = array() ) {
156
  $to_hash = json_encode( $query_args );
157
  $query_args_hash = 'jm_' . md5( $to_hash . JOB_MANAGER_VERSION ) . WP_Job_Manager_Cache_Helper::get_transient_version( 'get_job_listings' );
158
  $result = false;
159
- $cached_query_results = false;
160
  $cached_query_posts = get_transient( $query_args_hash );
161
  if ( is_string( $cached_query_posts ) ) {
162
  $cached_query_posts = json_decode( $cached_query_posts, false );
@@ -604,6 +605,11 @@ endif;
604
  function job_manager_user_can_upload_file_via_ajax() {
605
  $can_upload = is_user_logged_in() && job_manager_user_can_post_job();
606
 
 
 
 
 
 
607
  /**
608
  * Override ability of a user to upload a file via Ajax.
609
  *
@@ -654,6 +660,138 @@ function job_manager_user_can_edit_job( $job_id ) {
654
  return apply_filters( 'job_manager_user_can_edit_job', $can_edit, $job_id );
655
  }
656
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
657
  /**
658
  * Checks to see if the standard password setup email should be used.
659
  *
@@ -816,6 +954,42 @@ function job_manager_user_can_edit_pending_submissions() {
816
  return apply_filters( 'job_manager_user_can_edit_pending_submissions', get_option( 'job_manager_user_can_edit_pending_submissions' ) == 1 ? true : false );
817
  }
818
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
819
  /**
820
  * Displays category select dropdown.
821
  *
114
  if ( 'featured' === $args['orderby'] ) {
115
  $query_args['orderby'] = array(
116
  'menu_order' => 'ASC',
117
+ 'date' => 'DESC',
118
+ 'ID' => 'DESC',
119
  );
120
  }
121
 
157
  $to_hash = json_encode( $query_args );
158
  $query_args_hash = 'jm_' . md5( $to_hash . JOB_MANAGER_VERSION ) . WP_Job_Manager_Cache_Helper::get_transient_version( 'get_job_listings' );
159
  $result = false;
160
+ $cached_query_results = true;
161
  $cached_query_posts = get_transient( $query_args_hash );
162
  if ( is_string( $cached_query_posts ) ) {
163
  $cached_query_posts = json_decode( $cached_query_posts, false );
605
  function job_manager_user_can_upload_file_via_ajax() {
606
  $can_upload = is_user_logged_in() && job_manager_user_can_post_job();
607
 
608
+ if ( has_filter( 'job_manager_ajax_file_upload_enabled' ) ) {
609
+ _deprecated_hook( 'job_manager_ajax_file_upload_enabled', '1.30.0', 'job_manager_user_can_upload_file_via_ajax' );
610
+ $can_upload = apply_filters( 'job_manager_ajax_file_upload_enabled', $can_upload );
611
+ }
612
+
613
  /**
614
  * Override ability of a user to upload a file via Ajax.
615
  *
660
  return apply_filters( 'job_manager_user_can_edit_job', $can_edit, $job_id );
661
  }
662
 
663
+ /**
664
+ * Checks if the visitor is currently on a WPJM page, job listing, or taxonomy.
665
+ *
666
+ * @since 1.30.0
667
+ *
668
+ * @return bool
669
+ */
670
+ function is_wpjm() {
671
+ /**
672
+ * Filter the result of is_wpjm()
673
+ *
674
+ * @since 1.30.0
675
+ *
676
+ * @param bool $is_wpjm
677
+ */
678
+ return apply_filters( 'is_wpjm', ( is_wpjm_page() || has_wpjm_shortcode() || is_wpjm_job_listing() || is_wpjm_taxonomy() ) ? true : false );
679
+ }
680
+
681
+ /**
682
+ * Checks if the visitor is currently on a WPJM page.
683
+ *
684
+ * @since 1.30.0
685
+ *
686
+ * @return bool
687
+ */
688
+ function is_wpjm_page() {
689
+ $is_wpjm_page = is_post_type_archive( 'job_listing' );
690
+
691
+ if ( ! $is_wpjm_page ) {
692
+ $wpjm_page_ids = array_filter( array(
693
+ get_option( 'job_manager_submit_job_form_page_id', false ),
694
+ get_option( 'job_manager_job_dashboard_page_id', false ),
695
+ get_option( 'job_manager_jobs_page_id', false ),
696
+ ) );
697
+
698
+ /**
699
+ * Filters a list of all page IDs related to WPJM.
700
+ *
701
+ * @since 1.30.0
702
+ *
703
+ * @param int[] $wpjm_page_ids
704
+ */
705
+ $wpjm_page_ids = array_unique( apply_filters( 'job_manager_page_ids', $wpjm_page_ids ) );
706
+
707
+ $is_wpjm_page = is_page( $wpjm_page_ids );
708
+ }
709
+
710
+ /**
711
+ * Filter the result of is_wpjm_page()
712
+ *
713
+ * @since 1.30.0
714
+ *
715
+ * @param bool $is_wpjm_page
716
+ */
717
+ return apply_filters( 'is_wpjm_page', $is_wpjm_page );
718
+ }
719
+
720
+ /**
721
+ * Checks if the provided content or the current single page or post has a WPJM shortcode.
722
+ *
723
+ * @param string|null $content Content to check. If not provided, it uses the current post content.
724
+ * @param string|array|null $tag Check specifically for one or more shortcodes. If not provided, checks for any WPJM shortcode.
725
+ *
726
+ * @return bool
727
+ */
728
+ function has_wpjm_shortcode( $content = null, $tag = null ) {
729
+ global $post;
730
+
731
+ $has_wpjm_shortcode = false;
732
+
733
+ if ( null === $content && is_singular() && is_a( $post, 'WP_Post' ) ) {
734
+ $content = $post->post_content;
735
+ }
736
+
737
+ if ( ! empty( $content ) ) {
738
+ $wpjm_shortcodes = array( 'submit_job_form', 'job_dashboard', 'jobs', 'job', 'job_summary', 'job_apply' );
739
+ /**
740
+ * Filters a list of all shortcodes associated with WPJM.
741
+ *
742
+ * @since 1.30.0
743
+ *
744
+ * @param string[] $wpjm_shortcodes
745
+ */
746
+ $wpjm_shortcodes = array_unique( apply_filters( 'job_manager_shortcodes', $wpjm_shortcodes ) );
747
+
748
+ if ( null !== $tag ) {
749
+ if ( ! is_array( $tag ) ) {
750
+ $tag = array( $tag );
751
+ }
752
+ $wpjm_shortcodes = array_intersect( $wpjm_shortcodes, $tag );
753
+ }
754
+
755
+ foreach ( $wpjm_shortcodes as $shortcode ) {
756
+ if ( has_shortcode( $content, $shortcode ) ) {
757
+ $has_wpjm_shortcode = true;
758
+ break;
759
+ }
760
+ }
761
+ }
762
+
763
+ /**
764
+ * Filter the result of has_wpjm_shortcode()
765
+ *
766
+ * @since 1.30.0
767
+ *
768
+ * @param bool $has_wpjm_shortcode
769
+ */
770
+ return apply_filters( 'has_wpjm_shortcode', $has_wpjm_shortcode );
771
+ }
772
+
773
+ /**
774
+ * Checks if the current page is a job listing.
775
+ *
776
+ * @since 1.30.0
777
+ *
778
+ * @return bool
779
+ */
780
+ function is_wpjm_job_listing() {
781
+ return is_singular( array( 'job_listing' ) );
782
+ }
783
+
784
+ /**
785
+ * Checks if the visitor is on a page for a WPJM taxonomy.
786
+ *
787
+ * @since 1.30.0
788
+ *
789
+ * @return bool
790
+ */
791
+ function is_wpjm_taxonomy() {
792
+ return is_tax( get_object_taxonomies( 'job_listing' ) );
793
+ }
794
+
795
  /**
796
  * Checks to see if the standard password setup email should be used.
797
  *
954
  return apply_filters( 'job_manager_user_can_edit_pending_submissions', get_option( 'job_manager_user_can_edit_pending_submissions' ) == 1 ? true : false );
955
  }
956
 
957
+ /**
958
+ * Checks if users are allowed to edit published submissions.
959
+ *
960
+ * @since 1.29.0
961
+ * @return bool
962
+ */
963
+ function wpjm_user_can_edit_published_submissions() {
964
+ /**
965
+ * Override the setting for allowing a user to edit published job listings.
966
+ *
967
+ * @since 1.29.0
968
+ *
969
+ * @param bool $can_edit_published_submissions
970
+ */
971
+ return apply_filters( 'job_manager_user_can_edit_published_submissions', in_array( get_option( 'job_manager_user_edit_published_submissions' ), array( 'yes', 'yes_moderated' ) ) );
972
+ }
973
+
974
+ /**
975
+ * Checks if moderation is required when users edit published submissions.
976
+ *
977
+ * @since 1.29.0
978
+ * @return bool
979
+ */
980
+ function wpjm_published_submission_edits_require_moderation() {
981
+ $require_moderation = 'yes_moderated' === get_option( 'job_manager_user_edit_published_submissions' );
982
+
983
+ /**
984
+ * Override the setting for user edits to job listings requiring moderation.
985
+ *
986
+ * @since 1.29.0
987
+ *
988
+ * @param bool $require_moderation
989
+ */
990
+ return apply_filters( 'job_manager_published_submission_edits_require_moderation', $require_moderation );
991
+ }
992
+
993
  /**
994
  * Displays category select dropdown.
995
  *
wp-job-manager.php CHANGED
@@ -3,7 +3,7 @@
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.29.3
7
  * Author: Automattic
8
  * Author URI: https://wpjobmanager.com/
9
  * Requires at least: 4.1
@@ -58,7 +58,7 @@ class WP_Job_Manager {
58
  */
59
  public function __construct() {
60
  // Define constants
61
- define( 'JOB_MANAGER_VERSION', '1.29.3' );
62
  define( 'JOB_MANAGER_PLUGIN_DIR', untrailingslashit( plugin_dir_path( __FILE__ ) ) );
63
  define( 'JOB_MANAGER_PLUGIN_URL', untrailingslashit( plugins_url( basename( plugin_dir_path( __FILE__ ) ), basename( __FILE__ ) ) ) );
64
 
@@ -105,6 +105,9 @@ class WP_Job_Manager {
105
  add_action( 'admin_init', array( $this, 'updater' ) );
106
  add_action( 'wp_logout', array( $this, 'cleanup_job_posting_cookies' ) );
107
 
 
 
 
108
  // Defaults for WPJM core actions
109
  add_action( 'wpjm_notify_new_user', 'wp_job_manager_notify_new_user', 10, 2 );
110
  }
@@ -171,6 +174,26 @@ class WP_Job_Manager {
171
  include_once( JOB_MANAGER_PLUGIN_DIR . '/includes/widgets/class-wp-job-manager-widget-featured-jobs.php' );
172
  }
173
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
174
  /**
175
  * Schedule cron jobs for WPJM events.
176
  */
@@ -204,6 +227,39 @@ class WP_Job_Manager {
204
  public function frontend_scripts() {
205
  global $post;
206
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
207
  $ajax_url = WP_Job_Manager_Ajax::get_endpoint();
208
  $ajax_filter_deps = array( 'jquery', 'jquery-deserialize' );
209
  $ajax_data = array(
@@ -221,7 +277,19 @@ class WP_Job_Manager {
221
  */
222
  $ajax_data['lang'] = apply_filters( 'wpjm_lang', null );
223
 
224
- if ( apply_filters( 'job_manager_chosen_enabled', true ) ) {
 
 
 
 
 
 
 
 
 
 
 
 
225
  wp_register_script( 'chosen', JOB_MANAGER_PLUGIN_URL . '/assets/js/jquery-chosen/chosen.jquery.min.js', array( 'jquery' ), '1.1.0', true );
226
  wp_register_script( 'wp-job-manager-term-multiselect', JOB_MANAGER_PLUGIN_URL . '/assets/js/term-multiselect.min.js', array( 'jquery', 'chosen' ), JOB_MANAGER_VERSION, true );
227
  wp_register_script( 'wp-job-manager-multiselect', JOB_MANAGER_PLUGIN_URL . '/assets/js/multiselect.min.js', array( 'jquery', 'chosen' ), JOB_MANAGER_VERSION, true );
@@ -235,7 +303,7 @@ class WP_Job_Manager {
235
  );
236
  }
237
 
238
- if ( apply_filters( 'job_manager_ajax_file_upload_enabled', true ) ) {
239
  wp_register_script( 'jquery-iframe-transport', JOB_MANAGER_PLUGIN_URL . '/assets/js/jquery-fileupload/jquery.iframe-transport.js', array( 'jquery' ), '1.8.3', true );
240
  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.11.2', true );
241
  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 );
@@ -274,9 +342,21 @@ class WP_Job_Manager {
274
  'i18n_confirm_delete' => __( 'Are you sure you want to delete this listing?', 'wp-job-manager' ),
275
  ) );
276
 
277
- wp_enqueue_style( 'wp-job-manager-frontend', JOB_MANAGER_PLUGIN_URL . '/assets/css/frontend.css', array(), JOB_MANAGER_VERSION );
278
- if ( is_a( $post, 'WP_Post' ) && has_shortcode( $post->post_content, 'submit_job_form' ) ) {
279
- wp_enqueue_style( 'wp-job-manager-job-submission', JOB_MANAGER_PLUGIN_URL . '/assets/css/job-submission.css', array(), JOB_MANAGER_VERSION );
 
 
 
 
 
 
 
 
 
 
 
 
280
  }
281
  }
282
  }
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.30.0
7
  * Author: Automattic
8
  * Author URI: https://wpjobmanager.com/
9
  * Requires at least: 4.1
58
  */
59
  public function __construct() {
60
  // Define constants
61
+ define( 'JOB_MANAGER_VERSION', '1.30.0' );
62
  define( 'JOB_MANAGER_PLUGIN_DIR', untrailingslashit( plugin_dir_path( __FILE__ ) ) );
63
  define( 'JOB_MANAGER_PLUGIN_URL', untrailingslashit( plugins_url( basename( plugin_dir_path( __FILE__ ) ), basename( __FILE__ ) ) ) );
64
 
105
  add_action( 'admin_init', array( $this, 'updater' ) );
106
  add_action( 'wp_logout', array( $this, 'cleanup_job_posting_cookies' ) );
107
 
108
+ add_action( 'init', array( $this, 'usage_tracking_init' ) );
109
+ register_deactivation_hook( __FILE__, array( $this, 'usage_tracking_cleanup' ) );
110
+
111
  // Defaults for WPJM core actions
112
  add_action( 'wpjm_notify_new_user', 'wp_job_manager_notify_new_user', 10, 2 );
113
  }
174
  include_once( JOB_MANAGER_PLUGIN_DIR . '/includes/widgets/class-wp-job-manager-widget-featured-jobs.php' );
175
  }
176
 
177
+ /**
178
+ * Initialize the Usage Tracking system.
179
+ */
180
+ public function usage_tracking_init() {
181
+ include_once( JOB_MANAGER_PLUGIN_DIR . '/includes/class-wp-job-manager-usage-tracking.php' );
182
+ include_once( JOB_MANAGER_PLUGIN_DIR . '/includes/class-wp-job-manager-usage-tracking-data.php' );
183
+
184
+ WP_Job_Manager_Usage_Tracking::get_instance()->set_callback(
185
+ array( 'WP_Job_Manager_Usage_Tracking_Data', 'get_usage_data' )
186
+ );
187
+ WP_Job_Manager_Usage_Tracking::get_instance()->schedule_tracking_task();
188
+ }
189
+
190
+ /**
191
+ * Cleanup the Usage Tracking system for plugin deactivation.
192
+ */
193
+ public function usage_tracking_cleanup() {
194
+ WP_Job_Manager_Usage_Tracking::get_instance()->unschedule_tracking_task();
195
+ }
196
+
197
  /**
198
  * Schedule cron jobs for WPJM events.
199
  */
227
  public function frontend_scripts() {
228
  global $post;
229
 
230
+ /**
231
+ * Starting in WP Job Manager 1.32.0, the chosen JS library and core frontend WPJM CSS will only be enqueued
232
+ * when used on a particular page. Theme and plugin authors as well as people who have overloaded WPJM's default
233
+ * template files should test this upcoming behavior.
234
+ *
235
+ * To test this behavior before 1.32.0, add this to your `wp-config.php`:
236
+ * define( 'JOB_MANAGER_TEST_NEW_ASSET_BEHAVIOR', true );
237
+ *
238
+ * Unless this constant is defined, WP Job Manager will default to its old behavior: chosen JS library and
239
+ * frontend styles are always enqueued.
240
+ *
241
+ * If your theme or plugin depend on the `frontend.css` or chosen JS library from WPJM core, you can use the
242
+ * `job_manager_chosen_enabled` and `job_manager_enqueue_frontend_style` filters.
243
+ *
244
+ * Example code for a custom shortcode that depends on the chosen library:
245
+ *
246
+ * add_filter( 'job_manager_chosen_enabled', function( $chosen_used_on_page ) {
247
+ * global $post;
248
+ * if ( is_singular()
249
+ * && is_a( $post, 'WP_Post' )
250
+ * && has_shortcode( $post->post_content, 'resumes' )
251
+ * ) {
252
+ * $chosen_used_on_page = true;
253
+ * }
254
+ * return $chosen_used_on_page;
255
+ * } );
256
+ *
257
+ */
258
+ if ( ! defined( 'JOB_MANAGER_TEST_NEW_ASSET_BEHAVIOR' ) || true !== JOB_MANAGER_TEST_NEW_ASSET_BEHAVIOR ) {
259
+ add_filter( 'job_manager_chosen_enabled', '__return_true' );
260
+ add_filter( 'job_manager_enqueue_frontend_style', '__return_true' );
261
+ }
262
+
263
  $ajax_url = WP_Job_Manager_Ajax::get_endpoint();
264
  $ajax_filter_deps = array( 'jquery', 'jquery-deserialize' );
265
  $ajax_data = array(
277
  */
278
  $ajax_data['lang'] = apply_filters( 'wpjm_lang', null );
279
 
280
+ $chosen_shortcodes = array( 'submit_job_form', 'job_dashboard', 'jobs' );
281
+ $chosen_used_on_page = has_wpjm_shortcode( null, $chosen_shortcodes );
282
+
283
+ /**
284
+ * Filter the use of the chosen library.
285
+ *
286
+ * NOTE: See above. Before WP Job Manager 1.32.0 is released, `job_manager_enqueue_frontend_style` will be filtered to `true` by default.
287
+ *
288
+ * @since 1.19.0
289
+ *
290
+ * @param bool $chosen_used_on_page Defaults to only when there are known shortcodes on the page.
291
+ */
292
+ if ( apply_filters( 'job_manager_chosen_enabled', $chosen_used_on_page ) ) {
293
  wp_register_script( 'chosen', JOB_MANAGER_PLUGIN_URL . '/assets/js/jquery-chosen/chosen.jquery.min.js', array( 'jquery' ), '1.1.0', true );
294
  wp_register_script( 'wp-job-manager-term-multiselect', JOB_MANAGER_PLUGIN_URL . '/assets/js/term-multiselect.min.js', array( 'jquery', 'chosen' ), JOB_MANAGER_VERSION, true );
295
  wp_register_script( 'wp-job-manager-multiselect', JOB_MANAGER_PLUGIN_URL . '/assets/js/multiselect.min.js', array( 'jquery', 'chosen' ), JOB_MANAGER_VERSION, true );
303
  );
304
  }
305
 
306
+ if ( job_manager_user_can_upload_file_via_ajax() ) {
307
  wp_register_script( 'jquery-iframe-transport', JOB_MANAGER_PLUGIN_URL . '/assets/js/jquery-fileupload/jquery.iframe-transport.js', array( 'jquery' ), '1.8.3', true );
308
  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.11.2', true );
309
  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 );
342
  'i18n_confirm_delete' => __( 'Are you sure you want to delete this listing?', 'wp-job-manager' ),
343
  ) );
344
 
345
+
346
+ /**
347
+ * Filter whether to enqueue WPJM core's frontend scripts. By default, they will only be enqueued on WPJM related
348
+ * pages.
349
+ *
350
+ * NOTE: See above. Before WP Job Manager 1.32.0 is released, `job_manager_enqueue_frontend_style` will be filtered to `true` by default.
351
+ *
352
+ * @since 1.30.0
353
+ *
354
+ * @param bool $is_frontend_style_enabled
355
+ */
356
+ if ( apply_filters( 'job_manager_enqueue_frontend_style', is_wpjm() ) ) {
357
+ wp_enqueue_style( 'wp-job-manager-frontend', JOB_MANAGER_PLUGIN_URL . '/assets/css/frontend.css', array(), JOB_MANAGER_VERSION );
358
+ } else {
359
+ wp_register_style( 'wp-job-manager-job-listings', JOB_MANAGER_PLUGIN_URL . '/assets/css/job-listings.css', array(), JOB_MANAGER_VERSION );
360
  }
361
  }
362
  }