WP Job Manager - Version 1.31.1

Version Description

  • Enhancement: Add option to show company logo in Recent Jobs widget. (@RajeebTheGreat)
  • Enhancement: Suggest additional cookie information on Privacy Policy page.
  • Enhancement: Add WPJM related meta data to user data extract.
  • Fix: Tightened the security of the plugin with additional string escaping.
  • Fix: Issue with map link in admin backend. (@RajeebTheGreat)
  • Fix: No longer auto-expire job listings in Draft status.
  • Fix: Issue with undefined index error in WP admin. (@albionselimaj)
  • Fix: Issue with duplicate usernames preventing submission of job listings. (@timothyjensen)
  • Dev: Widespread code formatting cleanup throughout the plugin.
Download this release

Release Info

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

Code changes from version 1.31.0 to 1.31.1

Files changed (146) hide show
  1. assets/css/admin.less +0 -550
  2. assets/css/chosen.less +0 -435
  3. assets/css/frontend.css +1 -1
  4. assets/css/frontend.less +0 -773
  5. assets/css/icons.less +0 -40
  6. assets/css/job-listings.css +1 -1
  7. assets/css/job-listings.less +0 -218
  8. assets/css/job-submission.less +0 -14
  9. assets/css/menu.less +0 -17
  10. assets/css/mixins.less +0 -105
  11. assets/css/setup.less +0 -93
  12. assets/js/admin.js +0 -94
  13. assets/js/ajax-file-upload.js +0 -95
  14. assets/js/ajax-filters.js +0 -298
  15. assets/js/ajax-filters.min.js +1 -1
  16. assets/js/datepicker.js +0 -27
  17. assets/js/job-application.js +0 -42
  18. assets/js/job-dashboard.js +0 -8
  19. assets/js/job-submission.js +0 -10
  20. assets/js/jquery-chosen/chosen.jquery.js +0 -1229
  21. assets/js/jquery-tiptip/jquery.tipTip.js +0 -191
  22. assets/js/jquery-tiptip/jquery.tipTip.min.js +1 -1
  23. assets/js/multiselect.js +0 -4
  24. assets/js/term-multiselect.js +0 -4
  25. changelog.txt +11 -0
  26. includes/3rd-party/all-in-one-seo-pack.php +2 -0
  27. includes/3rd-party/jetpack.php +2 -0
  28. includes/3rd-party/polylang.php +2 -0
  29. includes/3rd-party/rp4wp.php +2 -0
  30. includes/3rd-party/wp-all-import.php +7 -2
  31. includes/3rd-party/wpml.php +7 -3
  32. includes/3rd-party/yoast.php +4 -2
  33. includes/abstracts/abstract-wp-job-manager-email-template.php +12 -10
  34. includes/abstracts/abstract-wp-job-manager-email.php +12 -4
  35. includes/abstracts/abstract-wp-job-manager-form.php +69 -46
  36. includes/admin/class-wp-job-manager-addons.php +32 -16
  37. includes/admin/class-wp-job-manager-admin.php +35 -25
  38. includes/admin/class-wp-job-manager-cpt-legacy.php +21 -14
  39. includes/admin/class-wp-job-manager-cpt.php +254 -202
  40. includes/admin/class-wp-job-manager-permalink-settings.php +13 -8
  41. includes/admin/class-wp-job-manager-settings.php +258 -155
  42. includes/admin/class-wp-job-manager-setup.php +104 -61
  43. includes/admin/class-wp-job-manager-taxonomy-meta.php +14 -12
  44. includes/admin/class-wp-job-manager-writepanels.php +216 -132
  45. includes/admin/views/html-admin-page-addons.php +17 -15
  46. includes/class-wp-job-manager-ajax.php +51 -49
  47. includes/class-wp-job-manager-api.php +6 -6
  48. includes/class-wp-job-manager-cache-helper.php +26 -20
  49. includes/class-wp-job-manager-category-walker.php +24 -10
  50. includes/class-wp-job-manager-data-cleaner.php +8 -6
  51. includes/class-wp-job-manager-data-exporter.php +89 -0
  52. includes/class-wp-job-manager-email-notifications.php +60 -47
  53. includes/class-wp-job-manager-forms.php +9 -8
  54. includes/class-wp-job-manager-geocode.php +51 -50
  55. includes/class-wp-job-manager-install.php +42 -38
  56. includes/class-wp-job-manager-post-types.php +285 -214
  57. includes/class-wp-job-manager-shortcodes.php +288 -236
  58. includes/class-wp-job-manager-usage-tracking-data.php +35 -37
  59. includes/class-wp-job-manager-usage-tracking.php +88 -11
  60. includes/class-wp-job-manager-widget.php +23 -15
  61. includes/emails/class-wp-job-manager-email-admin-expiring-job.php +1 -1
  62. includes/emails/class-wp-job-manager-email-admin-new-job.php +5 -1
  63. includes/emails/class-wp-job-manager-email-admin-updated-job.php +5 -1
  64. includes/emails/class-wp-job-manager-email-employer-expiring-job.php +10 -6
  65. includes/forms/class-wp-job-manager-form-edit-job.php +34 -24
  66. includes/forms/class-wp-job-manager-form-submit-job.php +251 -225
  67. includes/helper/class-wp-job-manager-helper-api.php +21 -18
  68. includes/helper/class-wp-job-manager-helper-options.php +1 -0
  69. includes/helper/class-wp-job-manager-helper.php +77 -62
  70. includes/helper/views/html-licence-key-error.php +2 -2
  71. includes/helper/views/html-licence-key-notice.php +2 -2
  72. includes/helper/views/html-licences.php +41 -41
  73. includes/rest-api/class-wp-job-manager-controllers-status.php +7 -5
  74. includes/rest-api/class-wp-job-manager-data-stores-status.php +5 -2
  75. includes/rest-api/class-wp-job-manager-filters-status.php +4 -4
  76. includes/rest-api/class-wp-job-manager-models-job-listings-custom-fields.php +1 -1
  77. includes/rest-api/class-wp-job-manager-models-job-types-custom-fields.php +14 -8
  78. includes/rest-api/class-wp-job-manager-models-settings.php +5 -3
  79. includes/rest-api/class-wp-job-manager-models-status.php +2 -2
  80. includes/rest-api/class-wp-job-manager-registrable-job-listings.php +29 -23
  81. includes/rest-api/class-wp-job-manager-registrable-taxonomy-type.php +33 -23
  82. includes/rest-api/class-wp-job-manager-rest-api.php +11 -6
  83. includes/widgets/class-wp-job-manager-widget-featured-jobs.php +46 -35
  84. includes/widgets/class-wp-job-manager-widget-recent-jobs.php +41 -24
  85. languages/wp-job-manager.pot +656 -498
  86. lib/usage-tracking/class-usage-tracking-base.php +10 -7
  87. lib/usage-tracking/tests/test-class-usage-tracking.php +19 -20
  88. readme.txt +23 -1
  89. templates/account-signin.php +11 -11
  90. templates/content-job_listing.php +1 -1
  91. templates/content-no-jobs-found.php +5 -5
  92. templates/content-single-job_listing-company.php +4 -4
  93. templates/content-single-job_listing-meta.php +1 -1
  94. templates/content-single-job_listing.php +1 -1
  95. templates/content-summary-job_listing.php +3 -3
  96. templates/content-widget-job_listing.php +21 -14
  97. templates/content-widget-no-jobs-found.php +1 -1
  98. templates/emails/admin-expiring-job.php +5 -5
  99. templates/emails/admin-new-job.php +16 -5
  100. templates/emails/admin-updated-job.php +9 -5
  101. templates/emails/email-footer.php +1 -1
  102. templates/emails/email-header.php +3 -3
  103. templates/emails/email-job-details.php +4 -4
  104. templates/emails/email-styles.php +1 -1
  105. templates/emails/employer-expiring-job.php +22 -5
  106. templates/emails/plain/admin-expiring-job.php +16 -5
  107. templates/emails/plain/admin-new-job.php +5 -5
  108. templates/emails/plain/admin-updated-job.php +5 -5
  109. templates/emails/plain/email-footer.php +1 -2
  110. templates/emails/plain/email-header.php +1 -2
  111. templates/emails/plain/email-job-details.php +3 -3
  112. templates/emails/plain/employer-expiring-job.php +5 -5
  113. templates/form-fields/checkbox-field.php +3 -3
  114. templates/form-fields/date-field.php +3 -3
  115. templates/form-fields/file-field.php +4 -4
  116. templates/form-fields/multiselect-field.php +4 -4
  117. templates/form-fields/password-field.php +4 -4
  118. templates/form-fields/radio-field.php +3 -3
  119. templates/form-fields/recaptcha-field.php +5 -5
  120. templates/form-fields/select-field.php +3 -3
  121. templates/form-fields/term-checklist-field.php +5 -5
  122. templates/form-fields/term-multiselect-field.php +4 -4
  123. templates/form-fields/term-select-field.php +5 -5
  124. templates/form-fields/text-field.php +4 -4
  125. templates/form-fields/textarea-field.php +4 -4
  126. templates/form-fields/uploaded-file-html.php +1 -1
  127. templates/form-fields/wp-editor-field.php +3 -3
  128. templates/job-application-email.php +3 -3
  129. templates/job-application-url.php +1 -1
  130. templates/job-application.php +5 -5
  131. templates/job-dashboard-login.php +4 -4
  132. templates/job-dashboard.php +7 -7
  133. templates/job-filter-job-types.php +5 -5
  134. templates/job-filters.php +7 -7
  135. templates/job-listings-end.php +1 -1
  136. templates/job-listings-start.php +1 -1
  137. templates/job-pagination.php +8 -8
  138. templates/job-preview.php +6 -6
  139. templates/job-submit.php +8 -8
  140. templates/job-submitted.php +17 -5
  141. templates/pagination.php +1 -1
  142. uninstall.php +1 -1
  143. wp-job-manager-deprecated.php +66 -62
  144. wp-job-manager-functions.php +540 -508
  145. wp-job-manager-template.php +198 -163
  146. wp-job-manager.php +110 -63
assets/css/admin.less DELETED
@@ -1,550 +0,0 @@
1
- @import "mixins";
2
- @import "icons.less";
3
-
4
- .job-manager-settings-wrap {
5
- .updated {
6
- display: none;
7
- }
8
- .job-manager-updated {
9
- display: block;
10
- margin: 1em 0 0;
11
- }
12
- }
13
-
14
- a.wpjm-activate-licence-link,
15
- a.wpjm-activate-licence-link:link,
16
- a.wpjm-activate-licence-link:hover,
17
- a.wpjm-activate-licence-link:visited,
18
- a.wpjm-activate-licence-link:active {
19
- color: orangered;
20
- }
21
-
22
- .wpjm-licences {
23
- margin-top: 10px;
24
- .licence-row {
25
- align-items: center;
26
- border: solid 1px #e2e0e2;
27
- display: flex;
28
- background-color: #fff;
29
- flex-wrap: wrap;
30
- min-height: 82px;
31
- margin-bottom: 20px;
32
- position: relative;
33
- }
34
- .plugin-info {
35
- font-size: 18px;
36
- flex-basis: 320px;
37
- padding: 0 20px;
38
- margin-right: 10px;
39
-
40
- .plugin-author {
41
- font-size: 12px;
42
- }
43
- }
44
- .plugin-licence {
45
- flex: 1;
46
- flex-basis: 40%;
47
- padding-bottom: 5px;
48
- label {
49
- white-space: nowrap;
50
- }
51
- }
52
- }
53
- .widefat {
54
- td.column-featured_job, td.column-filled, td.column-job_status {
55
- width: 46px;
56
- text-align: left;
57
- padding-left: 11px;
58
- }
59
- th.column-featured_job, th.column-filled, th.column-job_status {
60
- width: 1em;
61
- span {
62
- display: block;
63
- width: 1em;
64
- height: 1em;
65
- line-height: 1em;
66
- padding: 1px 0 0 0;
67
- overflow: hidden;
68
- &:before {
69
- content: '\e803';
70
- .jm-icon;
71
- }
72
- }
73
- }
74
- th.column-filled {
75
- span {
76
- &:before {
77
- content: '\e807';
78
- }
79
- }
80
- }
81
- th.column-job_status {
82
- span {
83
- &:before {
84
- content: '\e828';
85
- }
86
- }
87
- }
88
- .column-job_posted {
89
- strong {
90
- display: block;
91
- margin-bottom: .2em;
92
- }
93
- }
94
- td.column-job_status {
95
- span {
96
- position: relative;
97
- font-size: 1em;
98
- line-height: 1.5em;
99
- width: 1em;
100
- height: 0;
101
- padding: 2em 0 0 0;
102
- overflow: hidden;
103
- display: block;
104
- }
105
- span:before {
106
- .jm-icon;
107
- position: absolute;
108
- top: 0;
109
- left: 0;
110
- line-height: 1.5em;
111
- vertical-align: middle;
112
- color: #999;
113
- content: '\e829';
114
- }
115
- .status-trash:before {
116
- content: '\e82b';
117
- color: #a00;
118
- }
119
- .status-pending:before {
120
- content: '\e82c';
121
- color: #ffba00;
122
- }
123
- .status-publish:before {
124
- content: '\e82f';
125
- color: #73a724;
126
- }
127
- .status-expired:before {
128
- content: '\e82e';
129
- color: #a00;
130
- }
131
- }
132
- .column-job_listing_type {
133
- text-align: left;
134
- width: 6em;
135
- word-wrap: normal !important;
136
- .job-type {
137
- color: #fff;
138
- padding: 4px;
139
- font-size: 11px;
140
- .border_radius( 2px );
141
- display:block;
142
- background-color: @part-time;
143
- text-align: center;
144
- }
145
- .full-time {
146
- background-color: @full-time;
147
- }
148
- .part-time {
149
- background-color: @part-time;
150
- }
151
- .temporary {
152
- background-color: @temporary;
153
- }
154
- .freelance {
155
- background-color: @freelance;
156
- }
157
- .internship {
158
- background-color: @internship;
159
- }
160
- }
161
- th.column-job_position {
162
- width: 20%;
163
- }
164
- td.column-job_position {
165
- width: 20%;
166
- height: 34px;
167
- .job_position {
168
- position: relative;
169
- padding-right: 50px !important;
170
- }
171
- a.job_title {
172
- font-weight: bold;
173
- }
174
- img {
175
- width: 32px;
176
- height: 32px;
177
- position: absolute;
178
- right: 7px;
179
- top: 0;
180
- .border_radius( 50% );
181
- .box_shadow( 0, 1px, 0, 1px, rgba( 0,0,0,0.1 ) );
182
- border: 1px solid #fff;
183
- }
184
- .company {
185
- margin-top: .2em;
186
- display: block;
187
- padding-top: 2px;
188
- color: #bbbbbb;
189
- }
190
- }
191
- .column-job_location {
192
- width: 10%;
193
- }
194
- .column-job_actions {
195
- text-align: right;
196
- width: 128px;
197
- strong {
198
- display: block;
199
- margin-bottom: .2em;
200
- }
201
- .actions {
202
- padding-top: 2px;
203
- }
204
- a.button {
205
- display: inline-block;
206
- margin: 0 0 2px 4px;
207
- cursor: pointer;
208
- padding: 0 6px !important;
209
- font-size: 1em !important;
210
- line-height: 2em !important;
211
- overflow: hidden;
212
- }
213
- a.button-icon {
214
- width: 2em !important;
215
- padding: 0 !important;
216
- &:before {
217
- .jm-icon;
218
- float: left;
219
- width: 2em !important;
220
- line-height: 2em;
221
- }
222
- }
223
- .icon-view:before {
224
- content: '\e805';
225
- }
226
- .icon-edit:before {
227
- content: '\e804';
228
- }
229
- .icon-delete:before {
230
- content: '\e82b';
231
- }
232
- .icon-approve:before {
233
- content: '\e802';
234
- }
235
- }
236
- }
237
- .wp_job_manager_meta_data {
238
- zoom: 1;
239
- &:before,
240
- &:after {
241
- content: "";
242
- display: table;
243
- }
244
- &:after {
245
- clear: both;
246
- }
247
- .form-field {
248
- width: 50%;
249
- line-height: 2em;
250
- float: left;
251
- box-sizing: border-box;
252
- padding: 0 12px 0 0;
253
- margin: 0 0 12px;
254
- clear: both;
255
- &:nth-child(even) {
256
- float: right;
257
- padding: 0 0 0 12px;
258
- clear: right;
259
- }
260
- &:nth-last-child(-n+2) {
261
- margin-bottom: 0;
262
- padding-bottom: 0;
263
- border-bottom: 0;
264
- }
265
- label {
266
- vertical-align: middle;
267
- display: block;
268
- font-weight: bold;
269
- margin: 0;
270
- }
271
- .tips {
272
- cursor: help;
273
- float: right;
274
- font-weight: normal;
275
- color: #999;
276
- }
277
- input {
278
- width: 100%;
279
- margin: 1px 0;
280
- -webkit-box-sizing: border-box; /* Safari/Chrome, other WebKit */
281
- -moz-box-sizing: border-box; /* Firefox, other Gecko */
282
- box-sizing: border-box; /* Opera/IE 8+ */
283
- vertical-align: middle;
284
- }
285
- input.checkbox, input.radio {
286
- width: auto;
287
- margin: 4px 2px;
288
- display: inline-block;
289
- }
290
- .description {
291
- display: block;
292
- color: #999;
293
- }
294
- &.form-field-checkbox .description {
295
- display: inline;
296
- }
297
- .file_url {
298
- input {
299
- width: 75%;
300
- }
301
- }
302
- .button {
303
- margin-left: 4px;
304
- }
305
- .file_no_url {
306
- .keyframes(flash; {
307
- from { background-color: unset; }
308
- to { background-color: #dc3232; }
309
- });
310
-
311
- .animation(flash 0.3s linear infinite alternate);
312
- }
313
- }
314
- }
315
-
316
- /* TipTip CSS - Version 1.2 */
317
- #tiptip_holder {
318
- display: none;
319
- position: absolute;
320
- top: 0;
321
- left: 0;
322
- z-index: 99999;
323
- }
324
- #tiptip_holder.tip_top {
325
- padding-bottom: 5px;
326
- }
327
- #tiptip_holder.tip_bottom {
328
- padding-top: 5px;
329
- }
330
- #tiptip_holder.tip_right {
331
- padding-left: 5px;
332
- }
333
- #tiptip_holder.tip_left {
334
- padding-right: 5px;
335
- }
336
- #tiptip_content {
337
- font-size: 11px;
338
- color: #fff;
339
- padding: 4px 8px;
340
- background:#464646;
341
- border-radius: 3px;
342
- -webkit-border-radius: 3px;
343
- -moz-border-radius: 3px;
344
- box-shadow: 1px 1px 3px rgba(0,0,0,0.10);
345
- -webkit-box-shadow: 1px 1px 3px rgba(0,0,0,0.10);
346
- -moz-box-shadow: 1px 1px 3px rgba(0,0,0,0.10);
347
- text-align: center;
348
- code {
349
- background: #999;
350
- padding: 1px;
351
- }
352
- }
353
- #tiptip_arrow, #tiptip_arrow_inner {
354
- position: absolute;
355
- border-color: transparent;
356
- border-style: solid;
357
- border-width: 6px;
358
- height: 0;
359
- width: 0;
360
- }
361
- #tiptip_holder.tip_top #tiptip_arrow_inner {
362
- margin-top: -7px;
363
- margin-left: -6px;
364
- border-top-color: #464646;
365
- }
366
-
367
- #tiptip_holder.tip_bottom #tiptip_arrow_inner {
368
- margin-top: -5px;
369
- margin-left: -6px;
370
- border-bottom-color: #464646;
371
- }
372
-
373
- #tiptip_holder.tip_right #tiptip_arrow_inner {
374
- margin-top: -6px;
375
- margin-left: -5px;
376
- border-right-color: #464646;
377
- }
378
-
379
- #tiptip_holder.tip_left #tiptip_arrow_inner {
380
- margin-top: -6px;
381
- margin-left: -7px;
382
- border-left-color: #464646;
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 {
428
- display: none;
429
- }
430
- }
431
- }
432
- }
433
- .rtl {
434
- .widefat {
435
- .column-job_actions {
436
- a.button-icon {
437
- &:before {
438
- float: right;
439
- }
440
- }
441
- }
442
- }
443
- .wp_job_manager_meta_data {
444
- p {
445
- padding: 0 20% 0 0;
446
- }
447
- label {
448
- left: auto;
449
- right: 0;
450
- }
451
- }
452
- }
453
-
454
- /**
455
- * Settings
456
- */
457
-
458
- table.form-table.settings {
459
- tr {
460
- border-bottom: 1px solid rgba( 0, 0, 0, .1);
461
-
462
- &:last-child,
463
- &.no-separator {
464
- border-bottom: 0;
465
- }
466
- }
467
- }
468
-
469
- div.setting-enable-expand {
470
- border: 1px solid rgba( 0, 0, 0, .1);
471
- padding: 15px 10px;
472
-
473
- .sub-settings-expandable {
474
- display: none;
475
- padding-left: 25px;
476
-
477
- &.expanded {
478
- display: block;
479
- }
480
- }
481
- }
482
-
483
- tr.email-setting-row {
484
- td {
485
- padding: 5px;
486
- }
487
- }
488
-
489
- /**
490
- * Mobile styles
491
- */
492
- @media only screen and (max-width: 782px) {
493
- .wpjm-licences {
494
- .plugin-info {
495
- padding: 10px;
496
- }
497
- .plugin-licence {
498
- padding: 10px;
499
- }
500
- }
501
- .widefat {
502
- .job_position.column-primary{
503
- display: table-cell !important;
504
- }
505
- .toggle-row:before{
506
- top: 5px;
507
- }
508
- .column-job_actions {
509
- text-align: left;
510
-
511
- a.button-icon {
512
- &:before {
513
- float: left;
514
- }
515
- }
516
- }
517
- }
518
- .rtl {
519
- .widefat {
520
- .column-job_actions {
521
- text-align: right;
522
-
523
- a.button-icon {
524
- &:before {
525
- float: right;
526
- }
527
- }
528
- }
529
- }
530
- }
531
- .wp_job_manager_meta_data {
532
- .form-field {
533
- width: 100%;
534
- padding: 0;
535
-
536
- &:nth-child(even) {
537
- float: none;
538
- padding: 0;
539
- margin-bottom: 12px;
540
- clear: both;
541
- }
542
- &:nth-last-child(-n+2) {
543
- float: none;
544
- padding: 0;
545
- margin-bottom: 12px;
546
- clear: both;
547
- }
548
- }
549
- }
550
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
assets/css/chosen.less DELETED
@@ -1,435 +0,0 @@
1
- /*!
2
- Chosen, a Select Box Enhancer for jQuery and Prototype
3
- by Patrick Filler for Harvest, http://getharvest.com
4
-
5
- Version 1.1.0
6
- Full source at https://github.com/harvesthq/chosen
7
- Copyright (c) 2011 Harvest http://getharvest.com
8
-
9
- MIT License, https://github.com/harvesthq/chosen/blob/master/LICENSE.md
10
- This file is generated by `grunt build`, do not edit it by hand.
11
- */
12
-
13
- /* @group Base */
14
- .chosen-container {
15
- position: relative;
16
- display: inline-block;
17
- vertical-align: middle;
18
- font-size: 13px;
19
- zoom: 1;
20
- *display: inline;
21
- -webkit-user-select: none;
22
- -moz-user-select: none;
23
- user-select: none;
24
- }
25
- .chosen-container .chosen-drop {
26
- position: absolute;
27
- top: 100%;
28
- left: -9999px;
29
- z-index: 1010;
30
- -webkit-box-sizing: border-box;
31
- -moz-box-sizing: border-box;
32
- box-sizing: border-box;
33
- width: 100%;
34
- border: 1px solid #aaa;
35
- border-top: 0;
36
- background: #fff;
37
- box-shadow: 0 4px 5px rgba(0, 0, 0, 0.15);
38
- }
39
- .chosen-container.chosen-with-drop .chosen-drop {
40
- left: 0;
41
- }
42
- .chosen-container a {
43
- cursor: pointer;
44
- }
45
-
46
- /* @end */
47
- /* @group Single Chosen */
48
- .chosen-container-single .chosen-single {
49
- position: relative;
50
- display: block;
51
- overflow: hidden;
52
- padding: 0 0 0 8px;
53
- height: 23px;
54
- border: 1px solid #aaa;
55
- border-radius: 5px;
56
- background-color: #fff;
57
- background: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(20%, #ffffff), color-stop(50%, #f6f6f6), color-stop(52%, #eeeeee), color-stop(100%, #f4f4f4));
58
- background: -webkit-linear-gradient(top, #ffffff 20%, #f6f6f6 50%, #eeeeee 52%, #f4f4f4 100%);
59
- background: -moz-linear-gradient(top, #ffffff 20%, #f6f6f6 50%, #eeeeee 52%, #f4f4f4 100%);
60
- background: -o-linear-gradient(top, #ffffff 20%, #f6f6f6 50%, #eeeeee 52%, #f4f4f4 100%);
61
- background: linear-gradient(top, #ffffff 20%, #f6f6f6 50%, #eeeeee 52%, #f4f4f4 100%);
62
- background-clip: padding-box;
63
- box-shadow: 0 0 3px white inset, 0 1px 1px rgba(0, 0, 0, 0.1);
64
- color: #444;
65
- text-decoration: none;
66
- white-space: nowrap;
67
- line-height: 24px;
68
- }
69
- .chosen-container-single .chosen-default {
70
- color: #999;
71
- }
72
- .chosen-container-single .chosen-single span {
73
- display: block;
74
- overflow: hidden;
75
- margin-right: 26px;
76
- text-overflow: ellipsis;
77
- white-space: nowrap;
78
- }
79
- .chosen-container-single .chosen-single-with-deselect span {
80
- margin-right: 38px;
81
- }
82
- .chosen-container-single .chosen-single abbr {
83
- position: absolute;
84
- top: 6px;
85
- right: 26px;
86
- display: block;
87
- width: 12px;
88
- height: 12px;
89
- background: url('../images/chosen-sprite.png') -42px 1px no-repeat;
90
- font-size: 1px;
91
- }
92
- .chosen-container-single .chosen-single abbr:hover {
93
- background-position: -42px -10px;
94
- }
95
- .chosen-container-single.chosen-disabled .chosen-single abbr:hover {
96
- background-position: -42px -10px;
97
- }
98
- .chosen-container-single .chosen-single div {
99
- position: absolute;
100
- top: 0;
101
- right: 0;
102
- display: block;
103
- width: 18px;
104
- height: 100%;
105
- }
106
- .chosen-container-single .chosen-single div b {
107
- display: block;
108
- width: 100%;
109
- height: 100%;
110
- background: url('../images/chosen-sprite.png') no-repeat 0px 2px;
111
- }
112
- .chosen-container-single .chosen-search {
113
- position: relative;
114
- z-index: 1010;
115
- margin: 0;
116
- padding: 3px 4px;
117
- white-space: nowrap;
118
- }
119
- .chosen-container-single .chosen-search input[type="text"] {
120
- -webkit-box-sizing: border-box;
121
- -moz-box-sizing: border-box;
122
- box-sizing: border-box;
123
- margin: 1px 0;
124
- padding: 4px 20px 4px 5px;
125
- width: 100%;
126
- height: auto;
127
- outline: 0;
128
- border: 1px solid #aaa;
129
- background: white url('../images/chosen-sprite.png') no-repeat 100% -20px;
130
- background: url('../images/chosen-sprite.png') no-repeat 100% -20px;
131
- font-size: 1em;
132
- font-family: sans-serif;
133
- line-height: normal;
134
- border-radius: 0;
135
- }
136
- .chosen-container-single .chosen-drop {
137
- margin-top: -1px;
138
- border-radius: 0 0 4px 4px;
139
- background-clip: padding-box;
140
- }
141
- .chosen-container-single.chosen-container-single-nosearch .chosen-search {
142
- position: absolute;
143
- left: -9999px;
144
- }
145
-
146
- /* @end */
147
- /* @group Results */
148
- .chosen-container .chosen-results {
149
- position: relative;
150
- overflow-x: hidden;
151
- overflow-y: auto;
152
- margin: 0 4px 4px 0;
153
- padding: 0 0 0 4px;
154
- max-height: 240px;
155
- -webkit-overflow-scrolling: touch;
156
- }
157
- .chosen-container .chosen-results li {
158
- display: none;
159
- margin: 0;
160
- padding: 5px 6px;
161
- list-style: none;
162
- line-height: 15px;
163
- -webkit-touch-callout: none;
164
- }
165
- .chosen-container .chosen-results li.active-result {
166
- display: list-item;
167
- cursor: pointer;
168
- }
169
- .chosen-container .chosen-results li.disabled-result {
170
- display: list-item;
171
- color: #ccc;
172
- cursor: default;
173
- }
174
- .chosen-container .chosen-results li.highlighted {
175
- background-color: #3875d7;
176
- background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(20%, #3875d7), color-stop(90%, #2a62bc));
177
- background-image: -webkit-linear-gradient(#3875d7 20%, #2a62bc 90%);
178
- background-image: -moz-linear-gradient(#3875d7 20%, #2a62bc 90%);
179
- background-image: -o-linear-gradient(#3875d7 20%, #2a62bc 90%);
180
- background-image: linear-gradient(#3875d7 20%, #2a62bc 90%);
181
- color: #fff;
182
- }
183
- .chosen-container .chosen-results li.no-results {
184
- display: list-item;
185
- background: #f4f4f4;
186
- }
187
- .chosen-container .chosen-results li.group-result {
188
- display: list-item;
189
- font-weight: bold;
190
- cursor: default;
191
- }
192
- .chosen-container .chosen-results li.group-option {
193
- padding-left: 15px;
194
- }
195
- .chosen-container .chosen-results li em {
196
- font-style: normal;
197
- text-decoration: underline;
198
- }
199
-
200
- /* @end */
201
- /* @group Multi Chosen */
202
- .chosen-container-multi .chosen-choices {
203
- position: relative;
204
- overflow: hidden;
205
- -webkit-box-sizing: border-box;
206
- -moz-box-sizing: border-box;
207
- box-sizing: border-box;
208
- margin: 0;
209
- padding: 0;
210
- width: 100%;
211
- height: auto !important;
212
- height: 1%;
213
- border: 1px solid #aaa;
214
- background-color: #fff;
215
- background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(1%, #eeeeee), color-stop(15%, #ffffff));
216
- background-image: -webkit-linear-gradient(#eeeeee 1%, #ffffff 15%);
217
- background-image: -moz-linear-gradient(#eeeeee 1%, #ffffff 15%);
218
- background-image: -o-linear-gradient(#eeeeee 1%, #ffffff 15%);
219
- background-image: linear-gradient(#eeeeee 1%, #ffffff 15%);
220
- cursor: text;
221
- }
222
- .chosen-container-multi .chosen-choices li {
223
- float: left;
224
- list-style: none;
225
- }
226
- .chosen-container-multi .chosen-choices li.search-field {
227
- margin: 0;
228
- padding: 0;
229
- white-space: nowrap;
230
- }
231
- .chosen-container-multi .chosen-choices li.search-field input[type="text"] {
232
- margin: 1px 0;
233
- padding: 5px;
234
- height: auto;
235
- outline: 0;
236
- border: 0 !important;
237
- background: transparent !important;
238
- box-shadow: none;
239
- color: #666;
240
- font-size: 100%;
241
- font-family: sans-serif;
242
- line-height: normal;
243
- border-radius: 0;
244
- }
245
- .chosen-container-multi .chosen-choices li.search-field .default {
246
- color: #999;
247
- }
248
- .chosen-container-multi .chosen-choices li.search-choice {
249
- position: relative;
250
- margin: 3px 0 3px 5px;
251
- padding: 3px 20px 3px 5px;
252
- border: 1px solid #aaa;
253
- border-radius: 3px;
254
- background-color: #e4e4e4;
255
- background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(20%, #f4f4f4), color-stop(50%, #f0f0f0), color-stop(52%, #e8e8e8), color-stop(100%, #eeeeee));
256
- background-image: -webkit-linear-gradient(#f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%);
257
- background-image: -moz-linear-gradient(#f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%);
258
- background-image: -o-linear-gradient(#f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%);
259
- background-image: linear-gradient(#f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%);
260
- background-clip: padding-box;
261
- box-shadow: 0 0 2px white inset, 0 1px 0 rgba(0, 0, 0, 0.05);
262
- color: #333;
263
- line-height: 13px;
264
- cursor: default;
265
- }
266
- .chosen-container-multi .chosen-choices li.search-choice .search-choice-close {
267
- position: absolute;
268
- top: 4px;
269
- right: 3px;
270
- display: block;
271
- width: 12px;
272
- height: 12px;
273
- background: url('../images/chosen-sprite.png') -42px 1px no-repeat;
274
- font-size: 1px;
275
- }
276
- .chosen-container-multi .chosen-choices li.search-choice .search-choice-close:hover {
277
- background-position: -42px -10px;
278
- }
279
- .chosen-container-multi .chosen-choices li.search-choice-disabled {
280
- padding-right: 5px;
281
- border: 1px solid #ccc;
282
- background-color: #e4e4e4;
283
- background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(20%, #f4f4f4), color-stop(50%, #f0f0f0), color-stop(52%, #e8e8e8), color-stop(100%, #eeeeee));
284
- background-image: -webkit-linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%);
285
- background-image: -moz-linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%);
286
- background-image: -o-linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%);
287
- background-image: linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%);
288
- color: #666;
289
- }
290
- .chosen-container-multi .chosen-choices li.search-choice-focus {
291
- background: #d4d4d4;
292
- }
293
- .chosen-container-multi .chosen-choices li.search-choice-focus .search-choice-close {
294
- background-position: -42px -10px;
295
- }
296
- .chosen-container-multi .chosen-results {
297
- margin: 0;
298
- padding: 0;
299
- }
300
- .chosen-container-multi .chosen-drop .result-selected {
301
- display: list-item;
302
- color: #ccc;
303
- cursor: default;
304
- }
305
-
306
- /* @end */
307
- /* @group Active */
308
- .chosen-container-active .chosen-single {
309
- border: 1px solid #5897fb;
310
- box-shadow: 0 0 5px rgba(0, 0, 0, 0.3);
311
- }
312
- .chosen-container-active.chosen-with-drop .chosen-single {
313
- border: 1px solid #aaa;
314
- -moz-border-radius-bottomright: 0;
315
- border-bottom-right-radius: 0;
316
- -moz-border-radius-bottomleft: 0;
317
- border-bottom-left-radius: 0;
318
- background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(20%, #eeeeee), color-stop(80%, #ffffff));
319
- background-image: -webkit-linear-gradient(#eeeeee 20%, #ffffff 80%);
320
- background-image: -moz-linear-gradient(#eeeeee 20%, #ffffff 80%);
321
- background-image: -o-linear-gradient(#eeeeee 20%, #ffffff 80%);
322
- background-image: linear-gradient(#eeeeee 20%, #ffffff 80%);
323
- box-shadow: 0 1px 0 #fff inset;
324
- }
325
- .chosen-container-active.chosen-with-drop .chosen-single div {
326
- border-left: none;
327
- background: transparent;
328
- }
329
- .chosen-container-active.chosen-with-drop .chosen-single div b {
330
- background-position: -18px 2px;
331
- }
332
- .chosen-container-active .chosen-choices {
333
- border: 1px solid #5897fb;
334
- box-shadow: 0 0 5px rgba(0, 0, 0, 0.3);
335
- }
336
- .chosen-container-active .chosen-choices li.search-field input[type="text"] {
337
- color: #111 !important;
338
- }
339
-
340
- /* @end */
341
- /* @group Disabled Support */
342
- .chosen-disabled {
343
- opacity: 0.5 !important;
344
- cursor: default;
345
- }
346
- .chosen-disabled .chosen-single {
347
- cursor: default;
348
- }
349
- .chosen-disabled .chosen-choices .search-choice .search-choice-close {
350
- cursor: default;
351
- }
352
-
353
- /* @end */
354
- /* @group Right to Left */
355
- .chosen-rtl {
356
- text-align: right;
357
- }
358
- .chosen-rtl .chosen-single {
359
- overflow: visible;
360
- padding: 0 8px 0 0;
361
- }
362
- .chosen-rtl .chosen-single span {
363
- margin-right: 0;
364
- margin-left: 26px;
365
- direction: rtl;
366
- }
367
- .chosen-rtl .chosen-single-with-deselect span {
368
- margin-left: 38px;
369
- }
370
- .chosen-rtl .chosen-single div {
371
- right: auto;
372
- left: 3px;
373
- }
374
- .chosen-rtl .chosen-single abbr {
375
- right: auto;
376
- left: 26px;
377
- }
378
- .chosen-rtl .chosen-choices li {
379
- float: right;
380
- }
381
- .chosen-rtl .chosen-choices li.search-field input[type="text"] {
382
- direction: rtl;
383
- }
384
- .chosen-rtl .chosen-choices li.search-choice {
385
- margin: 3px 5px 3px 0;
386
- padding: 3px 5px 3px 19px;
387
- }
388
- .chosen-rtl .chosen-choices li.search-choice .search-choice-close {
389
- right: auto;
390
- left: 4px;
391
- }
392
- .chosen-rtl.chosen-container-single-nosearch .chosen-search,
393
- .chosen-rtl .chosen-drop {
394
- left: 9999px;
395
- }
396
- .chosen-rtl.chosen-container-single .chosen-results {
397
- margin: 0 0 4px 4px;
398
- padding: 0 4px 0 0;
399
- }
400
- .chosen-rtl .chosen-results li.group-option {
401
- padding-right: 15px;
402
- padding-left: 0;
403
- }
404
- .chosen-rtl.chosen-container-active.chosen-with-drop .chosen-single div {
405
- border-right: none;
406
- }
407
- .chosen-rtl .chosen-search input[type="text"] {
408
- padding: 4px 5px 4px 20px;
409
- background: white url('../images/chosen-sprite.png') no-repeat -30px -20px;
410
- background: url('../images/chosen-sprite.png') no-repeat -30px -20px;
411
- direction: rtl;
412
- }
413
- .chosen-rtl.chosen-container-single .chosen-single div b {
414
- background-position: 6px 2px;
415
- }
416
- .chosen-rtl.chosen-container-single.chosen-with-drop .chosen-single div b {
417
- background-position: -12px 2px;
418
- }
419
-
420
- /* @end */
421
- /* @group Retina compatibility */
422
- @media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min-resolution: 144dpi) {
423
- .chosen-rtl .chosen-search input[type="text"],
424
- .chosen-container-single .chosen-single abbr,
425
- .chosen-container-single .chosen-single div b,
426
- .chosen-container-single .chosen-search input[type="text"],
427
- .chosen-container-multi .chosen-choices .search-choice .search-choice-close,
428
- .chosen-container .chosen-results-scroll-down span,
429
- .chosen-container .chosen-results-scroll-up span {
430
- background-image: url('../images/chosen-sprite@2x.png') !important;
431
- background-size: 52px 37px !important;
432
- background-repeat: no-repeat !important;
433
- }
434
- }
435
- /* @end */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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}.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}
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 .image{float:left}.widget ul.job_listings li.job_listing .image img{left:0;position:relative}.widget ul.job_listings li.job_listing .content{overflow:hidden}.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 DELETED
@@ -1,773 +0,0 @@
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 */
7
-
8
- @secondary: desaturate(lighten(@primary,40%),18%); /* Secondary buttons */
9
- @secondarytext: desaturate(darken(@secondary,60%),18%); /* Text on secondary colour bg */
10
-
11
- @highlight: spin( @primary, 150 ); /* Prices, In stock labels, sales flash */
12
- @highlightext: desaturate(lighten(@highlight,50%),18%); /* Text on highlight colour bg */
13
-
14
- @contentbg: #fff; /* Content BG - Tabs (active state) */
15
- @subtext: #777; /* small, breadcrumbs etc */
16
-
17
- .display-icon {
18
- display: inline-block;
19
- width: 16px;
20
- height: 16px;
21
- -webkit-font-smoothing: antialiased;
22
- font-size: 16px;
23
- font-family: "job-manager" !important;
24
- text-decoration: none;
25
- font-weight: normal;
26
- font-style: normal;
27
- vertical-align: top;
28
- font-size: 16px;
29
- margin: 0 2px 0 0;
30
-
31
- *overflow: auto;
32
- *zoom: 1;
33
- *display: inline;
34
- }
35
-
36
- /* =Global styles/layout
37
- -------------------------------------------------------------- */
38
- .job-manager-message, .job-manager-error, .job-manager-info {
39
- padding: 1em 2em 1em 3.5em !important;
40
- margin: 0 0 2em !important;
41
- position: relative;
42
- background-color: lighten(@secondary,5%);
43
- color: @secondarytext;
44
- border-top: 3px solid @primary;
45
- list-style: none outside !important;
46
- width: auto;
47
- .clearfix;
48
- box-shadow: 0 1px 1px rgba(0,0,0,0.2);
49
- &:before {
50
- content: "";
51
- font-family: sans-serif;
52
- display: inline-block;
53
- position: absolute;
54
- top: 1em;
55
- left: 1.5em;
56
- }
57
- li {
58
- list-style: none outside !important;
59
- padding-left: 0 !important;
60
- margin-left: 0 !important;
61
- }
62
- &.job-manager-message {
63
- border-top-color: #8fae1b;
64
- &:before {
65
- color:#8fae1b;
66
- content: "\2713";
67
- }
68
- }
69
- &.job-manager-info {
70
- border-top-color: #1e85be;
71
- &:before {
72
- color:#1e85be;
73
- content: "i";
74
- font-family: Times, Georgia, serif;
75
- font-style: italic;
76
- }
77
- }
78
- &.job-manager-error {
79
- border-top-color: #b81c23;
80
- &:before {
81
- color:#b81c23;
82
- content: "\00d7";
83
- font-weight: 700;
84
- }
85
- }
86
- }
87
-
88
- .job-manager-form {
89
- fieldset {
90
- margin: 0 0 1em 0;
91
- padding: 0 0 1em 0;
92
- line-height: 2em;
93
- border: 0;
94
- border-bottom: 1px solid #eee;
95
- .clearfix;
96
- label {
97
- display: block;
98
- margin: 0;
99
- width: 29%;
100
- float: left;
101
- vertical-align: middle;
102
- small {
103
- opacity: .75;
104
- font-size: 0.83em;
105
- }
106
- }
107
- div.field {
108
- width: 70%;
109
- float: right;
110
- vertical-align: middle;
111
- }
112
- .wp-editor-container {
113
- border: 1px solid #ccc;
114
- -webkit-border-radius: 3px;
115
- -moz-border-radius: 3px;
116
- border-radius: 3px;
117
- }
118
- .account-sign-in {
119
- .button {
120
- margin-right: .5em;
121
- &:before {
122
- .display-icon;
123
- content: '\e808';
124
- }
125
- }
126
- }
127
- abbr.required {
128
- color: red;
129
- font-weight: bold;
130
- border: 0;
131
- }
132
- input.input-text, textarea, select {
133
- margin: 0;
134
- vertical-align: middle;
135
- width: 100%;
136
- -webkit-box-sizing: border-box; /* Safari/Chrome, other WebKit */
137
- -moz-box-sizing: border-box; /* Firefox, other Gecko */
138
- box-sizing: border-box; /* Opera/IE 8+ */
139
- }
140
- small.description {
141
- opacity: .75;
142
- font-size: 0.83em;
143
- margin: 1.2em 0 0 0;
144
- display: block;
145
- line-height: 1.2em;
146
- }
147
- .job-manager-uploaded-files {
148
- display: table;
149
- .job-manager-uploaded-file {
150
- line-height: 2em;
151
- font-style: italic;
152
- margin-bottom: 1em;
153
- display: block;
154
- .job-manager-uploaded-file-preview {
155
- img {
156
- height: 64px;
157
- margin: 0;
158
- vertical-align: top;
159
- }
160
- a {
161
- line-height: 64px;
162
- display: inline-block;
163
- padding: 0 0 0 1em;
164
- }
165
- }
166
- .job-manager-uploaded-file-name {
167
- display: block;
168
- }
169
- }
170
- }
171
- }
172
- .submit-job {
173
- padding: 1em 0;
174
- }
175
- .job-manager-term-checklist {
176
- list-style: none outside;
177
- max-height: 200px;
178
- overflow: auto;
179
- margin: 0;
180
- li {
181
- list-style: none outside;
182
- margin: 0;
183
- display: block;
184
- float: none;
185
- label {
186
- width: auto;
187
- float: none;
188
- }
189
- li {
190
- margin: 0 0 0 2em;
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;
215
- ul.job_listings {
216
- margin: 0;
217
- }
218
- }
219
-
220
- .single_job_listing {
221
- .company {
222
- position: relative;
223
- border: 1px solid #eee;
224
- padding: 1em;
225
- margin: 0 0 2em;
226
- display: block;
227
- clear: both;
228
- min-height: 3em;
229
- box-shadow: 0 1px 1px rgba(0,0,0,0.1);
230
-
231
- img {
232
- width: 3em;
233
- height: 3em;
234
- position: absolute;
235
- left: 1em;
236
- float: left;
237
- vertical-align: middle;
238
- box-shadow: none;
239
- }
240
- .name {
241
- margin: 0 0 0 3em;
242
- padding: 0 0 0 1em;
243
- line-height: 1.5em;
244
- a {
245
- float: right;
246
- margin-left: 1em;
247
- }
248
- }
249
- .tagline {
250
- display: block;
251
- margin: 0 0 0 42px;
252
- padding: 0 0 0 1em;
253
- line-height: 1.5em;
254
- font-style: italic;
255
- color: #999;
256
- }
257
- .website:before {
258
- .display-icon;
259
- content: '\e809';
260
- }
261
- .company_twitter:before {
262
- .display-icon;
263
- content: '\e80a';
264
- }
265
- .company_video {
266
- border-top: 1px solid #eee;
267
- padding: 1em 0 0;
268
- margin: 1em 0 0 0;
269
- position: relative;
270
- padding-bottom: 56.25%;
271
- padding-top: 30px;
272
- height: 0;
273
- overflow: hidden;
274
- iframe,
275
- object,
276
- embed {
277
- position: absolute;
278
- top: 0;
279
- left: 0;
280
- width: 100%;
281
- height: 100%;
282
- margin: 0;
283
- display: block;
284
- }
285
- }
286
- }
287
- .meta {
288
- list-style: none outside;
289
- padding: 0;
290
- margin: 0 0 1.5em;
291
- overflow: hidden;
292
- zoom: 1;
293
- clear: both;
294
- li {
295
- margin: 0 1em 0 0;
296
- padding: .5em;
297
- float: left;
298
- line-height: 1em;
299
- color: #999;
300
- }
301
- .job-type {
302
- color: #fff;
303
- background-color: @part-time;
304
- }
305
- .full-time {
306
- background-color: @full-time;
307
- }
308
- .part-time {
309
- background-color: @part-time;
310
- }
311
- .temporary {
312
- background-color: @temporary;
313
- }
314
- .freelance {
315
- background-color: @freelance;
316
- }
317
- .internship {
318
- background-color: @internship;
319
- }
320
- .position-filled, .listing-expired {
321
- color: #b81c23;
322
- }
323
- .location:before {
324
- .display-icon;
325
- content: '\e81d';
326
- }
327
- .date-posted:before {
328
- .display-icon;
329
- content: '\e80f';
330
- }
331
- .position-filled:before, .listing-expired:before {
332
- .display-icon;
333
- content: '\e80e';
334
- }
335
- }
336
- .job_description {
337
- margin: 0 0 1.5em;
338
- }
339
- }
340
- .job-manager-application-wrapper {
341
- clear: both;
342
- border: 1px solid #eee;
343
- padding: .75em 1em 0;
344
- margin: 1em 0;
345
- line-height: 1.5em;
346
- display: block;
347
- position: relative;
348
- box-shadow: 0 1px 1px rgba(0,0,0,0.1);
349
- }
350
- .single_job_listing, .job-manager-application-wrapper {
351
- .application {
352
- padding: 0;
353
- margin: 0 0 1em;
354
- overflow: hidden;
355
-
356
- .application_button, .application_details {
357
- -webkit-box-sizing: border-box; /* Safari/Chrome, other WebKit */
358
- -moz-box-sizing: border-box; /* Firefox, other Gecko */
359
- box-sizing: border-box; /* Opera/IE 8+ */
360
- }
361
- .application_button {
362
- text-align: center;
363
- font-size: 1.1em;
364
- line-height: 1em;
365
- display: inline-block;
366
- margin: 0 .5em 0 0;
367
- padding: 1/1.1em 2em;
368
- outline: 0;
369
- }
370
- .application_details {
371
- clear: both;
372
- border: 1px solid #eee;
373
- padding: .75em 1em 0;
374
- margin: 1em 0;
375
- line-height: 1.5em;
376
- display: block;
377
- position: relative;
378
- box-shadow: 0 1px 1px rgba(0,0,0,0.1);
379
-
380
- p {
381
- margin: 0 0 .75em;
382
- }
383
-
384
- &:before {
385
- content: "";
386
- position: absolute;
387
- margin: -10px 0 0 0;
388
- top: 0;
389
- left: 5em;
390
- width: 0;
391
- height: 0;
392
- border-left: 10px solid transparent;
393
- border-right: 10px solid transparent;
394
- border-bottom:10px solid #eee;
395
- }
396
- &:after {
397
- content: "";
398
- position: absolute;
399
- margin: -9px 0 0 1px;
400
- left: 5em;
401
- top: 0;
402
- width: 0;
403
- height: 0;
404
- border-left: 9px solid transparent;
405
- border-right: 9px solid transparent;
406
- border-bottom: 9px solid #fff;
407
- }
408
- }
409
- }
410
- }
411
- .job_filters {
412
- background: #eee;
413
- .clearfix;
414
-
415
- .search_jobs {
416
- padding: 1em;
417
- .clearfix;
418
- div {
419
- -webkit-box-sizing: border-box; /* Safari/Chrome, other WebKit */
420
- -moz-box-sizing: border-box; /* Firefox, other Gecko */
421
- box-sizing: border-box; /* Opera/IE 8+ */
422
-
423
- label {
424
- display: none;
425
- }
426
- &.search_keywords, &.filter_first {
427
- float: left;
428
- padding-right: .5em;
429
- width: 50%;
430
- }
431
- &.search_location, &.filter_last {
432
- float: right;
433
- padding-left: .5em;
434
- width: 50%;
435
- }
436
- &.search_categories, &.filter_wide {
437
- padding-top: .5em;
438
- clear: both;
439
- width: 100%;
440
- }
441
- .showing_jobs {
442
- a {
443
- padding: .25em;
444
- }
445
- a.active {
446
- background: #ddd;
447
- text-decoration: none;
448
- }
449
- }
450
- }
451
- input, select {
452
- -webkit-box-sizing: border-box; /* Safari/Chrome, other WebKit */
453
- -moz-box-sizing: border-box; /* Firefox, other Gecko */
454
- box-sizing: border-box; /* Opera/IE 8+ */
455
- width: 100%;
456
- }
457
- }
458
- .job_types {
459
- list-style: none outside;
460
- margin: 0;
461
- padding: 0;
462
- font-size: 0.83em;
463
- background: #f9f9f9;
464
- border-top: 1px solid #e5e5e5;
465
- .clearfix;
466
- li {
467
- margin: 0;
468
- padding: .5em 1em;
469
- float: left;
470
- border-right: 1px solid #eee;
471
-
472
- &:last-child {
473
- border-right: 0;
474
- }
475
- }
476
- }
477
-
478
- .showing_jobs {
479
- padding: .5em 1em;
480
- display: none;
481
- font-size: 0.83em;
482
- background: #f9f9f9;
483
- border-top: 1px solid #e5e5e5;
484
-
485
- a {
486
- float: right;
487
- padding-left: 10px;
488
- border: 0;
489
- }
490
- }
491
- }
492
- div.job_listings {
493
- .job-manager-pagination {
494
- text-align: center;
495
- display: block;
496
- padding: 1em 0 1em 0;
497
- border-bottom: 1px solid #eee;
498
- line-height: 1;
499
- }
500
- .load_previous {
501
- border-top: 1px solid #eee;
502
- }
503
- .load_more_jobs + ul.job_listings {
504
- border-top: 0;
505
- }
506
- .load_more_jobs {
507
- text-align: center;
508
- display: block;
509
- padding: 1em 1em 1em 2em;
510
- border-bottom: 1px solid #eee;
511
- font-weight: bold;
512
- &.loading {
513
- background: url(../images/ajax-loader.gif) no-repeat center;
514
- strong {
515
- visibility: hidden;
516
- }
517
- }
518
- &:hover, &:focus {
519
- background-color: #fcfcfc;
520
- border-bottom: 1px solid #eee;
521
- }
522
- }
523
- }
524
- .job_listing_preview {
525
- padding: 0 1em 1em;
526
- border: 5px solid #eee;
527
- }
528
- .single-job_listing .entry-header .attachment-post-thumbnail,
529
- .single-job_listing .job_listing.has-post-thumbnail .post-thumbnail {
530
- display: none;
531
- }
532
- .job_listing_preview_title, .entry-content .job_listing_preview_title {
533
- padding: .5em 1em;
534
- vertical-align: middle;
535
- position: relative;
536
- background: #eee;
537
- h2 {
538
- margin: 0;
539
- clear: none;
540
- }
541
- .button {
542
- float: right;
543
- margin-left: .25em;
544
- }
545
- }
546
- .job_summary_shortcode {
547
- border: 1px solid #ccc;
548
- -moz-border-radius: 4px;
549
- -webkit-border-radius: 4px;
550
- border-radius: 4px;
551
- text-align: center;
552
- position: relative;
553
- box-shadow: 0 2px 4px rgba(0,0,0,0.1),inset 0 1px 0 rgba(255,255,255,0.4);
554
- -webkit-box-sizing: border-box; /* Safari/Chrome, other WebKit */
555
- -moz-box-sizing: border-box; /* Firefox, other Gecko */
556
- box-sizing: border-box; /* Opera/IE 8+ */
557
-
558
- &.aligncenter {
559
- display: block;
560
- margin: 2em auto 2em;
561
- }
562
-
563
- &.alignleft {
564
- float: left;
565
- margin: 0 2em 2em 0;
566
- }
567
-
568
- &.alignright {
569
- float: right;
570
- margin: 0 0 2em 2em;
571
- }
572
-
573
- a {
574
- text-decoration: none;
575
- color: inherit;
576
- }
577
-
578
- img {
579
- margin: 0;
580
- padding: 0;
581
- display: block;
582
- width: 100%;
583
- -moz-border-radius: 0;
584
- -webkit-border-radius: 0;
585
- -moz-border-top-left-radius: 3px;
586
- -moz-border-top-right-radius: 3px;
587
- -webkit-border-top-left-radius: 3px;
588
- -webkit-border-top-right-radius: 3px;
589
- border-radius: 0;
590
- border-top-left-radius: 3px;
591
- border-top-right-radius: 3px;
592
- box-shadow: inset 0 1px 0 rgba(255,255,255,0.4);
593
- }
594
-
595
- .job_summary_content {
596
- padding: 0 1em;
597
- }
598
-
599
- .meta {
600
- font-style: italic;
601
- color: #777;
602
- }
603
-
604
- .job-type {
605
- -moz-border-radius: 1em;
606
- -webkit-border-radius: 1em;
607
- border-radius: 1em;
608
- color: #fff;
609
- text-shadow: 0 1px 0 rgba(255,255,255,0.5);
610
- box-shadow: 0 2px 4px rgba(0,0,0,0.1), inset 0 1px 0 rgba(255,255,255,0.4);
611
- position: absolute;
612
- top: 0;
613
- right: 0;
614
- padding: .5em;
615
- height: 1em;
616
- width: auto;
617
- min-width: 1em;
618
- font-size: 1em;
619
- text-align: center;
620
- vertical-align: middle;
621
- line-height: 1em;
622
- margin: -.5em -.5em 0 0;
623
-
624
- &.full-time {
625
- background-color: @full-time;
626
- }
627
- &.part-time {
628
- background-color: @part-time;
629
- }
630
- &.temporary {
631
- background-color: @temporary;
632
- }
633
- &.freelance {
634
- background-color: @freelance;
635
- }
636
- &.internship {
637
- background-color: @internship;
638
- }
639
- }
640
- }
641
-
642
- #job-manager-job-dashboard {
643
- .account-sign-in {
644
- .button {
645
- margin-right: .5em;
646
- &:before {
647
- .display-icon;
648
- content: '\e808';
649
- }
650
- }
651
- }
652
- table {
653
- ul.job-dashboard-actions {
654
- margin: 0;
655
- padding:0;
656
- visibility: hidden;
657
- font-size: 0.92em;
658
- li {
659
- float: none;
660
- display: inline;
661
- padding: 0;
662
- margin: 0 .5em 0 0;
663
- font-weight: normal;
664
- list-style: none outside;
665
-
666
- &:after {
667
- padding: 0 0 0 .5em;
668
- content: "\2023";
669
- }
670
- &:last-child:after {
671
- content: '';
672
- }
673
- .job-dashboard-action-delete {
674
- color: red;
675
- }
676
- }
677
- }
678
- tr:hover, tr:focus {
679
- ul.job-dashboard-actions {
680
- visibility: visible;
681
- }
682
- }
683
- td, th {
684
- padding: .5em 1em .5em 0;
685
- }
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
- }
698
- }
699
- }
700
-
701
- nav.job-manager-pagination, #content nav.job-manager-pagination {
702
- text-align: center;
703
- ul {
704
- display: inline-block;
705
- white-space: nowrap;
706
- padding:0;
707
- clear: both;
708
- border-left: 1px solid #eee;
709
- margin: 1px;
710
- li {
711
- border-right: 1px solid #eee;
712
- border-top: 1px solid #eee;
713
- border-bottom: 1px solid #eee;
714
- padding: 0;
715
- margin: 0;
716
- float: left;
717
- display: inline;
718
- overflow: hidden;
719
- a, span {
720
- margin: 0;
721
- text-decoration: none;
722
- padding: 0;
723
- line-height: 1em;
724
- font-size: 1em;
725
- font-weight: normal;
726
- padding: .5em;
727
- min-width: 1em;
728
- display: block;
729
- border: 0;
730
- }
731
- span.current, a:hover, a:focus {
732
- background: #eee;
733
- color: darken( #eee, 40 );
734
- }
735
- }
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;
748
- }
749
- }
750
-
751
- .rtl {
752
- .job-manager-form {
753
- label {
754
- float: right;
755
- }
756
- div.field {
757
- float: left;
758
- }
759
- }
760
- .job_listing_preview_title, .entry-content .job_listing_preview_title {
761
- .button {
762
- float: left;
763
- }
764
- }
765
- .single_job_listing {
766
- .meta {
767
- li {
768
- float: right;
769
- margin: 0 0 0 1em;
770
- }
771
- }
772
- }
773
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
assets/css/icons.less DELETED
@@ -1,40 +0,0 @@
1
- @font-face {
2
- font-family: 'job-manager';
3
- src: url('../font/job-manager.eot?4963673');
4
- src: url('../font/job-manager.eot?4963673#iefix') format('embedded-opentype'),
5
- url('../font/job-manager.woff?4963673') format('woff'),
6
- url('../font/job-manager.ttf?4963673') format('truetype'),
7
- url('../font/job-manager.svg?4963673#job-manager') format('svg');
8
- font-weight: normal;
9
- font-style: normal;
10
- }
11
-
12
- @font-face {
13
- font-family: 'jm-logo';
14
- src:url('../font/jm-logo/jm.eot?ycsbky');
15
- src:url('../font/jm-logo/jm.eot?#iefixycsbky') format('embedded-opentype'),
16
- url('../font/jm-logo/jm.woff?ycsbky') format('woff'),
17
- url('../font/jm-logo/jm.ttf?ycsbky') format('truetype'),
18
- url('../font/jm-logo/jm.svg?ycsbky#icomoon') format('svg');
19
- font-weight: normal;
20
- font-style: normal;
21
- }
22
-
23
- .jm-icon {
24
- font-family: "job-manager" !important;
25
- font-style: normal;
26
- font-weight: normal;
27
- speak: none;
28
-
29
- display: inline-block;
30
- text-decoration: inherit;
31
- width: 1em;
32
- text-align: center;
33
-
34
- /* For safety - reset parent styles, that can break glyph codes*/
35
- font-variant: normal;
36
- text-transform: none;
37
-
38
- /* fix buttons height, for twitter bootstrap */
39
- line-height: 1em;
40
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
assets/css/job-listings.css CHANGED
@@ -1 +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}
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 .image{float:left}.widget ul.job_listings li.job_listing .image img{left:0;position:relative}.widget ul.job_listings li.job_listing .content{overflow:hidden}.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 DELETED
@@ -1,218 +0,0 @@
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/css/job-submission.less DELETED
@@ -1,14 +0,0 @@
1
- #wp-link {
2
- #search-panel, #wplink-link-existing-content {
3
- display: none;
4
- }
5
- }
6
-
7
- div#wp-link-wrap.wp-core-ui {
8
- height: 300px;
9
- }
10
-
11
- .wplink-autocomplete.ui-autocomplete {
12
- display: none;
13
- visibility: hidden;
14
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
assets/css/menu.less DELETED
@@ -1,17 +0,0 @@
1
- @import "icons.less";
2
-
3
- /* Menu */
4
- #adminmenu {
5
- #menu-posts-job_listing {
6
- .wp-menu-image:before {
7
- content: '\e800';
8
- .jm-icon;
9
- }
10
- }
11
- #menu-posts-resume {
12
- .wp-menu-image:before {
13
- content: '\e806';
14
- .jm-icon;
15
- }
16
- }
17
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
assets/css/mixins.less DELETED
@@ -1,105 +0,0 @@
1
- @full-time: #90da36;
2
- @part-time: #f08d3c;
3
- @internship:#6033cc;
4
- @freelance: #3399cc;
5
- @temporary: #d93674;
6
-
7
- .clearfix {
8
- zoom: 1; /* For IE 6/7 (trigger hasLayout) */
9
-
10
- &:before, &:after {
11
- content: "";
12
- display: table;
13
- }
14
- &:after {
15
- clear: both;
16
- }
17
- }
18
- .border_radius(@radius:4px) {
19
- -webkit-border-radius:@radius;
20
- border-radius:@radius;
21
- }
22
- .border_radius_right(@radius:4px) {
23
- -webkit-border-top-right-radius: @radius;
24
- -webkit-border-bottom-right-radius: @radius;
25
- border-top-right-radius: @radius;
26
- border-bottom-right-radius: @radius;
27
- }
28
- .border_radius_left(@radius:4px) {
29
- -webkit-border-top-left-radius: @radius;
30
- -webkit-border-bottom-left-radius: @radius;
31
- border-top-left-radius: @radius;
32
- border-bottom-left-radius: @radius;
33
- }
34
- .border_radius_bottom(@radius:4px) {
35
- -webkit-border-bottom-left-radius: @radius;
36
- -webkit-border-bottom-right-radius: @radius;
37
- border-bottom-left-radius: @radius;
38
- border-bottom-right-radius: @radius;
39
- }
40
- .border_radius_top(@radius:4px) {
41
- -webkit-border-top-left-radius: @radius;
42
- -webkit-border-top-right-radius: @radius;
43
- border-top-left-radius: @radius;
44
- border-top-right-radius: @radius;
45
- }
46
- .opacity(@opacity:0.75) {
47
- filter:~"alpha(opacity=@opacity * 100)";
48
- -khtml-opacity: @opacity;
49
- opacity: @opacity;
50
- }
51
- .box_shadow(@shadow_x:3px, @shadow_y:3px, @shadow_rad:3px, @shadow_in:3px, @shadow_color:#888) {
52
- box-shadow:@shadow_x @shadow_y @shadow_rad @shadow_in @shadow_color;
53
- -webkit-box-shadow:@shadow_x @shadow_y @shadow_rad @shadow_in @shadow_color;
54
- -moz-box-shadow:@shadow_x @shadow_y @shadow_rad @shadow_in @shadow_color;
55
- }
56
- .inset_box_shadow(@shadow_x:3px, @shadow_y:3px, @shadow_rad:3px, @shadow_in:3px, @shadow_color:#888) {
57
- box-shadow:inset @shadow_x @shadow_y @shadow_rad @shadow_in @shadow_color;
58
- -webkit-box-shadow:inset @shadow_x @shadow_y @shadow_rad @shadow_in @shadow_color;
59
- -moz-box-shadow:inset @shadow_x @shadow_y @shadow_rad @shadow_in @shadow_color;
60
- }
61
- .text_shadow(@shadow_x:3px, @shadow_y:3px, @shadow_rad:3px, @shadow_color:#fff) {
62
- text-shadow:@shadow_x @shadow_y @shadow_rad @shadow_color;
63
- }
64
- .vertical_gradient(@from: #000, @to: #FFF) {
65
- background: @from;
66
- background: -webkit-gradient(linear, left top, left bottom, from(@from), to(@to));
67
- background: -webkit-linear-gradient(@from, @to);
68
- background: -moz-linear-gradient(center top, @from 0%, @to 100%);
69
- background: -moz-gradient(center top, @from 0%, @to 100%);
70
- }
71
- .transition(@selector:all, @animation:ease-in-out, @duration:.2s) {
72
- -webkit-transition:@selector @animation @duration;
73
- -moz-transition:@selector @animation @duration;
74
- -o-transition:@selector @animation @duration;
75
- transition:@selector @animation @duration;
76
- }
77
- .scale(@ratio:1.5){
78
- -webkit-transform:scale(@ratio);
79
- -moz-transform:scale(@ratio);
80
- -ms-transform:scale(@ratio);
81
- -o-transform:scale(@ratio);
82
- transform:scale(@ratio);
83
- }
84
- .borderbox () {
85
- -webkit-box-sizing: border-box; /* Safari/Chrome, other WebKit */
86
- -moz-box-sizing: border-box; /* Firefox, other Gecko */
87
- box-sizing: border-box; /* Opera/IE 8+ */
88
- }
89
- .darkorlighttextshadow ( @a, @opacity: 0.8 ) when (lightness(@a) >= 65%) { .text_shadow( 0, -1px, 0, rgba(0,0,0,@opacity) ); }
90
- .darkorlighttextshadow ( @a, @opacity: 0.8 ) when (lightness(@a) < 65%) { .text_shadow( 0, 1px, 0, rgba(255,255,255,@opacity) ); }
91
-
92
- .keyframes(@name; @arguments) {
93
- @-o-keyframes @name { @arguments(); }
94
- @-ms-keyframes @name { @arguments(); }
95
- @-moz-keyframes @name { @arguments(); }
96
- @-webkit-keyframes @name { @arguments(); }
97
- @keyframes @name { @arguments(); }
98
- }
99
-
100
- .animation(@animation) {
101
- -o-animation: @animation;
102
- -webkit-animation: @animation;
103
- -moz-animation: @animation;
104
- animation: @animation;
105
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
assets/css/setup.less DELETED
@@ -1,93 +0,0 @@
1
- .help-page-link {
2
- cursor: help;
3
- }
4
-
5
- .wp-job-manager-setup-steps {
6
- margin: 1em 0 2em;
7
- overflow: hidden;
8
- li {
9
- width: 33.3%;
10
- padding: 7px 1em;
11
- font-weight: bold;
12
- margin: 0;
13
- color: #eee;
14
- background: #222222;
15
- float: left;
16
- -moz-box-sizing: border-box;
17
- -webkit-box-sizing: border-box;
18
- box-sizing: border-box;
19
-
20
- &:first-child {
21
- margin-left: 0;
22
- }
23
- &.wp-job-manager-setup-active-step {
24
- background: #0074a2;
25
- color: #eee;
26
- }
27
- }
28
- }
29
-
30
- .wp-job-manager-shortcodes {
31
- td, th {
32
- vertical-align: middle;
33
- p {
34
- margin: 9px 0;
35
- }
36
- }
37
- tr:nth-child(even) {
38
- td, th {
39
- background: #f9f9f9;
40
- }
41
- }
42
- }
43
-
44
- .wp-job-manager-next-steps {
45
- font-size: 1.1em;
46
- list-style: disc inside;
47
- margin: 1.5em 2em;
48
- }
49
-
50
- .wp-job-manager-support-the-plugin {
51
- background: #fff;
52
- padding: 2em;
53
- margin: 2em 0;
54
- h3 {
55
- margin-top: 0;
56
- }
57
- ul {
58
- margin-bottom: 0;
59
- }
60
- li {
61
- line-height: 2em;
62
- font-size: 1.1em;
63
- a {
64
- text-decoration: none;
65
- }
66
- }
67
- li a:before {
68
- font-family: "dashicons";
69
- font-size: 2em;
70
- vertical-align: middle;
71
- padding-right: .25em;
72
- }
73
- li.icon-review {
74
- a:before {
75
- content: "\f155";
76
- }
77
- }
78
- li.icon-localization {
79
- a:before {
80
- content: "\f319";
81
- }
82
- }
83
- li.icon-code {
84
- a:before {
85
- content: "\f111";
86
- }
87
- }
88
- li.icon-forum {
89
- a:before {
90
- content: "\f328";
91
- }
92
- }
93
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
assets/js/admin.js DELETED
@@ -1,94 +0,0 @@
1
- jQuery(document).ready(function($) {
2
- // Tooltips
3
- $( '.tips, .help_tip' ).tipTip({
4
- 'attribute' : 'data-tip',
5
- 'fadeIn' : 50,
6
- 'fadeOut' : 50,
7
- 'delay' : 200
8
- });
9
-
10
- // Author
11
- $( 'p.form-field-author' ).on( 'click', 'a.change-author', function() {
12
- $(this).closest( 'p' ).find('.current-author').hide();
13
- $(this).closest( 'p' ).find('.change-author').show();
14
- return false;
15
- });
16
-
17
- // Uploading files
18
- var file_frame;
19
- var file_target_input;
20
- var file_target_wrapper;
21
-
22
- $( document.body ).on('click', '.wp_job_manager_add_another_file_button', function( event ){
23
- event.preventDefault();
24
-
25
- var field_name = $( this ).data( 'field_name' );
26
- var field_placeholder = $( this ).data( 'field_placeholder' );
27
- var button_text = $( this ).data( 'uploader_button_text' );
28
- var button = $( this ).data( 'uploader_button' );
29
- var view_button = $( this ).data( 'view_button' );
30
-
31
- $( this ).before( '<span class="file_url"><input type="text" name="' + field_name + '[]" placeholder="' + field_placeholder + '" /><button class="button button-small wp_job_manager_upload_file_button" data-uploader_button_text="' + button_text + '">' + button + '</button><button class="button button-small wp_job_manager_view_file_button">' + view_button + '</button></span>' );
32
- } );
33
-
34
- $( document.body ).on('click', '.wp_job_manager_view_file_button', function ( event ) {
35
- event.preventDefault();
36
-
37
- file_target_wrapper = $( this ).closest( '.file_url' );
38
- file_target_input = file_target_wrapper.find( 'input' );
39
-
40
- var attachment_url = file_target_input.val();
41
-
42
- if ( attachment_url.indexOf( '://' ) > - 1 ) {
43
- window.open( attachment_url, '_blank' );
44
- } else {
45
- file_target_input.addClass( 'file_no_url' );
46
- setTimeout( function () {
47
- file_target_input.removeClass( 'file_no_url' );
48
- }, 1000 );
49
- }
50
-
51
- });
52
-
53
- $( document.body ).on('click', '.wp_job_manager_upload_file_button', function( event ){
54
- event.preventDefault();
55
-
56
- file_target_wrapper = $( this ).closest('.file_url');
57
- file_target_input = file_target_wrapper.find('input');
58
-
59
- // If the media frame already exists, reopen it.
60
- if ( file_frame ) {
61
- file_frame.open();
62
- return;
63
- }
64
-
65
- // Create the media frame.
66
- file_frame = wp.media.frames.file_frame = wp.media({
67
- title: $( this ).data( 'uploader_title' ),
68
- button: {
69
- text: $( this ).data( 'uploader_button_text' )
70
- },
71
- multiple: false // Set to true to allow multiple files to be selected
72
- });
73
-
74
- // When an image is selected, run a callback.
75
- file_frame.on( 'select', function() {
76
- // We set multiple to false so only get one image from the uploader
77
- var attachment = file_frame.state().get('selection').first().toJSON();
78
-
79
- $( file_target_input ).val( attachment.url );
80
- });
81
-
82
- // Finally, open the modal
83
- file_frame.open();
84
- });
85
- });
86
-
87
- jQuery(document).ready(function($) {
88
- var taxonomy = 'job_listing_type';
89
- $('#' + taxonomy + 'checklist li :radio, #' + taxonomy + 'checklist-pop :radio').live( 'click', function(){
90
- var t = $(this), c = t.is(':checked'), id = t.val();
91
- $('#' + taxonomy + 'checklist li :radio, #' + taxonomy + 'checklist-pop :radio').prop('checked',false);
92
- $('#in-' + taxonomy + '-' + id + ', #in-popular-' + taxonomy + '-' + id).prop( 'checked', c );
93
- });
94
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
assets/js/ajax-file-upload.js DELETED
@@ -1,95 +0,0 @@
1
- /* global job_manager_ajax_file_upload */
2
- jQuery(function($) {
3
- $('.wp-job-manager-file-upload').each(function(){
4
- $(this).fileupload({
5
- dataType: 'json',
6
- dropZone: $(this),
7
- url: job_manager_ajax_file_upload.ajax_url.toString().replace( '%%endpoint%%', 'upload_file' ),
8
- maxNumberOfFiles: 1,
9
- formData: {
10
- script: true
11
- },
12
- add: function (e, data) {
13
- var $file_field = $( this );
14
- var $form = $file_field.closest( 'form' );
15
- var $uploaded_files = $file_field.parent().find('.job-manager-uploaded-files');
16
- var uploadErrors = [];
17
-
18
- // Validate type
19
- var allowed_types = $(this).data('file_types');
20
-
21
- if ( allowed_types ) {
22
- var acceptFileTypes = new RegExp( '(\.|\/)(' + allowed_types + ')$', 'i' );
23
-
24
- if ( data.originalFiles[0].name.length && ! acceptFileTypes.test( data.originalFiles[0].name ) ) {
25
- uploadErrors.push( job_manager_ajax_file_upload.i18n_invalid_file_type + ' ' + allowed_types );
26
- }
27
- }
28
-
29
- if ( uploadErrors.length > 0 ) {
30
- window.alert( uploadErrors.join( '\n' ) );
31
- } else {
32
- $form.find(':input[type="submit"]').attr( 'disabled', 'disabled' );
33
- data.context = $('<progress value="" max="100"></progress>').appendTo( $uploaded_files );
34
- data.submit();
35
- }
36
- },
37
- progress: function (e, data) {
38
- var progress = parseInt(data.loaded / data.total * 100, 10);
39
- data.context.val( progress );
40
- },
41
- fail: function (e, data) {
42
- var $file_field = $( this );
43
- var $form = $file_field.closest( 'form' );
44
-
45
- if ( data.errorThrown ) {
46
- window.alert( data.errorThrown );
47
- }
48
-
49
- data.context.remove();
50
-
51
- $form.find(':input[type="submit"]').removeAttr( 'disabled' );
52
- },
53
- done: function (e, data) {
54
- var $file_field = $( this );
55
- var $form = $file_field.closest( 'form' );
56
- var $uploaded_files = $file_field.parent().find('.job-manager-uploaded-files');
57
- var multiple = $file_field.attr( 'multiple' ) ? 1 : 0;
58
- var image_types = [ 'jpg', 'gif', 'png', 'jpeg', 'jpe' ];
59
-
60
- data.context.remove();
61
-
62
- // Handle JSON errors when success is false
63
- if( typeof data.result.success !== 'undefined' && ! data.result.success ){
64
- window.alert( data.result.data );
65
- }
66
-
67
- $.each(data.result.files, function(index, file) {
68
- if ( file.error ) {
69
- window.alert( file.error );
70
- } else {
71
- var html;
72
- if ( $.inArray( file.extension, image_types ) >= 0 ) {
73
- html = $.parseHTML( job_manager_ajax_file_upload.js_field_html_img );
74
- $( html ).find('.job-manager-uploaded-file-preview img').attr( 'src', file.url );
75
- } else {
76
- html = $.parseHTML( job_manager_ajax_file_upload.js_field_html );
77
- $( html ).find('.job-manager-uploaded-file-name code').text( file.name );
78
- }
79
-
80
- $( html ).find('.input-text').val( file.url );
81
- $( html ).find('.input-text').attr( 'name', 'current_' + $file_field.attr( 'name' ) );
82
-
83
- if ( multiple ) {
84
- $uploaded_files.append( html );
85
- } else {
86
- $uploaded_files.html( html );
87
- }
88
- }
89
- });
90
-
91
- $form.find(':input[type="submit"]').removeAttr( 'disabled' );
92
- }
93
- });
94
- });
95
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
assets/js/ajax-filters.js DELETED
@@ -1,298 +0,0 @@
1
- /* global job_manager_ajax_filters */
2
- jQuery( document ).ready( function ( $ ) {
3
-
4
- var xhr = [];
5
-
6
- $( '.job_listings' ).on( 'update_results', function ( event, page, append, loading_previous ) {
7
- var data = '';
8
- var target = $( this );
9
- var form = target.find( '.job_filters' );
10
- var showing = target.find( '.showing_jobs' );
11
- var results = target.find( '.job_listings' );
12
- var per_page = target.data( 'per_page' );
13
- var orderby = target.data( 'orderby' );
14
- var order = target.data( 'order' );
15
- var featured = target.data( 'featured' );
16
- var filled = target.data( 'filled' );
17
- var job_types = target.data( 'job_types' );
18
- var post_status = target.data( 'post_status' );
19
- var index = $( 'div.job_listings' ).index(this);
20
- var categories, keywords, location;
21
-
22
- if ( index < 0 ) {
23
- return;
24
- }
25
-
26
- if ( xhr[index] ) {
27
- xhr[index].abort();
28
- }
29
-
30
- if ( ! append ) {
31
- $( results ).addClass( 'loading' );
32
- $( 'li.job_listing, li.no_job_listings_found', results ).css( 'visibility', 'hidden' );
33
-
34
- // Not appending. If page > 1, we should show a load previous button so the user can get to earlier-page listings if needed
35
- if ( page > 1 && true !== target.data( 'show_pagination' ) ) {
36
- $( results ).before( '<a class="load_more_jobs load_previous" href="#"><strong>' + job_manager_ajax_filters.i18n_load_prev_listings + '</strong></a>' );
37
- } else {
38
- target.find( '.load_previous' ).remove();
39
- }
40
-
41
- target.find( '.load_more_jobs' ).data( 'page', page );
42
- }
43
-
44
- if ( true === target.data( 'show_filters' ) ) {
45
-
46
- var filter_job_type = [];
47
-
48
- $( ':input[name="filter_job_type[]"]:checked, :input[name="filter_job_type[]"][type="hidden"], :input[name="filter_job_type"]', form ).each( function () {
49
- filter_job_type.push( $( this ).val() );
50
- } );
51
-
52
- categories = form.find( ':input[name^="search_categories"]' ).map( function () {
53
- return $( this ).val();
54
- } ).get();
55
- keywords = '';
56
- location = '';
57
- var $keywords = form.find( ':input[name="search_keywords"]' );
58
- var $location = form.find( ':input[name="search_location"]' );
59
-
60
- // Workaround placeholder scripts
61
- if ( $keywords.val() !== $keywords.attr( 'placeholder' ) ) {
62
- keywords = $keywords.val();
63
- }
64
-
65
- if ( $location.val() !== $location.attr( 'placeholder' ) ) {
66
- location = $location.val();
67
- }
68
-
69
- data = {
70
- lang: job_manager_ajax_filters.lang,
71
- search_keywords: keywords,
72
- search_location: location,
73
- search_categories: categories,
74
- filter_job_type: filter_job_type,
75
- filter_post_status: post_status,
76
- per_page: per_page,
77
- orderby: orderby,
78
- order: order,
79
- page: page,
80
- featured: featured,
81
- filled: filled,
82
- show_pagination: target.data( 'show_pagination' ),
83
- form_data: form.serialize()
84
- };
85
-
86
- } else {
87
-
88
- categories = target.data( 'categories' );
89
- keywords = target.data( 'keywords' );
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
-
99
- data = {
100
- lang: job_manager_ajax_filters.lang,
101
- search_categories: categories,
102
- search_keywords: keywords,
103
- search_location: location,
104
- filter_post_status: post_status,
105
- filter_job_type: job_types,
106
- per_page: per_page,
107
- orderby: orderby,
108
- order: order,
109
- page: page,
110
- featured: featured,
111
- filled: filled,
112
- show_pagination: target.data( 'show_pagination' )
113
- };
114
-
115
- }
116
-
117
- xhr[index] = $.ajax( {
118
- type: 'POST',
119
- url: job_manager_ajax_filters.ajax_url.toString().replace( '%%endpoint%%', 'get_listings' ),
120
- data: data,
121
- success: function ( result ) {
122
- if ( result ) {
123
- try {
124
- if ( result.showing ) {
125
- $( showing ).show().html( '<span>' + result.showing + '</span>' + result.showing_links );
126
- } else {
127
- $( showing ).hide();
128
- }
129
-
130
- if ( result.showing_all ) {
131
- $( showing ).addClass( 'wp-job-manager-showing-all' );
132
- } else {
133
- $( showing ).removeClass( 'wp-job-manager-showing-all' );
134
- }
135
-
136
- if ( result.html ) {
137
- if ( append && loading_previous ) {
138
- $( results ).prepend( result.html );
139
- } else if ( append ) {
140
- $( results ).append( result.html );
141
- } else {
142
- $( results ).html( result.html );
143
- }
144
- }
145
-
146
- if ( true === target.data( 'show_pagination' ) ) {
147
- target.find('.job-manager-pagination').remove();
148
-
149
- if ( result.pagination ) {
150
- target.append( result.pagination );
151
- }
152
- } else {
153
- if ( ! result.found_jobs || result.max_num_pages <= page ) {
154
- $( '.load_more_jobs:not(.load_previous)', target ).hide();
155
- } else if ( ! loading_previous ) {
156
- $( '.load_more_jobs', target ).show();
157
- }
158
- $( '.load_more_jobs', target ).removeClass( 'loading' );
159
- $( 'li.job_listing', results ).css( 'visibility', 'visible' );
160
- }
161
-
162
- $( results ).removeClass( 'loading' );
163
-
164
- target.triggerHandler( 'updated_results', result );
165
-
166
- } catch ( err ) {
167
- if ( window.console ) {
168
- window.console.log( err );
169
- }
170
- }
171
- }
172
- },
173
- error: function ( jqXHR, textStatus, error ) {
174
- if ( window.console && 'abort' !== textStatus ) {
175
- window.console.log( textStatus + ': ' + error );
176
- }
177
- },
178
- statusCode: {
179
- 404: function() {
180
- if ( window.console ) {
181
- window.console.log( 'Error 404: Ajax Endpoint cannot be reached. Go to Settings > Permalinks and save to resolve.' );
182
- }
183
- }
184
- }
185
- } );
186
- } );
187
-
188
- $( '#search_keywords, #search_location, .job_types :input, #search_categories, .job-manager-filter' ).change( function() {
189
- var target = $( this ).closest( 'div.job_listings' );
190
- target.triggerHandler( 'update_results', [ 1, false ] );
191
- job_manager_store_state( target, 1 );
192
- } )
193
-
194
- .on( 'keyup', function(e) {
195
- if ( e.which === 13 ) {
196
- $( this ).trigger( 'change' );
197
- }
198
- } );
199
-
200
- $( '.job_filters' ).on( 'click', '.reset', function () {
201
- var target = $( this ).closest( 'div.job_listings' );
202
- var form = $( this ).closest( 'form' );
203
-
204
- form.find( ':input[name="search_keywords"], :input[name="search_location"], .job-manager-filter' ).not(':input[type="hidden"]').val( '' ).trigger( 'chosen:updated' );
205
- form.find( ':input[name^="search_categories"]' ).not(':input[type="hidden"]').val( '' ).trigger( 'chosen:updated' );
206
- $( ':input[name="filter_job_type[]"]', form ).not(':input[type="hidden"]').attr( 'checked', 'checked' );
207
-
208
- target.triggerHandler( 'reset' );
209
- target.triggerHandler( 'update_results', [ 1, false ] );
210
- job_manager_store_state( target, 1 );
211
-
212
- return false;
213
- } );
214
-
215
- $( document.body ).on( 'click', '.load_more_jobs', function() {
216
- var target = $( this ).closest( 'div.job_listings' );
217
- var page = parseInt( ( $( this ).data( 'page' ) || 1 ), 10 );
218
- var loading_previous = false;
219
-
220
- $(this).addClass( 'loading' );
221
-
222
- if ( $(this).is('.load_previous') ) {
223
- page = page - 1;
224
- loading_previous = true;
225
- if ( page === 1 ) {
226
- $(this).remove();
227
- } else {
228
- $( this ).data( 'page', page );
229
- }
230
- } else {
231
- page = page + 1;
232
- $( this ).data( 'page', page );
233
- job_manager_store_state( target, page );
234
- }
235
-
236
- target.triggerHandler( 'update_results', [ page, true, loading_previous ] );
237
- return false;
238
- } );
239
-
240
- $( 'div.job_listings' ).on( 'click', '.job-manager-pagination a', function() {
241
- var target = $( this ).closest( 'div.job_listings' );
242
- var page = $( this ).data( 'page' );
243
-
244
- job_manager_store_state( target, page );
245
-
246
- target.triggerHandler( 'update_results', [ page, false ] );
247
-
248
- $( 'body, html' ).animate({
249
- scrollTop: target.offset().top
250
- }, 600 );
251
-
252
- return false;
253
- } );
254
-
255
- if ( $.isFunction( $.fn.chosen ) ) {
256
- if ( job_manager_ajax_filters.is_rtl === 1 ) {
257
- $( 'select[name^="search_categories"]' ).addClass( 'chosen-rtl' );
258
- }
259
- $( 'select[name^="search_categories"]' ).chosen({ search_contains: true });
260
- }
261
-
262
- var $supports_html5_history = false;
263
- if ( window.history && window.history.pushState ) {
264
- $supports_html5_history = true;
265
- }
266
-
267
- var location = document.location.href.split('#')[0];
268
-
269
- function job_manager_store_state( target, page ) {
270
- if ( $supports_html5_history ) {
271
- var form = target.find( '.job_filters' );
272
- var data = $( form ).serialize();
273
- var index = $( 'div.job_listings' ).index( target );
274
- window.history.replaceState( { id: 'job_manager_state', page: page, data: data, index: index }, '', location + '#s=1' );
275
- }
276
- }
277
-
278
- // Inital job and form population
279
- $(window).on( 'load', function() {
280
- $( '.job_filters' ).each( function() {
281
- var target = $( this ).closest( 'div.job_listings' );
282
- var form = target.find( '.job_filters' );
283
- var inital_page = 1;
284
- var index = $( 'div.job_listings' ).index( target );
285
-
286
- if ( window.history.state && window.location.hash ) {
287
- var state = window.history.state;
288
- if ( state.id && 'job_manager_state' === state.id && index === state.index ) {
289
- inital_page = state.page;
290
- form.deserialize( state.data );
291
- form.find( ':input[name^="search_categories"]' ).not(':input[type="hidden"]').trigger( 'chosen:updated' );
292
- }
293
- }
294
-
295
- target.triggerHandler( 'update_results', [ inital_page, false ] );
296
- });
297
- });
298
- } );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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&&("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])})})});
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){if(e(p).addClass("loading"),e("li.job_listing, li.no_job_listings_found",p).css("visibility","hidden"),i>1&&!0!==_.data("show_pagination")){var y=jQuery("<strong>").text(job_manager_ajax_filters.i18n_load_prev_listings).wrap('<a class="load_more_jobs load_previous" href="#"></a>');e(p).before(y)}else _.find(".load_previous").remove();_.find(".load_more_jobs").data("page",i)}if(!0===_.data("show_filters")){var k=[];e(':input[name="filter_job_type[]"]:checked, :input[name="filter_job_type[]"][type="hidden"], :input[name="filter_job_type"]',g).each(function(){k.push(e(this).val())}),s=g.find(':input[name^="search_categories"]').map(function(){return e(this).val()}).get(),r="",d="";var x=g.find(':input[name="search_keywords"]'),C=g.find(':input[name="search_location"]');x.val()!==x.attr("placeholder")&&(r=x.val()),C.val()!==C.attr("placeholder")&&(d=C.val()),l={lang:job_manager_ajax_filters.lang,search_keywords:r,search_location:d,search_categories:s,filter_job_type:k,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{if(a.showing){var t=jQuery("<span>").html(a.showing);e(c).show().html("").html(a.showing_links).prepend(t)}else 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 DELETED
@@ -1,27 +0,0 @@
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/job-application.js DELETED
@@ -1,42 +0,0 @@
1
- jQuery(document).ready(function($) {
2
- // Slide toggle
3
- if ( ! $( 'body' ).hasClass( 'job-application-details-keep-open' ) ) {
4
- $( '.application_details' ).hide();
5
- }
6
-
7
- $( document.body ).on( 'click', '.job_application .application_button', function() {
8
- var $details = $(this).siblings('.application_details').first();
9
- var $button = $(this);
10
- $details.slideToggle( 400, function() {
11
- if ( ! $(this).is(':visible') ) {
12
- // Only care if we toggled to be visible
13
- return;
14
- }
15
-
16
- // If max(33% height, 200px) of the application details aren't shown, scroll.
17
- var minimum_details_threshold = Math.max( Math.min( $details.outerHeight(), 200 ), $details.outerHeight() * .33 );
18
- var details_visible_threshold = $details.offset().top + minimum_details_threshold;
19
- var nice_buffer = 5;
20
- var top_viewport_buffer = nice_buffer;
21
- // We can't account for all theme headers with a fixed position on the top, but we can at least account for #wpadminbar and a fixed <header>
22
- if ( $( '#wpadminbar' ).length > 0 && 'fixed' === $( '#wpadminbar' ).css( 'position' ) ) {
23
- top_viewport_buffer += $( '#wpadminbar' ).outerHeight();
24
- }
25
- if ( $( 'header' ).length > 0 && 'fixed' === $( 'header' ).css( 'position' ) ) {
26
- top_viewport_buffer += $( 'header' ).outerHeight();
27
- }
28
- var bottom_of_screen = $(window).scrollTop() + window.innerHeight;
29
- var amount_hidden = $details.offset().top + $details.outerHeight() - bottom_of_screen;
30
- var window_height = window.innerHeight - top_viewport_buffer;
31
-
32
- if ( amount_hidden > 0 && $details.outerHeight() < ( window_height * .9 ) ) {
33
- // Application contents are shorter than the 90% of viewport, just scroll to show the bottom of details (with `nice_buffer` buffer)
34
- $('html, body').animate( { scrollTop: $(window).scrollTop() + amount_hidden + nice_buffer }, 400 );
35
- } else if( bottom_of_screen < details_visible_threshold ){
36
- // The application box is larger than the viewport AND our `minimum_details_threshold` is not visible.
37
- // Scroll to show top of application button, showing top of details
38
- $('html, body').animate( { scrollTop: $button.offset().top - top_viewport_buffer }, 600 );
39
- }
40
- });
41
- });
42
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
assets/js/job-dashboard.js DELETED
@@ -1,8 +0,0 @@
1
- /* global job_manager_job_dashboard */
2
- jQuery(document).ready(function($) {
3
-
4
- $('.job-dashboard-action-delete').click(function() {
5
- return window.confirm( job_manager_job_dashboard.i18n_confirm_delete );
6
- });
7
-
8
- });
 
 
 
 
 
 
 
 
assets/js/job-submission.js DELETED
@@ -1,10 +0,0 @@
1
- jQuery(document).ready(function($) {
2
- $( document.body ).on( 'click', '.job-manager-remove-uploaded-file', function() {
3
- $(this).closest( '.job-manager-uploaded-file' ).remove();
4
- return false;
5
- });
6
- $( document.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/jquery-chosen/chosen.jquery.js DELETED
@@ -1,1229 +0,0 @@
1
- /*!
2
- Chosen, a Select Box Enhancer for jQuery and Prototype
3
- by Patrick Filler for Harvest, http://getharvest.com
4
-
5
- Version 1.2.0
6
- Full source at https://github.com/harvesthq/chosen
7
- Copyright (c) 2011-2014 Harvest http://getharvest.com
8
-
9
- MIT License, https://github.com/harvesthq/chosen/blob/master/LICENSE.md
10
- This file is generated by `grunt build`, do not edit it by hand.
11
- */
12
-
13
- (function() {
14
- var $, AbstractChosen, Chosen, SelectParser, _ref,
15
- __hasProp = {}.hasOwnProperty,
16
- __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
17
-
18
- SelectParser = (function() {
19
- function SelectParser() {
20
- this.options_index = 0;
21
- this.parsed = [];
22
- }
23
-
24
- SelectParser.prototype.add_node = function(child) {
25
- if (child.nodeName.toUpperCase() === "OPTGROUP") {
26
- return this.add_group(child);
27
- } else {
28
- return this.add_option(child);
29
- }
30
- };
31
-
32
- SelectParser.prototype.add_group = function(group) {
33
- var group_position, option, _i, _len, _ref, _results;
34
- group_position = this.parsed.length;
35
- this.parsed.push({
36
- array_index: group_position,
37
- group: true,
38
- label: this.escapeExpression(group.label),
39
- children: 0,
40
- disabled: group.disabled
41
- });
42
- _ref = group.childNodes;
43
- _results = [];
44
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
45
- option = _ref[_i];
46
- _results.push(this.add_option(option, group_position, group.disabled));
47
- }
48
- return _results;
49
- };
50
-
51
- SelectParser.prototype.add_option = function(option, group_position, group_disabled) {
52
- if (option.nodeName.toUpperCase() === "OPTION") {
53
- if (option.text !== "") {
54
- if (group_position != null) {
55
- this.parsed[group_position].children += 1;
56
- }
57
- this.parsed.push({
58
- array_index: this.parsed.length,
59
- options_index: this.options_index,
60
- value: option.value,
61
- text: option.text,
62
- html: option.innerHTML,
63
- selected: option.selected,
64
- disabled: group_disabled === true ? group_disabled : option.disabled,
65
- group_array_index: group_position,
66
- classes: option.className,
67
- style: option.style.cssText
68
- });
69
- } else {
70
- this.parsed.push({
71
- array_index: this.parsed.length,
72
- options_index: this.options_index,
73
- empty: true
74
- });
75
- }
76
- return this.options_index += 1;
77
- }
78
- };
79
-
80
- SelectParser.prototype.escapeExpression = function(text) {
81
- var map, unsafe_chars;
82
- if ((text == null) || text === false) {
83
- return "";
84
- }
85
- if (!/[\&\<\>\"\'\`]/.test(text)) {
86
- return text;
87
- }
88
- map = {
89
- "<": "&lt;",
90
- ">": "&gt;",
91
- '"': "&quot;",
92
- "'": "&#x27;",
93
- "`": "&#x60;"
94
- };
95
- unsafe_chars = /&(?!\w+;)|[\<\>\"\'\`]/g;
96
- return text.replace(unsafe_chars, function(chr) {
97
- return map[chr] || "&amp;";
98
- });
99
- };
100
-
101
- return SelectParser;
102
-
103
- })();
104
-
105
- SelectParser.select_to_array = function(select) {
106
- var child, parser, _i, _len, _ref;
107
- parser = new SelectParser();
108
- _ref = select.childNodes;
109
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
110
- child = _ref[_i];
111
- parser.add_node(child);
112
- }
113
- return parser.parsed;
114
- };
115
-
116
- AbstractChosen = (function() {
117
- function AbstractChosen(form_field, options) {
118
- this.form_field = form_field;
119
- this.options = options != null ? options : {};
120
- if (!AbstractChosen.browser_is_supported()) {
121
- return;
122
- }
123
- this.is_multiple = this.form_field.multiple;
124
- this.set_default_text();
125
- this.set_default_values();
126
- this.setup();
127
- this.set_up_html();
128
- this.register_observers();
129
- }
130
-
131
- AbstractChosen.prototype.set_default_values = function() {
132
- var _this = this;
133
- this.click_test_action = function(evt) {
134
- return _this.test_active_click(evt);
135
- };
136
- this.activate_action = function(evt) {
137
- return _this.activate_field(evt);
138
- };
139
- this.active_field = false;
140
- this.mouse_on_container = false;
141
- this.results_showing = false;
142
- this.result_highlighted = null;
143
- this.allow_single_deselect = (this.options.allow_single_deselect != null) && (this.form_field.options[0] != null) && this.form_field.options[0].text === "" ? this.options.allow_single_deselect : false;
144
- this.disable_search_threshold = this.options.disable_search_threshold || 0;
145
- this.disable_search = this.options.disable_search || false;
146
- this.enable_split_word_search = this.options.enable_split_word_search != null ? this.options.enable_split_word_search : true;
147
- this.group_search = this.options.group_search != null ? this.options.group_search : true;
148
- this.search_contains = this.options.search_contains || false;
149
- this.single_backstroke_delete = this.options.single_backstroke_delete != null ? this.options.single_backstroke_delete : true;
150
- this.max_selected_options = this.options.max_selected_options || Infinity;
151
- this.inherit_select_classes = this.options.inherit_select_classes || false;
152
- this.display_selected_options = this.options.display_selected_options != null ? this.options.display_selected_options : true;
153
- return this.display_disabled_options = this.options.display_disabled_options != null ? this.options.display_disabled_options : true;
154
- };
155
-
156
- AbstractChosen.prototype.set_default_text = function() {
157
- if (this.form_field.getAttribute("data-placeholder")) {
158
- this.default_text = this.form_field.getAttribute("data-placeholder");
159
- } else if (this.is_multiple) {
160
- this.default_text = this.options.placeholder_text_multiple || this.options.placeholder_text || AbstractChosen.default_multiple_text;
161
- } else {
162
- this.default_text = this.options.placeholder_text_single || this.options.placeholder_text || AbstractChosen.default_single_text;
163
- }
164
- return this.results_none_found = this.form_field.getAttribute("data-no_results_text") || this.options.no_results_text || AbstractChosen.default_no_result_text;
165
- };
166
-
167
- AbstractChosen.prototype.mouse_enter = function() {
168
- return this.mouse_on_container = true;
169
- };
170
-
171
- AbstractChosen.prototype.mouse_leave = function() {
172
- return this.mouse_on_container = false;
173
- };
174
-
175
- AbstractChosen.prototype.input_focus = function(evt) {
176
- var _this = this;
177
- if (this.is_multiple) {
178
- if (!this.active_field) {
179
- return setTimeout((function() {
180
- return _this.container_mousedown();
181
- }), 50);
182
- }
183
- } else {
184
- if (!this.active_field) {
185
- return this.activate_field();
186
- }
187
- }
188
- };
189
-
190
- AbstractChosen.prototype.input_blur = function(evt) {
191
- var _this = this;
192
- if (!this.mouse_on_container) {
193
- this.active_field = false;
194
- return setTimeout((function() {
195
- return _this.blur_test();
196
- }), 100);
197
- }
198
- };
199
-
200
- AbstractChosen.prototype.results_option_build = function(options) {
201
- var content, data, _i, _len, _ref;
202
- content = '';
203
- _ref = this.results_data;
204
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
205
- data = _ref[_i];
206
- if (data.group) {
207
- content += this.result_add_group(data);
208
- } else {
209
- content += this.result_add_option(data);
210
- }
211
- if (options != null ? options.first : void 0) {
212
- if (data.selected && this.is_multiple) {
213
- this.choice_build(data);
214
- } else if (data.selected && !this.is_multiple) {
215
- this.single_set_selected_text(data.text);
216
- }
217
- }
218
- }
219
- return content;
220
- };
221
-
222
- AbstractChosen.prototype.result_add_option = function(option) {
223
- var classes, option_el;
224
- if (!option.search_match) {
225
- return '';
226
- }
227
- if (!this.include_option_in_results(option)) {
228
- return '';
229
- }
230
- classes = [];
231
- if (!option.disabled && !(option.selected && this.is_multiple)) {
232
- classes.push("active-result");
233
- }
234
- if (option.disabled && !(option.selected && this.is_multiple)) {
235
- classes.push("disabled-result");
236
- }
237
- if (option.selected) {
238
- classes.push("result-selected");
239
- }
240
- if (option.group_array_index != null) {
241
- classes.push("group-option");
242
- }
243
- if (option.classes !== "") {
244
- classes.push(option.classes);
245
- }
246
- option_el = document.createElement("li");
247
- option_el.className = classes.join(" ");
248
- option_el.style.cssText = option.style;
249
- option_el.setAttribute("data-option-array-index", option.array_index);
250
- option_el.innerHTML = option.search_text;
251
- return this.outerHTML(option_el);
252
- };
253
-
254
- AbstractChosen.prototype.result_add_group = function(group) {
255
- var group_el;
256
- if (!(group.search_match || group.group_match)) {
257
- return '';
258
- }
259
- if (!(group.active_options > 0)) {
260
- return '';
261
- }
262
- group_el = document.createElement("li");
263
- group_el.className = "group-result";
264
- group_el.innerHTML = group.search_text;
265
- return this.outerHTML(group_el);
266
- };
267
-
268
- AbstractChosen.prototype.results_update_field = function() {
269
- this.set_default_text();
270
- if (!this.is_multiple) {
271
- this.results_reset_cleanup();
272
- }
273
- this.result_clear_highlight();
274
- this.results_build();
275
- if (this.results_showing) {
276
- return this.winnow_results();
277
- }
278
- };
279
-
280
- AbstractChosen.prototype.reset_single_select_options = function() {
281
- var result, _i, _len, _ref, _results;
282
- _ref = this.results_data;
283
- _results = [];
284
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
285
- result = _ref[_i];
286
- if (result.selected) {
287
- _results.push(result.selected = false);
288
- } else {
289
- _results.push(void 0);
290
- }
291
- }
292
- return _results;
293
- };
294
-
295
- AbstractChosen.prototype.results_toggle = function() {
296
- if (this.results_showing) {
297
- return this.results_hide();
298
- } else {
299
- return this.results_show();
300
- }
301
- };
302
-
303
- AbstractChosen.prototype.results_search = function(evt) {
304
- if (this.results_showing) {
305
- return this.winnow_results();
306
- } else {
307
- return this.results_show();
308
- }
309
- };
310
-
311
- AbstractChosen.prototype.winnow_results = function() {
312
- var escapedSearchText, option, regex, results, results_group, searchText, startpos, text, zregex, _i, _len, _ref;
313
- this.no_results_clear();
314
- results = 0;
315
- searchText = this.get_search_text();
316
- escapedSearchText = searchText.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
317
- zregex = new RegExp(escapedSearchText, 'i');
318
- regex = this.get_search_regex(escapedSearchText);
319
- _ref = this.results_data;
320
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
321
- option = _ref[_i];
322
- option.search_match = false;
323
- results_group = null;
324
- if (this.include_option_in_results(option)) {
325
- if (option.group) {
326
- option.group_match = false;
327
- option.active_options = 0;
328
- }
329
- if ((option.group_array_index != null) && this.results_data[option.group_array_index]) {
330
- results_group = this.results_data[option.group_array_index];
331
- if (results_group.active_options === 0 && results_group.search_match) {
332
- results += 1;
333
- }
334
- results_group.active_options += 1;
335
- }
336
- if (!(option.group && !this.group_search)) {
337
- option.search_text = option.group ? option.label : option.text;
338
- option.search_match = this.search_string_match(option.search_text, regex);
339
- if (option.search_match && !option.group) {
340
- results += 1;
341
- }
342
- if (option.search_match) {
343
- if (searchText.length) {
344
- startpos = option.search_text.search(zregex);
345
- text = option.search_text.substr(0, startpos + searchText.length) + '</em>' + option.search_text.substr(startpos + searchText.length);
346
- option.search_text = text.substr(0, startpos) + '<em>' + text.substr(startpos);
347
- }
348
- if (results_group != null) {
349
- results_group.group_match = true;
350
- }
351
- } else if ((option.group_array_index != null) && this.results_data[option.group_array_index].search_match) {
352
- option.search_match = true;
353
- }
354
- }
355
- }
356
- }
357
- this.result_clear_highlight();
358
- if (results < 1 && searchText.length) {
359
- this.update_results_content("");
360
- return this.no_results(searchText);
361
- } else {
362
- this.update_results_content(this.results_option_build());
363
- return this.winnow_results_set_highlight();
364
- }
365
- };
366
-
367
- AbstractChosen.prototype.get_search_regex = function(escaped_search_string) {
368
- var regex_anchor;
369
- regex_anchor = this.search_contains ? "" : "^";
370
- return new RegExp(regex_anchor + escaped_search_string, 'i');
371
- };
372
-
373
- AbstractChosen.prototype.search_string_match = function(search_string, regex) {
374
- var part, parts, _i, _len;
375
- if (regex.test(search_string)) {
376
- return true;
377
- } else if (this.enable_split_word_search && (search_string.indexOf(" ") >= 0 || search_string.indexOf("[") === 0)) {
378
- parts = search_string.replace(/\[|\]/g, "").split(" ");
379
- if (parts.length) {
380
- for (_i = 0, _len = parts.length; _i < _len; _i++) {
381
- part = parts[_i];
382
- if (regex.test(part)) {
383
- return true;
384
- }
385
- }
386
- }
387
- }
388
- };
389
-
390
- AbstractChosen.prototype.choices_count = function() {
391
- var option, _i, _len, _ref;
392
- if (this.selected_option_count != null) {
393
- return this.selected_option_count;
394
- }
395
- this.selected_option_count = 0;
396
- _ref = this.form_field.options;
397
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
398
- option = _ref[_i];
399
- if (option.selected) {
400
- this.selected_option_count += 1;
401
- }
402
- }
403
- return this.selected_option_count;
404
- };
405
-
406
- AbstractChosen.prototype.choices_click = function(evt) {
407
- evt.preventDefault();
408
- if (!(this.results_showing || this.is_disabled)) {
409
- return this.results_show();
410
- }
411
- };
412
-
413
- AbstractChosen.prototype.keyup_checker = function(evt) {
414
- var stroke, _ref;
415
- stroke = (_ref = evt.which) != null ? _ref : evt.keyCode;
416
- this.search_field_scale();
417
- switch (stroke) {
418
- case 8:
419
- if (this.is_multiple && this.backstroke_length < 1 && this.choices_count() > 0) {
420
- return this.keydown_backstroke();
421
- } else if (!this.pending_backstroke) {
422
- this.result_clear_highlight();
423
- return this.results_search();
424
- }
425
- break;
426
- case 13:
427
- evt.preventDefault();
428
- if (this.results_showing) {
429
- return this.result_select(evt);
430
- }
431
- break;
432
- case 27:
433
- if (this.results_showing) {
434
- this.results_hide();
435
- }
436
- return true;
437
- case 9:
438
- case 38:
439
- case 40:
440
- case 16:
441
- case 91:
442
- case 17:
443
- break;
444
- default:
445
- return this.results_search();
446
- }
447
- };
448
-
449
- AbstractChosen.prototype.clipboard_event_checker = function(evt) {
450
- var _this = this;
451
- return setTimeout((function() {
452
- return _this.results_search();
453
- }), 50);
454
- };
455
-
456
- AbstractChosen.prototype.container_width = function() {
457
- if (this.options.width != null) {
458
- return this.options.width;
459
- } else {
460
- return "" + this.form_field.offsetWidth + "px";
461
- }
462
- };
463
-
464
- AbstractChosen.prototype.include_option_in_results = function(option) {
465
- if (this.is_multiple && (!this.display_selected_options && option.selected)) {
466
- return false;
467
- }
468
- if (!this.display_disabled_options && option.disabled) {
469
- return false;
470
- }
471
- if (option.empty) {
472
- return false;
473
- }
474
- return true;
475
- };
476
-
477
- AbstractChosen.prototype.search_results_touchstart = function(evt) {
478
- this.touch_started = true;
479
- return this.search_results_mouseover(evt);
480
- };
481
-
482
- AbstractChosen.prototype.search_results_touchmove = function(evt) {
483
- this.touch_started = false;
484
- return this.search_results_mouseout(evt);
485
- };
486
-
487
- AbstractChosen.prototype.search_results_touchend = function(evt) {
488
- if (this.touch_started) {
489
- return this.search_results_mouseup(evt);
490
- }
491
- };
492
-
493
- AbstractChosen.prototype.outerHTML = function(element) {
494
- var tmp;
495
- if (element.outerHTML) {
496
- return element.outerHTML;
497
- }
498
- tmp = document.createElement("div");
499
- tmp.appendChild(element);
500
- return tmp.innerHTML;
501
- };
502
-
503
- AbstractChosen.browser_is_supported = function() {
504
- if (window.navigator.appName === "Microsoft Internet Explorer") {
505
- return document.documentMode >= 8;
506
- }
507
- if (/iP(od|hone)/i.test(window.navigator.userAgent)) {
508
- return false;
509
- }
510
- if (/Android/i.test(window.navigator.userAgent)) {
511
- if (/Mobile/i.test(window.navigator.userAgent)) {
512
- return false;
513
- }
514
- }
515
- return true;
516
- };
517
-
518
- AbstractChosen.default_multiple_text = "Select Some Options";
519
-
520
- AbstractChosen.default_single_text = "Select an Option";
521
-
522
- AbstractChosen.default_no_result_text = "No results match";
523
-
524
- return AbstractChosen;
525
-
526
- })();
527
-
528
- $ = jQuery;
529
-
530
- $.fn.extend({
531
- chosen: function(options) {
532
- if (!AbstractChosen.browser_is_supported()) {
533
- return this;
534
- }
535
- return this.each(function(input_field) {
536
- var $this, chosen;
537
- $this = $(this);
538
- chosen = $this.data('chosen');
539
- if (options === 'destroy' && chosen instanceof Chosen) {
540
- chosen.destroy();
541
- } else if (!(chosen instanceof Chosen)) {
542
- $this.data('chosen', new Chosen(this, options));
543
- }
544
- });
545
- }
546
- });
547
-
548
- Chosen = (function(_super) {
549
- __extends(Chosen, _super);
550
-
551
- function Chosen() {
552
- _ref = Chosen.__super__.constructor.apply(this, arguments);
553
- return _ref;
554
- }
555
-
556
- Chosen.prototype.setup = function() {
557
- this.form_field_jq = $(this.form_field);
558
- this.current_selectedIndex = this.form_field.selectedIndex;
559
- return this.is_rtl = this.form_field_jq.hasClass("chosen-rtl");
560
- };
561
-
562
- Chosen.prototype.set_up_html = function() {
563
- var container_classes, container_props;
564
- container_classes = ["chosen-container"];
565
- container_classes.push("chosen-container-" + (this.is_multiple ? "multi" : "single"));
566
- if (this.inherit_select_classes && this.form_field.className) {
567
- container_classes.push(this.form_field.className);
568
- }
569
- if (this.is_rtl) {
570
- container_classes.push("chosen-rtl");
571
- }
572
- container_props = {
573
- 'class': container_classes.join(' '),
574
- 'style': "width: " + (this.container_width()) + ";",
575
- 'title': this.form_field.title
576
- };
577
- if (this.form_field.id.length) {
578
- container_props.id = this.form_field.id.replace(/[^\w]/g, '_') + "_chosen";
579
- }
580
- this.container = $("<div />", container_props);
581
- if (this.is_multiple) {
582
- this.container.html('<ul class="chosen-choices"><li class="search-field"><input type="text" value="' + this.default_text + '" class="default" autocomplete="off" style="width:25px;" /></li></ul><div class="chosen-drop"><ul class="chosen-results"></ul></div>');
583
- } else {
584
- this.container.html('<a class="chosen-single chosen-default" tabindex="-1"><span>' + this.default_text + '</span><div><b></b></div></a><div class="chosen-drop"><div class="chosen-search"><input type="text" autocomplete="off" /></div><ul class="chosen-results"></ul></div>');
585
- }
586
- this.form_field_jq.hide().after(this.container);
587
- this.dropdown = this.container.find('div.chosen-drop').first();
588
- this.search_field = this.container.find('input').first();
589
- this.search_results = this.container.find('ul.chosen-results').first();
590
- this.search_field_scale();
591
- this.search_no_results = this.container.find('li.no-results').first();
592
- if (this.is_multiple) {
593
- this.search_choices = this.container.find('ul.chosen-choices').first();
594
- this.search_container = this.container.find('li.search-field').first();
595
- } else {
596
- this.search_container = this.container.find('div.chosen-search').first();
597
- this.selected_item = this.container.find('.chosen-single').first();
598
- }
599
- this.results_build();
600
- this.set_tab_index();
601
- this.set_label_behavior();
602
- return this.form_field_jq.trigger("chosen:ready", {
603
- chosen: this
604
- });
605
- };
606
-
607
- Chosen.prototype.register_observers = function() {
608
- var _this = this;
609
- this.container.bind('touchstart.chosen', function(evt) {
610
- _this.container_mousedown(evt);
611
- });
612
- this.container.bind('touchend.chosen', function(evt) {
613
- _this.container_mouseup(evt);
614
- });
615
- this.container.bind('mousedown.chosen', function(evt) {
616
- _this.container_mousedown(evt);
617
- });
618
- this.container.bind('mouseup.chosen', function(evt) {
619
- _this.container_mouseup(evt);
620
- });
621
- this.container.bind('mouseenter.chosen', function(evt) {
622
- _this.mouse_enter(evt);
623
- });
624
- this.container.bind('mouseleave.chosen', function(evt) {
625
- _this.mouse_leave(evt);
626
- });
627
- this.search_results.bind('mouseup.chosen', function(evt) {
628
- _this.search_results_mouseup(evt);
629
- });
630
- this.search_results.bind('mouseover.chosen', function(evt) {
631
- _this.search_results_mouseover(evt);
632
- });
633
- this.search_results.bind('mouseout.chosen', function(evt) {
634
- _this.search_results_mouseout(evt);
635
- });
636
- this.search_results.bind('mousewheel.chosen DOMMouseScroll.chosen', function(evt) {
637
- _this.search_results_mousewheel(evt);
638
- });
639
- this.search_results.bind('touchstart.chosen', function(evt) {
640
- _this.search_results_touchstart(evt);
641
- });
642
- this.search_results.bind('touchmove.chosen', function(evt) {
643
- _this.search_results_touchmove(evt);
644
- });
645
- this.search_results.bind('touchend.chosen', function(evt) {
646
- _this.search_results_touchend(evt);
647
- });
648
- this.form_field_jq.bind("chosen:updated.chosen", function(evt) {
649
- _this.results_update_field(evt);
650
- });
651
- this.form_field_jq.bind("chosen:activate.chosen", function(evt) {
652
- _this.activate_field(evt);
653
- });
654
- this.form_field_jq.bind("chosen:open.chosen", function(evt) {
655
- _this.container_mousedown(evt);
656
- });
657
- this.form_field_jq.bind("chosen:close.chosen", function(evt) {
658
- _this.input_blur(evt);
659
- });
660
- this.search_field.bind('blur.chosen', function(evt) {
661
- _this.input_blur(evt);
662
- });
663
- this.search_field.bind('keyup.chosen', function(evt) {
664
- _this.keyup_checker(evt);
665
- });
666
- this.search_field.bind('keydown.chosen', function(evt) {
667
- _this.keydown_checker(evt);
668
- });
669
- this.search_field.bind('focus.chosen', function(evt) {
670
- _this.input_focus(evt);
671
- });
672
- this.search_field.bind('cut.chosen', function(evt) {
673
- _this.clipboard_event_checker(evt);
674
- });
675
- this.search_field.bind('paste.chosen', function(evt) {
676
- _this.clipboard_event_checker(evt);
677
- });
678
- if (this.is_multiple) {
679
- return this.search_choices.bind('click.chosen', function(evt) {
680
- _this.choices_click(evt);
681
- });
682
- } else {
683
- return this.container.bind('click.chosen', function(evt) {
684
- evt.preventDefault();
685
- });
686
- }
687
- };
688
-
689
- Chosen.prototype.destroy = function() {
690
- $(this.container[0].ownerDocument).unbind("click.chosen", this.click_test_action);
691
- if (this.search_field[0].tabIndex) {
692
- this.form_field_jq[0].tabIndex = this.search_field[0].tabIndex;
693
- }
694
- this.container.remove();
695
- this.form_field_jq.removeData('chosen');
696
- return this.form_field_jq.show();
697
- };
698
-
699
- Chosen.prototype.search_field_disabled = function() {
700
- this.is_disabled = this.form_field_jq[0].disabled;
701
- if (this.is_disabled) {
702
- this.container.addClass('chosen-disabled');
703
- this.search_field[0].disabled = true;
704
- if (!this.is_multiple) {
705
- this.selected_item.unbind("focus.chosen", this.activate_action);
706
- }
707
- return this.close_field();
708
- } else {
709
- this.container.removeClass('chosen-disabled');
710
- this.search_field[0].disabled = false;
711
- if (!this.is_multiple) {
712
- return this.selected_item.bind("focus.chosen", this.activate_action);
713
- }
714
- }
715
- };
716
-
717
- Chosen.prototype.container_mousedown = function(evt) {
718
- if (!this.is_disabled) {
719
- if (evt && evt.type === "mousedown" && !this.results_showing) {
720
- evt.preventDefault();
721
- }
722
- if (!((evt != null) && ($(evt.target)).hasClass("search-choice-close"))) {
723
- if (!this.active_field) {
724
- if (this.is_multiple) {
725
- this.search_field.val("");
726
- }
727
- $(this.container[0].ownerDocument).bind('click.chosen', this.click_test_action);
728
- this.results_show();
729
- } else if (!this.is_multiple && evt && (($(evt.target)[0] === this.selected_item[0]) || $(evt.target).parents("a.chosen-single").length)) {
730
- evt.preventDefault();
731
- this.results_toggle();
732
- }
733
- return this.activate_field();
734
- }
735
- }
736
- };
737
-
738
- Chosen.prototype.container_mouseup = function(evt) {
739
- if (evt.target.nodeName === "ABBR" && !this.is_disabled) {
740
- return this.results_reset(evt);
741
- }
742
- };
743
-
744
- Chosen.prototype.search_results_mousewheel = function(evt) {
745
- var delta;
746
- if (evt.originalEvent) {
747
- delta = evt.originalEvent.deltaY || -evt.originalEvent.wheelDelta || evt.originalEvent.detail;
748
- }
749
- if (delta != null) {
750
- evt.preventDefault();
751
- if (evt.type === 'DOMMouseScroll') {
752
- delta = delta * 40;
753
- }
754
- return this.search_results.scrollTop(delta + this.search_results.scrollTop());
755
- }
756
- };
757
-
758
- Chosen.prototype.blur_test = function(evt) {
759
- if (!this.active_field && this.container.hasClass("chosen-container-active")) {
760
- return this.close_field();
761
- }
762
- };
763
-
764
- Chosen.prototype.close_field = function() {
765
- $(this.container[0].ownerDocument).unbind("click.chosen", this.click_test_action);
766
- this.active_field = false;
767
- this.results_hide();
768
- this.container.removeClass("chosen-container-active");
769
- this.clear_backstroke();
770
- this.show_search_field_default();
771
- return this.search_field_scale();
772
- };
773
-
774
- Chosen.prototype.activate_field = function() {
775
- this.container.addClass("chosen-container-active");
776
- this.active_field = true;
777
- this.search_field.val(this.search_field.val());
778
- return this.search_field.focus();
779
- };
780
-
781
- Chosen.prototype.test_active_click = function(evt) {
782
- var active_container;
783
- active_container = $(evt.target).closest('.chosen-container');
784
- if (active_container.length && this.container[0] === active_container[0]) {
785
- return this.active_field = true;
786
- } else {
787
- return this.close_field();
788
- }
789
- };
790
-
791
- Chosen.prototype.results_build = function() {
792
- this.parsing = true;
793
- this.selected_option_count = null;
794
- this.results_data = SelectParser.select_to_array(this.form_field);
795
- if (this.is_multiple) {
796
- this.search_choices.find("li.search-choice").remove();
797
- } else if (!this.is_multiple) {
798
- this.single_set_selected_text();
799
- if (this.disable_search || this.form_field.options.length <= this.disable_search_threshold) {
800
- this.search_field[0].readOnly = true;
801
- this.container.addClass("chosen-container-single-nosearch");
802
- } else {
803
- this.search_field[0].readOnly = false;
804
- this.container.removeClass("chosen-container-single-nosearch");
805
- }
806
- }
807
- this.update_results_content(this.results_option_build({
808
- first: true
809
- }));
810
- this.search_field_disabled();
811
- this.show_search_field_default();
812
- this.search_field_scale();
813
- return this.parsing = false;
814
- };
815
-
816
- Chosen.prototype.result_do_highlight = function(el) {
817
- var high_bottom, high_top, maxHeight, visible_bottom, visible_top;
818
- if (el.length) {
819
- this.result_clear_highlight();
820
- this.result_highlight = el;
821
- this.result_highlight.addClass("highlighted");
822
- maxHeight = parseInt(this.search_results.css("maxHeight"), 10);
823
- visible_top = this.search_results.scrollTop();
824
- visible_bottom = maxHeight + visible_top;
825
- high_top = this.result_highlight.position().top + this.search_results.scrollTop();
826
- high_bottom = high_top + this.result_highlight.outerHeight();
827
- if (high_bottom >= visible_bottom) {
828
- return this.search_results.scrollTop((high_bottom - maxHeight) > 0 ? high_bottom - maxHeight : 0);
829
- } else if (high_top < visible_top) {
830
- return this.search_results.scrollTop(high_top);
831
- }
832
- }
833
- };
834
-
835
- Chosen.prototype.result_clear_highlight = function() {
836
- if (this.result_highlight) {
837
- this.result_highlight.removeClass("highlighted");
838
- }
839
- return this.result_highlight = null;
840
- };
841
-
842
- Chosen.prototype.results_show = function() {
843
- if (this.is_multiple && this.max_selected_options <= this.choices_count()) {
844
- this.form_field_jq.trigger("chosen:maxselected", {
845
- chosen: this
846
- });
847
- return false;
848
- }
849
- this.container.addClass("chosen-with-drop");
850
- this.results_showing = true;
851
- this.search_field.focus();
852
- this.search_field.val(this.search_field.val());
853
- this.winnow_results();
854
- return this.form_field_jq.trigger("chosen:showing_dropdown", {
855
- chosen: this
856
- });
857
- };
858
-
859
- Chosen.prototype.update_results_content = function(content) {
860
- return this.search_results.html(content);
861
- };
862
-
863
- Chosen.prototype.results_hide = function() {
864
- if (this.results_showing) {
865
- this.result_clear_highlight();
866
- this.container.removeClass("chosen-with-drop");
867
- this.form_field_jq.trigger("chosen:hiding_dropdown", {
868
- chosen: this
869
- });
870
- }
871
- return this.results_showing = false;
872
- };
873
-
874
- Chosen.prototype.set_tab_index = function(el) {
875
- var ti;
876
- if (this.form_field.tabIndex) {
877
- ti = this.form_field.tabIndex;
878
- this.form_field.tabIndex = -1;
879
- return this.search_field[0].tabIndex = ti;
880
- }
881
- };
882
-
883
- Chosen.prototype.set_label_behavior = function() {
884
- var _this = this;
885
- this.form_field_label = this.form_field_jq.parents("label");
886
- if (!this.form_field_label.length && this.form_field.id.length) {
887
- this.form_field_label = $("label[for='" + this.form_field.id + "']");
888
- }
889
- if (this.form_field_label.length > 0) {
890
- return this.form_field_label.bind('click.chosen', function(evt) {
891
- if (_this.is_multiple) {
892
- return _this.container_mousedown(evt);
893
- } else {
894
- return _this.activate_field();
895
- }
896
- });
897
- }
898
- };
899
-
900
- Chosen.prototype.show_search_field_default = function() {
901
- if (this.is_multiple && this.choices_count() < 1 && !this.active_field) {
902
- this.search_field.val(this.default_text);
903
- return this.search_field.addClass("default");
904
- } else {
905
- this.search_field.val("");
906
- return this.search_field.removeClass("default");
907
- }
908
- };
909
-
910
- Chosen.prototype.search_results_mouseup = function(evt) {
911
- var target;
912
- target = $(evt.target).hasClass("active-result") ? $(evt.target) : $(evt.target).parents(".active-result").first();
913
- if (target.length) {
914
- this.result_highlight = target;
915
- this.result_select(evt);
916
- return this.search_field.focus();
917
- }
918
- };
919
-
920
- Chosen.prototype.search_results_mouseover = function(evt) {
921
- var target;
922
- target = $(evt.target).hasClass("active-result") ? $(evt.target) : $(evt.target).parents(".active-result").first();
923
- if (target) {
924
- return this.result_do_highlight(target);
925
- }
926
- };
927
-
928
- Chosen.prototype.search_results_mouseout = function(evt) {
929
- if ($(evt.target).hasClass("active-result" || $(evt.target).parents('.active-result').first())) {
930
- return this.result_clear_highlight();
931
- }
932
- };
933
-
934
- Chosen.prototype.choice_build = function(item) {
935
- var choice, close_link,
936
- _this = this;
937
- choice = $('<li />', {
938
- "class": "search-choice"
939
- }).html("<span>" + item.html + "</span>");
940
- if (item.disabled) {
941
- choice.addClass('search-choice-disabled');
942
- } else {
943
- close_link = $('<a />', {
944
- "class": 'search-choice-close',
945
- 'data-option-array-index': item.array_index
946
- });
947
- close_link.bind('click.chosen', function(evt) {
948
- return _this.choice_destroy_link_click(evt);
949
- });
950
- choice.append(close_link);
951
- }
952
- return this.search_container.before(choice);
953
- };
954
-
955
- Chosen.prototype.choice_destroy_link_click = function(evt) {
956
- evt.preventDefault();
957
- evt.stopPropagation();
958
- if (!this.is_disabled) {
959
- return this.choice_destroy($(evt.target));
960
- }
961
- };
962
-
963
- Chosen.prototype.choice_destroy = function(link) {
964
- if (this.result_deselect(link[0].getAttribute("data-option-array-index"))) {
965
- this.show_search_field_default();
966
- if (this.is_multiple && this.choices_count() > 0 && this.search_field.val().length < 1) {
967
- this.results_hide();
968
- }
969
- link.parents('li').first().remove();
970
- return this.search_field_scale();
971
- }
972
- };
973
-
974
- Chosen.prototype.results_reset = function() {
975
- this.reset_single_select_options();
976
- this.form_field.options[0].selected = true;
977
- this.single_set_selected_text();
978
- this.show_search_field_default();
979
- this.results_reset_cleanup();
980
- this.form_field_jq.trigger("change");
981
- if (this.active_field) {
982
- return this.results_hide();
983
- }
984
- };
985
-
986
- Chosen.prototype.results_reset_cleanup = function() {
987
- this.current_selectedIndex = this.form_field.selectedIndex;
988
- return this.selected_item.find("abbr").remove();
989
- };
990
-
991
- Chosen.prototype.result_select = function(evt) {
992
- var high, item;
993
- if (this.result_highlight) {
994
- high = this.result_highlight;
995
- this.result_clear_highlight();
996
- if (this.is_multiple && this.max_selected_options <= this.choices_count()) {
997
- this.form_field_jq.trigger("chosen:maxselected", {
998
- chosen: this
999
- });
1000
- return false;
1001
- }
1002
- if (this.is_multiple) {
1003
- high.removeClass("active-result");
1004
- } else {
1005
- this.reset_single_select_options();
1006
- }
1007
- item = this.results_data[high[0].getAttribute("data-option-array-index")];
1008
- item.selected = true;
1009
- this.form_field.options[item.options_index].selected = true;
1010
- this.selected_option_count = null;
1011
- if (this.is_multiple) {
1012
- this.choice_build(item);
1013
- } else {
1014
- this.single_set_selected_text(item.text);
1015
- }
1016
- if (!((evt.metaKey || evt.ctrlKey) && this.is_multiple)) {
1017
- this.results_hide();
1018
- }
1019
- this.search_field.val("");
1020
- if (this.is_multiple || this.form_field.selectedIndex !== this.current_selectedIndex) {
1021
- this.form_field_jq.trigger("change", {
1022
- 'selected': this.form_field.options[item.options_index].value
1023
- });
1024
- }
1025
- this.current_selectedIndex = this.form_field.selectedIndex;
1026
- return this.search_field_scale();
1027
- }
1028
- };
1029
-
1030
- Chosen.prototype.single_set_selected_text = function(text) {
1031
- if (text == null) {
1032
- text = this.default_text;
1033
- }
1034
- if (text === this.default_text) {
1035
- this.selected_item.addClass("chosen-default");
1036
- } else {
1037
- this.single_deselect_control_build();
1038
- this.selected_item.removeClass("chosen-default");
1039
- }
1040
- return this.selected_item.find("span").text(text);
1041
- };
1042
-
1043
- Chosen.prototype.result_deselect = function(pos) {
1044
- var result_data;
1045
- result_data = this.results_data[pos];
1046
- if (!this.form_field.options[result_data.options_index].disabled) {
1047
- result_data.selected = false;
1048
- this.form_field.options[result_data.options_index].selected = false;
1049
- this.selected_option_count = null;
1050
- this.result_clear_highlight();
1051
- if (this.results_showing) {
1052
- this.winnow_results();
1053
- }
1054
- this.form_field_jq.trigger("change", {
1055
- deselected: this.form_field.options[result_data.options_index].value
1056
- });
1057
- this.search_field_scale();
1058
- return true;
1059
- } else {
1060
- return false;
1061
- }
1062
- };
1063
-
1064
- Chosen.prototype.single_deselect_control_build = function() {
1065
- if (!this.allow_single_deselect) {
1066
- return;
1067
- }
1068
- if (!this.selected_item.find("abbr").length) {
1069
- this.selected_item.find("span").first().after("<abbr class=\"search-choice-close\"></abbr>");
1070
- }
1071
- return this.selected_item.addClass("chosen-single-with-deselect");
1072
- };
1073
-
1074
- Chosen.prototype.get_search_text = function() {
1075
- if (this.search_field.val() === this.default_text) {
1076
- return "";
1077
- } else {
1078
- return $('<div/>').text($.trim(this.search_field.val())).html();
1079
- }
1080
- };
1081
-
1082
- Chosen.prototype.winnow_results_set_highlight = function() {
1083
- var do_high, selected_results;
1084
- selected_results = !this.is_multiple ? this.search_results.find(".result-selected.active-result") : [];
1085
- do_high = selected_results.length ? selected_results.first() : this.search_results.find(".active-result").first();
1086
- if (do_high != null) {
1087
- return this.result_do_highlight(do_high);
1088
- }
1089
- };
1090
-
1091
- Chosen.prototype.no_results = function(terms) {
1092
- var no_results_html;
1093
- no_results_html = $('<li class="no-results">' + this.results_none_found + ' "<span></span>"</li>');
1094
- no_results_html.find("span").first().html(terms);
1095
- this.search_results.append(no_results_html);
1096
- return this.form_field_jq.trigger("chosen:no_results", {
1097
- chosen: this
1098
- });
1099
- };
1100
-
1101
- Chosen.prototype.no_results_clear = function() {
1102
- return this.search_results.find(".no-results").remove();
1103
- };
1104
-
1105
- Chosen.prototype.keydown_arrow = function() {
1106
- var next_sib;
1107
- if (this.results_showing && this.result_highlight) {
1108
- next_sib = this.result_highlight.nextAll("li.active-result").first();
1109
- if (next_sib) {
1110
- return this.result_do_highlight(next_sib);
1111
- }
1112
- } else {
1113
- return this.results_show();
1114
- }
1115
- };
1116
-
1117
- Chosen.prototype.keyup_arrow = function() {
1118
- var prev_sibs;
1119
- if (!this.results_showing && !this.is_multiple) {
1120
- return this.results_show();
1121
- } else if (this.result_highlight) {
1122
- prev_sibs = this.result_highlight.prevAll("li.active-result");
1123
- if (prev_sibs.length) {
1124
- return this.result_do_highlight(prev_sibs.first());
1125
- } else {
1126
- if (this.choices_count() > 0) {
1127
- this.results_hide();
1128
- }
1129
- return this.result_clear_highlight();
1130
- }
1131
- }
1132
- };
1133
-
1134
- Chosen.prototype.keydown_backstroke = function() {
1135
- var next_available_destroy;
1136
- if (this.pending_backstroke) {
1137
- this.choice_destroy(this.pending_backstroke.find("a").first());
1138
- return this.clear_backstroke();
1139
- } else {
1140
- next_available_destroy = this.search_container.siblings("li.search-choice").last();
1141
- if (next_available_destroy.length && !next_available_destroy.hasClass("search-choice-disabled")) {
1142
- this.pending_backstroke = next_available_destroy;
1143
- if (this.single_backstroke_delete) {
1144
- return this.keydown_backstroke();
1145
- } else {
1146
- return this.pending_backstroke.addClass("search-choice-focus");
1147
- }
1148
- }
1149
- }
1150
- };
1151
-
1152
- Chosen.prototype.clear_backstroke = function() {
1153
- if (this.pending_backstroke) {
1154
- this.pending_backstroke.removeClass("search-choice-focus");
1155
- }
1156
- return this.pending_backstroke = null;
1157
- };
1158
-
1159
- Chosen.prototype.keydown_checker = function(evt) {
1160
- var stroke, _ref1;
1161
- stroke = (_ref1 = evt.which) != null ? _ref1 : evt.keyCode;
1162
- this.search_field_scale();
1163
- if (stroke !== 8 && this.pending_backstroke) {
1164
- this.clear_backstroke();
1165
- }
1166
- switch (stroke) {
1167
- case 8:
1168
- this.backstroke_length = this.search_field.val().length;
1169
- break;
1170
- case 9:
1171
- if (this.results_showing && !this.is_multiple) {
1172
- this.result_select(evt);
1173
- }
1174
- this.mouse_on_container = false;
1175
- break;
1176
- case 13:
1177
- if (this.results_showing) {
1178
- evt.preventDefault();
1179
- }
1180
- break;
1181
- case 32:
1182
- if (this.disable_search) {
1183
- evt.preventDefault();
1184
- }
1185
- break;
1186
- case 38:
1187
- evt.preventDefault();
1188
- this.keyup_arrow();
1189
- break;
1190
- case 40:
1191
- evt.preventDefault();
1192
- this.keydown_arrow();
1193
- break;
1194
- }
1195
- };
1196
-
1197
- Chosen.prototype.search_field_scale = function() {
1198
- var div, f_width, h, style, style_block, styles, w, _i, _len;
1199
- if (this.is_multiple) {
1200
- h = 0;
1201
- w = 0;
1202
- style_block = "position:absolute; left: -1000px; top: -1000px; display:none;";
1203
- styles = ['font-size', 'font-style', 'font-weight', 'font-family', 'line-height', 'text-transform', 'letter-spacing'];
1204
- for (_i = 0, _len = styles.length; _i < _len; _i++) {
1205
- style = styles[_i];
1206
- style_block += style + ":" + this.search_field.css(style) + ";";
1207
- }
1208
- div = $('<div />', {
1209
- 'style': style_block
1210
- });
1211
- div.text(this.search_field.val());
1212
- $('body').append(div);
1213
- w = div.width() + 25;
1214
- div.remove();
1215
- f_width = this.container.outerWidth();
1216
- if (w > f_width - 10) {
1217
- w = f_width - 10;
1218
- }
1219
- return this.search_field.css({
1220
- 'width': w + 'px'
1221
- });
1222
- }
1223
- };
1224
-
1225
- return Chosen;
1226
-
1227
- })(AbstractChosen);
1228
-
1229
- }).call(this);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
assets/js/jquery-tiptip/jquery.tipTip.js DELETED
@@ -1,191 +0,0 @@
1
- /*
2
- * TipTip
3
- * Copyright 2010 Drew Wilson
4
- * www.drewwilson.com
5
- * code.drewwilson.com/entry/tiptip-jquery-plugin
6
- *
7
- * Version 1.3 - Updated: Mar. 23, 2010
8
- *
9
- * This Plug-In will create a custom tooltip to replace the default
10
- * browser tooltip. It is extremely lightweight and very smart in
11
- * that it detects the edges of the browser window and will make sure
12
- * the tooltip stays within the current window size. As a result the
13
- * tooltip will adjust itself to be displayed above, below, to the left
14
- * or to the right depending on what is necessary to stay within the
15
- * browser window. It is completely customizable as well via CSS.
16
- *
17
- * This TipTip jQuery plug-in is dual licensed under the MIT and GPL licenses:
18
- * http://www.opensource.org/licenses/mit-license.php
19
- * http://www.gnu.org/licenses/gpl.html
20
- */
21
-
22
- (function($){
23
- $.fn.tipTip = function(options) {
24
- var defaults = {
25
- activation: "hover",
26
- keepAlive: false,
27
- maxWidth: "200px",
28
- edgeOffset: 3,
29
- defaultPosition: "bottom",
30
- delay: 400,
31
- fadeIn: 200,
32
- fadeOut: 200,
33
- attribute: "title",
34
- content: false, // HTML or String to fill TipTIp with
35
- enter: function(){},
36
- exit: function(){}
37
- };
38
- var opts = $.extend(defaults, options);
39
-
40
- // Setup tip tip elements and render them to the DOM
41
- if($("#tiptip_holder").length <= 0){
42
- var tiptip_holder = $('<div id="tiptip_holder" style="max-width:'+ opts.maxWidth +';"></div>');
43
- var tiptip_content = $('<div id="tiptip_content"></div>');
44
- var tiptip_arrow = $('<div id="tiptip_arrow"></div>');
45
- $("body").append(tiptip_holder.html(tiptip_content).prepend(tiptip_arrow.html('<div id="tiptip_arrow_inner"></div>')));
46
- } else {
47
- var tiptip_holder = $("#tiptip_holder");
48
- var tiptip_content = $("#tiptip_content");
49
- var tiptip_arrow = $("#tiptip_arrow");
50
- }
51
-
52
- return this.each(function(){
53
- var org_elem = $(this);
54
- if(opts.content){
55
- var org_title = opts.content;
56
- } else {
57
- var org_title = org_elem.attr(opts.attribute);
58
- }
59
- if(org_title != ""){
60
- if(!opts.content){
61
- org_elem.removeAttr(opts.attribute); //remove original Attribute
62
- }
63
- var timeout = false;
64
-
65
- if(opts.activation == "hover"){
66
- org_elem.hover(function(){
67
- active_tiptip();
68
- }, function(){
69
- if(!opts.keepAlive){
70
- deactive_tiptip();
71
- }
72
- });
73
- if(opts.keepAlive){
74
- tiptip_holder.hover(function(){}, function(){
75
- deactive_tiptip();
76
- });
77
- }
78
- } else if(opts.activation == "focus"){
79
- org_elem.focus(function(){
80
- active_tiptip();
81
- }).blur(function(){
82
- deactive_tiptip();
83
- });
84
- } else if(opts.activation == "click"){
85
- org_elem.click(function(){
86
- active_tiptip();
87
- return false;
88
- }).hover(function(){},function(){
89
- if(!opts.keepAlive){
90
- deactive_tiptip();
91
- }
92
- });
93
- if(opts.keepAlive){
94
- tiptip_holder.hover(function(){}, function(){
95
- deactive_tiptip();
96
- });
97
- }
98
- }
99
-
100
- function active_tiptip(){
101
- opts.enter.call(this);
102
- tiptip_content.html(org_title);
103
- tiptip_holder.hide().removeAttr("class").css("margin","0");
104
- tiptip_arrow.removeAttr("style");
105
-
106
- var top = parseInt(org_elem.offset()['top']);
107
- var left = parseInt(org_elem.offset()['left']);
108
- var org_width = parseInt(org_elem.outerWidth());
109
- var org_height = parseInt(org_elem.outerHeight());
110
- var tip_w = tiptip_holder.outerWidth();
111
- var tip_h = tiptip_holder.outerHeight();
112
- var w_compare = Math.round((org_width - tip_w) / 2);
113
- var h_compare = Math.round((org_height - tip_h) / 2);
114
- var marg_left = Math.round(left + w_compare);
115
- var marg_top = Math.round(top + org_height + opts.edgeOffset);
116
- var t_class = "";
117
- var arrow_top = "";
118
- var arrow_left = Math.round(tip_w - 12) / 2;
119
-
120
- if(opts.defaultPosition == "bottom"){
121
- t_class = "_bottom";
122
- } else if(opts.defaultPosition == "top"){
123
- t_class = "_top";
124
- } else if(opts.defaultPosition == "left"){
125
- t_class = "_left";
126
- } else if(opts.defaultPosition == "right"){
127
- t_class = "_right";
128
- }
129
-
130
- var right_compare = (w_compare + left) < parseInt($(window).scrollLeft());
131
- var left_compare = (tip_w + left) > parseInt($(window).width());
132
-
133
- if((right_compare && w_compare < 0) || (t_class == "_right" && !left_compare) || (t_class == "_left" && left < (tip_w + opts.edgeOffset + 5))){
134
- t_class = "_right";
135
- arrow_top = Math.round(tip_h - 13) / 2;
136
- arrow_left = -12;
137
- marg_left = Math.round(left + org_width + opts.edgeOffset);
138
- marg_top = Math.round(top + h_compare);
139
- } else if((left_compare && w_compare < 0) || (t_class == "_left" && !right_compare)){
140
- t_class = "_left";
141
- arrow_top = Math.round(tip_h - 13) / 2;
142
- arrow_left = Math.round(tip_w);
143
- marg_left = Math.round(left - (tip_w + opts.edgeOffset + 5));
144
- marg_top = Math.round(top + h_compare);
145
- }
146
-
147
- var top_compare = (top + org_height + opts.edgeOffset + tip_h + 8) > parseInt($(window).height() + $(window).scrollTop());
148
- var bottom_compare = ((top + org_height) - (opts.edgeOffset + tip_h + 8)) < 0;
149
-
150
- if(top_compare || (t_class == "_bottom" && top_compare) || (t_class == "_top" && !bottom_compare)){
151
- if(t_class == "_top" || t_class == "_bottom"){
152
- t_class = "_top";
153
- } else {
154
- t_class = t_class+"_top";
155
- }
156
- arrow_top = tip_h;
157
- marg_top = Math.round(top - (tip_h + 5 + opts.edgeOffset));
158
- } else if(bottom_compare | (t_class == "_top" && bottom_compare) || (t_class == "_bottom" && !top_compare)){
159
- if(t_class == "_top" || t_class == "_bottom"){
160
- t_class = "_bottom";
161
- } else {
162
- t_class = t_class+"_bottom";
163
- }
164
- arrow_top = -12;
165
- marg_top = Math.round(top + org_height + opts.edgeOffset);
166
- }
167
-
168
- if(t_class == "_right_top" || t_class == "_left_top"){
169
- marg_top = marg_top + 5;
170
- } else if(t_class == "_right_bottom" || t_class == "_left_bottom"){
171
- marg_top = marg_top - 5;
172
- }
173
- if(t_class == "_left_top" || t_class == "_left_bottom"){
174
- marg_left = marg_left + 5;
175
- }
176
- tiptip_arrow.css({"margin-left": arrow_left+"px", "margin-top": arrow_top+"px"});
177
- tiptip_holder.css({"margin-left": marg_left+"px", "margin-top": marg_top+"px"}).attr("class","tip"+t_class);
178
-
179
- if (timeout){ clearTimeout(timeout); }
180
- timeout = setTimeout(function(){ tiptip_holder.stop(true,true).fadeIn(opts.fadeIn); }, opts.delay);
181
- }
182
-
183
- function deactive_tiptip(){
184
- opts.exit.call(this);
185
- if (timeout){ clearTimeout(timeout); }
186
- tiptip_holder.fadeOut(opts.fadeOut);
187
- }
188
- }
189
- });
190
- }
191
- })(jQuery);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
assets/js/jquery-tiptip/jquery.tipTip.min.js CHANGED
@@ -17,4 +17,4 @@
17
  * This TipTip jQuery plug-in is dual licensed under the MIT and GPL licenses:
18
  * http://www.opensource.org/licenses/mit-license.php
19
  * http://www.gnu.org/licenses/gpl.html
20
- */(function(e){e.fn.tipTip=function(t){var n={activation:"hover",keepAlive:!1,maxWidth:"200px",edgeOffset:3,defaultPosition:"bottom",delay:400,fadeIn:200,fadeOut:200,attribute:"title",content:!1,enter:function(){},exit:function(){}},r=e.extend(n,t);if(e("#tiptip_holder").length<=0){var i=e('<div id="tiptip_holder" style="max-width:'+r.maxWidth+';"></div>'),s=e('<div id="tiptip_content"></div>'),o=e('<div id="tiptip_arrow"></div>');e("body").append(i.html(s).prepend(o.html('<div id="tiptip_arrow_inner"></div>')))}else var i=e("#tiptip_holder"),s=e("#tiptip_content"),o=e("#tiptip_arrow");return this.each(function(){var t=e(this);if(r.content)var n=r.content;else var n=t.attr(r.attribute);if(n!=""){r.content||t.removeAttr(r.attribute);var u=!1;if(r.activation=="hover"){t.hover(function(){a()},function(){r.keepAlive||f()});r.keepAlive&&i.hover(function(){},function(){f()})}else if(r.activation=="focus")t.focus(function(){a()}).blur(function(){f()});else if(r.activation=="click"){t.click(function(){a();return!1}).hover(function(){},function(){r.keepAlive||f()});r.keepAlive&&i.hover(function(){},function(){f()})}function a(){r.enter.call(this);s.html(n);i.hide().removeAttr("class").css("margin","0");o.removeAttr("style");var a=parseInt(t.offset().top),f=parseInt(t.offset().left),l=parseInt(t.outerWidth()),c=parseInt(t.outerHeight()),h=i.outerWidth(),p=i.outerHeight(),d=Math.round((l-h)/2),v=Math.round((c-p)/2),m=Math.round(f+d),g=Math.round(a+c+r.edgeOffset),y="",b="",w=Math.round(h-12)/2;r.defaultPosition=="bottom"?y="_bottom":r.defaultPosition=="top"?y="_top":r.defaultPosition=="left"?y="_left":r.defaultPosition=="right"&&(y="_right");var E=d+f<parseInt(e(window).scrollLeft()),S=h+f>parseInt(e(window).width());if(E&&d<0||y=="_right"&&!S||y=="_left"&&f<h+r.edgeOffset+5){y="_right";b=Math.round(p-13)/2;w=-12;m=Math.round(f+l+r.edgeOffset);g=Math.round(a+v)}else if(S&&d<0||y=="_left"&&!E){y="_left";b=Math.round(p-13)/2;w=Math.round(h);m=Math.round(f-(h+r.edgeOffset+5));g=Math.round(a+v)}var x=a+c+r.edgeOffset+p+8>parseInt(e(window).height()+e(window).scrollTop()),T=a+c-(r.edgeOffset+p+8)<0;if(x||y=="_bottom"&&x||y=="_top"&&!T){y=="_top"||y=="_bottom"?y="_top":y+="_top";b=p;g=Math.round(a-(p+5+r.edgeOffset))}else if(T|(y=="_top"&&T)||y=="_bottom"&&!x){y=="_top"||y=="_bottom"?y="_bottom":y+="_bottom";b=-12;g=Math.round(a+c+r.edgeOffset)}if(y=="_right_top"||y=="_left_top")g+=5;else if(y=="_right_bottom"||y=="_left_bottom")g-=5;if(y=="_left_top"||y=="_left_bottom")m+=5;o.css({"margin-left":w+"px","margin-top":b+"px"});i.css({"margin-left":m+"px","margin-top":g+"px"}).attr("class","tip"+y);u&&clearTimeout(u);u=setTimeout(function(){i.stop(!0,!0).fadeIn(r.fadeIn)},r.delay)}function f(){r.exit.call(this);u&&clearTimeout(u);i.fadeOut(r.fadeOut)}}})}})(jQuery);
17
  * This TipTip jQuery plug-in is dual licensed under the MIT and GPL licenses:
18
  * http://www.opensource.org/licenses/mit-license.php
19
  * http://www.gnu.org/licenses/gpl.html
20
+ */!function(t){t.fn.tipTip=function(e){var o={activation:"hover",keepAlive:!1,maxWidth:"200px",edgeOffset:3,defaultPosition:"bottom",delay:400,fadeIn:200,fadeOut:200,attribute:"title",content:!1,enter:function(){},exit:function(){}},i=t.extend(o,e);if(t("#tiptip_holder").length<=0){(a=t('<div id="tiptip_holder"></div>')).css("max-width",i.maxWidth);var n=t('<div id="tiptip_content"></div>'),r=t('<div id="tiptip_arrow"></div>');t("body").append(a.html(n).prepend(r.html('<div id="tiptip_arrow_inner"></div>')))}else var a=t("#tiptip_holder"),n=t("#tiptip_content"),r=t("#tiptip_arrow");return this.each(function(){function e(){i.enter.call(this),n.html(d),a.hide().removeAttr("class").css("margin","0"),r.removeAttr("style");var e=parseInt(f.offset().top),o=parseInt(f.offset().left),p=parseInt(f.outerWidth()),l=parseInt(f.outerHeight()),h=a.outerWidth(),c=a.outerHeight(),s=Math.round((p-h)/2),_=Math.round((l-c)/2),v=Math.round(o+s),m=Math.round(e+l+i.edgeOffset),g="",b="",M=Math.round(h-12)/2;"bottom"==i.defaultPosition?g="_bottom":"top"==i.defaultPosition?g="_top":"left"==i.defaultPosition?g="_left":"right"==i.defaultPosition&&(g="_right");var w=s+o<parseInt(t(window).scrollLeft()),O=h+o>parseInt(t(window).width());w&&s<0||"_right"==g&&!O||"_left"==g&&o<h+i.edgeOffset+5?(g="_right",b=Math.round(c-13)/2,M=-12,v=Math.round(o+p+i.edgeOffset),m=Math.round(e+_)):(O&&s<0||"_left"==g&&!w)&&(g="_left",b=Math.round(c-13)/2,M=Math.round(h),v=Math.round(o-(h+i.edgeOffset+5)),m=Math.round(e+_));var x=e+l+i.edgeOffset+c+8>parseInt(t(window).height()+t(window).scrollTop()),I=e+l-(i.edgeOffset+c+8)<0;x||"_bottom"==g&&x||"_top"==g&&!I?("_top"==g||"_bottom"==g?g="_top":g+="_top",b=c,m=Math.round(e-(c+5+i.edgeOffset))):(I|("_top"==g&&I)||"_bottom"==g&&!x)&&("_top"==g||"_bottom"==g?g="_bottom":g+="_bottom",b=-12,m=Math.round(e+l+i.edgeOffset)),"_right_top"==g||"_left_top"==g?m+=5:"_right_bottom"!=g&&"_left_bottom"!=g||(m-=5),"_left_top"!=g&&"_left_bottom"!=g||(v+=5),r.css({"margin-left":M+"px","margin-top":b+"px"}),a.css({"margin-left":v+"px","margin-top":m+"px"}).attr("class","tip"+g),u&&clearTimeout(u),u=setTimeout(function(){a.stop(!0,!0).fadeIn(i.fadeIn)},i.delay)}function o(){i.exit.call(this),u&&clearTimeout(u),a.fadeOut(i.fadeOut)}var f=t(this);if(i.content)d=i.content;else var d=f.attr(i.attribute);if(""!=d){i.content||f.removeAttr(i.attribute);var u=!1;"hover"==i.activation?(f.hover(function(){e()},function(){i.keepAlive||o()}),i.keepAlive&&a.hover(function(){},function(){o()})):"focus"==i.activation?f.focus(function(){e()}).blur(function(){o()}):"click"==i.activation&&(f.click(function(){return e(),!1}).hover(function(){},function(){i.keepAlive||o()}),i.keepAlive&&a.hover(function(){},function(){o()}))}})}}(jQuery);
assets/js/multiselect.js DELETED
@@ -1,4 +0,0 @@
1
- /* global job_manager_chosen_multiselect_args */
2
- jQuery(function(){
3
- jQuery( '.job-manager-multiselect' ).chosen( job_manager_chosen_multiselect_args );
4
- });
 
 
 
 
assets/js/term-multiselect.js DELETED
@@ -1,4 +0,0 @@
1
- /* global job_manager_chosen_multiselect_args */
2
- jQuery(function(){
3
- jQuery( '.job-manager-category-dropdown' ).chosen( job_manager_chosen_multiselect_args );
4
- });
 
 
 
 
changelog.txt CHANGED
@@ -1,3 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
1
  = 1.31.0 =
2
  * Change: Minimum WordPress version is now 4.7.0.
3
  * Enhancement: Add email notifications with initial support for new jobs, updated jobs, and expiring listings.
1
+ = 1.31.1 =
2
+ * Enhancement: Add option to show company logo in Recent Jobs widget. (@RajeebTheGreat)
3
+ * Enhancement: Suggest additional cookie information on Privacy Policy page.
4
+ * Enhancement: Add WPJM related meta data to user data extract.
5
+ * Fix: Tightened the security of the plugin with additional string escaping.
6
+ * Fix: Issue with map link in admin backend. (@RajeebTheGreat)
7
+ * Fix: No longer auto-expire job listings in Draft status.
8
+ * Fix: Issue with undefined index error in WP admin. (@albionselimaj)
9
+ * Fix: Issue with duplicate usernames preventing submission of job listings. (@timothyjensen)
10
+ * Dev: Widespread code formatting cleanup throughout the plugin.
11
+
12
  = 1.31.0 =
13
  * Change: Minimum WordPress version is now 4.7.0.
14
  * Enhancement: Add email notifications with initial support for new jobs, updated jobs, and expiring listings.
includes/3rd-party/all-in-one-seo-pack.php CHANGED
@@ -1,6 +1,8 @@
1
  <?php
2
  /**
3
  * Adds additional compatibility with All in One SEO Pack.
 
 
4
  */
5
 
6
  /**
1
  <?php
2
  /**
3
  * Adds additional compatibility with All in One SEO Pack.
4
+ *
5
+ * @package wp-job-manager
6
  */
7
 
8
  /**
includes/3rd-party/jetpack.php CHANGED
@@ -1,6 +1,8 @@
1
  <?php
2
  /**
3
  * Adds additional compatibility with Jetpack.
 
 
4
  */
5
 
6
  /**
1
  <?php
2
  /**
3
  * Adds additional compatibility with Jetpack.
4
+ *
5
+ * @package wp-job-manager
6
  */
7
 
8
  /**
includes/3rd-party/polylang.php CHANGED
@@ -1,6 +1,8 @@
1
  <?php
2
  /**
3
  * Only load these if Polylang plugin is installed and active.
 
 
4
  */
5
 
6
  /**
1
  <?php
2
  /**
3
  * Only load these if Polylang plugin is installed and active.
4
+ *
5
+ * @package wp-job-manager
6
  */
7
 
8
  /**
includes/3rd-party/rp4wp.php CHANGED
@@ -1,6 +1,8 @@
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 );
1
  <?php
2
  /**
3
  * Adds additional compatibility with Related Post for WordPress.
4
+ *
5
+ * @package wp-job-manager
6
  */
7
 
8
  add_filter( 'rp4wp_get_template', 'wpjm_rp4wp_template', 10, 3 );
includes/3rd-party/wp-all-import.php CHANGED
@@ -1,6 +1,8 @@
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 );
@@ -13,8 +15,11 @@ add_action( 'pmxi_saved_post', 'wpjm_pmxi_saved_post', 10, 1 );
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
  }
1
  <?php
2
  /**
3
  * Adds additional compatibility with WP All Import.
4
+ *
5
+ * @package wp-job-manager
6
  */
7
 
8
  add_action( 'pmxi_saved_post', 'wpjm_pmxi_saved_post', 10, 1 );
15
  function wpjm_pmxi_saved_post( $post_id ) {
16
  if ( 'job_listing' === get_post_type( $post_id ) ) {
17
  WP_Job_Manager_Post_Types::instance()->maybe_add_default_meta_data( $post_id );
18
+ if ( ! WP_Job_Manager_Geocode::has_location_data( $post_id ) ) {
19
+ $location = get_post_meta( $post_id, '_job_location', true );
20
+ if ( $location ) {
21
+ WP_Job_Manager_Geocode::generate_location_data( $post_id, $location );
22
+ }
23
  }
24
  }
25
  }
includes/3rd-party/wpml.php CHANGED
@@ -1,6 +1,8 @@
1
  <?php
2
  /**
3
  * Only load these if WPML plugin is installed and active.
 
 
4
  */
5
 
6
  /**
@@ -89,11 +91,13 @@ function wpml_wpjm_hide_page_selection( $settings ) {
89
  }
90
  }
91
 
92
- $default_lang = apply_filters( 'wpml_default_language', null );
93
- $url_to_edit_page = admin_url( 'edit.php?post_type=job_listing&page=job-manager-settings&lang=' . $default_lang . '#settings-job_pages' );
 
 
94
  $setting['desc'] = sprintf( __( '<a href="%s">Switch to primary language</a> to edit this setting.', 'wp-job-manager' ), $url_to_edit_page );
95
  $settings['job_pages'][1][ $key ] = $setting;
96
  }
97
 
98
  return $settings;
99
- }
1
  <?php
2
  /**
3
  * Only load these if WPML plugin is installed and active.
4
+ *
5
+ * @package wp-job-manager
6
  */
7
 
8
  /**
91
  }
92
  }
93
 
94
+ $default_lang = apply_filters( 'wpml_default_language', null );
95
+ $url_to_edit_page = admin_url( 'edit.php?post_type=job_listing&page=job-manager-settings&lang=' . $default_lang . '#settings-job_pages' );
96
+
97
+ // translators: Placeholder (%s) is the URL to edit the primary language in WPML.
98
  $setting['desc'] = sprintf( __( '<a href="%s">Switch to primary language</a> to edit this setting.', 'wp-job-manager' ), $url_to_edit_page );
99
  $settings['job_pages'][1][ $key ] = $setting;
100
  }
101
 
102
  return $settings;
103
+ }
includes/3rd-party/yoast.php CHANGED
@@ -3,6 +3,8 @@
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
  /**
@@ -10,8 +12,8 @@
10
  *
11
  * @param array $url Array of URL parts.
12
  * @param string $type URL type.
13
- * @param object $user Data object for the URL.
14
- * @return string|bool False if we're skipping
15
  */
16
  function wpjm_yoast_skip_filled_job_listings( $url, $type, $post ) {
17
  if ( 'job_listing' !== $post->post_type ) {
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
+ * @package wp-job-manager
8
  */
9
 
10
  /**
12
  *
13
  * @param array $url Array of URL parts.
14
  * @param string $type URL type.
15
+ * @param object $post Post object.
16
+ * @return string|bool False if we're skipping.
17
  */
18
  function wpjm_yoast_skip_filled_job_listings( $url, $type, $post ) {
19
  if ( 'job_listing' !== $post->post_type ) {
includes/abstracts/abstract-wp-job-manager-email-template.php CHANGED
@@ -1,9 +1,4 @@
1
  <?php
2
-
3
- if ( ! defined( 'ABSPATH' ) ) {
4
- exit; // Exit if accessed directly
5
- }
6
-
7
  /**
8
  * Abstract class for an email notification built using templates.
9
  *
@@ -12,6 +7,13 @@ if ( ! defined( 'ABSPATH' ) ) {
12
  * @since 1.31.0
13
  */
14
 
 
 
 
 
 
 
 
15
  abstract class WP_Job_Manager_Email_Template extends WP_Job_Manager_Email {
16
  /**
17
  * Get the template path for overriding templates.
@@ -65,7 +67,7 @@ abstract class WP_Job_Manager_Email_Template extends WP_Job_Manager_Email {
65
  if ( ! $template_file ) {
66
  return '';
67
  }
68
- $args = $this->get_args();
69
  $email = $this;
70
 
71
  ob_start();
@@ -91,8 +93,8 @@ abstract class WP_Job_Manager_Email_Template extends WP_Job_Manager_Email {
91
  * @return string
92
  */
93
  protected function locate_template( $plain_text ) {
94
- $class_name = get_class( $this );
95
- $template_path = call_user_func( array( $class_name, 'get_template_path' ) );
96
  $template_default_path = call_user_func( array( $class_name, 'get_template_default_path' ) );
97
  return locate_job_manager_template( $this->get_template_file_name( $plain_text ), $template_path, $template_default_path );
98
  }
@@ -106,8 +108,8 @@ abstract class WP_Job_Manager_Email_Template extends WP_Job_Manager_Email {
106
  protected function get_template_file_name( $plain_text = false ) {
107
  $class_name = get_class( $this );
108
  // PHP 5.2: Using `call_user_func()` but `$class_name::get_key()` preferred.
109
- $email_notification_key = call_user_func( array( $class_name, 'get_key') );
110
- $template_name = str_replace( '_', '-', $email_notification_key );
111
  return self::generate_template_file_name( $template_name, $plain_text );
112
  }
113
 
1
  <?php
 
 
 
 
 
2
  /**
3
  * Abstract class for an email notification built using templates.
4
  *
7
  * @since 1.31.0
8
  */
9
 
10
+ if ( ! defined( 'ABSPATH' ) ) {
11
+ exit; // Exit if accessed directly.
12
+ }
13
+
14
+ /**
15
+ * Class WP_Job_Manager_Email_Template
16
+ */
17
  abstract class WP_Job_Manager_Email_Template extends WP_Job_Manager_Email {
18
  /**
19
  * Get the template path for overriding templates.
67
  if ( ! $template_file ) {
68
  return '';
69
  }
70
+ $args = $this->get_args();
71
  $email = $this;
72
 
73
  ob_start();
93
  * @return string
94
  */
95
  protected function locate_template( $plain_text ) {
96
+ $class_name = get_class( $this );
97
+ $template_path = call_user_func( array( $class_name, 'get_template_path' ) );
98
  $template_default_path = call_user_func( array( $class_name, 'get_template_default_path' ) );
99
  return locate_job_manager_template( $this->get_template_file_name( $plain_text ), $template_path, $template_default_path );
100
  }
108
  protected function get_template_file_name( $plain_text = false ) {
109
  $class_name = get_class( $this );
110
  // PHP 5.2: Using `call_user_func()` but `$class_name::get_key()` preferred.
111
+ $email_notification_key = call_user_func( array( $class_name, 'get_key' ) );
112
+ $template_name = str_replace( '_', '-', $email_notification_key );
113
  return self::generate_template_file_name( $template_name, $plain_text );
114
  }
115
 
includes/abstracts/abstract-wp-job-manager-email.php CHANGED
@@ -1,7 +1,12 @@
1
  <?php
 
 
 
 
 
2
 
3
  if ( ! defined( 'ABSPATH' ) ) {
4
- exit; // Exit if accessed directly
5
  }
6
 
7
  /**
@@ -27,14 +32,17 @@ if ( ! defined( 'ABSPATH' ) ) {
27
  *
28
  * @since 1.31.0
29
  */
30
-
31
  abstract class WP_Job_Manager_Email {
32
  /**
 
 
33
  * @var array
34
  */
35
  private $args = array();
36
 
37
  /**
 
 
38
  * @var array
39
  */
40
  private $settings = array();
@@ -122,8 +130,8 @@ abstract class WP_Job_Manager_Email {
122
  /**
123
  * Expand arguments as necessary for the generation of the email.
124
  *
125
- * @param $args
126
- * @return mixed
127
  */
128
  protected function prepare_args( $args ) {
129
  if ( isset( $args['job_id'] ) ) {
1
  <?php
2
+ /**
3
+ * Abstract email notification class.
4
+ *
5
+ * @package wp-job-manager
6
+ */
7
 
8
  if ( ! defined( 'ABSPATH' ) ) {
9
+ exit; // Exit if accessed directly.
10
  }
11
 
12
  /**
32
  *
33
  * @since 1.31.0
34
  */
 
35
  abstract class WP_Job_Manager_Email {
36
  /**
37
+ * Arguments used in an instance of an email notification.
38
+ *
39
  * @var array
40
  */
41
  private $args = array();
42
 
43
  /**
44
+ * Settings for this email notification.
45
+ *
46
  * @var array
47
  */
48
  private $settings = array();
130
  /**
131
  * Expand arguments as necessary for the generation of the email.
132
  *
133
+ * @param array $args Arguments used to generate the email.
134
+ * @return array
135
  */
136
  protected function prepare_args( $args ) {
137
  if ( isset( $args['job_id'] ) ) {
includes/abstracts/abstract-wp-job-manager-form.php CHANGED
@@ -76,17 +76,17 @@ abstract class WP_Job_Manager_Form {
76
  */
77
  public function process() {
78
 
79
- // reset cookie
80
  if (
81
- isset( $_GET[ 'new' ] ) &&
82
- isset( $_COOKIE[ 'wp-job-manager-submitting-job-id' ] ) &&
83
- isset( $_COOKIE[ 'wp-job-manager-submitting-job-key' ] ) &&
84
- get_post_meta( $_COOKIE[ 'wp-job-manager-submitting-job-id' ], '_submitting_key', true ) == $_COOKIE['wp-job-manager-submitting-job-key']
85
  ) {
86
- delete_post_meta( $_COOKIE[ 'wp-job-manager-submitting-job-id' ], '_submitting_key' );
87
  setcookie( 'wp-job-manager-submitting-job-id', '', time() - 3600, COOKIEPATH, COOKIE_DOMAIN, false );
88
  setcookie( 'wp-job-manager-submitting-job-key', '', time() - 3600, COOKIEPATH, COOKIE_DOMAIN, false );
89
- wp_redirect( remove_query_arg( array( 'new', 'key' ), $_SERVER[ 'REQUEST_URI' ] ) );
90
  }
91
 
92
  $step_key = $this->get_step_key( $this->step );
@@ -132,7 +132,7 @@ abstract class WP_Job_Manager_Form {
132
  */
133
  public function show_errors() {
134
  foreach ( $this->errors as $error ) {
135
- echo '<div class="job-manager-error">' . $error . '</div>';
136
  }
137
  }
138
 
@@ -237,10 +237,10 @@ abstract class WP_Job_Manager_Form {
237
  * @return int
238
  */
239
  protected function sort_by_priority( $a, $b ) {
240
- if ( $a['priority'] == $b['priority'] ) {
241
- return 0;
242
- }
243
- return ( $a['priority'] < $b['priority'] ) ? -1 : 1;
244
  }
245
 
246
  /**
@@ -265,8 +265,8 @@ abstract class WP_Job_Manager_Form {
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
  /**
@@ -292,11 +292,17 @@ abstract class WP_Job_Manager_Form {
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
  /**
@@ -309,20 +315,31 @@ abstract class WP_Job_Manager_Form {
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;
@@ -331,7 +348,7 @@ abstract class WP_Job_Manager_Form {
331
  /**
332
  * Gets post data for fields.
333
  *
334
- * @return array of data
335
  */
336
  protected function get_posted_fields() {
337
  $this->init_fields();
@@ -340,10 +357,11 @@ abstract class WP_Job_Manager_Form {
340
 
341
  foreach ( $this->fields as $group_key => $group_fields ) {
342
  foreach ( $group_fields as $key => $field ) {
343
- // Get the value
344
  $field_type = str_replace( '-', '_', $field['type'] );
 
345
 
346
- if ( $handler = apply_filters( "job_manager_get_posted_{$field_type}_field", false ) ) {
347
  $values[ $group_key ][ $key ] = call_user_func( $handler, $key, $field );
348
  } elseif ( method_exists( $this, "get_posted_{$field_type}_field" ) ) {
349
  $values[ $group_key ][ $key ] = call_user_func( array( $this, "get_posted_{$field_type}_field" ), $key, $field );
@@ -351,7 +369,7 @@ abstract class WP_Job_Manager_Form {
351
  $values[ $group_key ][ $key ] = $this->get_posted_field( $key, $field );
352
  }
353
 
354
- // Set fields value
355
  $this->fields[ $group_key ][ $key ]['value'] = $values[ $group_key ][ $key ];
356
  }
357
  }
@@ -371,7 +389,7 @@ abstract class WP_Job_Manager_Form {
371
  * @return array|string $value The sanitized array (or string from the callback).
372
  */
373
  protected function sanitize_posted_field( $value, $sanitizer = null ) {
374
- // Sanitize value
375
  if ( is_array( $value ) ) {
376
  foreach ( $value as $key => $val ) {
377
  $value[ $key ] = $this->sanitize_posted_field( $val, $sanitizer );
@@ -387,18 +405,18 @@ abstract class WP_Job_Manager_Form {
387
  } elseif ( 'email' === $sanitizer ) {
388
  return sanitize_email( $value );
389
  } elseif ( 'url_or_email' === $sanitizer ) {
390
- if ( null !== parse_url( $value, PHP_URL_HOST ) ) {
391
- // Sanitize as URL
392
  return esc_url_raw( $value );
393
  }
394
 
395
- // Sanitize as email
396
  return sanitize_email( $value );
397
  } elseif ( is_callable( $sanitizer ) ) {
398
  return call_user_func( $sanitizer, $value );
399
  }
400
 
401
- // Use standard text sanitizer
402
  return sanitize_text_field( stripslashes( $value ) );
403
  }
404
 
@@ -433,7 +451,9 @@ abstract class WP_Job_Manager_Form {
433
  *
434
  * @param string $key
435
  * @param array $field
 
436
  * @return string|array
 
437
  */
438
  protected function get_posted_file_field( $key, $field ) {
439
  $file = $this->upload_file( $key, $field );
@@ -477,8 +497,8 @@ abstract class WP_Job_Manager_Form {
477
  * @return array
478
  */
479
  protected function get_posted_term_checklist_field( $key, $field ) {
480
- if ( isset( $_POST[ 'tax_input' ] ) && isset( $_POST[ 'tax_input' ][ $field['taxonomy'] ] ) ) {
481
- return array_map( 'absint', $_POST[ 'tax_input' ][ $field['taxonomy'] ] );
482
  } else {
483
  return array();
484
  }
@@ -489,7 +509,7 @@ abstract class WP_Job_Manager_Form {
489
  *
490
  * @param string $key
491
  * @param array $field
492
- * @return int
493
  */
494
  protected function get_posted_term_multiselect_field( $key, $field ) {
495
  return isset( $_POST[ $key ] ) ? array_map( 'absint', $_POST[ $key ] ) : array();
@@ -511,7 +531,7 @@ abstract class WP_Job_Manager_Form {
511
  *
512
  * @param string $field_key
513
  * @param array $field
514
- * @throws Exception When file upload failed
515
  * @return string|array
516
  */
517
  protected function upload_file( $field_key, $field ) {
@@ -526,10 +546,13 @@ abstract class WP_Job_Manager_Form {
526
  $files_to_upload = job_manager_prepare_uploaded_files( $_FILES[ $field_key ] );
527
 
528
  foreach ( $files_to_upload as $file_to_upload ) {
529
- $uploaded_file = job_manager_upload_file( $file_to_upload, array(
530
- 'file_key' => $field_key,
531
- 'allowed_mime_types' => $allowed_mime_types,
532
- ) );
 
 
 
533
 
534
  if ( is_wp_error( $uploaded_file ) ) {
535
  throw new Exception( $uploaded_file->get_error_message() );
76
  */
77
  public function process() {
78
 
79
+ // reset cookie.
80
  if (
81
+ isset( $_GET['new'] ) &&
82
+ isset( $_COOKIE['wp-job-manager-submitting-job-id'] ) &&
83
+ isset( $_COOKIE['wp-job-manager-submitting-job-key'] ) &&
84
+ get_post_meta( $_COOKIE['wp-job-manager-submitting-job-id'], '_submitting_key', true ) === $_COOKIE['wp-job-manager-submitting-job-key']
85
  ) {
86
+ delete_post_meta( $_COOKIE['wp-job-manager-submitting-job-id'], '_submitting_key' );
87
  setcookie( 'wp-job-manager-submitting-job-id', '', time() - 3600, COOKIEPATH, COOKIE_DOMAIN, false );
88
  setcookie( 'wp-job-manager-submitting-job-key', '', time() - 3600, COOKIEPATH, COOKIE_DOMAIN, false );
89
+ wp_redirect( remove_query_arg( array( 'new', 'key' ), $_SERVER['REQUEST_URI'] ) );
90
  }
91
 
92
  $step_key = $this->get_step_key( $this->step );
132
  */
133
  public function show_errors() {
134
  foreach ( $this->errors as $error ) {
135
+ echo '<div class="job-manager-error">' . wp_kses_post( $error ) . '</div>';
136
  }
137
  }
138
 
237
  * @return int
238
  */
239
  protected function sort_by_priority( $a, $b ) {
240
+ if ( intval( $a['priority'] ) === intval( $b['priority'] ) ) {
241
+ return 0;
242
+ }
243
+ return ( intval( $a['priority'] ) < intval( $b['priority'] ) ) ? -1 : 1;
244
  }
245
 
246
  /**
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
  /**
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(
300
+ 'form-fields/recaptcha-field.php',
301
+ array(
302
+ 'key' => 'recaptcha',
303
+ 'field' => $field,
304
+ )
305
+ );
306
  }
307
 
308
  /**
315
  public function validate_recaptcha_field( $success ) {
316
  $recaptcha_field_label = get_option( 'job_manager_recaptcha_label' );
317
  if ( empty( $_POST['g-recaptcha-response'] ) ) {
318
+ // translators: Placeholder is for the label of the reCAPTCHA field.
319
+ return new WP_Error( 'validation-error', sprintf( esc_html__( '"%s" check failed. Please try again.', 'wp-job-manager' ), $recaptcha_field_label ) );
320
+ }
321
+
322
+ $response = wp_remote_get(
323
+ add_query_arg(
324
+ array(
325
+ 'secret' => get_option( 'job_manager_recaptcha_secret_key' ),
326
+ 'response' => isset( $_POST['g-recaptcha-response'] ) ? $_POST['g-recaptcha-response'] : '',
327
+ 'remoteip' => isset( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ? $_SERVER['HTTP_X_FORWARDED_FOR'] : $_SERVER['REMOTE_ADDR'],
328
+ ),
329
+ 'https://www.google.com/recaptcha/api/siteverify'
330
+ )
331
+ );
332
+
333
+ // translators: %s is the name of the form validation that failed.
334
+ $validation_error = new WP_Error( 'validation-error', sprintf( esc_html__( '"%s" check failed. Please try again.', 'wp-job-manager' ), $recaptcha_field_label ) );
335
+
336
+ if ( is_wp_error( $response ) || empty( $response['body'] ) ) {
337
+ return $validation_error;
338
  }
339
 
340
+ $json = json_decode( $response['body'] );
341
+ if ( ! $json || ! $json->success ) {
342
+ return $validation_error;
 
 
 
 
 
 
 
 
343
  }
344
 
345
  return $success;
348
  /**
349
  * Gets post data for fields.
350
  *
351
+ * @return array of data.
352
  */
353
  protected function get_posted_fields() {
354
  $this->init_fields();
357
 
358
  foreach ( $this->fields as $group_key => $group_fields ) {
359
  foreach ( $group_fields as $key => $field ) {
360
+ // Get the value.
361
  $field_type = str_replace( '-', '_', $field['type'] );
362
+ $handler = apply_filters( "job_manager_get_posted_{$field_type}_field", false );
363
 
364
+ if ( $handler ) {
365
  $values[ $group_key ][ $key ] = call_user_func( $handler, $key, $field );
366
  } elseif ( method_exists( $this, "get_posted_{$field_type}_field" ) ) {
367
  $values[ $group_key ][ $key ] = call_user_func( array( $this, "get_posted_{$field_type}_field" ), $key, $field );
369
  $values[ $group_key ][ $key ] = $this->get_posted_field( $key, $field );
370
  }
371
 
372
+ // Set fields value.
373
  $this->fields[ $group_key ][ $key ]['value'] = $values[ $group_key ][ $key ];
374
  }
375
  }
389
  * @return array|string $value The sanitized array (or string from the callback).
390
  */
391
  protected function sanitize_posted_field( $value, $sanitizer = null ) {
392
+ // Sanitize value.
393
  if ( is_array( $value ) ) {
394
  foreach ( $value as $key => $val ) {
395
  $value[ $key ] = $this->sanitize_posted_field( $val, $sanitizer );
405
  } elseif ( 'email' === $sanitizer ) {
406
  return sanitize_email( $value );
407
  } elseif ( 'url_or_email' === $sanitizer ) {
408
+ if ( null !== wp_parse_url( $value, PHP_URL_HOST ) ) {
409
+ // Sanitize as URL.
410
  return esc_url_raw( $value );
411
  }
412
 
413
+ // Sanitize as email.
414
  return sanitize_email( $value );
415
  } elseif ( is_callable( $sanitizer ) ) {
416
  return call_user_func( $sanitizer, $value );
417
  }
418
 
419
+ // Use standard text sanitizer.
420
  return sanitize_text_field( stripslashes( $value ) );
421
  }
422
 
451
  *
452
  * @param string $key
453
  * @param array $field
454
+ *
455
  * @return string|array
456
+ * @throws Exception When the upload fails.
457
  */
458
  protected function get_posted_file_field( $key, $field ) {
459
  $file = $this->upload_file( $key, $field );
497
  * @return array
498
  */
499
  protected function get_posted_term_checklist_field( $key, $field ) {
500
+ if ( isset( $_POST['tax_input'] ) && isset( $_POST['tax_input'][ $field['taxonomy'] ] ) ) {
501
+ return array_map( 'absint', $_POST['tax_input'][ $field['taxonomy'] ] );
502
  } else {
503
  return array();
504
  }
509
  *
510
  * @param string $key
511
  * @param array $field
512
+ * @return array
513
  */
514
  protected function get_posted_term_multiselect_field( $key, $field ) {
515
  return isset( $_POST[ $key ] ) ? array_map( 'absint', $_POST[ $key ] ) : array();
531
  *
532
  * @param string $field_key
533
  * @param array $field
534
+ * @throws Exception When file upload failed.
535
  * @return string|array
536
  */
537
  protected function upload_file( $field_key, $field ) {
546
  $files_to_upload = job_manager_prepare_uploaded_files( $_FILES[ $field_key ] );
547
 
548
  foreach ( $files_to_upload as $file_to_upload ) {
549
+ $uploaded_file = job_manager_upload_file(
550
+ $file_to_upload,
551
+ array(
552
+ 'file_key' => $field_key,
553
+ 'allowed_mime_types' => $allowed_mime_types,
554
+ )
555
+ );
556
 
557
  if ( is_wp_error( $uploaded_file ) ) {
558
  throw new Exception( $uploaded_file->get_error_message() );
includes/admin/class-wp-job-manager-addons.php CHANGED
@@ -1,11 +1,13 @@
1
  <?php
2
  /**
3
- * Addons Page
 
 
4
  */
5
 
6
- if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
7
-
8
- if ( ! class_exists( 'WP_Job_Manager_Addons' ) ) :
9
 
10
  /**
11
  * Handles the admin add-ons page.
@@ -45,7 +47,7 @@ class WP_Job_Manager_Addons {
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(
@@ -62,7 +64,7 @@ class WP_Job_Manager_Addons {
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' );
@@ -83,13 +85,18 @@ class WP_Job_Manager_Addons {
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 ) );
@@ -108,20 +115,31 @@ class WP_Job_Manager_Addons {
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' ) ) : ?>
113
- <a href="<?php echo esc_url( admin_url( 'edit.php?post_type=job_listing&page=job-manager-addons&section=helper' ) ); ?>" class="nav-tab<?php if ( isset( $_GET['section'] ) && 'helper' === $_GET['section'] ) { echo ' nav-tab-active'; } ?>"><?php _e( 'Licenses', 'wp-job-manager' ); ?></a>
 
 
 
 
 
114
  <?php endif; ?>
115
  </nav>
116
  <?php
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>
@@ -129,6 +147,4 @@ class WP_Job_Manager_Addons {
129
  }
130
  }
131
 
132
- endif;
133
-
134
  return WP_Job_Manager_Addons::instance();
1
  <?php
2
  /**
3
+ * Addons Page.
4
+ *
5
+ * @package wp-job-manager
6
  */
7
 
8
+ if ( ! defined( 'ABSPATH' ) ) {
9
+ exit; // Exit if accessed directly.
10
+ }
11
 
12
  /**
13
  * Handles the admin add-ons page.
47
  *
48
  * @param string $category
49
  *
50
+ * @return array of add-ons.
51
  */
52
  private function get_add_ons( $category = null ) {
53
  $raw_add_ons = wp_remote_get(
64
  *
65
  * @since 1.30.0
66
  *
67
+ * @return array of objects.
68
  */
69
  private function get_categories() {
70
  $add_on_categories = get_transient( 'jm_wpjmcom_add_on_categories' );
85
  *
86
  * @since 1.30.0
87
  *
88
+ * @return array of objects.
89
  */
90
  private function get_messages() {
91
  $add_on_messages = get_transient( 'jm_wpjmcom_add_on_messages' );
92
  if ( false === ( $add_on_messages ) ) {
93
  $raw_messages = wp_safe_remote_get(
94
+ add_query_arg(
95
+ array(
96
+ 'version' => JOB_MANAGER_VERSION,
97
+ 'lang' => get_locale(),
98
+ ), self::WPJM_COM_PRODUCTS_API_BASE_URL . '/messages'
99
+ )
100
  );
101
  if ( ! is_wp_error( $raw_messages ) ) {
102
  $add_on_messages = json_decode( wp_remote_retrieve_body( $raw_messages ) );
115
  ?>
116
  <div class="wrap wp_job_manager wp_job_manager_add_ons_wrap">
117
  <nav class="nav-tab-wrapper woo-nav-tab-wrapper">
118
+ <a href="<?php echo esc_url( admin_url( 'edit.php?post_type=job_listing&page=job-manager-addons' ) ); ?>" class="nav-tab
119
+ <?php
120
+ if ( ! isset( $_GET['section'] ) || 'helper' !== $_GET['section'] ) {
121
+ echo ' nav-tab-active';
122
+ }
123
+ ?>
124
+ "><?php esc_html_e( 'WP Job Manager Add-ons', 'wp-job-manager' ); ?></a>
125
  <?php if ( current_user_can( 'update_plugins' ) ) : ?>
126
+ <a href="<?php echo esc_url( admin_url( 'edit.php?post_type=job_listing&page=job-manager-addons&section=helper' ) ); ?>" class="nav-tab
127
+ <?php
128
+ if ( isset( $_GET['section'] ) && 'helper' === $_GET['section'] ) {
129
+ echo ' nav-tab-active'; }
130
+ ?>
131
+ "><?php esc_html_e( 'Licenses', 'wp-job-manager' ); ?></a>
132
  <?php endif; ?>
133
  </nav>
134
  <?php
135
  if ( isset( $_GET['section'] ) && 'helper' === $_GET['section'] ) {
136
  do_action( 'job_manager_helper_output' );
137
  } else {
138
+ $category = isset( $_GET['category'] ) ? sanitize_text_field( $_GET['category'] ) : null;
139
+ $messages = $this->get_messages();
140
  $categories = $this->get_categories();
141
+ $add_ons = $this->get_add_ons( $category );
142
+ include_once dirname( __FILE__ ) . '/views/html-admin-page-addons.php';
143
  }
144
  ?>
145
  </div>
147
  }
148
  }
149
 
 
 
150
  return WP_Job_Manager_Addons::instance();
includes/admin/class-wp-job-manager-admin.php CHANGED
@@ -1,6 +1,8 @@
1
  <?php
2
 
3
- if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
 
 
4
 
5
  /**
6
  * Handles front admin page for WP Job Manager.
@@ -38,16 +40,16 @@ class WP_Job_Manager_Admin {
38
  public function __construct() {
39
  global $wp_version;
40
 
41
- include_once( dirname( __FILE__ ) . '/class-wp-job-manager-cpt.php' );
42
  if ( version_compare( $wp_version, '4.7.0', '<' ) ) {
43
- include_once( dirname( __FILE__ ) . '/class-wp-job-manager-cpt-legacy.php' );
44
  WP_Job_Manager_CPT_Legacy::instance();
45
  } else {
46
  WP_Job_Manager_CPT::instance();
47
  }
48
- include_once( dirname( __FILE__ ) . '/class-wp-job-manager-settings.php' );
49
- include_once( dirname( __FILE__ ) . '/class-wp-job-manager-writepanels.php' );
50
- include_once( dirname( __FILE__ ) . '/class-wp-job-manager-setup.php' );
51
 
52
  $this->settings_page = WP_Job_Manager_Settings::instance();
53
 
@@ -63,7 +65,7 @@ class WP_Job_Manager_Admin {
63
  public function admin_init() {
64
  global $wp_version;
65
 
66
- include_once( dirname( __FILE__ ) . '/class-wp-job-manager-taxonomy-meta.php' );
67
 
68
  if ( version_compare( $wp_version, JOB_MANAGER_MINIMUM_WP_VERSION, '<' ) ) {
69
  add_action( 'admin_notices', array( $this, 'wp_version_admin_notice' ) );
@@ -76,14 +78,15 @@ class WP_Job_Manager_Admin {
76
  */
77
  public function wp_version_admin_notice() {
78
  // We only want to show the notices on the plugins page and WPJM admin pages.
79
- $screen = get_current_screen();
80
  $valid_screens = array( 'plugins', 'edit-job_listing', 'job_listing_page_job-manager-settings', 'edit-job_listing_type', 'edit-job_listing_category', 'job_listing' );
81
- if ( null === $screen || ! in_array( $screen->id, $valid_screens ) ) {
82
  return;
83
  }
84
 
85
  echo '<div class="error">';
86
- echo '<p>' . sprintf( __( '<strong>WP Job Manager</strong> requires a more recent version of WordPress. <a href="%s">Please update WordPresse</a> to avoid issues.', 'wp-job-manager' ), esc_url( self_admin_url( 'update-core.php' ) ) ) . '</p>';
 
87
  echo '</div>';
88
  }
89
 
@@ -94,7 +97,8 @@ class WP_Job_Manager_Admin {
94
  * @return array
95
  */
96
  public function wp_version_plugin_action_notice( $actions ) {
97
- $actions[] = sprintf( __( '<a href="%s" style="color: red">WordPress Update Required</a>', 'wp-job-manager' ), esc_url( self_admin_url( 'update-core.php' ) ) );
 
98
  return $actions;
99
  }
100
 
@@ -102,12 +106,13 @@ class WP_Job_Manager_Admin {
102
  * Include admin files conditionally.
103
  */
104
  public function conditional_includes() {
105
- if ( ! $screen = get_current_screen() ) {
 
106
  return;
107
  }
108
  switch ( $screen->id ) {
109
- case 'options-permalink' :
110
- include( 'class-wp-job-manager-permalink-settings.php' );
111
  break;
112
  }
113
  }
@@ -118,18 +123,22 @@ class WP_Job_Manager_Admin {
118
  public function admin_enqueue_scripts() {
119
  $screen = get_current_screen();
120
 
121
- if ( in_array( $screen->id, apply_filters( 'job_manager_admin_screen_ids', array( 'edit-job_listing', 'plugins', 'job_listing', 'job_listing_page_job-manager-settings', 'job_listing_page_job-manager-addons' ) ) ) ) {
122
  wp_enqueue_style( 'jquery-ui' );
123
  wp_enqueue_style( 'job_manager_admin_css', JOB_MANAGER_PLUGIN_URL . '/assets/css/admin.css', array(), JOB_MANAGER_VERSION );
124
- wp_register_script( 'jquery-tiptip', JOB_MANAGER_PLUGIN_URL. '/assets/js/jquery-tiptip/jquery.tipTip.min.js', array( 'jquery' ), JOB_MANAGER_VERSION, true );
125
- 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 );
126
- wp_enqueue_script( 'job_manager_admin_js', JOB_MANAGER_PLUGIN_URL. '/assets/js/admin.min.js', array( 'jquery', 'jquery-tiptip' ), JOB_MANAGER_VERSION, true );
127
 
128
  if ( ! function_exists( 'wp_localize_jquery_ui_datepicker' ) || ! has_action( 'admin_enqueue_scripts', 'wp_localize_jquery_ui_datepicker' ) ) {
129
- wp_localize_script( 'job_manager_datepicker_js', 'job_manager_datepicker', array(
130
- /* translators: jQuery date format, see http://api.jqueryui.com/datepicker/#utility-formatDate */
131
- 'date_format' => _x( 'yy-mm-dd', 'Date format for jQuery datepicker.', 'wp-job-manager' )
132
- ) );
 
 
 
 
133
  }
134
  }
135
 
@@ -142,15 +151,16 @@ class WP_Job_Manager_Admin {
142
  public function admin_menu() {
143
  add_submenu_page( 'edit.php?post_type=job_listing', __( 'Settings', 'wp-job-manager' ), __( 'Settings', 'wp-job-manager' ), 'manage_options', 'job-manager-settings', array( $this->settings_page, 'output' ) );
144
 
145
- if ( WP_Job_Manager_Helper::instance()->has_licenced_products() || apply_filters( 'job_manager_show_addons_page', true ) )
146
- add_submenu_page( 'edit.php?post_type=job_listing', __( 'WP Job Manager Add-ons', 'wp-job-manager' ), __( 'Add-ons', 'wp-job-manager' ) , 'manage_options', 'job-manager-addons', array( $this, 'addons_page' ) );
 
147
  }
148
 
149
  /**
150
  * Displays addons page.
151
  */
152
  public function addons_page() {
153
- $addons = include( 'class-wp-job-manager-addons.php' );
154
  $addons->output();
155
  }
156
  }
1
  <?php
2
 
3
+ if ( ! defined( 'ABSPATH' ) ) {
4
+ exit; // Exit if accessed directly.
5
+ }
6
 
7
  /**
8
  * Handles front admin page for WP Job Manager.
40
  public function __construct() {
41
  global $wp_version;
42
 
43
+ include_once dirname( __FILE__ ) . '/class-wp-job-manager-cpt.php';
44
  if ( version_compare( $wp_version, '4.7.0', '<' ) ) {
45
+ include_once dirname( __FILE__ ) . '/class-wp-job-manager-cpt-legacy.php';
46
  WP_Job_Manager_CPT_Legacy::instance();
47
  } else {
48
  WP_Job_Manager_CPT::instance();
49
  }
50
+ include_once dirname( __FILE__ ) . '/class-wp-job-manager-settings.php';
51
+ include_once dirname( __FILE__ ) . '/class-wp-job-manager-writepanels.php';
52
+ include_once dirname( __FILE__ ) . '/class-wp-job-manager-setup.php';
53
 
54
  $this->settings_page = WP_Job_Manager_Settings::instance();
55
 
65
  public function admin_init() {
66
  global $wp_version;
67
 
68
+ include_once dirname( __FILE__ ) . '/class-wp-job-manager-taxonomy-meta.php';
69
 
70
  if ( version_compare( $wp_version, JOB_MANAGER_MINIMUM_WP_VERSION, '<' ) ) {
71
  add_action( 'admin_notices', array( $this, 'wp_version_admin_notice' ) );
78
  */
79
  public function wp_version_admin_notice() {
80
  // We only want to show the notices on the plugins page and WPJM admin pages.
81
+ $screen = get_current_screen();
82
  $valid_screens = array( 'plugins', 'edit-job_listing', 'job_listing_page_job-manager-settings', 'edit-job_listing_type', 'edit-job_listing_category', 'job_listing' );
83
+ if ( null === $screen || ! in_array( $screen->id, $valid_screens, true ) ) {
84
  return;
85
  }
86
 
87
  echo '<div class="error">';
88
+ // translators: %s is the URL for the page where users can go to update WordPress.
89
+ echo '<p>' . wp_kses_post( sprintf( __( '<strong>WP Job Manager</strong> requires a more recent version of WordPress. <a href="%s">Please update WordPresse</a> to avoid issues.', 'wp-job-manager' ), esc_url( self_admin_url( 'update-core.php' ) ) ) ) . '</p>';
90
  echo '</div>';
91
  }
92
 
97
  * @return array
98
  */
99
  public function wp_version_plugin_action_notice( $actions ) {
100
+ // translators: Placeholder (%s) is the URL where users can go to update WordPress.
101
+ $actions[] = wp_kses_post( sprintf( __( '<a href="%s" style="color: red">WordPress Update Required</a>', 'wp-job-manager' ), esc_url( self_admin_url( 'update-core.php' ) ) ) );
102
  return $actions;
103
  }
104
 
106
  * Include admin files conditionally.
107
  */
108
  public function conditional_includes() {
109
+ $screen = get_current_screen();
110
+ if ( ! $screen ) {
111
  return;
112
  }
113
  switch ( $screen->id ) {
114
+ case 'options-permalink':
115
+ include 'class-wp-job-manager-permalink-settings.php';
116
  break;
117
  }
118
  }
123
  public function admin_enqueue_scripts() {
124
  $screen = get_current_screen();
125
 
126
+ if ( in_array( $screen->id, apply_filters( 'job_manager_admin_screen_ids', array( 'edit-job_listing', 'plugins', 'job_listing', 'job_listing_page_job-manager-settings', 'job_listing_page_job-manager-addons' ) ), true ) ) {
127
  wp_enqueue_style( 'jquery-ui' );
128
  wp_enqueue_style( 'job_manager_admin_css', JOB_MANAGER_PLUGIN_URL . '/assets/css/admin.css', array(), JOB_MANAGER_VERSION );
129
+ wp_register_script( 'jquery-tiptip', JOB_MANAGER_PLUGIN_URL . '/assets/js/jquery-tiptip/jquery.tipTip.min.js', array( 'jquery' ), JOB_MANAGER_VERSION, true );
130
+ 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 );
131
+ wp_enqueue_script( 'job_manager_admin_js', JOB_MANAGER_PLUGIN_URL . '/assets/js/admin.min.js', array( 'jquery', 'jquery-tiptip' ), JOB_MANAGER_VERSION, true );
132
 
133
  if ( ! function_exists( 'wp_localize_jquery_ui_datepicker' ) || ! has_action( 'admin_enqueue_scripts', 'wp_localize_jquery_ui_datepicker' ) ) {
134
+ wp_localize_script(
135
+ 'job_manager_datepicker_js',
136
+ 'job_manager_datepicker',
137
+ array(
138
+ /* translators: jQuery date format, see http://api.jqueryui.com/datepicker/#utility-formatDate */
139
+ 'date_format' => _x( 'yy-mm-dd', 'Date format for jQuery datepicker.', 'wp-job-manager' ),
140
+ )
141
+ );
142
  }
143
  }
144
 
151
  public function admin_menu() {
152
  add_submenu_page( 'edit.php?post_type=job_listing', __( 'Settings', 'wp-job-manager' ), __( 'Settings', 'wp-job-manager' ), 'manage_options', 'job-manager-settings', array( $this->settings_page, 'output' ) );
153
 
154
+ if ( WP_Job_Manager_Helper::instance()->has_licenced_products() || apply_filters( 'job_manager_show_addons_page', true ) ) {
155
+ add_submenu_page( 'edit.php?post_type=job_listing', __( 'WP Job Manager Add-ons', 'wp-job-manager' ), __( 'Add-ons', 'wp-job-manager' ), 'manage_options', 'job-manager-addons', array( $this, 'addons_page' ) );
156
+ }
157
  }
158
 
159
  /**
160
  * Displays addons page.
161
  */
162
  public function addons_page() {
163
+ $addons = include 'class-wp-job-manager-addons.php';
164
  $addons->output();
165
  }
166
  }
includes/admin/class-wp-job-manager-cpt-legacy.php CHANGED
@@ -1,6 +1,8 @@
1
  <?php
2
 
3
- if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
 
 
4
 
5
  /**
6
  * Handles legacy actions and filters specific to the custom post type for Job Listings.
@@ -48,18 +50,23 @@ class WP_Job_Manager_CPT_Legacy extends WP_Job_Manager_CPT {
48
  public function add_bulk_actions_legacy() {
49
  global $post_type, $wp_post_types;
50
 
51
- if ( $post_type === 'job_listing' ) {
 
 
 
 
 
 
 
 
52
  ?>
53
  <script type="text/javascript">
54
  jQuery(document).ready(function() {
55
- <?php
56
- foreach( $this->get_bulk_actions() as $key => $bulk_action ) {
57
- if ( isset( $bulk_action[ 'label' ] ) ) {
58
- echo 'jQuery(\'<option>\').val(\'' . $key . '\').text(\'' . addslashes( sprintf( $bulk_action[ 'label' ], $wp_post_types[ 'job_listing' ]->labels->name ) ) . '\').appendTo("select[name=\'action\']");';
59
- echo 'jQuery(\'<option>\').val(\'' . $key . '\').text(\'' . addslashes( sprintf( $bulk_action[ 'label' ], $wp_post_types[ 'job_listing' ]->labels->name ) ) . '\').appendTo("select[name=\'action2\']");';
60
- }
61
- }
62
- ?>
63
  });
64
  </script>
65
  <?php
@@ -70,12 +77,12 @@ class WP_Job_Manager_CPT_Legacy extends WP_Job_Manager_CPT {
70
  * Performs bulk actions on Job Listing admin page.
71
  */
72
  public function do_bulk_actions_legacy() {
73
- $wp_list_table = _get_list_table( 'WP_Posts_List_Table' );
74
- $action = $wp_list_table->current_action();
75
  $actions_handled = $this->get_bulk_actions();
76
- if ( isset ( $actions_handled[ $action ] ) && isset ( $actions_handled[ $action ]['handler'] ) ) {
77
  check_admin_referer( 'bulk-posts' );
78
- $post_ids = array_map( 'absint', array_filter( (array) $_GET['post'] ) );
79
  if ( ! empty( $post_ids ) ) {
80
  $this->do_bulk_actions( admin_url( 'edit.php?post_type=job_listing' ), $action, $post_ids );
81
  }
1
  <?php
2
 
3
+ if ( ! defined( 'ABSPATH' ) ) {
4
+ exit; // Exit if accessed directly.
5
+ }
6
 
7
  /**
8
  * Handles legacy actions and filters specific to the custom post type for Job Listings.
50
  public function add_bulk_actions_legacy() {
51
  global $post_type, $wp_post_types;
52
 
53
+ $bulk_actions = array();
54
+ foreach ( $this->get_bulk_actions() as $key => $bulk_action ) {
55
+ $bulk_actions[] = array(
56
+ 'key' => $key,
57
+ 'label' => sprintf( $bulk_action['label'], $wp_post_types['job_listing']->labels->name ),
58
+ );
59
+ }
60
+
61
+ if ( 'job_listing' === $post_type ) {
62
  ?>
63
  <script type="text/javascript">
64
  jQuery(document).ready(function() {
65
+ var actions = <?php echo wp_json_encode( $bulk_actions ); ?>;
66
+ actions.forEach(function(el){
67
+ jQuery( '<option>').val( el.key ).text(el.label).appendTo("select[name='action']");
68
+ jQuery( '<option>').val( el.key ).text(el.label).appendTo("select[name='action2']");
69
+ });
 
 
 
70
  });
71
  </script>
72
  <?php
77
  * Performs bulk actions on Job Listing admin page.
78
  */
79
  public function do_bulk_actions_legacy() {
80
+ $wp_list_table = _get_list_table( 'WP_Posts_List_Table' );
81
+ $action = $wp_list_table->current_action();
82
  $actions_handled = $this->get_bulk_actions();
83
+ if ( isset( $actions_handled[ $action ] ) && isset( $actions_handled[ $action ]['handler'] ) ) {
84
  check_admin_referer( 'bulk-posts' );
85
+ $post_ids = array_map( 'absint', array_filter( (array) $_GET['post'] ) );
86
  if ( ! empty( $post_ids ) ) {
87
  $this->do_bulk_actions( admin_url( 'edit.php?post_type=job_listing' ), $action, $post_ids );
88
  }
includes/admin/class-wp-job-manager-cpt.php CHANGED
@@ -1,6 +1,8 @@
1
  <?php
2
 
3
- if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
 
 
4
 
5
  /**
6
  * Handles actions and filters specific to the custom post type for Job Listings.
@@ -54,12 +56,12 @@ class WP_Job_Manager_CPT {
54
  add_action( 'view_mode_post_types', array( $this, 'disable_view_mode' ) );
55
 
56
  if ( get_option( 'job_manager_enable_categories' ) ) {
57
- add_action( "restrict_manage_posts", array( $this, "jobs_by_category" ) );
58
  }
59
- add_action( "restrict_manage_posts", array( $this, "jobs_meta_filters" ) );
60
 
61
  foreach ( array( 'post', 'post-new' ) as $hook ) {
62
- add_action( "admin_footer-{$hook}.php", array( $this,'extend_submitdiv_post_status' ) );
63
  }
64
  }
65
 
@@ -69,25 +71,33 @@ class WP_Job_Manager_CPT {
69
  * @return array
70
  */
71
  public function get_bulk_actions() {
72
- $actions_handled = array();
73
- $actions_handled['approve_jobs'] = array(
74
- 'label' => __( 'Approve %s', 'wp-job-manager' ),
75
- 'notice' => __( '%s approved', 'wp-job-manager' ),
 
 
76
  'handler' => array( $this, 'bulk_action_handle_approve_job' ),
77
  );
78
- $actions_handled['expire_jobs'] = array(
79
- 'label' => __( 'Expire %s', 'wp-job-manager' ),
80
- 'notice' => __( '%s expired', 'wp-job-manager' ),
 
 
81
  'handler' => array( $this, 'bulk_action_handle_expire_job' ),
82
  );
83
- $actions_handled['mark_jobs_filled'] = array(
84
- 'label' => __( 'Mark %s Filled', 'wp-job-manager' ),
85
- 'notice' => __( '%s marked as filled', 'wp-job-manager' ),
 
 
86
  'handler' => array( $this, 'bulk_action_handle_mark_job_filled' ),
87
  );
88
  $actions_handled['mark_jobs_not_filled'] = array(
89
- 'label' => __( 'Mark %s Not Filled', 'wp-job-manager' ),
90
- 'notice' => __( '%s marked as not filled', 'wp-job-manager' ),
 
 
91
  'handler' => array( $this, 'bulk_action_handle_mark_job_not_filled' ),
92
  );
93
 
@@ -137,12 +147,12 @@ class WP_Job_Manager_CPT {
137
  */
138
  public function do_bulk_actions( $redirect_url, $action, $post_ids ) {
139
  $actions_handled = $this->get_bulk_actions();
140
- if ( isset ( $actions_handled[ $action ] ) && isset ( $actions_handled[ $action ]['handler'] ) ) {
141
  $handled_jobs = array();
142
  if ( ! empty( $post_ids ) ) {
143
  foreach ( $post_ids as $post_id ) {
144
  if ( 'job_listing' === get_post_type( $post_id )
145
- && call_user_func( $actions_handled[ $action ]['handler'], $post_id ) ) {
146
  $handled_jobs[] = $post_id;
147
  }
148
  }
@@ -155,7 +165,7 @@ class WP_Job_Manager_CPT {
155
  /**
156
  * Performs bulk action to approve a single job listing.
157
  *
158
- * @param $post_id
159
  *
160
  * @return bool
161
  */
@@ -164,9 +174,9 @@ class WP_Job_Manager_CPT {
164
  'ID' => $post_id,
165
  'post_status' => 'publish',
166
  );
167
- if ( in_array( get_post_status( $post_id ), array( 'pending', 'pending_payment' ) )
168
- && current_user_can( 'publish_post', $post_id )
169
- && wp_update_post( $job_data )
170
  ) {
171
  return true;
172
  }
@@ -176,8 +186,7 @@ class WP_Job_Manager_CPT {
176
  /**
177
  * Performs bulk action to expire a single job listing.
178
  *
179
- * @param $post_id
180
- *
181
  * @return bool
182
  */
183
  public function bulk_action_handle_expire_job( $post_id ) {
@@ -186,7 +195,7 @@ class WP_Job_Manager_CPT {
186
  'post_status' => 'expired',
187
  );
188
  if ( current_user_can( 'manage_job_listings', $post_id )
189
- && wp_update_post( $job_data )
190
  ) {
191
  return true;
192
  }
@@ -196,13 +205,13 @@ class WP_Job_Manager_CPT {
196
  /**
197
  * Performs bulk action to mark a single job listing as filled.
198
  *
199
- * @param $post_id
200
  *
201
  * @return bool
202
  */
203
  public function bulk_action_handle_mark_job_filled( $post_id ) {
204
  if ( current_user_can( 'manage_job_listings', $post_id )
205
- && update_post_meta( $post_id, '_filled', 1 )
206
  ) {
207
  return true;
208
  }
@@ -212,13 +221,12 @@ class WP_Job_Manager_CPT {
212
  /**
213
  * Performs bulk action to mark a single job listing as not filled.
214
  *
215
- * @param $post_id
216
- *
217
  * @return bool
218
  */
219
  public function bulk_action_handle_mark_job_not_filled( $post_id ) {
220
  if ( current_user_can( 'manage_job_listings', $post_id )
221
- && update_post_meta( $post_id, '_filled', 0 )
222
  ) {
223
  return true;
224
  }
@@ -230,10 +238,10 @@ class WP_Job_Manager_CPT {
230
  */
231
  public function approve_job() {
232
  if ( ! empty( $_GET['approve_job'] ) && wp_verify_nonce( $_REQUEST['_wpnonce'], 'approve_job' ) && current_user_can( 'publish_post', $_GET['approve_job'] ) ) {
233
- $post_id = absint( $_GET['approve_job'] );
234
  $job_data = array(
235
  'ID' => $post_id,
236
- 'post_status' => 'publish'
237
  );
238
  wp_update_post( $job_data );
239
  wp_redirect( remove_query_arg( 'approve_job', add_query_arg( 'handled_jobs', $post_id, add_query_arg( 'action_performed', 'approve_jobs', admin_url( 'edit.php?post_type=job_listing' ) ) ) ) );
@@ -247,16 +255,16 @@ class WP_Job_Manager_CPT {
247
  public function action_notices() {
248
  global $post_type, $pagenow;
249
 
250
- $handled_jobs = isset ( $_REQUEST['handled_jobs'] ) ? $_REQUEST['handled_jobs'] : false;
251
- $action = isset ( $_REQUEST['action_performed'] ) ? $_REQUEST['action_performed'] : false;
252
  $actions_handled = $this->get_bulk_actions();
253
 
254
- if ( $pagenow == 'edit.php'
255
- && $post_type == 'job_listing'
256
  && $action
257
  && ! empty( $handled_jobs )
258
- && isset ( $actions_handled[ $action ] )
259
- && isset ( $actions_handled[ $action ]['notice'] )
260
  ) {
261
  if ( is_array( $handled_jobs ) ) {
262
  $handled_jobs = array_map( 'absint', $handled_jobs );
@@ -264,9 +272,9 @@ class WP_Job_Manager_CPT {
264
  foreach ( $handled_jobs as $job_id ) {
265
  $titles[] = wpjm_get_the_job_title( $job_id );
266
  }
267
- echo '<div class="updated"><p>' . sprintf( $actions_handled[ $action ]['notice'], '&quot;' . implode( '&quot;, &quot;', $titles ) . '&quot;' ) . '</p></div>';
268
  } else {
269
- echo '<div class="updated"><p>' . sprintf( $actions_handled[ $action ]['notice'], '&quot;' . wpjm_get_the_job_title( absint( $handled_jobs ) ) . '&quot;' ) . '</p></div>';
270
  }
271
  }
272
  }
@@ -277,11 +285,11 @@ class WP_Job_Manager_CPT {
277
  public function jobs_by_category() {
278
  global $typenow, $wp_query;
279
 
280
- if ( $typenow != 'job_listing' || ! taxonomy_exists( 'job_listing_category' ) ) {
281
- return;
282
- }
283
 
284
- include_once( JOB_MANAGER_PLUGIN_DIR . '/includes/class-wp-job-manager-category-walker.php' );
285
 
286
  $r = array();
287
  $r['taxonomy'] = 'job_listing_category';
@@ -292,18 +300,17 @@ class WP_Job_Manager_CPT {
292
  $r['selected'] = ( isset( $wp_query->query['job_listing_category'] ) ) ? $wp_query->query['job_listing_category'] : '';
293
  $r['menu_order'] = false;
294
  $terms = get_terms( $r );
295
- $walker = new WP_Job_Manager_Category_Walker;
296
 
297
  if ( ! $terms ) {
298
  return;
299
  }
300
 
301
- $output = "<select name='job_listing_category' id='dropdown_job_listing_category'>";
302
- $output .= '<option value="" ' . selected( isset( $_GET['job_listing_category'] ) ? $_GET['job_listing_category'] : '', '', false ) . '>' . __( 'Select category', 'wp-job-manager' ) . '</option>';
303
- $output .= $walker->walk( $terms, 0, $r );
304
- $output .= "</select>";
305
 
306
- echo $output;
307
  }
308
 
309
  /**
@@ -314,42 +321,48 @@ class WP_Job_Manager_CPT {
314
  public function jobs_meta_filters() {
315
  global $typenow;
316
 
317
- // Only add the filters for job_listings
318
- if ( 'job_listing' !== $typenow ) {
319
  return;
320
  }
321
 
322
  // Filter by Filled.
323
- $this->jobs_filter_dropdown( 'job_listing_filled', array(
324
- array(
325
- 'value' => '',
326
- 'text' => __( 'Select Filled', 'wp-job-manager' ),
327
- ),
328
- array(
329
- 'value' => '1',
330
- 'text' => __( 'Filled', 'wp-job-manager' ),
331
- ),
332
  array(
333
- 'value' => '0',
334
- 'text' => __( 'Not Filled', 'wp-job-manager' ),
335
- ),
336
- ) );
 
 
 
 
 
 
 
 
 
 
337
 
338
  // Filter by Featured.
339
- $this->jobs_filter_dropdown( 'job_listing_featured', array(
340
- array(
341
- 'value' => '',
342
- 'text' => __( 'Select Featured', 'wp-job-manager' ),
343
- ),
344
- array(
345
- 'value' => '1',
346
- 'text' => __( 'Featured', 'wp-job-manager' ),
347
- ),
348
  array(
349
- 'value' => '0',
350
- 'text' => __( 'Not Featured', 'wp-job-manager' ),
351
- ),
352
- ) );
 
 
 
 
 
 
 
 
 
 
353
  }
354
 
355
  /**
@@ -366,22 +379,20 @@ class WP_Job_Manager_CPT {
366
  * @since 1.31.0
367
  *
368
  * @param string $param The URL parameter.
369
- * @param array $options The options for the dropdown. See the
370
- * description above.
371
  */
372
  private function jobs_filter_dropdown( $param, $options ) {
373
  $selected = isset( $_GET[ $param ] ) ? $_GET[ $param ] : '';
374
 
375
- $output = "<select name=\"$param\" id=\"dropdown_$param\">";
376
 
377
  foreach ( $options as $option ) {
378
- $output .= '<option value="' . esc_attr( $option['value'] ) . '"'
379
  . ( $selected === $option['value'] ? ' selected' : '' )
380
  . '>' . esc_html( $option['text'] ) . '</option>';
381
  }
382
- $output .= '</select>';
383
 
384
- echo $output;
385
  }
386
 
387
  /**
@@ -392,8 +403,9 @@ class WP_Job_Manager_CPT {
392
  * @return string
393
  */
394
  public function enter_title_here( $text, $post ) {
395
- if ( $post->post_type == 'job_listing' )
396
- return __( 'Position', 'wp-job-manager' );
 
397
  return $text;
398
  }
399
 
@@ -407,18 +419,30 @@ class WP_Job_Manager_CPT {
407
  global $post, $post_ID, $wp_post_types;
408
 
409
  $messages['job_listing'] = array(
410
- 0 => '',
411
- 1 => sprintf( __( '%s updated. <a href="%s">View</a>', 'wp-job-manager' ), $wp_post_types['job_listing']->labels->singular_name, esc_url( get_permalink( $post_ID ) ) ),
412
- 2 => __( 'Custom field updated.', 'wp-job-manager' ),
413
- 3 => __( 'Custom field deleted.', 'wp-job-manager' ),
414
- 4 => sprintf( __( '%s updated.', 'wp-job-manager' ), $wp_post_types['job_listing']->labels->singular_name ),
415
- 5 => isset( $_GET['revision'] ) ? sprintf( __( '%s restored to revision from %s', 'wp-job-manager' ), $wp_post_types['job_listing']->labels->singular_name, wp_post_revision_title( (int) $_GET['revision'], false ) ) : false,
416
- 6 => sprintf( __( '%s published. <a href="%s">View</a>', 'wp-job-manager' ), $wp_post_types['job_listing']->labels->singular_name, esc_url( get_permalink( $post_ID ) ) ),
417
- 7 => sprintf( __( '%s saved.', 'wp-job-manager' ), $wp_post_types['job_listing']->labels->singular_name ),
418
- 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) ) ) ),
419
- 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,
420
- date_i18n( get_option( 'date_format' ) . ' @ '. get_option( 'time_format' ), strtotime( $post->post_date ) ), esc_url( get_permalink( $post_ID ) ) ),
421
- 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 ) ) ) ),
 
 
 
 
 
 
 
 
 
 
 
 
422
  );
423
 
424
  return $messages;
@@ -437,23 +461,23 @@ class WP_Job_Manager_CPT {
437
 
438
  unset( $columns['title'], $columns['date'], $columns['author'] );
439
 
440
- $columns["job_position"] = __( "Position", 'wp-job-manager' );
441
- $columns["job_listing_type"] = __( "Type", 'wp-job-manager' );
442
- $columns["job_location"] = __( "Location", 'wp-job-manager' );
443
- $columns['job_status'] = '<span class="tips" data-tip="' . __( "Status", 'wp-job-manager' ) . '">' . __( "Status", 'wp-job-manager' ) . '</span>';
444
- $columns["job_posted"] = __( "Posted", 'wp-job-manager' );
445
- $columns["job_expires"] = __( "Expires", 'wp-job-manager' );
446
- $columns["job_listing_category"] = __( "Categories", 'wp-job-manager' );
447
- $columns['featured_job'] = '<span class="tips" data-tip="' . __( "Featured?", 'wp-job-manager' ) . '">' . __( "Featured?", 'wp-job-manager' ) . '</span>';
448
- $columns['filled'] = '<span class="tips" data-tip="' . __( "Filled?", 'wp-job-manager' ) . '">' . __( "Filled?", 'wp-job-manager' ) . '</span>';
449
- $columns['job_actions'] = __( "Actions", 'wp-job-manager' );
450
 
451
  if ( ! get_option( 'job_manager_enable_categories' ) ) {
452
- unset( $columns["job_listing_category"] );
453
  }
454
 
455
  if ( ! get_option( 'job_manager_enable_types' ) ) {
456
- unset( $columns["job_listing_type"] );
457
  }
458
 
459
  return $columns;
@@ -484,7 +508,7 @@ class WP_Job_Manager_CPT {
484
  * @return array
485
  */
486
  public function row_actions( $actions ) {
487
- if ( 'job_listing' == get_post_type() ) {
488
  return array();
489
  }
490
  return $actions;
@@ -499,18 +523,19 @@ class WP_Job_Manager_CPT {
499
  global $post;
500
 
501
  switch ( $column ) {
502
- case "job_listing_type" :
503
  $types = wpjm_get_the_job_types( $post );
504
 
505
  if ( $types && ! empty( $types ) ) {
506
  foreach ( $types as $type ) {
507
- echo '<span class="job-type ' . $type->slug . '">' . $type->name . '</span>';
508
  }
509
  }
510
- break;
511
- case "job_position" :
512
  echo '<div class="job_position">';
513
- echo '<a href="' . admin_url('post.php?post=' . $post->ID . '&action=edit') . '" class="tips job_title" data-tip="' . sprintf( __( 'ID: %d', 'wp-job-manager' ), $post->ID ) . '">' . wpjm_get_the_job_title() . '</a>';
 
514
 
515
  echo '<div class="company">';
516
 
@@ -525,63 +550,78 @@ class WP_Job_Manager_CPT {
525
  the_company_logo();
526
  echo '</div>';
527
  echo '<button type="button" class="toggle-row"><span class="screen-reader-text">Show more details</span></button>';
528
- break;
529
- case "job_location" :
530
- the_job_location( $post );
531
- break;
532
- case "job_listing_category" :
533
- if ( ! $terms = get_the_term_list( $post->ID, $column, '', ', ', '' ) ) echo '<span class="na">&ndash;</span>'; else echo $terms;
534
- break;
535
- case "filled" :
536
- if ( is_position_filled( $post ) ) echo '&#10004;'; else echo '&ndash;';
537
- break;
538
- case "featured_job" :
539
- if ( is_position_featured( $post ) ) echo '&#10004;'; else echo '&ndash;';
540
- break;
541
- case "job_posted" :
542
- echo '<strong>' . date_i18n( get_option( 'date_format' ), strtotime( $post->post_date ) ) . '</strong><span>';
543
- 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>';
544
- break;
545
- case "job_expires" :
546
- if ( $post->_job_expires )
547
- echo '<strong>' . date_i18n( get_option( 'date_format' ), strtotime( $post->_job_expires ) ) . '</strong>';
548
- else
 
 
 
 
 
 
 
 
 
 
 
 
 
 
549
  echo '&ndash;';
550
- break;
551
- case "job_status" :
552
- echo '<span data-tip="' . esc_attr( get_the_job_status( $post ) ) . '" class="tips status-' . esc_attr( $post->post_status ) . '">' . get_the_job_status( $post ) . '</span>';
553
- break;
554
- case "job_actions" :
 
555
  echo '<div class="actions">';
556
  $admin_actions = apply_filters( 'post_row_actions', array(), $post );
557
 
558
- if ( in_array( $post->post_status, array( 'pending', 'pending_payment' ) ) && current_user_can ( 'publish_post', $post->ID ) ) {
559
- $admin_actions['approve'] = array(
560
- 'action' => 'approve',
561
- 'name' => __( 'Approve', 'wp-job-manager' ),
562
- 'url' => wp_nonce_url( add_query_arg( 'approve_job', $post->ID ), 'approve_job' )
563
  );
564
  }
565
- if ( $post->post_status !== 'trash' ) {
566
  if ( current_user_can( 'read_post', $post->ID ) ) {
567
- $admin_actions['view'] = array(
568
- 'action' => 'view',
569
- 'name' => __( 'View', 'wp-job-manager' ),
570
- 'url' => get_permalink( $post->ID )
571
  );
572
  }
573
  if ( current_user_can( 'edit_post', $post->ID ) ) {
574
- $admin_actions['edit'] = array(
575
- 'action' => 'edit',
576
- 'name' => __( 'Edit', 'wp-job-manager' ),
577
- 'url' => get_edit_post_link( $post->ID )
578
  );
579
  }
580
  if ( current_user_can( 'delete_post', $post->ID ) ) {
581
  $admin_actions['delete'] = array(
582
- 'action' => 'delete',
583
- 'name' => __( 'Delete', 'wp-job-manager' ),
584
- 'url' => get_delete_post_link( $post->ID )
585
  );
586
  }
587
  }
@@ -590,15 +630,15 @@ class WP_Job_Manager_CPT {
590
 
591
  foreach ( $admin_actions as $action ) {
592
  if ( is_array( $action ) ) {
593
- printf( '<a class="button button-icon tips icon-%1$s" href="%2$s" data-tip="%3$s">%4$s</a>', $action['action'], esc_url( $action['url'] ), esc_attr( $action['name'] ), esc_html( $action['name'] ) );
594
  } else {
595
- echo str_replace( 'class="', 'class="button ', $action );
596
  }
597
  }
598
 
599
  echo '</div>';
600
 
601
- break;
602
  }
603
  }
604
 
@@ -613,7 +653,7 @@ class WP_Job_Manager_CPT {
613
  'job_posted' => 'date',
614
  'job_position' => 'title',
615
  'job_location' => 'job_location',
616
- 'job_expires' => 'job_expires'
617
  );
618
  return wp_parse_args( $custom, $columns );
619
  }
@@ -621,21 +661,27 @@ class WP_Job_Manager_CPT {
621
  /**
622
  * Sorts the admin listing of Job Listings by updating the main query in the request.
623
  *
624
- * @param mixed $vars
625
  * @return array
626
  */
627
  public function sort_columns( $vars ) {
628
  if ( isset( $vars['orderby'] ) ) {
629
  if ( 'job_expires' === $vars['orderby'] ) {
630
- $vars = array_merge( $vars, array(
631
- 'meta_key' => '_job_expires',
632
- 'orderby' => 'meta_value'
633
- ) );
 
 
 
634
  } elseif ( 'job_location' === $vars['orderby'] ) {
635
- $vars = array_merge( $vars, array(
636
- 'meta_key' => '_job_location',
637
- 'orderby' => 'meta_value'
638
- ) );
 
 
 
639
  }
640
  }
641
  return $vars;
@@ -653,29 +699,32 @@ class WP_Job_Manager_CPT {
653
  return;
654
  }
655
 
656
- $post_ids = array_unique( array_merge(
657
- $wpdb->get_col(
658
- $wpdb->prepare( "
 
 
659
  SELECT posts.ID
660
  FROM {$wpdb->posts} posts
661
  INNER JOIN {$wpdb->postmeta} p1 ON posts.ID = p1.post_id
662
- WHERE p1.meta_value LIKE '%%%s%%'
663
- OR posts.post_title LIKE '%%%s%%'
664
- OR posts.post_content LIKE '%%%s%%'
665
  AND posts.post_type = 'job_listing'
666
  ",
667
- esc_sql( $wp->query_vars['s'] ),
668
- esc_sql( $wp->query_vars['s'] ),
669
- esc_sql( $wp->query_vars['s'] )
670
- )
671
- ),
672
- array( 0 )
673
- ) );
 
674
 
675
- // Adjust the query vars
676
  unset( $wp->query_vars['s'] );
677
  $wp->query_vars['job_listing_search'] = true;
678
- $wp->query_vars['post__in'] = $post_ids;
679
  }
680
 
681
  /**
@@ -686,7 +735,7 @@ class WP_Job_Manager_CPT {
686
  public function filter_meta( $wp ) {
687
  global $pagenow;
688
 
689
- if ( 'edit.php' !== $pagenow || 'job_listing' !== $wp->query_vars['post_type'] ) {
690
  return;
691
  }
692
 
@@ -698,7 +747,7 @@ class WP_Job_Manager_CPT {
698
  // Filter on _filled meta.
699
  if ( isset( $_GET['job_listing_filled'] ) && '' !== $_GET['job_listing_filled'] ) {
700
  $meta_query[] = array(
701
- 'key' => '_filled',
702
  'value' => $_GET['job_listing_filled'],
703
  );
704
  }
@@ -706,7 +755,7 @@ class WP_Job_Manager_CPT {
706
  // Filter on _featured meta.
707
  if ( isset( $_GET['job_listing_featured'] ) && '' !== $_GET['job_listing_featured'] ) {
708
  $meta_query[] = array(
709
- 'key' => '_featured',
710
  'value' => $_GET['job_listing_featured'],
711
  );
712
  }
@@ -726,7 +775,7 @@ class WP_Job_Manager_CPT {
726
  public function search_meta_label( $query ) {
727
  global $pagenow, $typenow;
728
 
729
- if ( 'edit.php' !== $pagenow || $typenow !== 'job_listing' || ! get_query_var( 'job_listing_search' ) ) {
730
  return $query;
731
  }
732
 
@@ -739,31 +788,34 @@ class WP_Job_Manager_CPT {
739
  public function extend_submitdiv_post_status() {
740
  global $post, $post_type;
741
 
742
- // Abort if we're on the wrong post type, but only if we got a restriction
743
  if ( 'job_listing' !== $post_type ) {
744
  return;
745
  }
746
 
747
- // Get all non-builtin post status and add them as <option>
748
- $options = $display = '';
 
749
  foreach ( get_job_listing_post_statuses() as $status => $name ) {
750
  $selected = selected( $post->post_status, $status, false );
751
 
752
- // If we one of our custom post status is selected, remember it
753
- $selected AND $display = $name;
 
 
754
 
755
- // Build the options
756
- $options .= "<option{$selected} value='{$status}'>{$name}</option>";
757
  }
758
  ?>
759
  <script type="text/javascript">
760
  jQuery( document ).ready( function($) {
761
  <?php if ( ! empty( $display ) ) : ?>
762
- jQuery( '#post-status-display' ).html( '<?php echo $display; ?>' );
763
  <?php endif; ?>
764
 
765
  var select = jQuery( '#post-status-select' ).find( 'select' );
766
- jQuery( select ).html( "<?php echo $options; ?>" );
767
  } );
768
  </script>
769
  <?php
@@ -772,8 +824,8 @@ class WP_Job_Manager_CPT {
772
  /**
773
  * Removes job_listing from the list of post types that support "View Mode" option
774
  *
775
- * @param array $post_types Array of post types that support view mode
776
- * @return array Array of post types that support view mode, without job_listing post type
777
  */
778
  public function disable_view_mode( $post_types ) {
779
  unset( $post_types['job_listing'] );
1
  <?php
2
 
3
+ if ( ! defined( 'ABSPATH' ) ) {
4
+ exit; // Exit if accessed directly.
5
+ }
6
 
7
  /**
8
  * Handles actions and filters specific to the custom post type for Job Listings.
56
  add_action( 'view_mode_post_types', array( $this, 'disable_view_mode' ) );
57
 
58
  if ( get_option( 'job_manager_enable_categories' ) ) {
59
+ add_action( 'restrict_manage_posts', array( $this, 'jobs_by_category' ) );
60
  }
61
+ add_action( 'restrict_manage_posts', array( $this, 'jobs_meta_filters' ) );
62
 
63
  foreach ( array( 'post', 'post-new' ) as $hook ) {
64
+ add_action( "admin_footer-{$hook}.php", array( $this, 'extend_submitdiv_post_status' ) );
65
  }
66
  }
67
 
71
  * @return array
72
  */
73
  public function get_bulk_actions() {
74
+ $actions_handled = array();
75
+ $actions_handled['approve_jobs'] = array(
76
+ // translators: Placeholder (%s) is the plural name of the job listings post type.
77
+ 'label' => __( 'Approve %s', 'wp-job-manager' ),
78
+ // translators: Placeholder (%s) is the plural name of the job listings post type.
79
+ 'notice' => __( '%s approved', 'wp-job-manager' ),
80
  'handler' => array( $this, 'bulk_action_handle_approve_job' ),
81
  );
82
+ $actions_handled['expire_jobs'] = array(
83
+ // translators: Placeholder (%s) is the plural name of the job listings post type.
84
+ 'label' => __( 'Expire %s', 'wp-job-manager' ),
85
+ // translators: Placeholder (%s) is the plural name of the job listings post type.
86
+ 'notice' => __( '%s expired', 'wp-job-manager' ),
87
  'handler' => array( $this, 'bulk_action_handle_expire_job' ),
88
  );
89
+ $actions_handled['mark_jobs_filled'] = array(
90
+ // translators: Placeholder (%s) is the plural name of the job listings post type.
91
+ 'label' => __( 'Mark %s Filled', 'wp-job-manager' ),
92
+ // translators: Placeholder (%s) is the plural name of the job listings post type.
93
+ 'notice' => __( '%s marked as filled', 'wp-job-manager' ),
94
  'handler' => array( $this, 'bulk_action_handle_mark_job_filled' ),
95
  );
96
  $actions_handled['mark_jobs_not_filled'] = array(
97
+ // translators: Placeholder (%s) is the plural name of the job listings post type.
98
+ 'label' => __( 'Mark %s Not Filled', 'wp-job-manager' ),
99
+ // translators: Placeholder (%s) is the plural name of the job listings post type.
100
+ 'notice' => __( '%s marked as not filled', 'wp-job-manager' ),
101
  'handler' => array( $this, 'bulk_action_handle_mark_job_not_filled' ),
102
  );
103
 
147
  */
148
  public function do_bulk_actions( $redirect_url, $action, $post_ids ) {
149
  $actions_handled = $this->get_bulk_actions();
150
+ if ( isset( $actions_handled[ $action ] ) && isset( $actions_handled[ $action ]['handler'] ) ) {
151
  $handled_jobs = array();
152
  if ( ! empty( $post_ids ) ) {
153
  foreach ( $post_ids as $post_id ) {
154
  if ( 'job_listing' === get_post_type( $post_id )
155
+ && call_user_func( $actions_handled[ $action ]['handler'], $post_id ) ) {
156
  $handled_jobs[] = $post_id;
157
  }
158
  }
165
  /**
166
  * Performs bulk action to approve a single job listing.
167
  *
168
+ * @param int $post_id Post ID.
169
  *
170
  * @return bool
171
  */
174
  'ID' => $post_id,
175
  'post_status' => 'publish',
176
  );
177
+ if ( in_array( get_post_status( $post_id ), array( 'pending', 'pending_payment' ), true )
178
+ && current_user_can( 'publish_post', $post_id )
179
+ && wp_update_post( $job_data )
180
  ) {
181
  return true;
182
  }
186
  /**
187
  * Performs bulk action to expire a single job listing.
188
  *
189
+ * @param int $post_id Post ID.
 
190
  * @return bool
191
  */
192
  public function bulk_action_handle_expire_job( $post_id ) {
195
  'post_status' => 'expired',
196
  );
197
  if ( current_user_can( 'manage_job_listings', $post_id )
198
+ && wp_update_post( $job_data )
199
  ) {
200
  return true;
201
  }
205
  /**
206
  * Performs bulk action to mark a single job listing as filled.
207
  *
208
+ * @param int $post_id Post ID.
209
  *
210
  * @return bool
211
  */
212
  public function bulk_action_handle_mark_job_filled( $post_id ) {
213
  if ( current_user_can( 'manage_job_listings', $post_id )
214
+ && update_post_meta( $post_id, '_filled', 1 )
215
  ) {
216
  return true;
217
  }
221
  /**
222
  * Performs bulk action to mark a single job listing as not filled.
223
  *
224
+ * @param int $post_id Post ID.
 
225
  * @return bool
226
  */
227
  public function bulk_action_handle_mark_job_not_filled( $post_id ) {
228
  if ( current_user_can( 'manage_job_listings', $post_id )
229
+ && update_post_meta( $post_id, '_filled', 0 )
230
  ) {
231
  return true;
232
  }
238
  */
239
  public function approve_job() {
240
  if ( ! empty( $_GET['approve_job'] ) && wp_verify_nonce( $_REQUEST['_wpnonce'], 'approve_job' ) && current_user_can( 'publish_post', $_GET['approve_job'] ) ) {
241
+ $post_id = absint( $_GET['approve_job'] );
242
  $job_data = array(
243
  'ID' => $post_id,
244
+ 'post_status' => 'publish',
245
  );
246
  wp_update_post( $job_data );
247
  wp_redirect( remove_query_arg( 'approve_job', add_query_arg( 'handled_jobs', $post_id, add_query_arg( 'action_performed', 'approve_jobs', admin_url( 'edit.php?post_type=job_listing' ) ) ) ) );
255
  public function action_notices() {
256
  global $post_type, $pagenow;
257
 
258
+ $handled_jobs = isset( $_REQUEST['handled_jobs'] ) ? $_REQUEST['handled_jobs'] : false;
259
+ $action = isset( $_REQUEST['action_performed'] ) ? $_REQUEST['action_performed'] : false;
260
  $actions_handled = $this->get_bulk_actions();
261
 
262
+ if ( 'edit.php' === $pagenow
263
+ && 'job_listing' === $post_type
264
  && $action
265
  && ! empty( $handled_jobs )
266
+ && isset( $actions_handled[ $action ] )
267
+ && isset( $actions_handled[ $action ]['notice'] )
268
  ) {
269
  if ( is_array( $handled_jobs ) ) {
270
  $handled_jobs = array_map( 'absint', $handled_jobs );
272
  foreach ( $handled_jobs as $job_id ) {
273
  $titles[] = wpjm_get_the_job_title( $job_id );
274
  }
275
+ echo '<div class="updated"><p>' . wp_kses_post( sprintf( $actions_handled[ $action ]['notice'], '&quot;' . implode( '&quot;, &quot;', $titles ) . '&quot;' ) ) . '</p></div>';
276
  } else {
277
+ echo '<div class="updated"><p>' . wp_kses_post( sprintf( $actions_handled[ $action ]['notice'], '&quot;' . wpjm_get_the_job_title( absint( $handled_jobs ) ) . '&quot;' ) ) . '</p></div>';
278
  }
279
  }
280
  }
285
  public function jobs_by_category() {
286
  global $typenow, $wp_query;
287
 
288
+ if ( 'job_listing' !== $typenow || ! taxonomy_exists( 'job_listing_category' ) ) {
289
+ return;
290
+ }
291
 
292
+ include_once JOB_MANAGER_PLUGIN_DIR . '/includes/class-wp-job-manager-category-walker.php';
293
 
294
  $r = array();
295
  $r['taxonomy'] = 'job_listing_category';
300
  $r['selected'] = ( isset( $wp_query->query['job_listing_category'] ) ) ? $wp_query->query['job_listing_category'] : '';
301
  $r['menu_order'] = false;
302
  $terms = get_terms( $r );
303
+ $walker = new WP_Job_Manager_Category_Walker();
304
 
305
  if ( ! $terms ) {
306
  return;
307
  }
308
 
309
+ echo "<select name='job_listing_category' id='dropdown_job_listing_category'>";
310
+ echo '<option value="" ' . selected( isset( $_GET['job_listing_category'] ) ? $_GET['job_listing_category'] : '', '', false ) . '>' . esc_html__( 'Select category', 'wp-job-manager' ) . '</option>';
311
+ echo wp_kses_post( $walker->walk( $terms, 0, $r ) );
312
+ echo '</select>';
313
 
 
314
  }
315
 
316
  /**
321
  public function jobs_meta_filters() {
322
  global $typenow;
323
 
324
+ // Only add the filters for job_listings.
325
+ if ( 'job_listing' !== $typenow ) {
326
  return;
327
  }
328
 
329
  // Filter by Filled.
330
+ $this->jobs_filter_dropdown(
331
+ 'job_listing_filled',
 
 
 
 
 
 
 
332
  array(
333
+ array(
334
+ 'value' => '',
335
+ 'text' => __( 'Select Filled', 'wp-job-manager' ),
336
+ ),
337
+ array(
338
+ 'value' => '1',
339
+ 'text' => __( 'Filled', 'wp-job-manager' ),
340
+ ),
341
+ array(
342
+ 'value' => '0',
343
+ 'text' => __( 'Not Filled', 'wp-job-manager' ),
344
+ ),
345
+ )
346
+ );
347
 
348
  // Filter by Featured.
349
+ $this->jobs_filter_dropdown(
350
+ 'job_listing_featured',
 
 
 
 
 
 
 
351
  array(
352
+ array(
353
+ 'value' => '',
354
+ 'text' => __( 'Select Featured', 'wp-job-manager' ),
355
+ ),
356
+ array(
357
+ 'value' => '1',
358
+ 'text' => __( 'Featured', 'wp-job-manager' ),
359
+ ),
360
+ array(
361
+ 'value' => '0',
362
+ 'text' => __( 'Not Featured', 'wp-job-manager' ),
363
+ ),
364
+ )
365
+ );
366
  }
367
 
368
  /**
379
  * @since 1.31.0
380
  *
381
  * @param string $param The URL parameter.
382
+ * @param array $options The options for the dropdown. See the description above.
 
383
  */
384
  private function jobs_filter_dropdown( $param, $options ) {
385
  $selected = isset( $_GET[ $param ] ) ? $_GET[ $param ] : '';
386
 
387
+ echo '<select name="' . esc_attr( $param ) . '" id="dropdown_' . esc_attr( $param ) . '">';
388
 
389
  foreach ( $options as $option ) {
390
+ echo '<option value="' . esc_attr( $option['value'] ) . '"'
391
  . ( $selected === $option['value'] ? ' selected' : '' )
392
  . '>' . esc_html( $option['text'] ) . '</option>';
393
  }
394
+ echo '</select>';
395
 
 
396
  }
397
 
398
  /**
403
  * @return string
404
  */
405
  public function enter_title_here( $text, $post ) {
406
+ if ( 'job_listing' === $post->post_type ) {
407
+ return esc_html__( 'Position', 'wp-job-manager' );
408
+ }
409
  return $text;
410
  }
411
 
419
  global $post, $post_ID, $wp_post_types;
420
 
421
  $messages['job_listing'] = array(
422
+ 0 => '',
423
+ // translators: %1$s is the singular name of the job listing post type; %2$s is the URL to view the listing.
424
+ 1 => sprintf( __( '%1$s updated. <a href="%2$s">View</a>', 'wp-job-manager' ), $wp_post_types['job_listing']->labels->singular_name, esc_url( get_permalink( $post_ID ) ) ),
425
+ 2 => __( 'Custom field updated.', 'wp-job-manager' ),
426
+ 3 => __( 'Custom field deleted.', 'wp-job-manager' ),
427
+ // translators: %s is the singular name of the job listing post type.
428
+ 4 => sprintf( esc_html__( '%s updated.', 'wp-job-manager' ), $wp_post_types['job_listing']->labels->singular_name ),
429
+ // translators: %1$s is the singular name of the job listing post type; %2$s is the revision number.
430
+ 5 => isset( $_GET['revision'] ) ? sprintf( __( '%1$s restored to revision from %2$s', 'wp-job-manager' ), $wp_post_types['job_listing']->labels->singular_name, wp_post_revision_title( (int) $_GET['revision'], false ) ) : false,
431
+ // translators: %1$s is the singular name of the job listing post type; %2$s is the URL to view the listing.
432
+ 6 => sprintf( __( '%1$s published. <a href="%2$s">View</a>', 'wp-job-manager' ), $wp_post_types['job_listing']->labels->singular_name, esc_url( get_permalink( $post_ID ) ) ),
433
+ // translators: %1$s is the singular name of the job listing post type; %2$s is the URL to view the listing.
434
+ 7 => sprintf( esc_html__( '%s saved.', 'wp-job-manager' ), $wp_post_types['job_listing']->labels->singular_name ),
435
+ // translators: %1$s is the singular name of the job listing post type; %2$s is the URL to preview the listing.
436
+ 8 => sprintf( __( '%1$s submitted. <a target="_blank" href="%2$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 ) ) ) ),
437
+ 9 => sprintf(
438
+ // translators: %1$s is the singular name of the post type; %2$s is the date the post will be published; %3$s is the URL to preview the listing.
439
+ __( '%1$s scheduled for: <strong>%2$s</strong>. <a target="_blank" href="%3$s">Preview</a>', 'wp-job-manager' ),
440
+ $wp_post_types['job_listing']->labels->singular_name,
441
+ date_i18n( get_option( 'date_format' ) . ' @ ' . get_option( 'time_format' ), strtotime( $post->post_date ) ),
442
+ esc_url( get_permalink( $post_ID ) )
443
+ ),
444
+ // translators: %1$s is the singular name of the job listing post type; %2$s is the URL to view the listing.
445
+ 10 => sprintf( __( '%1$s draft updated. <a target="_blank" href="%2$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 ) ) ) ),
446
  );
447
 
448
  return $messages;
461
 
462
  unset( $columns['title'], $columns['date'], $columns['author'] );
463
 
464
+ $columns['job_position'] = __( 'Position', 'wp-job-manager' );
465
+ $columns['job_listing_type'] = __( 'Type', 'wp-job-manager' );
466
+ $columns['job_location'] = __( 'Location', 'wp-job-manager' );
467
+ $columns['job_status'] = '<span class="tips" data-tip="' . __( 'Status', 'wp-job-manager' ) . '">' . __( 'Status', 'wp-job-manager' ) . '</span>';
468
+ $columns['job_posted'] = __( 'Posted', 'wp-job-manager' );
469
+ $columns['job_expires'] = __( 'Expires', 'wp-job-manager' );
470
+ $columns['job_listing_category'] = __( 'Categories', 'wp-job-manager' );
471
+ $columns['featured_job'] = '<span class="tips" data-tip="' . __( 'Featured?', 'wp-job-manager' ) . '">' . __( 'Featured?', 'wp-job-manager' ) . '</span>';
472
+ $columns['filled'] = '<span class="tips" data-tip="' . __( 'Filled?', 'wp-job-manager' ) . '">' . __( 'Filled?', 'wp-job-manager' ) . '</span>';
473
+ $columns['job_actions'] = __( 'Actions', 'wp-job-manager' );
474
 
475
  if ( ! get_option( 'job_manager_enable_categories' ) ) {
476
+ unset( $columns['job_listing_category'] );
477
  }
478
 
479
  if ( ! get_option( 'job_manager_enable_types' ) ) {
480
+ unset( $columns['job_listing_type'] );
481
  }
482
 
483
  return $columns;
508
  * @return array
509
  */
510
  public function row_actions( $actions ) {
511
+ if ( 'job_listing' === get_post_type() ) {
512
  return array();
513
  }
514
  return $actions;
523
  global $post;
524
 
525
  switch ( $column ) {
526
+ case 'job_listing_type':
527
  $types = wpjm_get_the_job_types( $post );
528
 
529
  if ( $types && ! empty( $types ) ) {
530
  foreach ( $types as $type ) {
531
+ echo '<span class="job-type ' . esc_attr( $type->slug ) . '">' . esc_html( $type->name ) . '</span>';
532
  }
533
  }
534
+ break;
535
+ case 'job_position':
536
  echo '<div class="job_position">';
537
+ // translators: %d is the post ID for the job listing.
538
+ echo '<a href="' . esc_url( admin_url( 'post.php?post=' . $post->ID . '&action=edit' ) ) . '" class="tips job_title" data-tip="' . sprintf( esc_html__( 'ID: %d', 'wp-job-manager' ), intval( $post->ID ) ) . '">' . esc_html( wpjm_get_the_job_title() ) . '</a>';
539
 
540
  echo '<div class="company">';
541
 
550
  the_company_logo();
551
  echo '</div>';
552
  echo '<button type="button" class="toggle-row"><span class="screen-reader-text">Show more details</span></button>';
553
+ break;
554
+ case 'job_location':
555
+ the_job_location( true, $post );
556
+ break;
557
+ case 'job_listing_category':
558
+ $terms = get_the_term_list( $post->ID, $column, '', ', ', '' );
559
+ if ( ! $terms ) {
560
+ echo '<span class="na">&ndash;</span>';
561
+ } else {
562
+ echo wp_kses_post( $terms );
563
+ }
564
+ break;
565
+ case 'filled':
566
+ if ( is_position_filled( $post ) ) {
567
+ echo '&#10004;';
568
+ } else {
569
+ echo '&ndash;';
570
+ }
571
+ break;
572
+ case 'featured_job':
573
+ if ( is_position_featured( $post ) ) {
574
+ echo '&#10004;';
575
+ } else {
576
+ echo '&ndash;';
577
+ }
578
+ break;
579
+ case 'job_posted':
580
+ echo '<strong>' . esc_html( date_i18n( get_option( 'date_format' ), strtotime( $post->post_date ) ) ) . '</strong><span>';
581
+ // translators: %s placeholder is the username of the user.
582
+ echo ( empty( $post->post_author ) ? esc_html__( 'by a guest', 'wp-job-manager' ) : sprintf( esc_html__( 'by %s', 'wp-job-manager' ), '<a href="' . esc_url( add_query_arg( 'author', $post->post_author ) ) . '">' . esc_html( get_the_author() ) . '</a>' ) ) . '</span>';
583
+ break;
584
+ case 'job_expires':
585
+ if ( $post->_job_expires ) {
586
+ echo '<strong>' . esc_html( date_i18n( get_option( 'date_format' ), strtotime( $post->_job_expires ) ) ) . '</strong>';
587
+ } else {
588
  echo '&ndash;';
589
+ }
590
+ break;
591
+ case 'job_status':
592
+ echo '<span data-tip="' . esc_attr( get_the_job_status( $post ) ) . '" class="tips status-' . esc_attr( $post->post_status ) . '">' . esc_html( get_the_job_status( $post ) ) . '</span>';
593
+ break;
594
+ case 'job_actions':
595
  echo '<div class="actions">';
596
  $admin_actions = apply_filters( 'post_row_actions', array(), $post );
597
 
598
+ if ( in_array( $post->post_status, array( 'pending', 'pending_payment' ), true ) && current_user_can( 'publish_post', $post->ID ) ) {
599
+ $admin_actions['approve'] = array(
600
+ 'action' => 'approve',
601
+ 'name' => __( 'Approve', 'wp-job-manager' ),
602
+ 'url' => wp_nonce_url( add_query_arg( 'approve_job', $post->ID ), 'approve_job' ),
603
  );
604
  }
605
+ if ( 'trash' !== $post->post_status ) {
606
  if ( current_user_can( 'read_post', $post->ID ) ) {
607
+ $admin_actions['view'] = array(
608
+ 'action' => 'view',
609
+ 'name' => __( 'View', 'wp-job-manager' ),
610
+ 'url' => get_permalink( $post->ID ),
611
  );
612
  }
613
  if ( current_user_can( 'edit_post', $post->ID ) ) {
614
+ $admin_actions['edit'] = array(
615
+ 'action' => 'edit',
616
+ 'name' => __( 'Edit', 'wp-job-manager' ),
617
+ 'url' => get_edit_post_link( $post->ID ),
618
  );
619
  }
620
  if ( current_user_can( 'delete_post', $post->ID ) ) {
621
  $admin_actions['delete'] = array(
622
+ 'action' => 'delete',
623
+ 'name' => __( 'Delete', 'wp-job-manager' ),
624
+ 'url' => get_delete_post_link( $post->ID ),
625
  );
626
  }
627
  }
630
 
631
  foreach ( $admin_actions as $action ) {
632
  if ( is_array( $action ) ) {
633
+ printf( '<a class="button button-icon tips icon-%1$s" href="%2$s" data-tip="%3$s">%4$s</a>', esc_attr( $action['action'] ), esc_url( $action['url'] ), esc_attr( $action['name'] ), esc_html( $action['name'] ) );
634
  } else {
635
+ echo wp_kses_post( str_replace( 'class="', 'class="button ', $action ) );
636
  }
637
  }
638
 
639
  echo '</div>';
640
 
641
+ break;
642
  }
643
  }
644
 
653
  'job_posted' => 'date',
654
  'job_position' => 'title',
655
  'job_location' => 'job_location',
656
+ 'job_expires' => 'job_expires',
657
  );
658
  return wp_parse_args( $custom, $columns );
659
  }
661
  /**
662
  * Sorts the admin listing of Job Listings by updating the main query in the request.
663
  *
664
+ * @param mixed $vars Variables with sort arguments.
665
  * @return array
666
  */
667
  public function sort_columns( $vars ) {
668
  if ( isset( $vars['orderby'] ) ) {
669
  if ( 'job_expires' === $vars['orderby'] ) {
670
+ $vars = array_merge(
671
+ $vars,
672
+ array(
673
+ 'meta_key' => '_job_expires',
674
+ 'orderby' => 'meta_value',
675
+ )
676
+ );
677
  } elseif ( 'job_location' === $vars['orderby'] ) {
678
+ $vars = array_merge(
679
+ $vars,
680
+ array(
681
+ 'meta_key' => '_job_location',
682
+ 'orderby' => 'meta_value',
683
+ )
684
+ );
685
  }
686
  }
687
  return $vars;
699
  return;
700
  }
701
 
702
+ $post_ids = array_unique(
703
+ array_merge(
704
+ $wpdb->get_col(
705
+ $wpdb->prepare(
706
+ "
707
  SELECT posts.ID
708
  FROM {$wpdb->posts} posts
709
  INNER JOIN {$wpdb->postmeta} p1 ON posts.ID = p1.post_id
710
+ WHERE p1.meta_value LIKE %s
711
+ OR posts.post_title LIKE %s
712
+ OR posts.post_content LIKE %s
713
  AND posts.post_type = 'job_listing'
714
  ",
715
+ '%' . $wpdb->esc_like( $wp->query_vars['s'] ) . '%',
716
+ '%' . $wpdb->esc_like( $wp->query_vars['s'] ) . '%',
717
+ '%' . $wpdb->esc_like( $wp->query_vars['s'] ) . '%'
718
+ )
719
+ ),
720
+ array( 0 )
721
+ )
722
+ );
723
 
724
+ // Adjust the query vars.
725
  unset( $wp->query_vars['s'] );
726
  $wp->query_vars['job_listing_search'] = true;
727
+ $wp->query_vars['post__in'] = $post_ids;
728
  }
729
 
730
  /**
735
  public function filter_meta( $wp ) {
736
  global $pagenow;
737
 
738
+ if ( 'edit.php' !== $pagenow || empty( $wp->query_vars['post_type'] ) || 'job_listing' !== $wp->query_vars['post_type'] ) {
739
  return;
740
  }
741
 
747
  // Filter on _filled meta.
748
  if ( isset( $_GET['job_listing_filled'] ) && '' !== $_GET['job_listing_filled'] ) {
749
  $meta_query[] = array(
750
+ 'key' => '_filled',
751
  'value' => $_GET['job_listing_filled'],
752
  );
753
  }
755
  // Filter on _featured meta.
756
  if ( isset( $_GET['job_listing_featured'] ) && '' !== $_GET['job_listing_featured'] ) {
757
  $meta_query[] = array(
758
+ 'key' => '_featured',
759
  'value' => $_GET['job_listing_featured'],
760
  );
761
  }
775
  public function search_meta_label( $query ) {
776
  global $pagenow, $typenow;
777
 
778
+ if ( 'edit.php' !== $pagenow || 'job_listing' !== $typenow || ! get_query_var( 'job_listing_search' ) ) {
779
  return $query;
780
  }
781
 
788
  public function extend_submitdiv_post_status() {
789
  global $post, $post_type;
790
 
791
+ // Abort if we're on the wrong post type, but only if we got a restriction.
792
  if ( 'job_listing' !== $post_type ) {
793
  return;
794
  }
795
 
796
+ // Get all non-builtin post status and add them as <option>.
797
+ $options = '';
798
+ $display = '';
799
  foreach ( get_job_listing_post_statuses() as $status => $name ) {
800
  $selected = selected( $post->post_status, $status, false );
801
 
802
+ // If we one of our custom post status is selected, remember it.
803
+ if ( $selected ) {
804
+ $display = $name;
805
+ }
806
 
807
+ // Build the options.
808
+ $options .= "<option{$selected} value='{$status}'>" . esc_html( $name ) . '</option>';
809
  }
810
  ?>
811
  <script type="text/javascript">
812
  jQuery( document ).ready( function($) {
813
  <?php if ( ! empty( $display ) ) : ?>
814
+ jQuery( '#post-status-display' ).html( <?php echo wp_json_encode( $display ); ?> );
815
  <?php endif; ?>
816
 
817
  var select = jQuery( '#post-status-select' ).find( 'select' );
818
+ jQuery( select ).html( <?php echo wp_json_encode( $options ); ?> );
819
  } );
820
  </script>
821
  <?php
824
  /**
825
  * Removes job_listing from the list of post types that support "View Mode" option
826
  *
827
+ * @param array $post_types Array of post types that support view mode.
828
+ * @return array Array of post types that support view mode, without job_listing post type.
829
  */
830
  public function disable_view_mode( $post_types ) {
831
  unset( $post_types['job_listing'] );
includes/admin/class-wp-job-manager-permalink-settings.php CHANGED
@@ -1,6 +1,8 @@
1
  <?php
2
 
3
- if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
 
 
4
 
5
  /**
6
  * Handles front admin page for WP Job Manager.
@@ -49,6 +51,9 @@ class WP_Job_Manager_Permalink_Settings {
49
  $this->permalinks = WP_Job_Manager_Post_Types::get_permalink_structure();
50
  }
51
 
 
 
 
52
  public function setup_fields() {
53
  add_settings_field(
54
  'wpjm_job_base_slug',
@@ -78,7 +83,7 @@ class WP_Job_Manager_Permalink_Settings {
78
  */
79
  public function job_base_slug_input() {
80
  ?>
81
- <input name="wpjm_job_base_slug" type="text" class="regular-text code" value="<?php echo esc_attr( $this->permalinks['job_base'] ); ?>" placeholder="<?php echo esc_attr_x( 'job', 'Job permalink - resave permalinks after changing this', 'wp-job-manager' ) ?>" />
82
  <?php
83
  }
84
 
@@ -87,7 +92,7 @@ class WP_Job_Manager_Permalink_Settings {
87
  */
88
  public function job_category_slug_input() {
89
  ?>
90
- <input name="wpjm_job_category_slug" type="text" class="regular-text code" value="<?php echo esc_attr( $this->permalinks['category_base'] ); ?>" placeholder="<?php echo esc_attr_x( 'job-category', 'Job category slug - resave permalinks after changing this', 'wp-job-manager' ) ?>" />
91
  <?php
92
  }
93
 
@@ -96,7 +101,7 @@ class WP_Job_Manager_Permalink_Settings {
96
  */
97
  public function job_type_slug_input() {
98
  ?>
99
- <input name="wpjm_job_type_slug" type="text" class="regular-text code" value="<?php echo esc_attr( $this->permalinks['type_base'] ); ?>" placeholder="<?php echo esc_attr_x( 'job-type', 'Job type slug - resave permalinks after changing this', 'wp-job-manager' ) ?>" />
100
  <?php
101
  }
102
 
@@ -113,10 +118,10 @@ class WP_Job_Manager_Permalink_Settings {
113
  switch_to_locale( get_locale() );
114
  }
115
 
116
- $permalinks = (array) get_option( 'wpjm_permalinks', array() );
117
- $permalinks['job_base'] = sanitize_title_with_dashes( $_POST['wpjm_job_base_slug'] );
118
- $permalinks['category_base'] = sanitize_title_with_dashes( $_POST['wpjm_job_category_slug'] );
119
- $permalinks['type_base'] = sanitize_title_with_dashes( $_POST['wpjm_job_type_slug'] );
120
 
121
  update_option( 'wpjm_permalinks', $permalinks );
122
 
1
  <?php
2
 
3
+ if ( ! defined( 'ABSPATH' ) ) {
4
+ exit; // Exit if accessed directly.
5
+ }
6
 
7
  /**
8
  * Handles front admin page for WP Job Manager.
51
  $this->permalinks = WP_Job_Manager_Post_Types::get_permalink_structure();
52
  }
53
 
54
+ /**
55
+ * Add setting fields related to permalinks.
56
+ */
57
  public function setup_fields() {
58
  add_settings_field(
59
  'wpjm_job_base_slug',
83
  */
84
  public function job_base_slug_input() {
85
  ?>
86
+ <input name="wpjm_job_base_slug" type="text" class="regular-text code" value="<?php echo esc_attr( $this->permalinks['job_base'] ); ?>" placeholder="<?php echo esc_attr_x( 'job', 'Job permalink - resave permalinks after changing this', 'wp-job-manager' ); ?>" />
87
  <?php
88
  }
89
 
92
  */
93
  public function job_category_slug_input() {
94
  ?>
95
+ <input name="wpjm_job_category_slug" type="text" class="regular-text code" value="<?php echo esc_attr( $this->permalinks['category_base'] ); ?>" placeholder="<?php echo esc_attr_x( 'job-category', 'Job category slug - resave permalinks after changing this', 'wp-job-manager' ); ?>" />
96
  <?php
97
  }
98
 
101
  */
102
  public function job_type_slug_input() {
103
  ?>
104
+ <input name="wpjm_job_type_slug" type="text" class="regular-text code" value="<?php echo esc_attr( $this->permalinks['type_base'] ); ?>" placeholder="<?php echo esc_attr_x( 'job-type', 'Job type slug - resave permalinks after changing this', 'wp-job-manager' ); ?>" />
105
  <?php
106
  }
107
 
118
  switch_to_locale( get_locale() );
119
  }
120
 
121
+ $permalinks = (array) get_option( 'wpjm_permalinks', array() );
122
+ $permalinks['job_base'] = sanitize_title_with_dashes( $_POST['wpjm_job_base_slug'] );
123
+ $permalinks['category_base'] = sanitize_title_with_dashes( $_POST['wpjm_job_category_slug'] );
124
+ $permalinks['type_base'] = sanitize_title_with_dashes( $_POST['wpjm_job_type_slug'] );
125
 
126
  update_option( 'wpjm_permalinks', $permalinks );
127
 
includes/admin/class-wp-job-manager-settings.php CHANGED
@@ -1,6 +1,7 @@
1
  <?php
2
-
3
- if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
 
4
 
5
  /**
6
  * Handles the management of plugin settings.
@@ -76,28 +77,30 @@ class WP_Job_Manager_Settings {
76
  $account_roles[ $key ] = $role['name'];
77
  }
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
  array(
103
  'name' => 'job_manager_delete_data_on_uninstall',
@@ -106,11 +109,11 @@ class WP_Job_Manager_Settings {
106
  'cb_label' => __( 'Delete WP Job Manager data when the plugin is deleted. Once removed, this data cannot be restored.', 'wp-job-manager' ),
107
  'desc' => '',
108
  'type' => 'checkbox',
109
- 'attributes' => array()
110
  ),
111
  ),
112
  ),
113
- 'job_listings' => array(
114
  __( 'Job Listings', 'wp-job-manager' ),
115
  array(
116
  array(
@@ -119,7 +122,7 @@ class WP_Job_Manager_Settings {
119
  'placeholder' => '',
120
  'label' => __( 'Listings Per Page', 'wp-job-manager' ),
121
  'desc' => __( 'Number of job listings to display per page.', 'wp-job-manager' ),
122
- 'attributes' => array()
123
  ),
124
  array(
125
  'name' => 'job_manager_hide_filled_positions',
@@ -128,16 +131,16 @@ class WP_Job_Manager_Settings {
128
  'cb_label' => __( 'Hide filled positions', 'wp-job-manager' ),
129
  'desc' => __( 'Filled positions will not display in your archives.', 'wp-job-manager' ),
130
  'type' => 'checkbox',
131
- 'attributes' => array()
132
  ),
133
  array(
134
  'name' => 'job_manager_hide_expired',
135
- 'std' => get_option( 'job_manager_hide_expired_content' ) ? '1' : '0', // back compat
136
  'label' => __( 'Hide Expired Listings', 'wp-job-manager' ),
137
  'cb_label' => __( 'Hide expired listings in job archives/search', 'wp-job-manager' ),
138
  'desc' => __( 'Expired job listings will not be searchable.', 'wp-job-manager' ),
139
  'type' => 'checkbox',
140
- 'attributes' => array()
141
  ),
142
  array(
143
  'name' => 'job_manager_hide_expired_content',
@@ -146,7 +149,7 @@ class WP_Job_Manager_Settings {
146
  'cb_label' => __( 'Hide content in expired single job listings', 'wp-job-manager' ),
147
  'desc' => __( 'Your site will display the titles of expired listings, but not the content of the listings. Otherwise, expired listings display their full content minus the application area.', 'wp-job-manager' ),
148
  'type' => 'checkbox',
149
- 'attributes' => array()
150
  ),
151
  array(
152
  'name' => 'job_manager_enable_categories',
@@ -155,7 +158,7 @@ class WP_Job_Manager_Settings {
155
  'cb_label' => __( 'Enable listing categories', 'wp-job-manager' ),
156
  'desc' => __( 'This lets users select from a list of categories when submitting a job. Note: an admin has to create categories before site users can select them.', 'wp-job-manager' ),
157
  'type' => 'checkbox',
158
- 'attributes' => array()
159
  ),
160
  array(
161
  'name' => 'job_manager_enable_default_category_multiselect',
@@ -164,18 +167,18 @@ class WP_Job_Manager_Settings {
164
  'cb_label' => __( 'Default to category multiselect', 'wp-job-manager' ),
165
  'desc' => __( 'The category selection box will default to allowing multiple selections on the [jobs] shortcode. Without this, users will only be able to select a single category when submitting jobs.', 'wp-job-manager' ),
166
  'type' => 'checkbox',
167
- 'attributes' => array()
168
  ),
169
  array(
170
- 'name' => 'job_manager_category_filter_type',
171
- 'std' => 'any',
172
- 'label' => __( 'Category Filter Type', 'wp-job-manager' ),
173
- 'desc' => __( 'Determines the logic used to display jobs when selecting multiple categories.', 'wp-job-manager' ),
174
- 'type' => 'radio',
175
  'options' => array(
176
- 'any' => __( 'Jobs will be shown if within ANY selected category', 'wp-job-manager' ),
177
  'all' => __( 'Jobs will be shown if within ALL selected categories', 'wp-job-manager' ),
178
- )
179
  ),
180
  array(
181
  'name' => 'job_manager_enable_types',
@@ -184,7 +187,7 @@ class WP_Job_Manager_Settings {
184
  'cb_label' => __( 'Enable listing types', 'wp-job-manager' ),
185
  'desc' => __( 'This lets users select from a list of types when submitting a job. Note: an admin has to create types before site users can select them.', 'wp-job-manager' ),
186
  'type' => 'checkbox',
187
- 'attributes' => array()
188
  ),
189
  array(
190
  'name' => 'job_manager_multi_job_type',
@@ -193,7 +196,7 @@ class WP_Job_Manager_Settings {
193
  'cb_label' => __( 'Allow multiple types for listings', 'wp-job-manager' ),
194
  'desc' => __( 'This allows users to select more than one type when submitting a job. The metabox on the post editor and the selection box on the front-end job submission form will both reflect this.', 'wp-job-manager' ),
195
  'type' => 'checkbox',
196
- 'attributes' => array()
197
  ),
198
  ),
199
  ),
@@ -207,7 +210,7 @@ class WP_Job_Manager_Settings {
207
  'cb_label' => __( 'Require an account to submit listings', 'wp-job-manager' ),
208
  'desc' => __( 'Limits job listing submissions to registered, logged-in users.', 'wp-job-manager' ),
209
  'type' => 'checkbox',
210
- 'attributes' => array()
211
  ),
212
  array(
213
  'name' => 'job_manager_enable_registration',
@@ -216,7 +219,7 @@ class WP_Job_Manager_Settings {
216
  'cb_label' => __( 'Enable account creation during submission', 'wp-job-manager' ),
217
  'desc' => __( 'Includes account creation on the listing submission form, to allow non-registered users to create an account and submit a job listing simultaneously.', 'wp-job-manager' ),
218
  'type' => 'checkbox',
219
- 'attributes' => array()
220
  ),
221
  array(
222
  'name' => 'job_manager_generate_username_from_email',
@@ -225,7 +228,7 @@ class WP_Job_Manager_Settings {
225
  'cb_label' => __( 'Generate usernames from email addresses', 'wp-job-manager' ),
226
  'desc' => __( 'Automatically generates usernames for new accounts from the registrant\'s email address. If this is not enabled, a "username" field will display instead.', 'wp-job-manager' ),
227
  'type' => 'checkbox',
228
- 'attributes' => array()
229
  ),
230
  array(
231
  'name' => 'job_manager_use_standard_password_setup_email',
@@ -234,15 +237,15 @@ class WP_Job_Manager_Settings {
234
  'cb_label' => __( 'Email new users a link to set a password', 'wp-job-manager' ),
235
  'desc' => __( 'Sends an email to the user with their username and a link to set their password. If this is not enabled, a "password" field will display instead, and their email address won\'t be verified.', 'wp-job-manager' ),
236
  'type' => 'checkbox',
237
- 'attributes' => array()
238
  ),
239
  array(
240
- 'name' => 'job_manager_registration_role',
241
- 'std' => 'employer',
242
- 'label' => __( 'Account Role', 'wp-job-manager' ),
243
- 'desc' => __( 'Any new accounts created during submission will have this role. If you haven\'t enabled account creation during submission in the options above, your own method of assigning roles will apply.', 'wp-job-manager' ),
244
- 'type' => 'select',
245
- 'options' => $account_roles
246
  ),
247
  array(
248
  'name' => 'job_manager_submission_requires_approval',
@@ -251,7 +254,7 @@ class WP_Job_Manager_Settings {
251
  'cb_label' => __( 'Require admin approval of all new listing submissions', 'wp-job-manager' ),
252
  'desc' => __( 'Sets all new submissions to "pending." They will not appear on your site until an admin approves them.', 'wp-job-manager' ),
253
  'type' => 'checkbox',
254
- 'attributes' => array()
255
  ),
256
  array(
257
  'name' => 'job_manager_user_can_edit_pending_submissions',
@@ -260,7 +263,7 @@ class WP_Job_Manager_Settings {
260
  'cb_label' => __( 'Allow editing of pending listings', 'wp-job-manager' ),
261
  'desc' => __( 'Users can continue to edit pending listings until they are approved by an admin.', 'wp-job-manager' ),
262
  'type' => 'checkbox',
263
- 'attributes' => array()
264
  ),
265
  array(
266
  'name' => 'job_manager_user_edit_published_submissions',
@@ -270,34 +273,34 @@ class WP_Job_Manager_Settings {
270
  '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' ),
271
  'type' => 'radio',
272
  'options' => array(
273
- 'no' => __( 'Users cannot edit', 'wp-job-manager' ),
274
- 'yes' => __( 'Users can edit without admin approval', 'wp-job-manager' ),
275
- 'yes_moderated' => __( 'Users can edit, but edits require admin approval', 'wp-job-manager' ),
276
  ),
277
- 'attributes' => array()
278
  ),
279
  array(
280
  'name' => 'job_manager_submission_duration',
281
  'std' => '30',
282
  'label' => __( 'Listing Duration', 'wp-job-manager' ),
283
  'desc' => __( 'Listings will display for the set number of days, then expire. Leave this field blank if you don\'t want listings to have an expiration date.', 'wp-job-manager' ),
284
- 'attributes' => array()
285
  ),
286
  array(
287
- 'name' => 'job_manager_allowed_application_method',
288
- 'std' => '',
289
- 'label' => __( 'Application Method', 'wp-job-manager' ),
290
- 'desc' => __( 'Choose the application method job listers will need to provide. Specify URL or email address only, or allow listers to choose which they prefer.', 'wp-job-manager' ),
291
- 'type' => 'radio',
292
- 'options' => array(
293
  '' => __( 'Email address or website URL', 'wp-job-manager' ),
294
  'email' => __( 'Email addresses only', 'wp-job-manager' ),
295
  'url' => __( 'Website URLs only', 'wp-job-manager' ),
296
- )
297
  ),
298
  ),
299
  ),
300
- 'recaptcha' => array(
301
  __( 'reCAPTCHA', 'wp-job-manager' ),
302
  array(
303
  array(
@@ -306,23 +309,25 @@ class WP_Job_Manager_Settings {
306
  'placeholder' => '',
307
  'label' => __( 'Field Label', 'wp-job-manager' ),
308
  'desc' => __( 'The label used for the reCAPTCHA field on forms.', 'wp-job-manager' ),
309
- 'attributes' => array()
310
  ),
311
  array(
312
  'name' => 'job_manager_recaptcha_site_key',
313
  'std' => '',
314
  'placeholder' => '',
315
  'label' => __( 'Site Key', 'wp-job-manager' ),
 
316
  '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' ),
317
- 'attributes' => array()
318
  ),
319
  array(
320
  'name' => 'job_manager_recaptcha_secret_key',
321
  'std' => '',
322
  'placeholder' => '',
323
  'label' => __( 'Secret Key', 'wp-job-manager' ),
 
324
  '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' ),
325
- 'attributes' => array()
326
  ),
327
  array(
328
  'name' => 'job_manager_enable_recaptcha_job_submission',
@@ -331,36 +336,36 @@ class WP_Job_Manager_Settings {
331
  'cb_label' => __( 'Display a reCAPTCHA field on job submission form.', 'wp-job-manager' ),
332
  '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' ),
333
  'type' => 'checkbox',
334
- 'attributes' => array()
335
  ),
336
- )
337
  ),
338
- 'job_pages' => array(
339
  __( 'Pages', 'wp-job-manager' ),
340
  array(
341
  array(
342
- 'name' => 'job_manager_submit_job_form_page_id',
343
- 'std' => '',
344
- 'label' => __( 'Submit Job Form Page', 'wp-job-manager' ),
345
- 'desc' => __( 'Select the page where you\'ve used the [submit_job_form] shortcode. This lets the plugin know the location of the form.', 'wp-job-manager' ),
346
- 'type' => 'page'
347
  ),
348
  array(
349
- 'name' => 'job_manager_job_dashboard_page_id',
350
- 'std' => '',
351
- 'label' => __( 'Job Dashboard Page', 'wp-job-manager' ),
352
- 'desc' => __( 'Select the page where you\'ve used the [job_dashboard] shortcode. This lets the plugin know the location of the dashboard.', 'wp-job-manager' ),
353
- 'type' => 'page'
354
  ),
355
  array(
356
- 'name' => 'job_manager_jobs_page_id',
357
- 'std' => '',
358
- 'label' => __( 'Job Listings Page', 'wp-job-manager' ),
359
- 'desc' => __( 'Select the page where you\'ve used the [jobs] shortcode. This lets the plugin know the location of the job listings page.', 'wp-job-manager' ),
360
- 'type' => 'page'
361
  ),
362
- )
363
- )
364
  )
365
  );
366
  }
@@ -373,8 +378,9 @@ class WP_Job_Manager_Settings {
373
 
374
  foreach ( $this->settings as $section ) {
375
  foreach ( $section[1] as $option ) {
376
- if ( isset( $option['std'] ) )
377
  add_option( $option['name'], $option['std'] );
 
378
  register_setting( $this->settings_group, $option['name'] );
379
  }
380
  }
@@ -393,41 +399,41 @@ class WP_Job_Manager_Settings {
393
 
394
  <h2 class="nav-tab-wrapper">
395
  <?php
396
- foreach ( $this->settings as $key => $section ) {
397
- echo '<a href="#settings-' . sanitize_title( $key ) . '" class="nav-tab">' . esc_html( $section[0] ) . '</a>';
398
- }
399
  ?>
400
  </h2>
401
 
402
  <?php
403
- if ( ! empty( $_GET['settings-updated'] ) ) {
404
- flush_rewrite_rules();
405
- echo '<div class="updated fade job-manager-updated"><p>' . __( 'Settings successfully saved', 'wp-job-manager' ) . '</p></div>';
 
 
 
 
 
 
 
406
  }
 
407
 
408
- foreach ( $this->settings as $key => $section ) {
409
- $section_args = isset( $section[2] ) ? (array) $section[2] : array();
410
- echo '<div id="settings-' . sanitize_title( $key ) . '" class="settings_panel">';
411
- if ( ! empty( $section_args['before'] ) ) {
412
- echo '<p class="before-settings">' . $section_args['before'] . '</p>';
413
- }
414
- echo '<table class="form-table settings parent-settings">';
415
-
416
- foreach ( $section[1] as $option ) {
417
- $value = get_option( $option['name'] );
418
- $this->output_field( $option, $value );
419
- }
420
-
421
- echo '</table>';
422
- if ( ! empty( $section_args['after'] ) ) {
423
- echo '<p class="after-settings">' . $section_args['after'] . '</p>';
424
- }
425
- echo '</div>';
426
 
 
 
 
427
  }
 
 
 
428
  ?>
429
  <p class="submit">
430
- <input type="submit" class="button-primary" value="<?php _e( 'Save Changes', 'wp-job-manager' ); ?>" />
431
  </p>
432
  </form>
433
  </div>
@@ -442,6 +448,7 @@ class WP_Job_Manager_Settings {
442
  jQuery(this).addClass('nav-tab-active');
443
  window.location.hash = jQuery(this).attr('href');
444
  jQuery( 'form.job-manager-options' ).attr( 'action', 'options.php' + jQuery(this).attr( 'href' ) );
 
445
  return false;
446
  });
447
  var goto_hash = window.location.hash;
@@ -510,15 +517,25 @@ class WP_Job_Manager_Settings {
510
  * @param array $option
511
  * @param array $attributes
512
  * @param mixed $value
513
- * @param string $placeholder (Ignored).
514
  */
515
- protected function input_checkbox( $option, $attributes, $value, $placeholder ) {
516
- ?><label>
517
- <input type="hidden" name="<?php echo $option['name']; ?>" value="0" />
518
- <input id="setting-<?php echo $option['name']; ?>" name="<?php echo $option['name']; ?>" type="checkbox" value="1" <?php echo implode( ' ', $attributes ); ?> <?php checked( '1', $value ); ?> /> <?php echo $option['cb_label']; ?></label><?php
519
-
 
 
 
 
 
 
 
 
 
 
520
  if ( ! empty( $option['desc'] ) ) {
521
- echo ' <p class="description">' . $option['desc'] . '</p>';
522
  }
523
  }
524
 
@@ -530,11 +547,25 @@ class WP_Job_Manager_Settings {
530
  * @param mixed $value
531
  * @param string $placeholder
532
  */
533
- protected function input_textarea ( $option, $attributes, $value, $placeholder ) {
534
- ?><textarea id="setting-<?php echo $option['name']; ?>" class="large-text" cols="50" rows="3" name="<?php echo $option['name']; ?>" <?php echo implode( ' ', $attributes ); ?> <?php echo $placeholder; ?>><?php echo esc_textarea( $value ); ?></textarea><?php
 
 
 
 
 
 
 
 
 
 
 
 
 
 
535
 
536
  if ( ! empty( $option['desc'] ) ) {
537
- echo ' <p class="description">' . $option['desc'] . '</p>';
538
  }
539
  }
540
 
@@ -544,16 +575,28 @@ class WP_Job_Manager_Settings {
544
  * @param array $option
545
  * @param array $attributes
546
  * @param mixed $value
547
- * @param string $placeholder (Ignored).
548
  */
549
- protected function input_select( $option, $attributes, $value, $placeholder ) {
550
- ?><select id="setting-<?php echo $option['name']; ?>" class="regular-text" name="<?php echo $option['name']; ?>" <?php echo implode( ' ', $attributes ); ?>><?php
551
- foreach( $option['options'] as $key => $name )
 
 
 
 
 
 
 
 
 
552
  echo '<option value="' . esc_attr( $key ) . '" ' . selected( $value, $key, false ) . '>' . esc_html( $name ) . '</option>';
553
- ?></select><?php
 
 
 
554
 
555
  if ( ! empty( $option['desc'] ) ) {
556
- echo ' <p class="description">' . $option['desc'] . '</p>';
557
  }
558
  }
559
 
@@ -561,34 +604,38 @@ class WP_Job_Manager_Settings {
561
  * Radio input field.
562
  *
563
  * @param array $option
564
- * @param array $attributes
565
  * @param mixed $value
566
- * @param string $placeholder (Ignored).
567
  */
568
- protected function input_radio( $option, $attributes, $value, $placeholder ) {
569
- ?><fieldset>
 
570
  <legend class="screen-reader-text">
571
  <span><?php echo esc_html( $option['label'] ); ?></span>
572
- </legend><?php
 
573
  if ( ! empty( $option['desc'] ) ) {
574
- echo ' <p class="description">' . $option['desc'] . '</p>';
575
  }
576
 
577
- foreach( $option['options'] as $key => $name ) {
578
  echo '<label><input name="' . esc_attr( $option['name'] ) . '" type="radio" value="' . esc_attr( $key ) . '" ' . checked( $value, $key, false ) . ' />' . esc_html( $name ) . '</label><br>';
579
  }
580
- ?></fieldset><?php
 
 
581
  }
582
 
583
  /**
584
  * Page input field.
585
  *
586
  * @param array $option
587
- * @param array $attributes
588
  * @param mixed $value
589
- * @param string $placeholder (Ignored).
590
  */
591
- protected function input_page( $option, $attributes, $value, $placeholder ) {
592
  $args = array(
593
  'name' => $option['name'],
594
  'id' => $option['name'],
@@ -596,13 +643,13 @@ class WP_Job_Manager_Settings {
596
  'sort_order' => 'ASC',
597
  'show_option_none' => __( '--no page--', 'wp-job-manager' ),
598
  'echo' => false,
599
- 'selected' => absint( $value )
600
  );
601
 
602
- echo str_replace(' id=', " data-placeholder='" . __( 'Select a page&hellip;', 'wp-job-manager' ) . "' id=", wp_dropdown_pages( $args ) );
603
 
604
  if ( ! empty( $option['desc'] ) ) {
605
- echo ' <p class="description">' . $option['desc'] . '</p>';
606
  }
607
  }
608
 
@@ -612,17 +659,27 @@ class WP_Job_Manager_Settings {
612
  * @param array $option
613
  * @param array $attributes
614
  * @param mixed $value
615
- * @param string $placeholder (Ignored).
616
  */
617
- protected function input_hidden( $option, $attributes, $value, $placeholder ) {
618
  $human_value = $value;
619
- if( $option['human_value'] ) {
620
  $human_value = $option['human_value'];
621
  }
622
- ?><input id="setting-<?php echo $option['name']; ?>" type="hidden" name="<?php echo $option['name']; ?>" value="<?php echo esc_attr( $value ); ?>" <?php echo implode( ' ', $attributes ); ?> /><strong><?php echo esc_html( $human_value ) ?></strong><?php
 
 
 
 
 
 
 
 
 
 
623
 
624
  if ( ! empty( $option['desc'] ) ) {
625
- echo ' <p class="description">' . $option['desc'] . '</p>';
626
  }
627
  }
628
 
@@ -635,10 +692,22 @@ class WP_Job_Manager_Settings {
635
  * @param string $placeholder
636
  */
637
  protected function input_password( $option, $attributes, $value, $placeholder ) {
638
- ?><input id="setting-<?php echo $option['name']; ?>" class="regular-text" type="password" name="<?php echo $option['name']; ?>" value="<?php echo esc_attr( $value ); ?>" <?php echo implode( ' ', $attributes ); ?> <?php echo $placeholder; ?> /><?php
 
 
 
 
 
 
 
 
 
 
 
 
639
 
640
  if ( ! empty( $option['desc'] ) ) {
641
- echo ' <p class="description">' . $option['desc'] . '</p>';
642
  }
643
  }
644
 
@@ -651,11 +720,23 @@ class WP_Job_Manager_Settings {
651
  * @param string $placeholder
652
  */
653
  protected function input_number( $option, $attributes, $value, $placeholder ) {
654
- echo isset( $option['before'] ) ? $option['before'] : '';
655
- ?><input id="setting-<?php echo $option['name']; ?>" class="small-text" type="number" name="<?php echo $option['name']; ?>" value="<?php echo esc_attr( $value ); ?>" <?php echo implode( ' ', $attributes ); ?> <?php echo $placeholder; ?> /><?php
656
- echo isset( $option['after'] ) ? $option['after'] : '';
 
 
 
 
 
 
 
 
 
 
 
 
657
  if ( ! empty( $option['desc'] ) ) {
658
- echo ' <p class="description">' . $option['desc'] . '</p>';
659
  }
660
  }
661
 
@@ -668,10 +749,22 @@ class WP_Job_Manager_Settings {
668
  * @param string $placeholder
669
  */
670
  protected function input_text( $option, $attributes, $value, $placeholder ) {
671
- ?><input id="setting-<?php echo $option['name']; ?>" class="regular-text" type="text" name="<?php echo $option['name']; ?>" value="<?php echo esc_attr( $value ); ?>" <?php echo implode( ' ', $attributes ); ?> <?php echo $placeholder; ?> /><?php
 
 
 
 
 
 
 
 
 
 
 
 
672
 
673
  if ( ! empty( $option['desc'] ) ) {
674
- echo ' <p class="description">' . $option['desc'] . '</p>';
675
  }
676
  }
677
 
@@ -682,7 +775,7 @@ class WP_Job_Manager_Settings {
682
  * @param mixed $value
683
  */
684
  protected function output_field( $option, $value ) {
685
- $placeholder = ( ! empty( $option['placeholder'] ) ) ? 'placeholder="' . $option['placeholder'] . '"' : '';
686
  $class = ! empty( $option['class'] ) ? $option['class'] : '';
687
  $option['type'] = ! empty( $option['type'] ) ? $option['type'] : 'text';
688
  $attributes = array();
@@ -692,10 +785,10 @@ class WP_Job_Manager_Settings {
692
  }
693
  }
694
 
695
- echo '<tr valign="top" class="' . $class . '">';
696
 
697
  if ( ! empty( $option['label'] ) ) {
698
- echo '<th scope="row"><label for="setting-' . $option[ 'name' ] . '">' . $option[ 'label' ] . '</a></th><td>';
699
  } else {
700
  echo '<td colspan="2">';
701
  }
@@ -704,6 +797,16 @@ class WP_Job_Manager_Settings {
704
  if ( method_exists( $this, $method_name ) ) {
705
  $this->$method_name( $option, $attributes, $value, $placeholder );
706
  } else {
 
 
 
 
 
 
 
 
 
 
707
  do_action( 'wp_job_manager_admin_field_' . $option['type'], $option, $attributes, $value, $placeholder );
708
  }
709
  echo '</td></tr>';
@@ -735,14 +838,14 @@ class WP_Job_Manager_Settings {
735
  * Multiple settings stored in one setting array.
736
  *
737
  * @param array $option
738
- * @param array $attributes
739
  * @param array $values
740
- * @param string $placeholder
741
  */
742
- protected function input_multi( $option, $attributes, $values, $placeholder ) {
743
  echo '<table class="form-table settings child-settings">';
744
  foreach ( $option['settings'] as $sub_option ) {
745
- $value = isset( $values[ $sub_option['name'] ] ) ? $values[ $sub_option['name'] ] : $sub_option['std'];
746
  $sub_option['name'] = $option['name'] . '[' . $sub_option['name'] . ']';
747
  $this->output_field( $sub_option, $value );
748
  }
1
  <?php
2
+ if ( ! defined( 'ABSPATH' ) ) {
3
+ exit; // Exit if accessed directly.
4
+ }
5
 
6
  /**
7
  * Handles the management of plugin settings.
77
  $account_roles[ $key ] = $role['name'];
78
  }
79
 
80
+ $this->settings = apply_filters(
81
+ 'job_manager_settings',
82
  array(
83
+ 'general' => array(
84
  __( 'General', 'wp-job-manager' ),
85
  array(
86
  array(
87
+ 'name' => 'job_manager_date_format',
88
+ 'std' => 'relative',
89
+ 'label' => __( 'Date Format', 'wp-job-manager' ),
90
+ 'desc' => __( 'Choose how you want the published date for jobs to be displayed on the front-end.', 'wp-job-manager' ),
91
+ 'type' => 'radio',
92
+ 'options' => array(
93
  'relative' => __( 'Relative to the current date (e.g., 1 day, 1 week, 1 month ago)', 'wp-job-manager' ),
94
+ 'default' => __( 'Default date format as defined in Settings', 'wp-job-manager' ),
95
+ ),
96
  ),
97
  array(
98
  'name' => 'job_manager_google_maps_api_key',
99
  'std' => '',
100
  'label' => __( 'Google Maps API Key', 'wp-job-manager' ),
101
+ // translators: Placeholder %s is URL to set up a Google Maps API key.
102
  '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' ),
103
+ 'attributes' => array(),
104
  ),
105
  array(
106
  'name' => 'job_manager_delete_data_on_uninstall',
109
  'cb_label' => __( 'Delete WP Job Manager data when the plugin is deleted. Once removed, this data cannot be restored.', 'wp-job-manager' ),
110
  'desc' => '',
111
  'type' => 'checkbox',
112
+ 'attributes' => array(),
113
  ),
114
  ),
115
  ),
116
+ 'job_listings' => array(
117
  __( 'Job Listings', 'wp-job-manager' ),
118
  array(
119
  array(
122
  'placeholder' => '',
123
  'label' => __( 'Listings Per Page', 'wp-job-manager' ),
124
  'desc' => __( 'Number of job listings to display per page.', 'wp-job-manager' ),
125
+ 'attributes' => array(),
126
  ),
127
  array(
128
  'name' => 'job_manager_hide_filled_positions',
131
  'cb_label' => __( 'Hide filled positions', 'wp-job-manager' ),
132
  'desc' => __( 'Filled positions will not display in your archives.', 'wp-job-manager' ),
133
  'type' => 'checkbox',
134
+ 'attributes' => array(),
135
  ),
136
  array(
137
  'name' => 'job_manager_hide_expired',
138
+ 'std' => get_option( 'job_manager_hide_expired_content' ) ? '1' : '0', // back compat.
139
  'label' => __( 'Hide Expired Listings', 'wp-job-manager' ),
140
  'cb_label' => __( 'Hide expired listings in job archives/search', 'wp-job-manager' ),
141
  'desc' => __( 'Expired job listings will not be searchable.', 'wp-job-manager' ),
142
  'type' => 'checkbox',
143
+ 'attributes' => array(),
144
  ),
145
  array(
146
  'name' => 'job_manager_hide_expired_content',
149
  'cb_label' => __( 'Hide content in expired single job listings', 'wp-job-manager' ),
150
  'desc' => __( 'Your site will display the titles of expired listings, but not the content of the listings. Otherwise, expired listings display their full content minus the application area.', 'wp-job-manager' ),
151
  'type' => 'checkbox',
152
+ 'attributes' => array(),
153
  ),
154
  array(
155
  'name' => 'job_manager_enable_categories',
158
  'cb_label' => __( 'Enable listing categories', 'wp-job-manager' ),
159
  'desc' => __( 'This lets users select from a list of categories when submitting a job. Note: an admin has to create categories before site users can select them.', 'wp-job-manager' ),
160
  'type' => 'checkbox',
161
+ 'attributes' => array(),
162
  ),
163
  array(
164
  'name' => 'job_manager_enable_default_category_multiselect',
167
  'cb_label' => __( 'Default to category multiselect', 'wp-job-manager' ),
168
  'desc' => __( 'The category selection box will default to allowing multiple selections on the [jobs] shortcode. Without this, users will only be able to select a single category when submitting jobs.', 'wp-job-manager' ),
169
  'type' => 'checkbox',
170
+ 'attributes' => array(),
171
  ),
172
  array(
173
+ 'name' => 'job_manager_category_filter_type',
174
+ 'std' => 'any',
175
+ 'label' => __( 'Category Filter Type', 'wp-job-manager' ),
176
+ 'desc' => __( 'Determines the logic used to display jobs when selecting multiple categories.', 'wp-job-manager' ),
177
+ 'type' => 'radio',
178
  'options' => array(
179
+ 'any' => __( 'Jobs will be shown if within ANY selected category', 'wp-job-manager' ),
180
  'all' => __( 'Jobs will be shown if within ALL selected categories', 'wp-job-manager' ),
181
+ ),
182
  ),
183
  array(
184
  'name' => 'job_manager_enable_types',
187
  'cb_label' => __( 'Enable listing types', 'wp-job-manager' ),
188
  'desc' => __( 'This lets users select from a list of types when submitting a job. Note: an admin has to create types before site users can select them.', 'wp-job-manager' ),
189
  'type' => 'checkbox',
190
+ 'attributes' => array(),
191
  ),
192
  array(
193
  'name' => 'job_manager_multi_job_type',
196
  'cb_label' => __( 'Allow multiple types for listings', 'wp-job-manager' ),
197
  'desc' => __( 'This allows users to select more than one type when submitting a job. The metabox on the post editor and the selection box on the front-end job submission form will both reflect this.', 'wp-job-manager' ),
198
  'type' => 'checkbox',
199
+ 'attributes' => array(),
200
  ),
201
  ),
202
  ),
210
  'cb_label' => __( 'Require an account to submit listings', 'wp-job-manager' ),
211
  'desc' => __( 'Limits job listing submissions to registered, logged-in users.', 'wp-job-manager' ),
212
  'type' => 'checkbox',
213
+ 'attributes' => array(),
214
  ),
215
  array(
216
  'name' => 'job_manager_enable_registration',
219
  'cb_label' => __( 'Enable account creation during submission', 'wp-job-manager' ),
220
  'desc' => __( 'Includes account creation on the listing submission form, to allow non-registered users to create an account and submit a job listing simultaneously.', 'wp-job-manager' ),
221
  'type' => 'checkbox',
222
+ 'attributes' => array(),
223
  ),
224
  array(
225
  'name' => 'job_manager_generate_username_from_email',
228
  'cb_label' => __( 'Generate usernames from email addresses', 'wp-job-manager' ),
229
  'desc' => __( 'Automatically generates usernames for new accounts from the registrant\'s email address. If this is not enabled, a "username" field will display instead.', 'wp-job-manager' ),
230
  'type' => 'checkbox',
231
+ 'attributes' => array(),
232
  ),
233
  array(
234
  'name' => 'job_manager_use_standard_password_setup_email',
237
  'cb_label' => __( 'Email new users a link to set a password', 'wp-job-manager' ),
238
  'desc' => __( 'Sends an email to the user with their username and a link to set their password. If this is not enabled, a "password" field will display instead, and their email address won\'t be verified.', 'wp-job-manager' ),
239
  'type' => 'checkbox',
240
+ 'attributes' => array(),
241
  ),
242
  array(
243
+ 'name' => 'job_manager_registration_role',
244
+ 'std' => 'employer',
245
+ 'label' => __( 'Account Role', 'wp-job-manager' ),
246
+ 'desc' => __( 'Any new accounts created during submission will have this role. If you haven\'t enabled account creation during submission in the options above, your own method of assigning roles will apply.', 'wp-job-manager' ),
247
+ 'type' => 'select',
248
+ 'options' => $account_roles,
249
  ),
250
  array(
251
  'name' => 'job_manager_submission_requires_approval',
254
  'cb_label' => __( 'Require admin approval of all new listing submissions', 'wp-job-manager' ),
255
  'desc' => __( 'Sets all new submissions to "pending." They will not appear on your site until an admin approves them.', 'wp-job-manager' ),
256
  'type' => 'checkbox',
257
+ 'attributes' => array(),
258
  ),
259
  array(
260
  'name' => 'job_manager_user_can_edit_pending_submissions',
263
  'cb_label' => __( 'Allow editing of pending listings', 'wp-job-manager' ),
264
  'desc' => __( 'Users can continue to edit pending listings until they are approved by an admin.', 'wp-job-manager' ),
265
  'type' => 'checkbox',
266
+ 'attributes' => array(),
267
  ),
268
  array(
269
  'name' => 'job_manager_user_edit_published_submissions',
273
  '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' ),
274
  'type' => 'radio',
275
  'options' => array(
276
+ 'no' => __( 'Users cannot edit', 'wp-job-manager' ),
277
+ 'yes' => __( 'Users can edit without admin approval', 'wp-job-manager' ),
278
+ 'yes_moderated' => __( 'Users can edit, but edits require admin approval', 'wp-job-manager' ),
279
  ),
280
+ 'attributes' => array(),
281
  ),
282
  array(
283
  'name' => 'job_manager_submission_duration',
284
  'std' => '30',
285
  'label' => __( 'Listing Duration', 'wp-job-manager' ),
286
  'desc' => __( 'Listings will display for the set number of days, then expire. Leave this field blank if you don\'t want listings to have an expiration date.', 'wp-job-manager' ),
287
+ 'attributes' => array(),
288
  ),
289
  array(
290
+ 'name' => 'job_manager_allowed_application_method',
291
+ 'std' => '',
292
+ 'label' => __( 'Application Method', 'wp-job-manager' ),
293
+ 'desc' => __( 'Choose the application method job listers will need to provide. Specify URL or email address only, or allow listers to choose which they prefer.', 'wp-job-manager' ),
294
+ 'type' => 'radio',
295
+ 'options' => array(
296
  '' => __( 'Email address or website URL', 'wp-job-manager' ),
297
  'email' => __( 'Email addresses only', 'wp-job-manager' ),
298
  'url' => __( 'Website URLs only', 'wp-job-manager' ),
299
+ ),
300
  ),
301
  ),
302
  ),
303
+ 'recaptcha' => array(
304
  __( 'reCAPTCHA', 'wp-job-manager' ),
305
  array(
306
  array(
309
  'placeholder' => '',
310
  'label' => __( 'Field Label', 'wp-job-manager' ),
311
  'desc' => __( 'The label used for the reCAPTCHA field on forms.', 'wp-job-manager' ),
312
+ 'attributes' => array(),
313
  ),
314
  array(
315
  'name' => 'job_manager_recaptcha_site_key',
316
  'std' => '',
317
  'placeholder' => '',
318
  'label' => __( 'Site Key', 'wp-job-manager' ),
319
+ // translators: Placeholder %s is URL to set up Google reCAPTCHA API key.
320
  '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' ),
321
+ 'attributes' => array(),
322
  ),
323
  array(
324
  'name' => 'job_manager_recaptcha_secret_key',
325
  'std' => '',
326
  'placeholder' => '',
327
  'label' => __( 'Secret Key', 'wp-job-manager' ),
328
+ // translators: Placeholder %s is URL to set up Google reCAPTCHA API key.
329
  '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' ),
330
+ 'attributes' => array(),
331
  ),
332
  array(
333
  'name' => 'job_manager_enable_recaptcha_job_submission',
336
  'cb_label' => __( 'Display a reCAPTCHA field on job submission form.', 'wp-job-manager' ),
337
  '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' ),
338
  'type' => 'checkbox',
339
+ 'attributes' => array(),
340
  ),
341
+ ),
342
  ),
343
+ 'job_pages' => array(
344
  __( 'Pages', 'wp-job-manager' ),
345
  array(
346
  array(
347
+ 'name' => 'job_manager_submit_job_form_page_id',
348
+ 'std' => '',
349
+ 'label' => __( 'Submit Job Form Page', 'wp-job-manager' ),
350
+ 'desc' => __( 'Select the page where you\'ve used the [submit_job_form] shortcode. This lets the plugin know the location of the form.', 'wp-job-manager' ),
351
+ 'type' => 'page',
352
  ),
353
  array(
354
+ 'name' => 'job_manager_job_dashboard_page_id',
355
+ 'std' => '',
356
+ 'label' => __( 'Job Dashboard Page', 'wp-job-manager' ),
357
+ 'desc' => __( 'Select the page where you\'ve used the [job_dashboard] shortcode. This lets the plugin know the location of the dashboard.', 'wp-job-manager' ),
358
+ 'type' => 'page',
359
  ),
360
  array(
361
+ 'name' => 'job_manager_jobs_page_id',
362
+ 'std' => '',
363
+ 'label' => __( 'Job Listings Page', 'wp-job-manager' ),
364
+ 'desc' => __( 'Select the page where you\'ve used the [jobs] shortcode. This lets the plugin know the location of the job listings page.', 'wp-job-manager' ),
365
+ 'type' => 'page',
366
  ),
367
+ ),
368
+ ),
369
  )
370
  );
371
  }
378
 
379
  foreach ( $this->settings as $section ) {
380
  foreach ( $section[1] as $option ) {
381
+ if ( isset( $option['std'] ) ) {
382
  add_option( $option['name'], $option['std'] );
383
+ }
384
  register_setting( $this->settings_group, $option['name'] );
385
  }
386
  }
399
 
400
  <h2 class="nav-tab-wrapper">
401
  <?php
402
+ foreach ( $this->settings as $key => $section ) {
403
+ echo '<a href="#settings-' . esc_attr( sanitize_title( $key ) ) . '" class="nav-tab">' . esc_html( $section[0] ) . '</a>';
404
+ }
405
  ?>
406
  </h2>
407
 
408
  <?php
409
+ if ( ! empty( $_GET['settings-updated'] ) ) {
410
+ flush_rewrite_rules();
411
+ echo '<div class="updated fade job-manager-updated"><p>' . esc_html__( 'Settings successfully saved', 'wp-job-manager' ) . '</p></div>';
412
+ }
413
+
414
+ foreach ( $this->settings as $key => $section ) {
415
+ $section_args = isset( $section[2] ) ? (array) $section[2] : array();
416
+ echo '<div id="settings-' . esc_attr( sanitize_title( $key ) ) . '" class="settings_panel">';
417
+ if ( ! empty( $section_args['before'] ) ) {
418
+ echo '<p class="before-settings">' . wp_kses_post( $section_args['before'] ) . '</p>';
419
  }
420
+ echo '<table class="form-table settings parent-settings">';
421
 
422
+ foreach ( $section[1] as $option ) {
423
+ $value = get_option( $option['name'] );
424
+ $this->output_field( $option, $value );
425
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
426
 
427
+ echo '</table>';
428
+ if ( ! empty( $section_args['after'] ) ) {
429
+ echo '<p class="after-settings">' . wp_kses_post( $section_args['after'] ) . '</p>';
430
  }
431
+ echo '</div>';
432
+
433
+ }
434
  ?>
435
  <p class="submit">
436
+ <input type="submit" class="button-primary" value="<?php esc_attr_e( 'Save Changes', 'wp-job-manager' ); ?>" />
437
  </p>
438
  </form>
439
  </div>
448
  jQuery(this).addClass('nav-tab-active');
449
  window.location.hash = jQuery(this).attr('href');
450
  jQuery( 'form.job-manager-options' ).attr( 'action', 'options.php' + jQuery(this).attr( 'href' ) );
451
+ window.scrollTo( 0, 0 );
452
  return false;
453
  });
454
  var goto_hash = window.location.hash;
517
  * @param array $option
518
  * @param array $attributes
519
  * @param mixed $value
520
+ * @param string $ignored_placeholder
521
  */
522
+ protected function input_checkbox( $option, $attributes, $value, $ignored_placeholder ) {
523
+ ?>
524
+ <label>
525
+ <input type="hidden" name="<?php echo esc_attr( $option['name'] ); ?>" value="0" />
526
+ <input
527
+ id="setting-<?php echo esc_attr( $option['name'] ); ?>"
528
+ name="<?php echo esc_attr( $option['name'] ); ?>"
529
+ type="checkbox"
530
+ value="1"
531
+ <?php
532
+ echo implode( ' ', $attributes ) . ' '; // WPCS: XSS ok.
533
+ checked( '1', $value );
534
+ ?>
535
+ /> <?php echo wp_kses_post( $option['cb_label'] ); ?></label>
536
+ <?php
537
  if ( ! empty( $option['desc'] ) ) {
538
+ echo ' <p class="description">' . wp_kses_post( $option['desc'] ) . '</p>';
539
  }
540
  }
541
 
547
  * @param mixed $value
548
  * @param string $placeholder
549
  */
550
+ protected function input_textarea( $option, $attributes, $value, $placeholder ) {
551
+ ?>
552
+ <textarea
553
+ id="setting-<?php echo esc_attr( $option['name'] ); ?>"
554
+ class="large-text"
555
+ cols="50"
556
+ rows="3"
557
+ name="<?php echo esc_attr( $option['name'] ); ?>"
558
+ <?php
559
+ echo implode( ' ', $attributes ) . ' '; // WPCS: XSS ok.
560
+ echo $placeholder; // WPCS: XSS ok.
561
+ ?>
562
+ >
563
+ <?php echo esc_textarea( $value ); ?>
564
+ </textarea>
565
+ <?php
566
 
567
  if ( ! empty( $option['desc'] ) ) {
568
+ echo ' <p class="description">' . wp_kses_post( $option['desc'] ) . '</p>';
569
  }
570
  }
571
 
575
  * @param array $option
576
  * @param array $attributes
577
  * @param mixed $value
578
+ * @param string $ignored_placeholder
579
  */
580
+ protected function input_select( $option, $attributes, $value, $ignored_placeholder ) {
581
+ ?>
582
+ <select
583
+ id="setting-<?php echo esc_attr( $option['name'] ); ?>"
584
+ class="regular-text"
585
+ name="<?php echo esc_attr( $option['name'] ); ?>"
586
+ <?php
587
+ echo implode( ' ', $attributes ); // WPCS: XSS ok.
588
+ ?>
589
+ >
590
+ <?php
591
+ foreach ( $option['options'] as $key => $name ) {
592
  echo '<option value="' . esc_attr( $key ) . '" ' . selected( $value, $key, false ) . '>' . esc_html( $name ) . '</option>';
593
+ }
594
+ ?>
595
+ </select>
596
+ <?php
597
 
598
  if ( ! empty( $option['desc'] ) ) {
599
+ echo ' <p class="description">' . wp_kses_post( $option['desc'] ) . '</p>';
600
  }
601
  }
602
 
604
  * Radio input field.
605
  *
606
  * @param array $option
607
+ * @param array $ignored_attributes
608
  * @param mixed $value
609
+ * @param string $ignored_placeholder
610
  */
611
+ protected function input_radio( $option, $ignored_attributes, $value, $ignored_placeholder ) {
612
+ ?>
613
+ <fieldset>
614
  <legend class="screen-reader-text">
615
  <span><?php echo esc_html( $option['label'] ); ?></span>
616
+ </legend>
617
+ <?php
618
  if ( ! empty( $option['desc'] ) ) {
619
+ echo ' <p class="description">' . wp_kses_post( $option['desc'] ) . '</p>';
620
  }
621
 
622
+ foreach ( $option['options'] as $key => $name ) {
623
  echo '<label><input name="' . esc_attr( $option['name'] ) . '" type="radio" value="' . esc_attr( $key ) . '" ' . checked( $value, $key, false ) . ' />' . esc_html( $name ) . '</label><br>';
624
  }
625
+ ?>
626
+ </fieldset>
627
+ <?php
628
  }
629
 
630
  /**
631
  * Page input field.
632
  *
633
  * @param array $option
634
+ * @param array $ignored_attributes
635
  * @param mixed $value
636
+ * @param string $ignored_placeholder
637
  */
638
+ protected function input_page( $option, $ignored_attributes, $value, $ignored_placeholder ) {
639
  $args = array(
640
  'name' => $option['name'],
641
  'id' => $option['name'],
643
  'sort_order' => 'ASC',
644
  'show_option_none' => __( '--no page--', 'wp-job-manager' ),
645
  'echo' => false,
646
+ 'selected' => absint( $value ),
647
  );
648
 
649
+ echo str_replace( ' id=', " data-placeholder='" . esc_attr__( 'Select a page&hellip;', 'wp-job-manager' ) . "' id=", wp_dropdown_pages( $args ) ); // WPCS: XSS ok.
650
 
651
  if ( ! empty( $option['desc'] ) ) {
652
+ echo ' <p class="description">' . wp_kses_post( $option['desc'] ) . '</p>';
653
  }
654
  }
655
 
659
  * @param array $option
660
  * @param array $attributes
661
  * @param mixed $value
662
+ * @param string $ignored_placeholder
663
  */
664
+ protected function input_hidden( $option, $attributes, $value, $ignored_placeholder ) {
665
  $human_value = $value;
666
+ if ( $option['human_value'] ) {
667
  $human_value = $option['human_value'];
668
  }
669
+ ?>
670
+ <input
671
+ id="setting-<?php echo esc_attr( $option['name'] ); ?>"
672
+ type="hidden"
673
+ name="<?php echo esc_attr( $option['name'] ); ?>"
674
+ value="<?php echo esc_attr( $value ); ?>"
675
+ <?php
676
+ echo implode( ' ', $attributes ); // WPCS: XSS ok.
677
+ ?>
678
+ /><strong><?php echo esc_html( $human_value ); ?></strong>
679
+ <?php
680
 
681
  if ( ! empty( $option['desc'] ) ) {
682
+ echo ' <p class="description">' . wp_kses_post( $option['desc'] ) . '</p>';
683
  }
684
  }
685
 
692
  * @param string $placeholder
693
  */
694
  protected function input_password( $option, $attributes, $value, $placeholder ) {
695
+ ?>
696
+ <input
697
+ id="setting-<?php echo esc_attr( $option['name'] ); ?>"
698
+ class="regular-text"
699
+ type="password"
700
+ name="<?php echo esc_attr( $option['name'] ); ?>"
701
+ value="<?php echo esc_attr( $value ); ?>"
702
+ <?php
703
+ echo implode( ' ', $attributes ) . ' '; // WPCS: XSS ok.
704
+ echo $placeholder; // WPCS: XSS ok.
705
+ ?>
706
+ />
707
+ <?php
708
 
709
  if ( ! empty( $option['desc'] ) ) {
710
+ echo ' <p class="description">' . wp_kses_post( $option['desc'] ) . '</p>';
711
  }
712
  }
713
 
720
  * @param string $placeholder
721
  */
722
  protected function input_number( $option, $attributes, $value, $placeholder ) {
723
+ echo isset( $option['before'] ) ? wp_kses_post( $option['before'] ) : '';
724
+ ?>
725
+ <input
726
+ id="setting-<?php echo esc_attr( $option['name'] ); ?>"
727
+ class="small-text"
728
+ type="number"
729
+ name="<?php echo esc_attr( $option['name'] ); ?>"
730
+ value="<?php echo esc_attr( $value ); ?>"
731
+ <?php
732
+ echo implode( ' ', $attributes ) . ' '; // WPCS: XSS ok.
733
+ echo $placeholder; // WPCS: XSS ok.
734
+ ?>
735
+ />
736
+ <?php
737
+ echo isset( $option['after'] ) ? wp_kses_post( $option['after'] ) : '';
738
  if ( ! empty( $option['desc'] ) ) {
739
+ echo ' <p class="description">' . wp_kses_post( $option['desc'] ) . '</p>';
740
  }
741
  }
742
 
749
  * @param string $placeholder
750
  */
751
  protected function input_text( $option, $attributes, $value, $placeholder ) {
752
+ ?>
753
+ <input
754
+ id="setting-<?php echo esc_attr( $option['name'] ); ?>"
755
+ class="regular-text"
756
+ type="text"
757
+ name="<?php echo esc_attr( $option['name'] ); ?>"
758
+ value="<?php echo esc_attr( $value ); ?>"
759
+ <?php
760
+ echo implode( ' ', $attributes ) . ' '; // WPCS: XSS ok.
761
+ echo $placeholder; // WPCS: XSS ok.
762
+ ?>
763
+ />
764
+ <?php
765
 
766
  if ( ! empty( $option['desc'] ) ) {
767
+ echo ' <p class="description">' . wp_kses_post( $option['desc'] ) . '</p>';
768
  }
769
  }
770
 
775
  * @param mixed $value
776
  */
777
  protected function output_field( $option, $value ) {
778
+ $placeholder = ( ! empty( $option['placeholder'] ) ) ? 'placeholder="' . esc_attr( $option['placeholder'] ) . '"' : '';
779
  $class = ! empty( $option['class'] ) ? $option['class'] : '';
780
  $option['type'] = ! empty( $option['type'] ) ? $option['type'] : 'text';
781
  $attributes = array();
785
  }
786
  }
787
 
788
+ echo '<tr valign="top" class="' . esc_attr( $class ) . '">';
789
 
790
  if ( ! empty( $option['label'] ) ) {
791
+ echo '<th scope="row"><label for="setting-' . esc_attr( $option['name'] ) . '">' . esc_html( $option['label'] ) . '</a></th><td>';
792
  } else {
793
  echo '<td colspan="2">';
794
  }
797
  if ( method_exists( $this, $method_name ) ) {
798
  $this->$method_name( $option, $attributes, $value, $placeholder );
799
  } else {
800
+ /**
801
+ * Allows for custom fields in admin setting panes.
802
+ *
803
+ * @since 1.14.0
804
+ *
805
+ * @param string $option Field name.
806
+ * @param array $attributes Array of attributes.
807
+ * @param mixed $value Field value.
808
+ * @param string $value Placeholder text.
809
+ */
810
  do_action( 'wp_job_manager_admin_field_' . $option['type'], $option, $attributes, $value, $placeholder );
811
  }
812
  echo '</td></tr>';
838
  * Multiple settings stored in one setting array.
839
  *
840
  * @param array $option
841
+ * @param array $ignored_attributes
842
  * @param array $values
843
+ * @param string $ignored_placeholder
844
  */
845
+ protected function input_multi( $option, $ignored_attributes, $values, $ignored_placeholder ) {
846
  echo '<table class="form-table settings child-settings">';
847
  foreach ( $option['settings'] as $sub_option ) {
848
+ $value = isset( $values[ $sub_option['name'] ] ) ? $values[ $sub_option['name'] ] : $sub_option['std'];
849
  $sub_option['name'] = $option['name'] . '[' . $sub_option['name'] . ']';
850
  $this->output_field( $sub_option, $value );
851
  }
includes/admin/class-wp-job-manager-setup.php CHANGED
@@ -40,8 +40,9 @@ class WP_Job_Manager_Setup {
40
  add_action( 'admin_menu', array( $this, 'admin_menu' ), 12 );
41
  add_action( 'admin_head', array( $this, 'admin_head' ) );
42
  add_action( 'admin_init', array( $this, 'redirect' ) );
43
- if ( isset( $_GET[ 'page' ] ) && $_GET[ 'page' ] == 'job-manager-setup' )
44
  add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ), 12 );
 
45
  }
46
 
47
  /**
@@ -62,24 +63,24 @@ class WP_Job_Manager_Setup {
62
  * Sends user to the setup page on first activation.
63
  */
64
  public function redirect() {
65
- // Bail if no activation redirect transient is set
66
- if ( ! get_transient( '_job_manager_activation_redirect' ) ) {
67
  return;
68
- }
69
 
70
- if ( ! current_user_can( 'manage_options' ) ) {
71
- return;
72
- }
73
 
74
- // Delete the redirect transient
75
  delete_transient( '_job_manager_activation_redirect' );
76
 
77
- // Bail if activating from network, or bulk, or within an iFrame
78
  if ( is_network_admin() || isset( $_GET['activate-multi'] ) || defined( 'IFRAME_REQUEST' ) ) {
79
  return;
80
  }
81
 
82
- if ( ( isset( $_GET['action'] ) && 'upgrade-plugin' == $_GET['action'] ) && ( isset( $_GET['plugin'] ) && strstr( $_GET['plugin'], 'wp-job-manager.php' ) ) ) {
83
  return;
84
  }
85
 
@@ -110,9 +111,9 @@ class WP_Job_Manager_Setup {
110
  'post_title' => $title,
111
  'post_content' => $content,
112
  'post_parent' => 0,
113
- 'comment_status' => 'closed'
114
  );
115
- $page_id = wp_insert_post( $page_data );
116
 
117
  if ( $option ) {
118
  update_option( $option, $page_id );
@@ -181,14 +182,15 @@ class WP_Job_Manager_Setup {
181
  $step = ! empty( $_GET['step'] ) ? absint( $_GET['step'] ) : 1;
182
 
183
  if ( 3 === $step && ! empty( $_POST ) ) {
184
- if ( false == wp_verify_nonce( $_REQUEST[ 'setup_wizard' ], 'step_3' ) )
185
  wp_die( 'Error in nonce. Try again.', 'wp-job-manager' );
 
186
  $create_pages = isset( $_POST['wp-job-manager-create-page'] ) ? $_POST['wp-job-manager-create-page'] : array();
187
  $page_titles = $_POST['wp-job-manager-page-title'];
188
  $pages_to_create = array(
189
  'submit_job_form' => '[submit_job_form]',
190
  'job_dashboard' => '[job_dashboard]',
191
- 'jobs' => '[jobs]'
192
  );
193
 
194
  foreach ( $pages_to_create as $page => $content ) {
@@ -200,21 +202,30 @@ class WP_Job_Manager_Setup {
200
  }
201
  ?>
202
  <div class="wrap wp_job_manager wp_job_manager_addons_wrap">
203
- <h2><?php _e( 'WP Job Manager Setup', 'wp-job-manager' ); ?></h2>
204
 
205
  <ul class="wp-job-manager-setup-steps">
206
- <li class="<?php if ( $step === 1 ) echo 'wp-job-manager-setup-active-step'; ?>"><?php _e( '1. Introduction', 'wp-job-manager' ); ?></li>
207
- <li class="<?php if ( $step === 2 ) echo 'wp-job-manager-setup-active-step'; ?>"><?php _e( '2. Page Setup', 'wp-job-manager' ); ?></li>
208
- <li class="<?php if ( $step === 3 ) echo 'wp-job-manager-setup-active-step'; ?>"><?php _e( '3. Done', 'wp-job-manager' ); ?></li>
 
 
 
 
209
  </ul>
210
 
211
  <?php if ( 1 === $step ) : ?>
212
 
213
- <h3><?php _e( 'Welcome to the Setup Wizard!', 'wp-job-manager' ); ?></h3>
214
 
215
- <p><?php _e( 'Thanks for installing <em>WP Job Manager</em>! Let\'s get your site ready to accept job listings.', 'wp-job-manager' ); ?></p>
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' ) ); ?>" />
@@ -230,10 +241,21 @@ class WP_Job_Manager_Setup {
230
  <?php endif; ?>
231
  <?php if ( 2 === $step ) : ?>
232
 
233
- <h3><?php _e( 'Page Setup', 'wp-job-manager' ); ?></h3>
234
 
235
- <p><?php _e( 'With WP Job Manager, employers and applicants can post, manage, and browse job listings right on your website. Tell us which of these common pages you\'d like your site to have and we\'ll create and configure them for you.', 'wp-job-manager' ); ?></p>
236
- <p><?php printf( __( '(These pages are created using %1$sshortcodes%2$s, which we take care of in this step. If you\'d like to build these pages yourself or want to add one of these options to an existing page on your site, you can skip this step and take a look at %4$sshortcode documentation%2$s for detailed instructions.)', 'wp-job-manager' ), '<a href="http://codex.wordpress.org/Shortcode" title="What is a shortcode?" target="_blank" class="help-page-link">', '</a>', '<a href="http://codex.wordpress.org/Pages" target="_blank" class="help-page-link">', '<a href="https://wpjobmanager.com/document/shortcode-reference/" target="_blank" class="help-page-link">' ); ?></p>
 
 
 
 
 
 
 
 
 
 
 
237
 
238
  <form action="<?php echo esc_url( add_query_arg( 'step', 3 ) ); ?>" method="post">
239
  <?php wp_nonce_field( 'step_3', 'setup_wizard' ); ?>
@@ -241,9 +263,9 @@ class WP_Job_Manager_Setup {
241
  <thead>
242
  <tr>
243
  <th>&nbsp;</th>
244
- <th><?php _e( 'Page Title', 'wp-job-manager' ); ?></th>
245
- <th><?php _e( 'Page Description', 'wp-job-manager' ); ?></th>
246
- <th><?php _e( 'Content Shortcode', 'wp-job-manager' ); ?></th>
247
  </tr>
248
  </thead>
249
  <tbody>
@@ -251,7 +273,7 @@ class WP_Job_Manager_Setup {
251
  <td><input type="checkbox" checked="checked" name="wp-job-manager-create-page[submit_job_form]" /></td>
252
  <td><input type="text" value="<?php echo esc_attr( _x( 'Post a Job', 'Default page title (wizard)', 'wp-job-manager' ) ); ?>" name="wp-job-manager-page-title[submit_job_form]" /></td>
253
  <td>
254
- <p><?php _e( 'Creates a page that allows employers to post new jobs directly from a page on your website, instead of requiring them to log in to an admin area. If you\'d rather not allow this -- for example, if you want employers to use the admin dashboard only -- you can uncheck this setting.', 'wp-job-manager' ); ?></p>
255
  </td>
256
  <td><code>[submit_job_form]</code></td>
257
  </tr>
@@ -259,14 +281,14 @@ class WP_Job_Manager_Setup {
259
  <td><input type="checkbox" checked="checked" name="wp-job-manager-create-page[job_dashboard]" /></td>
260
  <td><input type="text" value="<?php echo esc_attr( _x( 'Job Dashboard', 'Default page title (wizard)', 'wp-job-manager' ) ); ?>" name="wp-job-manager-page-title[job_dashboard]" /></td>
261
  <td>
262
- <p><?php _e( 'Creates a page that allows employers to manage their job listings directly from a page on your website, instead of requiring them to log in to an admin area. If you want to manage all job listings from the admin dashboard only, you can uncheck this setting.', 'wp-job-manager' ); ?></p>
263
  </td>
264
  <td><code>[job_dashboard]</code></td>
265
  </tr>
266
  <tr>
267
  <td><input type="checkbox" checked="checked" name="wp-job-manager-create-page[jobs]" /></td>
268
  <td><input type="text" value="<?php echo esc_attr( _x( 'Jobs', 'Default page title (wizard)', 'wp-job-manager' ) ); ?>" name="wp-job-manager-page-title[jobs]" /></td>
269
- <td><?php _e( 'Creates a page where visitors can browse, search, and filter job listings.', 'wp-job-manager' ); ?></td>
270
  <td><code>[jobs]</code></td>
271
  </tr>
272
  </tbody>
@@ -274,7 +296,7 @@ class WP_Job_Manager_Setup {
274
  <tr>
275
  <th colspan="4">
276
  <input type="submit" class="button button-primary" value="Create selected pages" />
277
- <a href="<?php echo esc_url( add_query_arg( 'step', 3 ) ); ?>" class="button"><?php _e( 'Skip this step', 'wp-job-manager' ); ?></a>
278
  </th>
279
  </tr>
280
  </tfoot>
@@ -284,43 +306,64 @@ class WP_Job_Manager_Setup {
284
  <?php endif; ?>
285
  <?php if ( 3 === $step ) : ?>
286
 
287
- <h3><?php _e( 'You\'re ready to start using WP Job Manager!', 'wp-job-manager' ); ?></h3>
288
 
289
- <p><?php _e( 'Wondering what to do now? Here are some of the most common next steps:', 'wp-job-manager' ); ?></p>
290
 
291
  <ul class="wp-job-manager-next-steps">
292
- <li><a href="<?php echo admin_url( 'edit.php?post_type=job_listing&page=job-manager-settings' ); ?>"><?php _e( 'Tweak your settings', 'wp-job-manager' ); ?></a></li>
293
- <li><a href="<?php echo admin_url( 'post-new.php?post_type=job_listing' ); ?>"><?php _e( 'Add a job using the admin dashboard', 'wp-job-manager' ); ?></a></li>
294
-
295
- <?php if ( $permalink = job_manager_get_permalink( 'jobs' ) ) : ?>
296
- <li><a href="<?php echo esc_url( $permalink ); ?>"><?php _e( 'View submitted job listings', 'wp-job-manager' ); ?></a></li>
297
- <?php else : ?>
298
- <li><a href="https://wpjobmanager.com/document/shortcode-reference/#section-1"><?php _e( 'Add job listings to a page using the [jobs] shortcode', 'wp-job-manager' ); ?></a></li>
299
- <?php endif; ?>
300
-
301
- <?php if ( $permalink = job_manager_get_permalink( 'submit_job_form' ) ) : ?>
302
- <li><a href="<?php echo esc_url( $permalink ); ?>"><?php _e( 'Add a job via the front-end', 'wp-job-manager' ); ?></a></li>
303
- <?php else : ?>
304
- <li><a href="https://wpjobmanager.com/document/the-job-submission-form/"><?php _e( 'Learn to use the front-end job submission board', 'wp-job-manager' ); ?></a></li>
305
- <?php endif; ?>
306
-
307
- <?php if ( $permalink = job_manager_get_permalink( 'job_dashboard' ) ) : ?>
308
- <li><a href="<?php echo esc_url( $permalink ); ?>"><?php _e( 'View the job dashboard', 'wp-job-manager' ); ?></a></li>
309
- <?php else : ?>
310
- <li><a href="https://wpjobmanager.com/document/the-job-dashboard/"><?php _e( 'Learn to use the front-end job dashboard', 'wp-job-manager' ); ?></a></li>
311
- <?php endif; ?>
 
 
 
 
 
 
 
 
312
  </ul>
313
 
314
- <p><?php printf( __( 'If you need help, you can find more detail in our %1$ssupport documentation%2$s or post your question on the %3$sWP Job Manager support forums%2$s. Happy hiring!', 'wp-job-manager' ), '<a href="https://wpjobmanager.com/documentation/">', '</a>', '<a href="https://wordpress.org/support/plugin/wp-job-manager">' ); ?></p>
 
 
 
 
 
 
 
 
 
 
 
 
 
315
 
316
  <div class="wp-job-manager-support-the-plugin">
317
- <h3><?php _e( 'Support WP Job Manager\'s Ongoing Development', 'wp-job-manager' ); ?></h3>
318
- <p><?php _e( 'There are lots of ways you can support open source software projects like this one: contributing code, fixing a bug, assisting with non-English translation, or just telling your friends about WP Job Manager to help spread the word. We appreciate your support!', 'wp-job-manager' ); ?></p>
319
  <ul>
320
- <li class="icon-review"><a href="https://wordpress.org/support/view/plugin-reviews/wp-job-manager#postform"><?php _e( 'Leave a positive review', 'wp-job-manager' ); ?></a></li>
321
- <li class="icon-localization"><a href="https://translate.wordpress.org/projects/wp-plugins/wp-job-manager"><?php _e( 'Contribute a localization', 'wp-job-manager' ); ?></a></li>
322
- <li class="icon-code"><a href="https://github.com/mikejolley/WP-Job-Manager"><?php _e( 'Contribute code or report a bug', 'wp-job-manager' ); ?></a></li>
323
- <li class="icon-forum"><a href="https://wordpress.org/support/plugin/wp-job-manager"><?php _e( 'Help other users on the forums', 'wp-job-manager' ); ?></a></li>
324
  </ul>
325
  </div>
326
 
40
  add_action( 'admin_menu', array( $this, 'admin_menu' ), 12 );
41
  add_action( 'admin_head', array( $this, 'admin_head' ) );
42
  add_action( 'admin_init', array( $this, 'redirect' ) );
43
+ if ( isset( $_GET['page'] ) && 'job-manager-setup' === $_GET['page'] ) {
44
  add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ), 12 );
45
+ }
46
  }
47
 
48
  /**
63
  * Sends user to the setup page on first activation.
64
  */
65
  public function redirect() {
66
+ // Bail if no activation redirect transient is set.
67
+ if ( ! get_transient( '_job_manager_activation_redirect' ) ) {
68
  return;
69
+ }
70
 
71
+ if ( ! current_user_can( 'manage_options' ) ) {
72
+ return;
73
+ }
74
 
75
+ // Delete the redirect transient.
76
  delete_transient( '_job_manager_activation_redirect' );
77
 
78
+ // Bail if activating from network, or bulk, or within an iFrame.
79
  if ( is_network_admin() || isset( $_GET['activate-multi'] ) || defined( 'IFRAME_REQUEST' ) ) {
80
  return;
81
  }
82
 
83
+ if ( ( isset( $_GET['action'] ) && 'upgrade-plugin' === $_GET['action'] ) && ( isset( $_GET['plugin'] ) && strstr( $_GET['plugin'], 'wp-job-manager.php' ) ) ) {
84
  return;
85
  }
86
 
111
  'post_title' => $title,
112
  'post_content' => $content,
113
  'post_parent' => 0,
114
+ 'comment_status' => 'closed',
115
  );
116
+ $page_id = wp_insert_post( $page_data );
117
 
118
  if ( $option ) {
119
  update_option( $option, $page_id );
182
  $step = ! empty( $_GET['step'] ) ? absint( $_GET['step'] ) : 1;
183
 
184
  if ( 3 === $step && ! empty( $_POST ) ) {
185
+ if ( false === wp_verify_nonce( $_REQUEST['setup_wizard'], 'step_3' ) ) {
186
  wp_die( 'Error in nonce. Try again.', 'wp-job-manager' );
187
+ }
188
  $create_pages = isset( $_POST['wp-job-manager-create-page'] ) ? $_POST['wp-job-manager-create-page'] : array();
189
  $page_titles = $_POST['wp-job-manager-page-title'];
190
  $pages_to_create = array(
191
  'submit_job_form' => '[submit_job_form]',
192
  'job_dashboard' => '[job_dashboard]',
193
+ 'jobs' => '[jobs]',
194
  );
195
 
196
  foreach ( $pages_to_create as $page => $content ) {
202
  }
203
  ?>
204
  <div class="wrap wp_job_manager wp_job_manager_addons_wrap">
205
+ <h2><?php esc_html_e( 'WP Job Manager Setup', 'wp-job-manager' ); ?></h2>
206
 
207
  <ul class="wp-job-manager-setup-steps">
208
+ <?php
209
+ $step_classes = array_fill( 1, 3, '' );
210
+ $step_classes[ $step ] = 'wp-job-manager-setup-active-step';
211
+ ?>
212
+ <li class="<?php echo sanitize_html_class( $step_classes[1] ); ?>"><?php esc_html_e( '1. Introduction', 'wp-job-manager' ); ?></li>
213
+ <li class="<?php echo sanitize_html_class( $step_classes[2] ); ?>"><?php esc_html_e( '2. Page Setup', 'wp-job-manager' ); ?></li>
214
+ <li class="<?php echo sanitize_html_class( $step_classes[3] ); ?>"><?php esc_html_e( '3. Done', 'wp-job-manager' ); ?></li>
215
  </ul>
216
 
217
  <?php if ( 1 === $step ) : ?>
218
 
219
+ <h3><?php esc_html_e( 'Welcome to the Setup Wizard!', 'wp-job-manager' ); ?></h3>
220
 
221
+ <p><?php echo wp_kses_post( __( 'Thanks for installing <em>WP Job Manager</em>! Let\'s get your site ready to accept job listings.', 'wp-job-manager' ) ); ?></p>
222
+ <p><?php echo wp_kses_post( __( 'This setup wizard will walk you through the process of creating pages for job submissions, management, and listings.', 'wp-job-manager' ) ); ?></p>
223
+ <p>
224
+ <?php
225
+ // translators: Placeholder %s is the path to WPJM documentation site.
226
+ echo wp_kses_post( sprintf( __( 'If you\'d prefer to skip this and set up your pages manually, our <a href="%s">documentation</a> will walk you through each step.', 'wp-job-manager' ), 'https://wpjobmanager.com/documentation/' ) );
227
+ ?>
228
+ </p>
229
 
230
  <form method="post" action="<?php echo esc_url( add_query_arg( 'step', 2 ) ); ?>">
231
  <input type="hidden" name="nonce" value="<?php echo esc_attr( wp_create_nonce( 'enable-usage-tracking' ) ); ?>" />
241
  <?php endif; ?>
242
  <?php if ( 2 === $step ) : ?>
243
 
244
+ <h3><?php esc_html_e( 'Page Setup', 'wp-job-manager' ); ?></h3>
245
 
246
+ <p><?php esc_html_e( 'With WP Job Manager, employers and applicants can post, manage, and browse job listings right on your website. Tell us which of these common pages you\'d like your site to have and we\'ll create and configure them for you.', 'wp-job-manager' ); ?></p>
247
+ <p>
248
+ <?php
249
+ echo wp_kses_post( sprintf(
250
+ // translators: %1$s is URL to WordPress core shortcode documentation. %2$s is URL to WPJM specific shortcode reference.
251
+ __( '(These pages are created using <a href="%1$s" title="What is a shortcode?" target="_blank" class="help-page-link">shortcodes</a>,
252
+ which we take care of in this step. If you\'d like to build these pages yourself or want to add one of these options to an existing
253
+ page on your site, you can skip this step and take a look at <a href="%2$s" target="_blank" class="help-page-link">shortcode documentation</a> for detailed instructions.)', 'wp-job-manager' ),
254
+ 'http://codex.wordpress.org/Shortcode',
255
+ 'https://wpjobmanager.com/document/shortcode-reference/'
256
+ ) );
257
+ ?>
258
+ </p>
259
 
260
  <form action="<?php echo esc_url( add_query_arg( 'step', 3 ) ); ?>" method="post">
261
  <?php wp_nonce_field( 'step_3', 'setup_wizard' ); ?>
263
  <thead>
264
  <tr>
265
  <th>&nbsp;</th>
266
+ <th><?php esc_html_e( 'Page Title', 'wp-job-manager' ); ?></th>
267
+ <th><?php esc_html_e( 'Page Description', 'wp-job-manager' ); ?></th>
268
+ <th><?php esc_html_e( 'Content Shortcode', 'wp-job-manager' ); ?></th>
269
  </tr>
270
  </thead>
271
  <tbody>
273
  <td><input type="checkbox" checked="checked" name="wp-job-manager-create-page[submit_job_form]" /></td>
274
  <td><input type="text" value="<?php echo esc_attr( _x( 'Post a Job', 'Default page title (wizard)', 'wp-job-manager' ) ); ?>" name="wp-job-manager-page-title[submit_job_form]" /></td>
275
  <td>
276
+ <p><?php esc_html_e( 'Creates a page that allows employers to post new jobs directly from a page on your website, instead of requiring them to log in to an admin area. If you\'d rather not allow this -- for example, if you want employers to use the admin dashboard only -- you can uncheck this setting.', 'wp-job-manager' ); ?></p>
277
  </td>
278
  <td><code>[submit_job_form]</code></td>
279
  </tr>
281
  <td><input type="checkbox" checked="checked" name="wp-job-manager-create-page[job_dashboard]" /></td>
282
  <td><input type="text" value="<?php echo esc_attr( _x( 'Job Dashboard', 'Default page title (wizard)', 'wp-job-manager' ) ); ?>" name="wp-job-manager-page-title[job_dashboard]" /></td>
283
  <td>
284
+ <p><?php esc_html_e( 'Creates a page that allows employers to manage their job listings directly from a page on your website, instead of requiring them to log in to an admin area. If you want to manage all job listings from the admin dashboard only, you can uncheck this setting.', 'wp-job-manager' ); ?></p>
285
  </td>
286
  <td><code>[job_dashboard]</code></td>
287
  </tr>
288
  <tr>
289
  <td><input type="checkbox" checked="checked" name="wp-job-manager-create-page[jobs]" /></td>
290
  <td><input type="text" value="<?php echo esc_attr( _x( 'Jobs', 'Default page title (wizard)', 'wp-job-manager' ) ); ?>" name="wp-job-manager-page-title[jobs]" /></td>
291
+ <td><?php esc_html_e( 'Creates a page where visitors can browse, search, and filter job listings.', 'wp-job-manager' ); ?></td>
292
  <td><code>[jobs]</code></td>
293
  </tr>
294
  </tbody>
296
  <tr>
297
  <th colspan="4">
298
  <input type="submit" class="button button-primary" value="Create selected pages" />
299
+ <a href="<?php echo esc_url( add_query_arg( 'step', 3 ) ); ?>" class="button"><?php esc_html_e( 'Skip this step', 'wp-job-manager' ); ?></a>
300
  </th>
301
  </tr>
302
  </tfoot>
306
  <?php endif; ?>
307
  <?php if ( 3 === $step ) : ?>
308
 
309
+ <h3><?php esc_html_e( 'You\'re ready to start using WP Job Manager!', 'wp-job-manager' ); ?></h3>
310
 
311
+ <p><?php esc_html_e( 'Wondering what to do now? Here are some of the most common next steps:', 'wp-job-manager' ); ?></p>
312
 
313
  <ul class="wp-job-manager-next-steps">
314
+ <li><a href="<?php echo esc_url( admin_url( 'edit.php?post_type=job_listing&page=job-manager-settings' ) ); ?>"><?php esc_html_e( 'Tweak your settings', 'wp-job-manager' ); ?></a></li>
315
+ <li><a href="<?php echo esc_url( admin_url( 'post-new.php?post_type=job_listing' ) ); ?>"><?php esc_html_e( 'Add a job using the admin dashboard', 'wp-job-manager' ); ?></a></li>
316
+ <?php
317
+ $permalink = job_manager_get_permalink( 'jobs' );
318
+ if ( $permalink ) {
319
+ ?>
320
+ <li><a href="<?php echo esc_url( $permalink ); ?>"><?php esc_html_e( 'View submitted job listings', 'wp-job-manager' ); ?></a></li>
321
+ <?php } else { ?>
322
+ <li><a href="https://wpjobmanager.com/document/shortcode-reference/#section-1"><?php esc_html_e( 'Add job listings to a page using the [jobs] shortcode', 'wp-job-manager' ); ?></a></li>
323
+ <?php } ?>
324
+
325
+ <?php
326
+ $permalink = job_manager_get_permalink( 'submit_job_form' );
327
+ if ( $permalink ) {
328
+ ?>
329
+ <li><a href="<?php echo esc_url( $permalink ); ?>"><?php esc_html_e( 'Add a job via the front-end', 'wp-job-manager' ); ?></a></li>
330
+ <?php } else { ?>
331
+ <li><a href="https://wpjobmanager.com/document/the-job-submission-form/"><?php esc_html_e( 'Learn to use the front-end job submission board', 'wp-job-manager' ); ?></a></li>
332
+ <?php } ?>
333
+
334
+ <?php
335
+ $permalink = job_manager_get_permalink( 'job_dashboard' );
336
+ if ( $permalink ) {
337
+ ?>
338
+ <li><a href="<?php echo esc_url( $permalink ); ?>"><?php esc_html_e( 'View the job dashboard', 'wp-job-manager' ); ?></a></li>
339
+ <?php } else { ?>
340
+ <li><a href="https://wpjobmanager.com/document/the-job-dashboard/"><?php esc_html_e( 'Learn to use the front-end job dashboard', 'wp-job-manager' ); ?></a></li>
341
+ <?php } ?>
342
  </ul>
343
 
344
+ <p>
345
+ <?php
346
+ echo wp_kses_post(
347
+ sprintf(
348
+ // translators: %1$s is the URL to WPJM support documentation; %2$s is the URL to WPJM support forums.
349
+ __( 'If you need help, you can find more detail in our
350
+ <a href="%1$s">support documentation</a> or post your question on the
351
+ <a href="%2$s">WP Job Manager support forums</a>. Happy hiring!', 'wp-job-manager' ),
352
+ 'https://wpjobmanager.com/documentation/',
353
+ 'https://wordpress.org/support/plugin/wp-job-manager'
354
+ )
355
+ );
356
+ ?>
357
+ </p>
358
 
359
  <div class="wp-job-manager-support-the-plugin">
360
+ <h3><?php esc_html_e( 'Support WP Job Manager\'s Ongoing Development', 'wp-job-manager' ); ?></h3>
361
+ <p><?php esc_html_e( 'There are lots of ways you can support open source software projects like this one: contributing code, fixing a bug, assisting with non-English translation, or just telling your friends about WP Job Manager to help spread the word. We appreciate your support!', 'wp-job-manager' ); ?></p>
362
  <ul>
363
+ <li class="icon-review"><a href="https://wordpress.org/support/view/plugin-reviews/wp-job-manager#postform"><?php esc_html_e( 'Leave a positive review', 'wp-job-manager' ); ?></a></li>
364
+ <li class="icon-localization"><a href="https://translate.wordpress.org/projects/wp-plugins/wp-job-manager"><?php esc_html_e( 'Contribute a localization', 'wp-job-manager' ); ?></a></li>
365
+ <li class="icon-code"><a href="https://github.com/mikejolley/WP-Job-Manager"><?php esc_html_e( 'Contribute code or report a bug', 'wp-job-manager' ); ?></a></li>
366
+ <li class="icon-forum"><a href="https://wordpress.org/support/plugin/wp-job-manager"><?php esc_html_e( 'Help other users on the forums', 'wp-job-manager' ); ?></a></li>
367
  </ul>
368
  </div>
369
 
includes/admin/class-wp-job-manager-taxonomy-meta.php CHANGED
@@ -44,7 +44,7 @@ class WP_Job_Manager_Taxonomy_Meta {
44
  add_filter( 'manage_edit-job_listing_type_columns', array( $this, 'add_employment_type_column' ) );
45
  add_filter( 'manage_job_listing_type_custom_column', array( $this, 'add_employment_type_column_content' ), 10, 3 );
46
  add_filter( 'manage_edit-job_listing_type_sortable_columns', array( $this, 'add_employment_type_column_sortable' ) );
47
- }
48
  }
49
 
50
  /**
@@ -55,7 +55,7 @@ class WP_Job_Manager_Taxonomy_Meta {
55
  */
56
  public function set_schema_org_employment_type_field( $term_id, $tt_id ) {
57
  $employment_types = wpjm_job_listing_employment_type_options();
58
- if( isset( $_POST['employment_type'] ) && isset( $employment_types[ $_POST['employment_type'] ] ) ){
59
  update_term_meta( $term_id, 'employment_type', $_POST['employment_type'] );
60
  } elseif ( isset( $_POST['employment_type'] ) ) {
61
  delete_term_meta( $term_id, 'employment_type' );
@@ -69,27 +69,28 @@ class WP_Job_Manager_Taxonomy_Meta {
69
  * @param string $taxonomy Taxonomy slug.
70
  */
71
  public function display_schema_org_employment_type_field( $term, $taxonomy ) {
72
- $employment_types = wpjm_job_listing_employment_type_options();
73
  $current_employment_type = get_term_meta( $term->term_id, 'employment_type', true );
74
 
75
  if ( ! empty( $employment_types ) ) {
76
  ?>
77
  <tr class="form-field term-group-wrap">
78
- <th scope="row"><label for="feature-group"><?php _e( 'Employment Type', 'wp-job-manager' ); ?></label></th>
79
  <td><select class="postform" id="employment_type" name="employment_type">
80
  <option value=""></option>
81
  <?php foreach ( $employment_types as $key => $employment_type ) : ?>
82
  <option value="<?php echo esc_attr( $key ); ?>" <?php selected( $current_employment_type, $key ); ?>><?php echo esc_html( $employment_type ); ?></option>
83
  <?php endforeach; ?>
84
  </select></td>
85
- </tr><?php
 
86
  }
87
  }
88
 
89
  /**
90
  * Add the option to select schema.org employmentType for job type on the add meta field form.
91
  *
92
- * @param string $taxonomy Taxonomy slug.
93
  */
94
  public function add_form_display_schema_org_employment_type_field( $taxonomy ) {
95
  $employment_types = wpjm_job_listing_employment_type_options();
@@ -97,14 +98,15 @@ class WP_Job_Manager_Taxonomy_Meta {
97
  if ( ! empty( $employment_types ) ) {
98
  ?>
99
  <div class="form-field term-group">
100
- <label for="feature-group"><?php _e( 'Employment Type', 'wp-job-manager' ); ?></label>
101
  <select class="postform" id="employment_type" name="employment_type">
102
  <option value=""></option>
103
  <?php foreach ( $employment_types as $key => $employment_type ) : ?>
104
  <option value="<?php echo esc_attr( $key ); ?>"><?php echo esc_html( $employment_type ); ?></option>
105
  <?php endforeach; ?>
106
  </select>
107
- </div><?php
 
108
  }
109
  }
110
 
@@ -139,11 +141,11 @@ class WP_Job_Manager_Taxonomy_Meta {
139
  * @return string
140
  */
141
  public function add_employment_type_column_content( $content, $column_name, $term_id ) {
142
- if( 'employment_type' !== $column_name ){
143
  return $content;
144
  }
145
- $employment_types = wpjm_job_listing_employment_type_options();
146
- $term_id = absint( $term_id );
147
  $term_employment_type = get_term_meta( $term_id, 'employment_type', true );
148
 
149
  if ( ! empty( $term_employment_type ) && isset( $employment_types[ $term_employment_type ] ) ) {
@@ -153,4 +155,4 @@ class WP_Job_Manager_Taxonomy_Meta {
153
  }
154
  }
155
 
156
- WP_Job_Manager_Taxonomy_Meta::instance();
44
  add_filter( 'manage_edit-job_listing_type_columns', array( $this, 'add_employment_type_column' ) );
45
  add_filter( 'manage_job_listing_type_custom_column', array( $this, 'add_employment_type_column_content' ), 10, 3 );
46
  add_filter( 'manage_edit-job_listing_type_sortable_columns', array( $this, 'add_employment_type_column_sortable' ) );
47
+ }
48
  }
49
 
50
  /**
55
  */
56
  public function set_schema_org_employment_type_field( $term_id, $tt_id ) {
57
  $employment_types = wpjm_job_listing_employment_type_options();
58
+ if ( isset( $_POST['employment_type'] ) && isset( $employment_types[ $_POST['employment_type'] ] ) ) {
59
  update_term_meta( $term_id, 'employment_type', $_POST['employment_type'] );
60
  } elseif ( isset( $_POST['employment_type'] ) ) {
61
  delete_term_meta( $term_id, 'employment_type' );
69
  * @param string $taxonomy Taxonomy slug.
70
  */
71
  public function display_schema_org_employment_type_field( $term, $taxonomy ) {
72
+ $employment_types = wpjm_job_listing_employment_type_options();
73
  $current_employment_type = get_term_meta( $term->term_id, 'employment_type', true );
74
 
75
  if ( ! empty( $employment_types ) ) {
76
  ?>
77
  <tr class="form-field term-group-wrap">
78
+ <th scope="row"><label for="feature-group"><?php esc_html_e( 'Employment Type', 'wp-job-manager' ); ?></label></th>
79
  <td><select class="postform" id="employment_type" name="employment_type">
80
  <option value=""></option>
81
  <?php foreach ( $employment_types as $key => $employment_type ) : ?>
82
  <option value="<?php echo esc_attr( $key ); ?>" <?php selected( $current_employment_type, $key ); ?>><?php echo esc_html( $employment_type ); ?></option>
83
  <?php endforeach; ?>
84
  </select></td>
85
+ </tr>
86
+ <?php
87
  }
88
  }
89
 
90
  /**
91
  * Add the option to select schema.org employmentType for job type on the add meta field form.
92
  *
93
+ * @param string $taxonomy Taxonomy slug.
94
  */
95
  public function add_form_display_schema_org_employment_type_field( $taxonomy ) {
96
  $employment_types = wpjm_job_listing_employment_type_options();
98
  if ( ! empty( $employment_types ) ) {
99
  ?>
100
  <div class="form-field term-group">
101
+ <label for="feature-group"><?php esc_html_e( 'Employment Type', 'wp-job-manager' ); ?></label>
102
  <select class="postform" id="employment_type" name="employment_type">
103
  <option value=""></option>
104
  <?php foreach ( $employment_types as $key => $employment_type ) : ?>
105
  <option value="<?php echo esc_attr( $key ); ?>"><?php echo esc_html( $employment_type ); ?></option>
106
  <?php endforeach; ?>
107
  </select>
108
+ </div>
109
+ <?php
110
  }
111
  }
112
 
141
  * @return string
142
  */
143
  public function add_employment_type_column_content( $content, $column_name, $term_id ) {
144
+ if ( 'employment_type' !== $column_name ) {
145
  return $content;
146
  }
147
+ $employment_types = wpjm_job_listing_employment_type_options();
148
+ $term_id = absint( $term_id );
149
  $term_employment_type = get_term_meta( $term_id, 'employment_type', true );
150
 
151
  if ( ! empty( $term_employment_type ) && isset( $employment_types[ $term_employment_type ] ) ) {
155
  }
156
  }
157
 
158
+ WP_Job_Manager_Taxonomy_Meta::instance();
includes/admin/class-wp-job-manager-writepanels.php CHANGED
@@ -1,5 +1,7 @@
1
  <?php
2
- if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
 
 
3
 
4
  /**
5
  * Handles the management of Job Listing meta fields.
@@ -51,60 +53,60 @@ class WP_Job_Manager_Writepanels {
51
  $current_user = wp_get_current_user();
52
 
53
  $fields = array(
54
- '_job_location' => array(
55
- 'label' => __( 'Location', 'wp-job-manager' ),
56
  'placeholder' => __( 'e.g. "London"', 'wp-job-manager' ),
57
  'description' => __( 'Leave this blank if the location is not important.', 'wp-job-manager' ),
58
- 'priority' => 1
59
  ),
60
- '_application' => array(
61
  'label' => __( 'Application Email or URL', 'wp-job-manager' ),
62
  'placeholder' => __( 'URL or email which applicants use to apply', 'wp-job-manager' ),
63
  'description' => __( 'This field is required for the "application" area to appear beneath the listing.', 'wp-job-manager' ),
64
  'value' => metadata_exists( 'post', $post->ID, '_application' ) ? get_post_meta( $post->ID, '_application', true ) : $current_user->user_email,
65
- 'priority' => 2
66
  ),
67
- '_company_name' => array(
68
  'label' => __( 'Company Name', 'wp-job-manager' ),
69
  'placeholder' => '',
70
- 'priority' => 3
71
  ),
72
  '_company_website' => array(
73
  'label' => __( 'Company Website', 'wp-job-manager' ),
74
  'placeholder' => '',
75
- 'priority' => 4
76
  ),
77
  '_company_tagline' => array(
78
  'label' => __( 'Company Tagline', 'wp-job-manager' ),
79
  'placeholder' => __( 'Brief description about the company', 'wp-job-manager' ),
80
- 'priority' => 5
81
  ),
82
  '_company_twitter' => array(
83
  'label' => __( 'Company Twitter', 'wp-job-manager' ),
84
  'placeholder' => '@yourcompany',
85
- 'priority' => 6
86
  ),
87
- '_company_video' => array(
88
  'label' => __( 'Company Video', 'wp-job-manager' ),
89
  'placeholder' => __( 'URL to the company video', 'wp-job-manager' ),
90
  'type' => 'file',
91
- 'priority' => 8
92
  ),
93
- '_filled' => array(
94
  'label' => __( 'Position Filled', 'wp-job-manager' ),
95
  'type' => 'checkbox',
96
  'priority' => 9,
97
  'description' => __( 'Filled listings will no longer accept applications.', 'wp-job-manager' ),
98
- )
99
  );
100
  if ( $current_user->has_cap( 'manage_job_listings' ) ) {
101
- $fields['_featured'] = array(
102
  'label' => __( 'Featured Listing', 'wp-job-manager' ),
103
  'type' => 'checkbox',
104
  'description' => __( 'Featured listings will be sticky during searches, and can be styled differently.', 'wp-job-manager' ),
105
- 'priority' => 10
106
  );
107
- $job_expires = get_post_meta( $post->ID, '_job_expires', true );
108
  $fields['_job_expires'] = array(
109
  'label' => __( 'Listing Expiry Date', 'wp-job-manager' ),
110
  'priority' => 11,
@@ -117,7 +119,7 @@ class WP_Job_Manager_Writepanels {
117
  $fields['_job_author'] = array(
118
  'label' => __( 'Posted by', 'wp-job-manager' ),
119
  'type' => 'author',
120
- 'priority' => 12
121
  );
122
  }
123
 
@@ -145,10 +147,10 @@ class WP_Job_Manager_Writepanels {
145
  * @return int
146
  */
147
  protected function sort_by_priority( $a, $b ) {
148
- if ( ! isset( $a['priority'] ) || ! isset( $b['priority'] ) || $a['priority'] === $b['priority'] ) {
149
- return 0;
150
- }
151
- return ( $a['priority'] < $b['priority'] ) ? -1 : 1;
152
  }
153
 
154
  /**
@@ -157,13 +159,14 @@ class WP_Job_Manager_Writepanels {
157
  public function add_meta_boxes() {
158
  global $wp_post_types;
159
 
 
160
  add_meta_box( 'job_listing_data', sprintf( __( '%s Data', 'wp-job-manager' ), $wp_post_types['job_listing']->labels->singular_name ), array( $this, 'job_listing_data' ), 'job_listing', 'normal', 'high' );
161
- if ( ! get_option( 'job_manager_enable_types' ) || wp_count_terms( 'job_listing_type' ) == 0 ) {
162
- remove_meta_box( 'job_listing_typediv', 'job_listing', 'side');
163
- } elseif ( false == job_manager_multi_job_type() ) {
164
- remove_meta_box( 'job_listing_typediv', 'job_listing', 'side');
165
  $job_listing_type = get_taxonomy( 'job_listing_type' );
166
- add_meta_box( 'job_listing_type', $job_listing_type->labels->menu_name, array( $this, 'job_listing_metabox' ),'job_listing' ,'side','core');
167
  }
168
  }
169
 
@@ -173,54 +176,71 @@ class WP_Job_Manager_Writepanels {
173
  * @param int|WP_Post $post
174
  */
175
  public function job_listing_metabox( $post ) {
176
- // Set up the taxonomy object and get terms
177
  $taxonomy = 'job_listing_type';
178
- $tax = get_taxonomy( $taxonomy );// This is the taxonomy object
179
 
180
- // The name of the form
181
  $name = 'tax_input[' . $taxonomy . ']';
182
 
183
- // Get all the terms for this taxonomy
184
- $terms = get_terms( array( 'taxonomy' => $taxonomy, 'hide_empty' => 0 ) );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
185
  $postterms = get_the_terms( $post->ID, $taxonomy );
186
- $current = ( $postterms ? array_pop( $postterms ) : false );
187
- $current = ( $current ? $current->term_id : 0 );
188
- // Get current and popular terms
189
- $popular = get_terms( array( 'taxonomy' => $taxonomy, 'orderby' => 'count', 'order' => 'DESC', 'number' => 10, 'hierarchical' => false ) );
190
- $postterms = get_the_terms( $post->ID,$taxonomy );
191
- $current = ($postterms ? array_pop($postterms) : false);
192
- $current = ($current ? $current->term_id : 0);
193
  ?>
194
 
195
- <div id="taxonomy-<?php echo $taxonomy; ?>" class="categorydiv">
196
 
197
  <!-- Display tabs-->
198
- <ul id="<?php echo $taxonomy; ?>-tabs" class="category-tabs">
199
- <li class="tabs"><a href="#<?php echo $taxonomy; ?>-all" tabindex="3"><?php echo $tax->labels->all_items; ?></a></li>
200
- <li class="hide-if-no-js"><a href="#<?php echo $taxonomy; ?>-pop" tabindex="3"><?php _e( 'Most Used', 'wp-job-manager' ); ?></a></li>
201
  </ul>
202
 
203
  <!-- Display taxonomy terms -->
204
- <div id="<?php echo $taxonomy; ?>-all" class="tabs-panel">
205
- <ul id="<?php echo $taxonomy; ?>checklist" class="list:<?php echo $taxonomy?> categorychecklist form-no-clear">
206
- <?php foreach($terms as $term){
207
- $id = $taxonomy.'-'.$term->term_id;
208
- echo "<li id='$id'><label class='selectit'>";
209
- echo "<input type='radio' id='in-$id' name='{$name}'".checked($current,$term->term_id,false)."value='$term->term_id' />$term->name<br />";
210
- echo "</label></li>";
211
- }?>
 
 
212
  </ul>
213
  </div>
214
 
215
  <!-- Display popular taxonomy terms -->
216
- <div id="<?php echo $taxonomy; ?>-pop" class="tabs-panel" style="display: none;">
217
- <ul id="<?php echo $taxonomy; ?>checklist-pop" class="categorychecklist form-no-clear" >
218
- <?php foreach($popular as $term){
219
- $id = 'popular-'.$taxonomy.'-'.$term->term_id;
220
- echo "<li id='$id'><label class='selectit'>";
221
- echo "<input type='radio' id='in-$id'".checked($current,$term->term_id,false)."value='$term->term_id' />$term->name<br />";
222
- echo "</label></li>";
223
- }?>
 
 
224
  </ul>
225
  </div>
226
 
@@ -250,17 +270,27 @@ class WP_Job_Manager_Writepanels {
250
  }
251
  ?>
252
  <p class="form-field">
253
- <label for="<?php echo esc_attr( $key ); ?>"><?php echo wp_strip_all_tags( $field['label'] ) ; ?>: <?php if ( ! empty( $field['description'] ) ) : ?><span class="tips" data-tip="<?php echo esc_attr( $field['description'] ); ?>">[?]</span><?php endif; ?></label>
 
 
 
 
254
  <?php
255
  if ( ! empty( $field['multiple'] ) ) {
256
  foreach ( (array) $field['value'] as $value ) {
257
- ?><span class="file_url"><input type="text" name="<?php echo esc_attr( $name ); ?>[]" placeholder="<?php echo esc_attr( $field['placeholder'] ); ?>" value="<?php echo esc_attr( $value ); ?>" /><button class="button button-small wp_job_manager_upload_file_button" data-uploader_button_text="<?php _e( 'Use file', 'wp-job-manager' ); ?>"><?php _e( 'Upload', 'wp-job-manager' ); ?></button><button class="button button-small wp_job_manager_view_file_button"><?php _e( 'View', 'wp-job-manager' ); ?></button></span><?php
 
 
258
  }
259
  } else {
260
- ?><span class="file_url"><input type="text" name="<?php echo esc_attr( $name ); ?>" id="<?php echo esc_attr( $key ); ?>" placeholder="<?php echo esc_attr( $field['placeholder'] ); ?>" value="<?php echo esc_attr( $field['value'] ); ?>" /><button class="button button-small wp_job_manager_upload_file_button" data-uploader_button_text="<?php _e( 'Use file', 'wp-job-manager' ); ?>"><?php _e( 'Upload', 'wp-job-manager' ); ?></button><button class="button button-small wp_job_manager_view_file_button"><?php _e( 'View', 'wp-job-manager' ); ?></button></span><?php
 
 
261
  }
262
  if ( ! empty( $field['multiple'] ) ) {
263
- ?><button class="button button-small wp_job_manager_add_another_file_button" data-field_name="<?php echo esc_attr( $key ); ?>" data-field_placeholder="<?php echo esc_attr( $field['placeholder'] ); ?>" data-uploader_button_text="<?php _e( 'Use file', 'wp-job-manager' ); ?>" data-uploader_button="<?php _e( 'Upload', 'wp-job-manager' ); ?>" data-view_button="<?php _e( 'View', 'wp-job-manager' ); ?>"><?php _e( 'Add file', 'wp-job-manager' ); ?></button><?php
 
 
264
  }
265
  ?>
266
  </p>
@@ -291,7 +321,11 @@ class WP_Job_Manager_Writepanels {
291
  }
292
  ?>
293
  <p class="form-field">
294
- <label for="<?php echo esc_attr( $key ); ?>"><?php echo wp_strip_all_tags( $field['label'] ) ; ?>: <?php if ( ! empty( $field['description'] ) ) : ?><span class="tips" data-tip="<?php echo esc_attr( $field['description'] ); ?>">[?]</span><?php endif; ?></label>
 
 
 
 
295
  <input type="text" autocomplete="off" name="<?php echo esc_attr( $name ); ?>" class="<?php echo esc_attr( $classes ); ?>" id="<?php echo esc_attr( $key ); ?>" placeholder="<?php echo esc_attr( $field['placeholder'] ); ?>" value="<?php echo esc_attr( $field['value'] ); ?>" />
296
  </p>
297
  <?php
@@ -333,19 +367,23 @@ class WP_Job_Manager_Writepanels {
333
  } else {
334
  $classes = '';
335
  }
336
- $hidden_input = '';
337
  if ( 'hidden' === $field['type'] ) {
338
- $hidden_input = '<input type="hidden" name="' . esc_attr( $name ) . '" class="' . esc_attr( $classes ) . '" id="' . esc_attr( $key ) . '" value="' . esc_attr( $field['value'] ) . '" />';
339
  if ( empty( $field['label'] ) ) {
340
- echo $hidden_input;
341
  return;
342
  }
343
  }
344
  ?>
345
  <p class="form-field">
346
- <label for="<?php echo esc_attr( $key ); ?>"><?php echo wp_strip_all_tags( $field['label'] ) ; ?>: <?php if ( ! empty( $field['description'] ) ) : ?><span class="tips" data-tip="<?php echo esc_attr( $field['description'] ); ?>">[?]</span><?php endif; ?></label>
347
- <?php if ( ! empty( $field['information'] ) ) : ?><span class="information"><?php echo wp_kses( $field['information'], array( 'a' => array( 'href' => array() ) ) ); ?></span><?php endif; ?>
348
- <?php echo $hidden_input; ?>
 
 
 
 
 
 
349
  </p>
350
  <?php
351
  }
@@ -369,7 +407,11 @@ class WP_Job_Manager_Writepanels {
369
  }
370
  ?>
371
  <p class="form-field">
372
- <label for="<?php echo esc_attr( $key ); ?>"><?php echo wp_strip_all_tags( $field['label'] ) ; ?>: <?php if ( ! empty( $field['description'] ) ) : ?><span class="tips" data-tip="<?php echo esc_attr( $field['description'] ); ?>">[?]</span><?php endif; ?></label>
 
 
 
 
373
  <textarea name="<?php echo esc_attr( $name ); ?>" id="<?php echo esc_attr( $key ); ?>" placeholder="<?php echo esc_attr( $field['placeholder'] ); ?>"><?php echo esc_html( $field['value'] ); ?></textarea>
374
  </p>
375
  <?php
@@ -394,10 +436,22 @@ class WP_Job_Manager_Writepanels {
394
  }
395
  ?>
396
  <p class="form-field">
397
- <label for="<?php echo esc_attr( $key ); ?>"><?php echo wp_strip_all_tags( $field['label'] ) ; ?>: <?php if ( ! empty( $field['description'] ) ) : ?><span class="tips" data-tip="<?php echo esc_attr( $field['description'] ); ?>">[?]</span><?php endif; ?></label>
 
 
 
 
 
398
  <select name="<?php echo esc_attr( $name ); ?>" id="<?php echo esc_attr( $key ); ?>">
399
  <?php foreach ( $field['options'] as $key => $value ) : ?>
400
- <option value="<?php echo esc_attr( $key ); ?>" <?php if ( isset( $field['value'] ) ) selected( $field['value'], $key ); ?>><?php echo esc_html( $value ); ?></option>
 
 
 
 
 
 
 
401
  <?php endforeach; ?>
402
  </select>
403
  </p>
@@ -423,10 +477,21 @@ class WP_Job_Manager_Writepanels {
423
  }
424
  ?>
425
  <p class="form-field">
426
- <label for="<?php echo esc_attr( $key ); ?>"><?php echo wp_strip_all_tags( $field['label'] ) ; ?>: <?php if ( ! empty( $field['description'] ) ) : ?><span class="tips" data-tip="<?php echo esc_attr( $field['description'] ); ?>">[?]</span><?php endif; ?></label>
 
 
 
 
427
  <select multiple="multiple" name="<?php echo esc_attr( $name ); ?>[]" id="<?php echo esc_attr( $key ); ?>">
428
  <?php foreach ( $field['options'] as $key => $value ) : ?>
429
- <option value="<?php echo esc_attr( $key ); ?>" <?php if ( ! empty( $field['value'] ) && is_array( $field['value'] ) ) selected( in_array( $key, $field['value'] ), true ); ?>><?php echo esc_html( $value ); ?></option>
 
 
 
 
 
 
 
430
  <?php endforeach; ?>
431
  </select>
432
  </p>
@@ -452,9 +517,11 @@ class WP_Job_Manager_Writepanels {
452
  }
453
  ?>
454
  <p class="form-field form-field-checkbox">
455
- <label for="<?php echo esc_attr( $key ); ?>"><?php echo wp_strip_all_tags( $field['label'] ) ; ?></label>
456
  <input type="checkbox" class="checkbox" name="<?php echo esc_attr( $name ); ?>" id="<?php echo esc_attr( $key ); ?>" value="1" <?php checked( $field['value'], 1 ); ?> />
457
- <?php if ( ! empty( $field['description'] ) ) : ?><span class="description"><?php echo $field['description']; ?></span><?php endif; ?>
 
 
458
  </p>
459
  <?php
460
  }
@@ -480,19 +547,20 @@ class WP_Job_Manager_Writepanels {
480
  $name = ! empty( $field['name'] ) ? $field['name'] : $key;
481
  ?>
482
  <p class="form-field form-field-author">
483
- <label for="<?php echo esc_attr( $key ); ?>"><?php echo wp_strip_all_tags( $field['label'] ) ; ?>:</label>
484
  <span class="current-author">
485
  <?php
486
- if ( $posted_by ) {
487
- echo '<a href="' . admin_url( 'user-edit.php?user_id=' . absint( $author_id ) ) . '">#' . absint( $author_id ) . ' &ndash; ' . $posted_by->user_login . '</a>';
488
- } else {
489
- _e( 'Guest User', 'wp-job-manager' );
490
- }
491
- ?> <a href="#" class="change-author button button-small"><?php _e( 'Change', 'wp-job-manager' ); ?></a>
 
492
  </span>
493
  <span class="hidden change-author">
494
  <input type="number" name="<?php echo esc_attr( $name ); ?>" id="<?php echo esc_attr( $key ); ?>" step="1" value="<?php echo esc_attr( $author_id ); ?>" style="width: 4em;" />
495
- <span class="description"><?php _e( 'Enter the ID of the user, or leave blank if submitted by a guest.', 'wp-job-manager' ) ?></span>
496
  </span>
497
  </p>
498
  <?php
@@ -517,11 +585,13 @@ class WP_Job_Manager_Writepanels {
517
  }
518
  ?>
519
  <p class="form-field form-field-checkbox">
520
- <label><?php echo wp_strip_all_tags( $field['label'] ) ; ?></label>
521
  <?php foreach ( $field['options'] as $option_key => $value ) : ?>
522
  <label><input type="radio" class="radio" name="<?php echo esc_attr( isset( $field['name'] ) ? $field['name'] : $key ); ?>" value="<?php echo esc_attr( $option_key ); ?>" <?php checked( $field['value'], $option_key ); ?> /> <?php echo esc_html( $value ); ?></label>
523
  <?php endforeach; ?>
524
- <?php if ( ! empty( $field['description'] ) ) : ?><span class="description"><?php echo $field['description']; ?></span><?php endif; ?>
 
 
525
  </p>
526
  <?php
527
  }
@@ -555,7 +625,8 @@ class WP_Job_Manager_Writepanels {
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
 
@@ -571,13 +642,27 @@ class WP_Job_Manager_Writepanels {
571
  * @param WP_Post $post
572
  */
573
  public function save_post( $post_id, $post ) {
574
- if ( empty( $post_id ) || empty( $post ) || empty( $_POST ) ) return;
575
- if ( defined('DOING_AUTOSAVE') && DOING_AUTOSAVE ) return;
576
- if ( is_int( wp_is_post_revision( $post ) ) ) return;
577
- if ( is_int( wp_is_post_autosave( $post ) ) ) return;
578
- if ( empty($_POST['job_manager_nonce']) || ! wp_verify_nonce( $_POST['job_manager_nonce'], 'save_meta_data' ) ) return;
579
- if ( ! current_user_can( 'edit_post', $post_id ) ) return;
580
- if ( $post->post_type != 'job_listing' ) return;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
581
 
582
  do_action( 'job_manager_save_job_listing', $post_id, $post );
583
  }
@@ -586,22 +671,22 @@ class WP_Job_Manager_Writepanels {
586
  * Handles the actual saving of job listing data fields.
587
  *
588
  * @param int $post_id
589
- * @param WP_Post $post (Unused)
590
  */
591
  public function save_job_listing_data( $post_id, $post ) {
592
  global $wpdb;
593
 
594
- // These need to exist
595
  add_post_meta( $post_id, '_filled', 0, true );
596
  add_post_meta( $post_id, '_featured', 0, true );
597
 
598
- // Save fields
599
  foreach ( $this->job_listing_fields() as $key => $field ) {
600
  if ( isset( $field['type'] ) && 'info' === $field['type'] ) {
601
  continue;
602
  }
603
 
604
- // Expirey date
605
  if ( '_job_expires' === $key ) {
606
  if ( empty( $_POST[ $key ] ) ) {
607
  if ( get_option( 'job_manager_submission_duration' ) ) {
@@ -612,41 +697,33 @@ class WP_Job_Manager_Writepanels {
612
  } else {
613
  update_post_meta( $post_id, $key, date( 'Y-m-d', strtotime( sanitize_text_field( $_POST[ $key ] ) ) ) );
614
  }
615
- }
616
-
617
- // Locations
618
- elseif ( '_job_location' === $key ) {
619
- if ( update_post_meta( $post_id, $key, sanitize_text_field( $_POST[ $key ] ) ) ) {
620
- // Location data will be updated by hooked in methods
621
- } elseif ( apply_filters( 'job_manager_geolocation_enabled', true ) && ! WP_Job_Manager_Geocode::has_location_data( $post_id ) ) {
622
  WP_Job_Manager_Geocode::generate_location_data( $post_id, sanitize_text_field( $_POST[ $key ] ) );
623
  }
624
- }
625
-
626
- elseif ( '_job_author' === $key ) {
627
  $wpdb->update( $wpdb->posts, array( 'post_author' => $_POST[ $key ] > 0 ? absint( $_POST[ $key ] ) : 0 ), array( 'ID' => $post_id ) );
628
- }
629
-
630
- elseif ( '_application' === $key ) {
631
  update_post_meta( $post_id, $key, sanitize_text_field( is_email( $_POST[ $key ] ) ? $_POST[ $key ] : urldecode( $_POST[ $key ] ) ) );
632
- }
633
-
634
- // Everything else
635
- else {
636
  $type = ! empty( $field['type'] ) ? $field['type'] : '';
637
 
638
  switch ( $type ) {
639
- case 'textarea' :
640
  update_post_meta( $post_id, $key, wp_kses_post( stripslashes( $_POST[ $key ] ) ) );
641
- break;
642
- case 'checkbox' :
643
  if ( isset( $_POST[ $key ] ) ) {
644
  update_post_meta( $post_id, $key, 1 );
645
  } else {
646
  update_post_meta( $post_id, $key, 0 );
647
  }
648
- break;
649
- default :
650
  if ( ! isset( $_POST[ $key ] ) ) {
651
  continue;
652
  } elseif ( is_array( $_POST[ $key ] ) ) {
@@ -654,18 +731,18 @@ class WP_Job_Manager_Writepanels {
654
  } else {
655
  update_post_meta( $post_id, $key, sanitize_text_field( $_POST[ $key ] ) );
656
  }
657
- break;
658
  }
659
  }
660
  }
661
 
662
  /* Set Post Status To Expired If Already Expired */
663
- $expiry_date = get_post_meta( $post_id, '_job_expires', true );
664
- $today_date = date( 'Y-m-d', current_time( 'timestamp' ) );
665
  $is_job_listing_expired = $expiry_date && $today_date > $expiry_date;
666
- if( $is_job_listing_expired ) {
667
  remove_action( 'job_manager_save_job_listing', array( $this, 'save_job_listing_data' ), 20, 2 );
668
- if ( $this->is_job_listing_being_reactivated() ) {
669
  update_post_meta( $post_id, '_job_expires', calculate_job_expiry( $post_id ) );
670
  } else {
671
  $job_data = array(
@@ -679,15 +756,22 @@ class WP_Job_Manager_Writepanels {
679
  }
680
 
681
  /**
682
- * Checks if the job listing is being reactivated from an expired state.
 
 
 
683
  *
684
- * @return bool True if being reactivated.
685
  */
686
- protected function is_job_listing_being_reactivated() {
687
  return isset( $_POST['post_status'] )
688
  && isset( $_POST['original_post_status'] )
689
- && 'expired' === $_POST['original_post_status']
690
- && 'publish' === $_POST['post_status'];
 
 
 
 
691
  }
692
  }
693
 
1
  <?php
2
+ if ( ! defined( 'ABSPATH' ) ) {
3
+ exit; // Exit if accessed directly.
4
+ }
5
 
6
  /**
7
  * Handles the management of Job Listing meta fields.
53
  $current_user = wp_get_current_user();
54
 
55
  $fields = array(
56
+ '_job_location' => array(
57
+ 'label' => __( 'Location', 'wp-job-manager' ),
58
  'placeholder' => __( 'e.g. "London"', 'wp-job-manager' ),
59
  'description' => __( 'Leave this blank if the location is not important.', 'wp-job-manager' ),
60
+ 'priority' => 1,
61
  ),
62
+ '_application' => array(
63
  'label' => __( 'Application Email or URL', 'wp-job-manager' ),
64
  'placeholder' => __( 'URL or email which applicants use to apply', 'wp-job-manager' ),
65
  'description' => __( 'This field is required for the "application" area to appear beneath the listing.', 'wp-job-manager' ),
66
  'value' => metadata_exists( 'post', $post->ID, '_application' ) ? get_post_meta( $post->ID, '_application', true ) : $current_user->user_email,
67
+ 'priority' => 2,
68
  ),
69
+ '_company_name' => array(
70
  'label' => __( 'Company Name', 'wp-job-manager' ),
71
  'placeholder' => '',
72
+ 'priority' => 3,
73
  ),
74
  '_company_website' => array(
75
  'label' => __( 'Company Website', 'wp-job-manager' ),
76
  'placeholder' => '',
77
+ 'priority' => 4,
78
  ),
79
  '_company_tagline' => array(
80
  'label' => __( 'Company Tagline', 'wp-job-manager' ),
81
  'placeholder' => __( 'Brief description about the company', 'wp-job-manager' ),
82
+ 'priority' => 5,
83
  ),
84
  '_company_twitter' => array(
85
  'label' => __( 'Company Twitter', 'wp-job-manager' ),
86
  'placeholder' => '@yourcompany',
87
+ 'priority' => 6,
88
  ),
89
+ '_company_video' => array(
90
  'label' => __( 'Company Video', 'wp-job-manager' ),
91
  'placeholder' => __( 'URL to the company video', 'wp-job-manager' ),
92
  'type' => 'file',
93
+ 'priority' => 8,
94
  ),
95
+ '_filled' => array(
96
  'label' => __( 'Position Filled', 'wp-job-manager' ),
97
  'type' => 'checkbox',
98
  'priority' => 9,
99
  'description' => __( 'Filled listings will no longer accept applications.', 'wp-job-manager' ),
100
+ ),
101
  );
102
  if ( $current_user->has_cap( 'manage_job_listings' ) ) {
103
+ $fields['_featured'] = array(
104
  'label' => __( 'Featured Listing', 'wp-job-manager' ),
105
  'type' => 'checkbox',
106
  'description' => __( 'Featured listings will be sticky during searches, and can be styled differently.', 'wp-job-manager' ),
107
+ 'priority' => 10,
108
  );
109
+ $job_expires = get_post_meta( $post->ID, '_job_expires', true );
110
  $fields['_job_expires'] = array(
111
  'label' => __( 'Listing Expiry Date', 'wp-job-manager' ),
112
  'priority' => 11,
119
  $fields['_job_author'] = array(
120
  'label' => __( 'Posted by', 'wp-job-manager' ),
121
  'type' => 'author',
122
+ 'priority' => 12,
123
  );
124
  }
125
 
147
  * @return int
148
  */
149
  protected function sort_by_priority( $a, $b ) {
150
+ if ( ! isset( $a['priority'] ) || ! isset( $b['priority'] ) || $a['priority'] === $b['priority'] ) {
151
+ return 0;
152
+ }
153
+ return ( $a['priority'] < $b['priority'] ) ? -1 : 1;
154
  }
155
 
156
  /**
159
  public function add_meta_boxes() {
160
  global $wp_post_types;
161
 
162
+ // translators: Placeholder %s is the singular name for a job listing post type.
163
  add_meta_box( 'job_listing_data', sprintf( __( '%s Data', 'wp-job-manager' ), $wp_post_types['job_listing']->labels->singular_name ), array( $this, 'job_listing_data' ), 'job_listing', 'normal', 'high' );
164
+ if ( ! get_option( 'job_manager_enable_types' ) || 0 === intval( wp_count_terms( 'job_listing_type' ) ) ) {
165
+ remove_meta_box( 'job_listing_typediv', 'job_listing', 'side' );
166
+ } elseif ( false === job_manager_multi_job_type() ) {
167
+ remove_meta_box( 'job_listing_typediv', 'job_listing', 'side' );
168
  $job_listing_type = get_taxonomy( 'job_listing_type' );
169
+ add_meta_box( 'job_listing_type', $job_listing_type->labels->menu_name, array( $this, 'job_listing_metabox' ), 'job_listing', 'side', 'core' );
170
  }
171
  }
172
 
176
  * @param int|WP_Post $post
177
  */
178
  public function job_listing_metabox( $post ) {
179
+ // Set up the taxonomy object and get terms.
180
  $taxonomy = 'job_listing_type';
181
+ $tax = get_taxonomy( $taxonomy );// This is the taxonomy object.
182
 
183
+ // The name of the form.
184
  $name = 'tax_input[' . $taxonomy . ']';
185
 
186
+ // Get all the terms for this taxonomy.
187
+ $terms = get_terms(
188
+ array(
189
+ 'taxonomy' => $taxonomy,
190
+ 'hide_empty' => 0,
191
+ )
192
+ );
193
+ $postterms = get_the_terms( $post->ID, $taxonomy );
194
+ $current = ( $postterms ? array_pop( $postterms ) : false );
195
+ $current = ( $current ? $current->term_id : 0 );
196
+ // Get current and popular terms.
197
+ $popular = get_terms(
198
+ array(
199
+ 'taxonomy' => $taxonomy,
200
+ 'orderby' => 'count',
201
+ 'order' => 'DESC',
202
+ 'number' => 10,
203
+ 'hierarchical' => false,
204
+ )
205
+ );
206
  $postterms = get_the_terms( $post->ID, $taxonomy );
207
+ $current = ( $postterms ? array_pop( $postterms ) : false );
208
+ $current = ( $current ? $current->term_id : 0 );
 
 
 
 
 
209
  ?>
210
 
211
+ <div id="taxonomy-<?php echo esc_attr( $taxonomy ); ?>" class="categorydiv">
212
 
213
  <!-- Display tabs-->
214
+ <ul id="<?php echo esc_attr( $taxonomy ); ?>-tabs" class="category-tabs">
215
+ <li class="tabs"><a href="#<?php echo esc_attr( $taxonomy ); ?>-all" tabindex="3"><?php echo esc_html( $tax->labels->all_items ); ?></a></li>
216
+ <li class="hide-if-no-js"><a href="#<?php echo esc_attr( $taxonomy ); ?>-pop" tabindex="3"><?php esc_html_e( 'Most Used', 'wp-job-manager' ); ?></a></li>
217
  </ul>
218
 
219
  <!-- Display taxonomy terms -->
220
+ <div id="<?php echo esc_attr( $taxonomy ); ?>-all" class="tabs-panel">
221
+ <ul id="<?php echo esc_attr( $taxonomy ); ?>checklist" class="list:<?php echo esc_attr( $taxonomy ); ?> categorychecklist form-no-clear">
222
+ <?php
223
+ foreach ( $terms as $term ) {
224
+ $id = $taxonomy . '-' . $term->term_id;
225
+ echo '<li id="' . esc_attr( $id ) . '"><label class="selectit">';
226
+ echo '<input type="radio" id="in-' . esc_attr( $id ) . ' name="' . esc_attr( $name ) . '" ' . checked( $current, $term->term_id ) . ' value="' . esc_attr( $term->term_id ) . '" />' . esc_attr( $term->name ) . '<br />';
227
+ echo '</label></li>';
228
+ }
229
+ ?>
230
  </ul>
231
  </div>
232
 
233
  <!-- Display popular taxonomy terms -->
234
+ <div id="<?php echo esc_attr( $taxonomy ); ?>-pop" class="tabs-panel" style="display: none;">
235
+ <ul id="<?php echo esc_attr( $taxonomy ); ?>checklist-pop" class="categorychecklist form-no-clear" >
236
+ <?php
237
+ foreach ( $popular as $term ) {
238
+ $id = 'popular-' . $taxonomy . '-' . $term->term_id;
239
+ echo '<li id="' . esc_attr( $id ) . '"><label class="selectit">';
240
+ echo '<input type="radio" id="in-' . esc_attr( $id ) . '" ' . checked( $current, $term->term_id, false ) . ' value="' . esc_attr( $term->term_id ) . '" />' . esc_attr( $term->name ) . '<br />';
241
+ echo '</label></li>';
242
+ }
243
+ ?>
244
  </ul>
245
  </div>
246
 
270
  }
271
  ?>
272
  <p class="form-field">
273
+ <label for="<?php echo esc_attr( $key ); ?>"><?php echo esc_html( wp_strip_all_tags( $field['label'] ) ); ?>:
274
+ <?php if ( ! empty( $field['description'] ) ) : ?>
275
+ <span class="tips" data-tip="<?php echo esc_attr( $field['description'] ); ?>">[?]</span>
276
+ <?php endif; ?>
277
+ </label>
278
  <?php
279
  if ( ! empty( $field['multiple'] ) ) {
280
  foreach ( (array) $field['value'] as $value ) {
281
+ ?>
282
+ <span class="file_url"><input type="text" name="<?php echo esc_attr( $name ); ?>[]" placeholder="<?php echo esc_attr( $field['placeholder'] ); ?>" value="<?php echo esc_attr( $value ); ?>" /><button class="button button-small wp_job_manager_upload_file_button" data-uploader_button_text="<?php esc_attr_e( 'Use file', 'wp-job-manager' ); ?>"><?php esc_html_e( 'Upload', 'wp-job-manager' ); ?></button><button class="button button-small wp_job_manager_view_file_button"><?php esc_html_e( 'View', 'wp-job-manager' ); ?></button></span>
283
+ <?php
284
  }
285
  } else {
286
+ ?>
287
+ <span class="file_url"><input type="text" name="<?php echo esc_attr( $name ); ?>" id="<?php echo esc_attr( $key ); ?>" placeholder="<?php echo esc_attr( $field['placeholder'] ); ?>" value="<?php echo esc_attr( $field['value'] ); ?>" /><button class="button button-small wp_job_manager_upload_file_button" data-uploader_button_text="<?php esc_attr_e( 'Use file', 'wp-job-manager' ); ?>"><?php esc_html_e( 'Upload', 'wp-job-manager' ); ?></button><button class="button button-small wp_job_manager_view_file_button"><?php esc_html_e( 'View', 'wp-job-manager' ); ?></button></span>
288
+ <?php
289
  }
290
  if ( ! empty( $field['multiple'] ) ) {
291
+ ?>
292
+ <button class="button button-small wp_job_manager_add_another_file_button" data-field_name="<?php echo esc_attr( $key ); ?>" data-field_placeholder="<?php echo esc_attr( $field['placeholder'] ); ?>" data-uploader_button_text="<?php esc_attr_e( 'Use file', 'wp-job-manager' ); ?>" data-uploader_button="<?php esc_attr_e( 'Upload', 'wp-job-manager' ); ?>" data-view_button="<?php esc_attr_e( 'View', 'wp-job-manager' ); ?>"><?php esc_html_e( 'Add file', 'wp-job-manager' ); ?></button>
293
+ <?php
294
  }
295
  ?>
296
  </p>
321
  }
322
  ?>
323
  <p class="form-field">
324
+ <label for="<?php echo esc_attr( $key ); ?>"><?php echo esc_html( wp_strip_all_tags( $field['label'] ) ); ?>:
325
+ <?php if ( ! empty( $field['description'] ) ) : ?>
326
+ <span class="tips" data-tip="<?php echo esc_attr( $field['description'] ); ?>">[?]</span>
327
+ <?php endif; ?>
328
+ </label>
329
  <input type="text" autocomplete="off" name="<?php echo esc_attr( $name ); ?>" class="<?php echo esc_attr( $classes ); ?>" id="<?php echo esc_attr( $key ); ?>" placeholder="<?php echo esc_attr( $field['placeholder'] ); ?>" value="<?php echo esc_attr( $field['value'] ); ?>" />
330
  </p>
331
  <?php
367
  } else {
368
  $classes = '';
369
  }
 
370
  if ( 'hidden' === $field['type'] ) {
 
371
  if ( empty( $field['label'] ) ) {
372
+ echo '<input type="hidden" name="' . esc_attr( $name ) . '" class="' . esc_attr( $classes ) . '" id="' . esc_attr( $key ) . '" value="' . esc_attr( $field['value'] ) . '" />';
373
  return;
374
  }
375
  }
376
  ?>
377
  <p class="form-field">
378
+ <label for="<?php echo esc_attr( $key ); ?>"><?php echo esc_html( wp_strip_all_tags( $field['label'] ) ); ?>:
379
+ <?php if ( ! empty( $field['description'] ) ) : ?>
380
+ <span class="tips" data-tip="<?php echo esc_attr( $field['description'] ); ?>">[?]</span>
381
+ <?php endif; ?>
382
+ </label>
383
+ <?php if ( ! empty( $field['information'] ) ) : ?>
384
+ <span class="information"><?php echo wp_kses( $field['information'], array( 'a' => array( 'href' => array() ) ) ); ?></span>
385
+ <?php endif; ?>
386
+ <?php echo '<input type="hidden" name="' . esc_attr( $name ) . '" class="' . esc_attr( $classes ) . '" id="' . esc_attr( $key ) . '" value="' . esc_attr( $field['value'] ) . '" />'; ?>
387
  </p>
388
  <?php
389
  }
407
  }
408
  ?>
409
  <p class="form-field">
410
+ <label for="<?php echo esc_attr( $key ); ?>"><?php echo esc_html( wp_strip_all_tags( $field['label'] ) ); ?>:
411
+ <?php if ( ! empty( $field['description'] ) ) : ?>
412
+ <span class="tips" data-tip="<?php echo esc_attr( $field['description'] ); ?>">[?]</span>
413
+ <?php endif; ?>
414
+ </label>
415
  <textarea name="<?php echo esc_attr( $name ); ?>" id="<?php echo esc_attr( $key ); ?>" placeholder="<?php echo esc_attr( $field['placeholder'] ); ?>"><?php echo esc_html( $field['value'] ); ?></textarea>
416
  </p>
417
  <?php
436
  }
437
  ?>
438
  <p class="form-field">
439
+ <label for="<?php echo esc_attr( $key ); ?>">
440
+ <?php echo esc_html( wp_strip_all_tags( $field['label'] ) ); ?>:
441
+ <?php if ( ! empty( $field['description'] ) ) : ?>
442
+ <span class="tips" data-tip="<?php echo esc_attr( $field['description'] ); ?>">[?]</span>
443
+ <?php endif; ?>
444
+ </label>
445
  <select name="<?php echo esc_attr( $name ); ?>" id="<?php echo esc_attr( $key ); ?>">
446
  <?php foreach ( $field['options'] as $key => $value ) : ?>
447
+ <option
448
+ value="<?php echo esc_attr( $key ); ?>"
449
+ <?php
450
+ if ( isset( $field['value'] ) ) {
451
+ selected( $field['value'], $key );
452
+ }
453
+ ?>
454
+ ><?php echo esc_html( $value ); ?></option>
455
  <?php endforeach; ?>
456
  </select>
457
  </p>
477
  }
478
  ?>
479
  <p class="form-field">
480
+ <label for="<?php echo esc_attr( $key ); ?>"><?php echo esc_html( wp_strip_all_tags( $field['label'] ) ); ?>:
481
+ <?php if ( ! empty( $field['description'] ) ) : ?>
482
+ <span class="tips" data-tip="<?php echo esc_attr( $field['description'] ); ?>">[?]</span>
483
+ <?php endif; ?>
484
+ </label>
485
  <select multiple="multiple" name="<?php echo esc_attr( $name ); ?>[]" id="<?php echo esc_attr( $key ); ?>">
486
  <?php foreach ( $field['options'] as $key => $value ) : ?>
487
+ <option value="<?php echo esc_attr( $key ); ?>"
488
+ <?php
489
+ if ( ! empty( $field['value'] ) && is_array( $field['value'] ) ) {
490
+ // phpcs:ignore WordPress.PHP.StrictInArray
491
+ selected( in_array( $key, $field['value'] ), true );
492
+ }
493
+ ?>
494
+ ><?php echo esc_html( $value ); ?></option>
495
  <?php endforeach; ?>
496
  </select>
497
  </p>
517
  }
518
  ?>
519
  <p class="form-field form-field-checkbox">
520
+ <label for="<?php echo esc_attr( $key ); ?>"><?php echo esc_html( wp_strip_all_tags( $field['label'] ) ); ?></label>
521
  <input type="checkbox" class="checkbox" name="<?php echo esc_attr( $name ); ?>" id="<?php echo esc_attr( $key ); ?>" value="1" <?php checked( $field['value'], 1 ); ?> />
522
+ <?php if ( ! empty( $field['description'] ) ) : ?>
523
+ <span class="description"><?php echo wp_kses_post( $field['description'] ); ?></span>
524
+ <?php endif; ?>
525
  </p>
526
  <?php
527
  }
547
  $name = ! empty( $field['name'] ) ? $field['name'] : $key;
548
  ?>
549
  <p class="form-field form-field-author">
550
+ <label for="<?php echo esc_attr( $key ); ?>"><?php echo esc_html( wp_strip_all_tags( $field['label'] ) ); ?>:</label>
551
  <span class="current-author">
552
  <?php
553
+ if ( $posted_by ) {
554
+ echo '<a href="' . esc_url( admin_url( 'user-edit.php?user_id=' . absint( $author_id ) ) ) . '">#' . absint( $author_id ) . ' &ndash; ' . esc_html( $posted_by->user_login ) . '</a>';
555
+ } else {
556
+ esc_html_e( 'Guest User', 'wp-job-manager' );
557
+ }
558
+ ?>
559
+ <a href="#" class="change-author button button-small"><?php esc_html_e( 'Change', 'wp-job-manager' ); ?></a>
560
  </span>
561
  <span class="hidden change-author">
562
  <input type="number" name="<?php echo esc_attr( $name ); ?>" id="<?php echo esc_attr( $key ); ?>" step="1" value="<?php echo esc_attr( $author_id ); ?>" style="width: 4em;" />
563
+ <span class="description"><?php esc_html_e( 'Enter the ID of the user, or leave blank if submitted by a guest.', 'wp-job-manager' ); ?></span>
564
  </span>
565
  </p>
566
  <?php
585
  }
586
  ?>
587
  <p class="form-field form-field-checkbox">
588
+ <label><?php echo esc_html( wp_strip_all_tags( $field['label'] ) ); ?></label>
589
  <?php foreach ( $field['options'] as $option_key => $value ) : ?>
590
  <label><input type="radio" class="radio" name="<?php echo esc_attr( isset( $field['name'] ) ? $field['name'] : $key ); ?>" value="<?php echo esc_attr( $option_key ); ?>" <?php checked( $field['value'], $option_key ); ?> /> <?php echo esc_html( $value ); ?></label>
591
  <?php endforeach; ?>
592
+ <?php if ( ! empty( $field['description'] ) ) : ?>
593
+ <span class="description"><?php echo wp_kses_post( $field['description'] ); ?></span>
594
+ <?php endif; ?>
595
  </p>
596
  <?php
597
  }
625
  $user_edited_date = get_post_meta( $post->ID, '_job_edited', true );
626
  if ( $user_edited_date ) {
627
  echo '<p class="form-field">';
628
+ // translators: %1$s is placeholder for singular name of the job listing post type; %2$s is the intl formatted date the listing was last modified.
629
+ echo '<em>' . sprintf( esc_html__( '%1$s was last modified by the user on %2$s.', 'wp-job-manager' ), esc_html( $wp_post_types['job_listing']->labels->singular_name ), esc_html( date_i18n( get_option( 'date_format' ), $user_edited_date ) ) ) . '</em>';
630
  echo '</p>';
631
  }
632
 
642
  * @param WP_Post $post
643
  */
644
  public function save_post( $post_id, $post ) {
645
+ if ( empty( $post_id ) || empty( $post ) || empty( $_POST ) ) {
646
+ return;
647
+ }
648
+ if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
649
+ return;
650
+ }
651
+ if ( is_int( wp_is_post_revision( $post ) ) ) {
652
+ return;
653
+ }
654
+ if ( is_int( wp_is_post_autosave( $post ) ) ) {
655
+ return;
656
+ }
657
+ if ( empty( $_POST['job_manager_nonce'] ) || ! wp_verify_nonce( $_POST['job_manager_nonce'], 'save_meta_data' ) ) {
658
+ return;
659
+ }
660
+ if ( ! current_user_can( 'edit_post', $post_id ) ) {
661
+ return;
662
+ }
663
+ if ( 'job_listing' !== $post->post_type ) {
664
+ return;
665
+ }
666
 
667
  do_action( 'job_manager_save_job_listing', $post_id, $post );
668
  }
671
  * Handles the actual saving of job listing data fields.
672
  *
673
  * @param int $post_id
674
+ * @param WP_Post $post (Unused).
675
  */
676
  public function save_job_listing_data( $post_id, $post ) {
677
  global $wpdb;
678
 
679
+ // These need to exist.
680
  add_post_meta( $post_id, '_filled', 0, true );
681
  add_post_meta( $post_id, '_featured', 0, true );
682
 
683
+ // Save fields.
684
  foreach ( $this->job_listing_fields() as $key => $field ) {
685
  if ( isset( $field['type'] ) && 'info' === $field['type'] ) {
686
  continue;
687
  }
688
 
689
+ // Expirey date.
690
  if ( '_job_expires' === $key ) {
691
  if ( empty( $_POST[ $key ] ) ) {
692
  if ( get_option( 'job_manager_submission_duration' ) ) {
697
  } else {
698
  update_post_meta( $post_id, $key, date( 'Y-m-d', strtotime( sanitize_text_field( $_POST[ $key ] ) ) ) );
699
  }
700
+ } elseif ( '_job_location' === $key ) {
701
+ // Locations.
702
+ $updated_result = update_post_meta( $post_id, $key, sanitize_text_field( $_POST[ $key ] ) );
703
+ if ( ! $updated_result && apply_filters( 'job_manager_geolocation_enabled', true ) && ! WP_Job_Manager_Geocode::has_location_data( $post_id ) ) {
704
+ // First time generation for job location data.
 
 
705
  WP_Job_Manager_Geocode::generate_location_data( $post_id, sanitize_text_field( $_POST[ $key ] ) );
706
  }
707
+ } elseif ( '_job_author' === $key ) {
 
 
708
  $wpdb->update( $wpdb->posts, array( 'post_author' => $_POST[ $key ] > 0 ? absint( $_POST[ $key ] ) : 0 ), array( 'ID' => $post_id ) );
709
+ } elseif ( '_application' === $key ) {
 
 
710
  update_post_meta( $post_id, $key, sanitize_text_field( is_email( $_POST[ $key ] ) ? $_POST[ $key ] : urldecode( $_POST[ $key ] ) ) );
711
+ } else {
712
+ // Everything else.
 
 
713
  $type = ! empty( $field['type'] ) ? $field['type'] : '';
714
 
715
  switch ( $type ) {
716
+ case 'textarea':
717
  update_post_meta( $post_id, $key, wp_kses_post( stripslashes( $_POST[ $key ] ) ) );
718
+ break;
719
+ case 'checkbox':
720
  if ( isset( $_POST[ $key ] ) ) {
721
  update_post_meta( $post_id, $key, 1 );
722
  } else {
723
  update_post_meta( $post_id, $key, 0 );
724
  }
725
+ break;
726
+ default:
727
  if ( ! isset( $_POST[ $key ] ) ) {
728
  continue;
729
  } elseif ( is_array( $_POST[ $key ] ) ) {
731
  } else {
732
  update_post_meta( $post_id, $key, sanitize_text_field( $_POST[ $key ] ) );
733
  }
734
+ break;
735
  }
736
  }
737
  }
738
 
739
  /* Set Post Status To Expired If Already Expired */
740
+ $expiry_date = get_post_meta( $post_id, '_job_expires', true );
741
+ $today_date = date( 'Y-m-d', current_time( 'timestamp' ) );
742
  $is_job_listing_expired = $expiry_date && $today_date > $expiry_date;
743
+ if ( $is_job_listing_expired && ! $this->is_job_listing_status_changing( null, 'draft' ) ) {
744
  remove_action( 'job_manager_save_job_listing', array( $this, 'save_job_listing_data' ), 20, 2 );
745
+ if ( $this->is_job_listing_status_changing( 'expired', 'publish' ) ) {
746
  update_post_meta( $post_id, '_job_expires', calculate_job_expiry( $post_id ) );
747
  } else {
748
  $job_data = array(
756
  }
757
 
758
  /**
759
+ * Checks if the job listing status is being changed from $from_status to $to_status.
760
+ *
761
+ * @param string|null $from_status Status to test if it is changing from. NULL if anything.
762
+ * @param string $to_status Status to test if it is changing to.
763
  *
764
+ * @return bool True if status is changing from $from_status to $to_status.
765
  */
766
+ private function is_job_listing_status_changing( $from_status, $to_status ) {
767
  return isset( $_POST['post_status'] )
768
  && isset( $_POST['original_post_status'] )
769
+ && $_POST['original_post_status'] !== $_POST['post_status']
770
+ && (
771
+ null === $from_status
772
+ || $from_status === $_POST['original_post_status']
773
+ )
774
+ && $to_status === $_POST['post_status'];
775
  }
776
  }
777
 
includes/admin/views/html-admin-page-addons.php CHANGED
@@ -1,5 +1,5 @@
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 ) ) {
@@ -7,18 +7,18 @@ if ( ! empty( $messages ) ) {
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 ) ) {
@@ -28,7 +28,7 @@ if ( ! empty( $categories ) ) {
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>
@@ -40,16 +40,18 @@ if ( ! empty( $categories ) ) {
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' ) ); ?>">
1
  <?php
2
+ echo '<h1 class="screen-reader-text">' . esc_html__( 'WP Job Manager Add-ons', 'wp-job-manager' ) . '</h1>';
3
  if ( ! empty( $messages ) ) {
4
  foreach ( $messages as $message ) {
5
  if ( empty( $message->message ) ) {
7
  }
8
  $type = 'info';
9
  if ( isset( $message->type )
10
+ && in_array( $message->type, array( 'info', 'success', 'warning', 'error' ), true ) ) {
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="' . esc_url( $action_url ) . '" target="' . esc_attr( $action_target ) . '" class="button">' . esc_html( $action_label ) . '</a>';
19
  }
20
 
21
+ echo '<div class="notice notice-' . esc_attr( $type ) . ' below-h2"><p><strong>' . esc_html( $message->message ) . '</strong>' . wp_kses_post( $action_str ) . '</p></div>';
22
  }
23
  }
24
  if ( ! empty( $categories ) ) {
28
  ?>
29
  <li>
30
  <a class="<?php echo $current_category === $category->slug ? 'current' : ''; ?>"
31
+ href="<?php echo esc_url( 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>
40
  echo '<br class="clear" />';
41
 
42
  if ( empty( $add_ons ) ) {
43
+ echo '<div class="notice notice-warning below-h2"><p><strong>' . esc_html__( '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(
48
+ array(
49
+ 'utm_source' => 'product',
50
+ 'utm_medium' => 'addonpage',
51
+ 'utm_campaign' => 'wpjmplugin',
52
+ 'utm_content' => 'listing',
53
+ ), $add_on->link
54
+ );
55
  ?>
56
  <li class="product">
57
  <a href="<?php echo esc_url( $url, array( 'http', 'https' ) ); ?>">
includes/class-wp-job-manager-ajax.php CHANGED
@@ -1,7 +1,7 @@
1
  <?php
2
 
3
  if ( ! defined( 'ABSPATH' ) ) {
4
- exit; // Exit if accessed directly
5
  }
6
 
7
  /**
@@ -41,11 +41,11 @@ class WP_Job_Manager_Ajax {
41
  add_action( 'init', array( __CLASS__, 'add_endpoint' ) );
42
  add_action( 'template_redirect', array( __CLASS__, 'do_jm_ajax' ), 0 );
43
 
44
- // JM Ajax endpoints
45
  add_action( 'job_manager_ajax_get_listings', array( $this, 'get_listings' ) );
46
  add_action( 'job_manager_ajax_upload_file', array( $this, 'upload_file' ) );
47
 
48
- // BW compatible handlers
49
  add_action( 'wp_ajax_nopriv_job_manager_get_listings', array( $this, 'get_listings' ) );
50
  add_action( 'wp_ajax_job_manager_get_listings', array( $this, 'get_listings' ) );
51
  add_action( 'wp_ajax_nopriv_job_manager_upload_file', array( $this, 'upload_file' ) );
@@ -64,8 +64,8 @@ class WP_Job_Manager_Ajax {
64
  /**
65
  * Gets Job Manager's Ajax Endpoint.
66
  *
67
- * @param string $request Optional
68
- * @param string $ssl (Unused) Optional
69
  * @return string
70
  */
71
  public static function get_endpoint( $request = '%%endpoint%%', $ssl = null ) {
@@ -89,12 +89,13 @@ class WP_Job_Manager_Ajax {
89
  $wp_query->set( 'jm-ajax', sanitize_text_field( $_GET['jm-ajax'] ) );
90
  }
91
 
92
- if ( $action = $wp_query->get( 'jm-ajax' ) ) {
 
93
  if ( ! defined( 'DOING_AJAX' ) ) {
94
  define( 'DOING_AJAX', true );
95
  }
96
 
97
- // Not home - this is an ajax endpoint
98
  $wp_query->is_home = false;
99
 
100
  /**
@@ -131,23 +132,23 @@ class WP_Job_Manager_Ajax {
131
  }
132
 
133
  $args = array(
134
- 'search_location' => $search_location,
135
- 'search_keywords' => $search_keywords,
136
- 'search_categories' => $search_categories,
137
- 'job_types' => is_null( $filter_job_types ) || sizeof( $types ) === sizeof( $filter_job_types ) ? '' : $filter_job_types + array( 0 ),
138
- 'post_status' => $filter_post_status,
139
- 'orderby' => $orderby,
140
- 'order' => sanitize_text_field( $_REQUEST['order'] ),
141
- 'offset' => ( absint( $_REQUEST['page'] ) - 1 ) * absint( $_REQUEST['per_page'] ),
142
- 'posts_per_page' => absint( $_REQUEST['per_page'] ),
143
  );
144
 
145
- if ( isset( $_REQUEST['filled'] ) && ( $_REQUEST['filled'] === 'true' || $_REQUEST['filled'] === 'false' ) ) {
146
- $args['filled'] = $_REQUEST['filled'] === 'true' ? true : false;
147
  }
148
 
149
- if ( isset( $_REQUEST['featured'] ) && ( $_REQUEST['featured'] === 'true' || $_REQUEST['featured'] === 'false' ) ) {
150
- $args['featured'] = $_REQUEST['featured'] === 'true' ? true : false;
151
  $args['orderby'] = 'featured' === $orderby ? 'date' : $orderby;
152
  }
153
 
@@ -156,18 +157,19 @@ class WP_Job_Manager_Ajax {
156
  *
157
  * @since 1.0.0
158
  *
159
- * @param array $args Arguments used for generating Job Listing query (see `get_job_listings()`)
160
  */
161
  $jobs = get_job_listings( apply_filters( 'job_manager_get_listings_args', $args ) );
162
 
163
  $result = array(
164
- 'found_jobs' => $jobs->have_posts(),
165
- 'showing' => '',
166
  'max_num_pages' => $jobs->max_num_pages,
167
  );
168
 
169
  if ( $jobs->post_count && ( $search_location || $search_keywords || $search_categories ) ) {
170
- $message = sprintf( _n( 'Search completed. Found %d matching record.', 'Search completed. Found %d matching records.', $jobs->found_posts, 'wp-job-manager' ), $jobs->found_posts );
 
171
  $result['showing_all'] = true;
172
  } else {
173
  $message = '';
@@ -195,13 +197,15 @@ class WP_Job_Manager_Ajax {
195
  */
196
  $result['showing'] = apply_filters( 'job_manager_get_listings_custom_filter_text', $message, $search_values );
197
 
198
- // Generate RSS link
199
- $result['showing_links'] = job_manager_get_filtered_links( array(
200
- 'filter_job_types' => $filter_job_types,
201
- 'search_location' => $search_location,
202
- 'search_categories' => $search_categories,
203
- 'search_keywords' => $search_keywords,
204
- ) );
 
 
205
 
206
  /**
207
  * Send back a response to the AJAX request without creating HTML.
@@ -234,24 +238,19 @@ class WP_Job_Manager_Ajax {
234
 
235
  ob_start();
236
 
237
- if ( $result['found_jobs'] ) : ?>
238
-
239
- <?php while ( $jobs->have_posts() ) : $jobs->the_post(); ?>
240
-
241
- <?php get_job_manager_template_part( 'content', 'job_listing' ); ?>
242
-
243
- <?php endwhile; ?>
244
-
245
- <?php else : ?>
246
-
247
- <?php get_job_manager_template_part( 'content', 'no-jobs-found' ); ?>
248
-
249
- <?php endif;
250
 
251
  $result['html'] = ob_get_clean();
252
 
253
- // Generate pagination
254
- if ( isset( $_REQUEST['show_pagination'] ) && $_REQUEST['show_pagination'] === 'true' ) {
255
  $result['pagination'] = get_job_listing_pagination( $jobs->max_num_pages, absint( $_REQUEST['page'] ) );
256
  }
257
 
@@ -277,9 +276,12 @@ class WP_Job_Manager_Ajax {
277
  foreach ( $_FILES as $file_key => $file ) {
278
  $files_to_upload = job_manager_prepare_uploaded_files( $file );
279
  foreach ( $files_to_upload as $file_to_upload ) {
280
- $uploaded_file = job_manager_upload_file( $file_to_upload, array(
281
- 'file_key' => $file_key,
282
- ) );
 
 
 
283
 
284
  if ( is_wp_error( $uploaded_file ) ) {
285
  $data['files'][] = array(
1
  <?php
2
 
3
  if ( ! defined( 'ABSPATH' ) ) {
4
+ exit; // Exit if accessed directly.
5
  }
6
 
7
  /**
41
  add_action( 'init', array( __CLASS__, 'add_endpoint' ) );
42
  add_action( 'template_redirect', array( __CLASS__, 'do_jm_ajax' ), 0 );
43
 
44
+ // JM Ajax endpoints.
45
  add_action( 'job_manager_ajax_get_listings', array( $this, 'get_listings' ) );
46
  add_action( 'job_manager_ajax_upload_file', array( $this, 'upload_file' ) );
47
 
48
+ // BW compatible handlers.
49
  add_action( 'wp_ajax_nopriv_job_manager_get_listings', array( $this, 'get_listings' ) );
50
  add_action( 'wp_ajax_job_manager_get_listings', array( $this, 'get_listings' ) );
51
  add_action( 'wp_ajax_nopriv_job_manager_upload_file', array( $this, 'upload_file' ) );
64
  /**
65
  * Gets Job Manager's Ajax Endpoint.
66
  *
67
+ * @param string $request Optional.
68
+ * @param string $ssl (Unused) Optional.
69
  * @return string
70
  */
71
  public static function get_endpoint( $request = '%%endpoint%%', $ssl = null ) {
89
  $wp_query->set( 'jm-ajax', sanitize_text_field( $_GET['jm-ajax'] ) );
90
  }
91
 
92
+ $action = $wp_query->get( 'jm-ajax' );
93
+ if ( $action ) {
94
  if ( ! defined( 'DOING_AJAX' ) ) {
95
  define( 'DOING_AJAX', true );
96
  }
97
 
98
+ // Not home - this is an ajax endpoint.
99
  $wp_query->is_home = false;
100
 
101
  /**
132
  }
133
 
134
  $args = array(
135
+ 'search_location' => $search_location,
136
+ 'search_keywords' => $search_keywords,
137
+ 'search_categories' => $search_categories,
138
+ 'job_types' => is_null( $filter_job_types ) || count( $types ) === count( $filter_job_types ) ? '' : $filter_job_types + array( 0 ),
139
+ 'post_status' => $filter_post_status,
140
+ 'orderby' => $orderby,
141
+ 'order' => sanitize_text_field( $_REQUEST['order'] ),
142
+ 'offset' => ( absint( $_REQUEST['page'] ) - 1 ) * absint( $_REQUEST['per_page'] ),
143
+ 'posts_per_page' => max( 1, absint( $_REQUEST['per_page'] ) ),
144
  );
145
 
146
+ if ( isset( $_REQUEST['filled'] ) && ( 'true' === $_REQUEST['filled'] || 'false' === $_REQUEST['filled'] ) ) {
147
+ $args['filled'] = 'true' === $_REQUEST['filled'];
148
  }
149
 
150
+ if ( isset( $_REQUEST['featured'] ) && ( 'true' === $_REQUEST['featured'] || 'false' === $_REQUEST['featured'] ) ) {
151
+ $args['featured'] = 'true' === $_REQUEST['featured'];
152
  $args['orderby'] = 'featured' === $orderby ? 'date' : $orderby;
153
  }
154
 
157
  *
158
  * @since 1.0.0
159
  *
160
+ * @param array $args Arguments used for generating Job Listing query (see `get_job_listings()`).
161
  */
162
  $jobs = get_job_listings( apply_filters( 'job_manager_get_listings_args', $args ) );
163
 
164
  $result = array(
165
+ 'found_jobs' => $jobs->have_posts(),
166
+ 'showing' => '',
167
  'max_num_pages' => $jobs->max_num_pages,
168
  );
169
 
170
  if ( $jobs->post_count && ( $search_location || $search_keywords || $search_categories ) ) {
171
+ // translators: Placeholder %d is the number of found search results.
172
+ $message = sprintf( _n( 'Search completed. Found %d matching record.', 'Search completed. Found %d matching records.', $jobs->found_posts, 'wp-job-manager' ), $jobs->found_posts );
173
  $result['showing_all'] = true;
174
  } else {
175
  $message = '';
197
  */
198
  $result['showing'] = apply_filters( 'job_manager_get_listings_custom_filter_text', $message, $search_values );
199
 
200
+ // Generate RSS link.
201
+ $result['showing_links'] = job_manager_get_filtered_links(
202
+ array(
203
+ 'filter_job_types' => $filter_job_types,
204
+ 'search_location' => $search_location,
205
+ 'search_categories' => $search_categories,
206
+ 'search_keywords' => $search_keywords,
207
+ )
208
+ );
209
 
210
  /**
211
  * Send back a response to the AJAX request without creating HTML.
238
 
239
  ob_start();
240
 
241
+ if ( $result['found_jobs'] ) {
242
+ while ( $jobs->have_posts() ) {
243
+ $jobs->the_post();
244
+ get_job_manager_template_part( 'content', 'job_listing' );
245
+ }
246
+ } else {
247
+ get_job_manager_template_part( 'content', 'no-jobs-found' );
248
+ }
 
 
 
 
 
249
 
250
  $result['html'] = ob_get_clean();
251
 
252
+ // Generate pagination.
253
+ if ( isset( $_REQUEST['show_pagination'] ) && 'true' === $_REQUEST['show_pagination'] ) {
254
  $result['pagination'] = get_job_listing_pagination( $jobs->max_num_pages, absint( $_REQUEST['page'] ) );
255
  }
256
 
276
  foreach ( $_FILES as $file_key => $file ) {
277
  $files_to_upload = job_manager_prepare_uploaded_files( $file );
278
  foreach ( $files_to_upload as $file_to_upload ) {
279
+ $uploaded_file = job_manager_upload_file(
280
+ $file_to_upload,
281
+ array(
282
+ 'file_key' => $file_key,
283
+ )
284
+ );
285
 
286
  if ( is_wp_error( $uploaded_file ) ) {
287
  $data['files'][] = array(
includes/class-wp-job-manager-api.php CHANGED
@@ -1,7 +1,7 @@
1
  <?php
2
 
3
  if ( ! defined( 'ABSPATH' ) ) {
4
- exit; // Exit if accessed directly
5
  }
6
 
7
  /**
@@ -45,7 +45,7 @@ class WP_Job_Manager_API {
45
  /**
46
  * Adds query vars used in API calls.
47
  *
48
- * @param array $vars the query vars
49
  * @return array
50
  */
51
  public function add_query_vars( $vars ) {
@@ -71,13 +71,13 @@ class WP_Job_Manager_API {
71
  }
72
 
73
  if ( ! empty( $wp->query_vars['job-manager-api'] ) ) {
74
- // Buffer, we won't want any output here
75
  ob_start();
76
 
77
- // Get API trigger
78
  $api = strtolower( esc_attr( $wp->query_vars['job-manager-api'] ) );
79
 
80
- // Load class if exists
81
  if ( has_action( 'job_manager_api_' . $api ) && class_exists( $api ) ) {
82
  $api_class = new $api();
83
  }
@@ -90,7 +90,7 @@ class WP_Job_Manager_API {
90
  */
91
  do_action( 'job_manager_api_' . $api );
92
 
93
- // Done, clear buffer and exit
94
  ob_end_clean();
95
  wp_die();
96
  }
1
  <?php
2
 
3
  if ( ! defined( 'ABSPATH' ) ) {
4
+ exit; // Exit if accessed directly.
5
  }
6
 
7
  /**
45
  /**
46
  * Adds query vars used in API calls.
47
  *
48
+ * @param array $vars the query vars.
49
  * @return array
50
  */
51
  public function add_query_vars( $vars ) {
71
  }
72
 
73
  if ( ! empty( $wp->query_vars['job-manager-api'] ) ) {
74
+ // Buffer, we won't want any output here.
75
  ob_start();
76
 
77
+ // Get API trigger.
78
  $api = strtolower( esc_attr( $wp->query_vars['job-manager-api'] ) );
79
 
80
+ // Load class if exists.
81
  if ( has_action( 'job_manager_api_' . $api ) && class_exists( $api ) ) {
82
  $api_class = new $api();
83
  }
90
  */
91
  do_action( 'job_manager_api_' . $api );
92
 
93
+ // Done, clear buffer and exit.
94
  ob_end_clean();
95
  wp_die();
96
  }
includes/class-wp-job-manager-cache-helper.php CHANGED
@@ -111,7 +111,7 @@ class WP_Job_Manager_Cache_Helper {
111
  private static function delete_version_transients( $version ) {
112
  if ( ! wp_using_ext_object_cache() && ! empty( $version ) ) {
113
  global $wpdb;
114
- $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->options} WHERE option_name LIKE %s;", "\_transient\_%" . $version ) );
115
  }
116
  }
117
 
@@ -122,13 +122,16 @@ class WP_Job_Manager_Cache_Helper {
122
  global $wpdb;
123
 
124
  if ( ! wp_using_ext_object_cache() && ! defined( 'WP_SETUP_CONFIG' ) && ! defined( 'WP_INSTALLING' ) ) {
125
- $sql = "
126
  DELETE a, b FROM $wpdb->options a, $wpdb->options b
127
  WHERE a.option_name LIKE %s
128
  AND a.option_name NOT LIKE %s
129
  AND b.option_name = CONCAT( '_transient_timeout_', SUBSTRING( a.option_name, 12 ) )
130
- AND b.option_value < %s;";
131
- $wpdb->query( $wpdb->prepare( $sql, $wpdb->esc_like( '_transient_jm_' ) . '%', $wpdb->esc_like( '_transient_timeout_jm_' ) . '%', time() ) );
 
 
 
132
  }
133
  }
134
 
@@ -159,8 +162,8 @@ class WP_Job_Manager_Cache_Helper {
159
  */
160
  $post_types = apply_filters( 'wpjm_count_cache_supported_post_types', array( 'job_listing' ), $new_status, $old_status, $post );
161
 
162
- // Only proceed when statuses do not match, and post type is supported post type
163
- if ( $new_status === $old_status || ! in_array( $post->post_type, $post_types ) ) {
164
  return;
165
  }
166
 
@@ -177,12 +180,12 @@ class WP_Job_Manager_Cache_Helper {
177
  $valid_statuses = apply_filters( 'wpjm_count_cache_supported_statuses', array( 'pending' ), $new_status, $old_status, $post );
178
 
179
  $rlike = array();
180
- // New status transient option name
181
- if( in_array( $new_status, $valid_statuses ) ){
182
  $rlike[] = "^_transient_jm_{$new_status}_{$post->post_type}_count_user_";
183
  }
184
- // Old status transient option name
185
- if( in_array( $old_status, $valid_statuses ) ){
186
  $rlike[] = "^_transient_jm_{$old_status}_{$post->post_type}_count_user_";
187
  }
188
 
@@ -190,8 +193,10 @@ class WP_Job_Manager_Cache_Helper {
190
  return;
191
  }
192
 
193
- $sql = $wpdb->prepare( "SELECT option_name FROM $wpdb->options WHERE option_name RLIKE '%s'", implode('|', $rlike ) );
194
- $transients = $wpdb->get_col( $sql );
 
 
195
 
196
  // For each transient...
197
  foreach ( $transients as $transient ) {
@@ -201,7 +206,7 @@ class WP_Job_Manager_Cache_Helper {
201
  delete_transient( $key );
202
  }
203
 
204
- // Sometimes transients are not in the DB, so we have to do this too:
205
  wp_cache_flush();
206
  }
207
 
@@ -212,23 +217,24 @@ class WP_Job_Manager_Cache_Helper {
212
  *
213
  * @param string $post_type
214
  * @param string $status
215
- * @param bool $force Force update cache
216
  *
217
  * @return int
218
  */
219
  public static function get_listings_count( $post_type = 'job_listing', $status = 'pending', $force = false ) {
220
 
221
- // Get user based cache transient
222
  $user_id = get_current_user_id();
223
  $transient = "jm_{$status}_{$post_type}_count_user_{$user_id}";
224
 
225
- // Set listings_count value from cache if exists, otherwise set to 0 as default
226
- $status_count = ( $cached_count = get_transient( $transient ) ) ? $cached_count : 0;
 
227
 
228
- // $cached_count will be false if transient does not exist
229
- if ( $cached_count === false || $force ) {
230
  $count_posts = wp_count_posts( $post_type, 'readable' );
231
- // Default to 0 $status if object does not have a value
232
  $status_count = isset( $count_posts->$status ) ? $count_posts->$status : 0;
233
  set_transient( $transient, $status_count, DAY_IN_SECONDS * 7 );
234
  }
111
  private static function delete_version_transients( $version ) {
112
  if ( ! wp_using_ext_object_cache() && ! empty( $version ) ) {
113
  global $wpdb;
114
+ $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->options} WHERE option_name LIKE %s;", '\_transient\_%' . $version ) );
115
  }
116
  }
117
 
122
  global $wpdb;
123
 
124
  if ( ! wp_using_ext_object_cache() && ! defined( 'WP_SETUP_CONFIG' ) && ! defined( 'WP_INSTALLING' ) ) {
125
+ $wpdb->query( $wpdb->prepare( "
126
  DELETE a, b FROM $wpdb->options a, $wpdb->options b
127
  WHERE a.option_name LIKE %s
128
  AND a.option_name NOT LIKE %s
129
  AND b.option_name = CONCAT( '_transient_timeout_', SUBSTRING( a.option_name, 12 ) )
130
+ AND b.option_value < %s;",
131
+ $wpdb->esc_like( '_transient_jm_' ) . '%',
132
+ $wpdb->esc_like( '_transient_timeout_jm_' ) . '%',
133
+ time()
134
+ ) );
135
  }
136
  }
137
 
162
  */
163
  $post_types = apply_filters( 'wpjm_count_cache_supported_post_types', array( 'job_listing' ), $new_status, $old_status, $post );
164
 
165
+ // Only proceed when statuses do not match, and post type is supported post type.
166
+ if ( $new_status === $old_status || ! in_array( $post->post_type, $post_types, true ) ) {
167
  return;
168
  }
169
 
180
  $valid_statuses = apply_filters( 'wpjm_count_cache_supported_statuses', array( 'pending' ), $new_status, $old_status, $post );
181
 
182
  $rlike = array();
183
+ // New status transient option name.
184
+ if ( in_array( $new_status, $valid_statuses, true ) ) {
185
  $rlike[] = "^_transient_jm_{$new_status}_{$post->post_type}_count_user_";
186
  }
187
+ // Old status transient option name.
188
+ if ( in_array( $old_status, $valid_statuses, true ) ) {
189
  $rlike[] = "^_transient_jm_{$old_status}_{$post->post_type}_count_user_";
190
  }
191
 
193
  return;
194
  }
195
 
196
+ $transients = $wpdb->get_col( $wpdb->prepare(
197
+ "SELECT option_name FROM $wpdb->options WHERE option_name RLIKE %s",
198
+ implode( '|', $rlike )
199
+ ) );
200
 
201
  // For each transient...
202
  foreach ( $transients as $transient ) {
206
  delete_transient( $key );
207
  }
208
 
209
+ // Sometimes transients are not in the DB, so we have to do this too:.
210
  wp_cache_flush();
211
  }
212
 
217
  *
218
  * @param string $post_type
219
  * @param string $status
220
+ * @param bool $force Force update cache.
221
  *
222
  * @return int
223
  */
224
  public static function get_listings_count( $post_type = 'job_listing', $status = 'pending', $force = false ) {
225
 
226
+ // Get user based cache transient.
227
  $user_id = get_current_user_id();
228
  $transient = "jm_{$status}_{$post_type}_count_user_{$user_id}";
229
 
230
+ // Set listings_count value from cache if exists, otherwise set to 0 as default.
231
+ $cached_count = get_transient( $transient );
232
+ $status_count = $cached_count ? $cached_count : 0;
233
 
234
+ // $cached_count will be false if transient does not exist.
235
+ if ( false === $cached_count || $force ) {
236
  $count_posts = wp_count_posts( $post_type, 'readable' );
237
+ // Default to 0 $status if object does not have a value.
238
  $status_count = isset( $count_posts->$status ) ? $count_posts->$status : 0;
239
  set_transient( $transient, $status_count, DAY_IN_SECONDS * 7 );
240
  }
includes/class-wp-job-manager-category-walker.php CHANGED
@@ -1,5 +1,7 @@
1
  <?php
2
- if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
 
 
3
 
4
  /**
5
  * Walks through categories.
@@ -22,9 +24,15 @@ class WP_Job_Manager_Category_Walker extends Walker {
22
  *
23
  * @var array
24
  */
25
- public $db_fields = array ('parent' => 'parent', 'id' => 'term_id', 'slug' => 'slug' );
 
 
 
 
26
 
27
  /**
 
 
28
  * @see Walker::start_el()
29
  * @since 2.1.0
30
  *
@@ -36,26 +44,32 @@ class WP_Job_Manager_Category_Walker extends Walker {
36
  */
37
  public function start_el( &$output, $object, $depth = 0, $args = array(), $current_object_id = 0 ) {
38
 
39
- if ( ! empty( $args['hierarchical'] ) )
40
- $pad = str_repeat('&nbsp;', $depth * 3);
41
- else
42
  $pad = '';
 
43
 
44
  $cat_name = apply_filters( 'list_product_cats', $object->name, $object );
45
 
46
- $value = isset( $args['value'] ) && $args['value'] == 'id' ? $object->term_id : $object->slug;
47
 
48
- $output .= "\t<option class=\"level-$depth\" value=\"" . $value . "\"";
49
 
50
- if ( isset( $args['selected'] ) && ( $value == $args['selected'] || ( is_array( $args['selected'] ) && in_array( $value, $args['selected'] ) ) ) )
 
 
 
 
51
  $output .= ' selected="selected"';
 
52
 
53
  $output .= '>';
54
 
55
- $output .= $pad . $cat_name;
56
 
57
  if ( ! empty( $args['show_count'] ) ) {
58
- $output .= '&nbsp;(' . $object->count . ')';
59
  }
60
 
61
  $output .= "</option>\n";
1
  <?php
2
+ if ( ! defined( 'ABSPATH' ) ) {
3
+ exit; // Exit if accessed directly.
4
+ }
5
 
6
  /**
7
  * Walks through categories.
24
  *
25
  * @var array
26
  */
27
+ public $db_fields = array(
28
+ 'parent' => 'parent',
29
+ 'id' => 'term_id',
30
+ 'slug' => 'slug',
31
+ );
32
 
33
  /**
34
+ * Start the list walker.
35
+ *
36
  * @see Walker::start_el()
37
  * @since 2.1.0
38
  *
44
  */
45
  public function start_el( &$output, $object, $depth = 0, $args = array(), $current_object_id = 0 ) {
46
 
47
+ if ( ! empty( $args['hierarchical'] ) ) {
48
+ $pad = str_repeat( '&nbsp;', $depth * 3 );
49
+ } else {
50
  $pad = '';
51
+ }
52
 
53
  $cat_name = apply_filters( 'list_product_cats', $object->name, $object );
54
 
55
+ $value = isset( $args['value'] ) && 'id' === $args['value'] ? $object->term_id : $object->slug;
56
 
57
+ $output .= "\t<option class=\"level-" . intval( $depth ) . '" value="' . esc_attr( $value ) . '"';
58
 
59
+ if ( isset( $args['selected'] ) && (
60
+ $value == $args['selected'] // phpcs:ignore WordPress.PHP.StrictComparisons
61
+ || ( is_array( $args['selected'] ) && in_array( $value, $args['selected'] ) ) // phpcs:ignore WordPress.PHP.StrictInArray
62
+ )
63
+ ) {
64
  $output .= ' selected="selected"';
65
+ }
66
 
67
  $output .= '>';
68
 
69
+ $output .= $pad . esc_html( $cat_name );
70
 
71
  if ( ! empty( $args['show_count'] ) ) {
72
+ $output .= '&nbsp;(' . intval( $object->count ) . ')';
73
  }
74
 
75
  $output .= "</option>\n";
includes/class-wp-job-manager-data-cleaner.php CHANGED
@@ -191,12 +191,14 @@ class WP_Job_Manager_Data_Cleaner {
191
  */
192
  private static function cleanup_custom_post_types() {
193
  foreach ( self::$custom_post_types as $post_type ) {
194
- $items = get_posts( array(
195
- 'post_type' => $post_type,
196
- 'post_status' => 'any',
197
- 'numberposts' => -1,
198
- 'fields' => 'ids',
199
- ) );
 
 
200
 
201
  foreach ( $items as $item ) {
202
  wp_trash_post( $item );
191
  */
192
  private static function cleanup_custom_post_types() {
193
  foreach ( self::$custom_post_types as $post_type ) {
194
+ $items = get_posts(
195
+ array(
196
+ 'post_type' => $post_type,
197
+ 'post_status' => 'any',
198
+ 'numberposts' => -1,
199
+ 'fields' => 'ids',
200
+ )
201
+ );
202
 
203
  foreach ( $items as $item ) {
204
  wp_trash_post( $item );
includes/class-wp-job-manager-data-exporter.php ADDED
@@ -0,0 +1,89 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Defines a class to handle the user data export
4
+ *
5
+ * @package wp-job-manager
6
+ * @since 1.31.1
7
+ */
8
+
9
+ if ( ! defined( 'ABSPATH' ) ) {
10
+ exit; // Exit if accessed directly.
11
+ }
12
+
13
+ /**
14
+ * Handles the user data export.
15
+ *
16
+ * @package
17
+ * @since
18
+ */
19
+ class WP_Job_Manager_Data_Exporter {
20
+ /**
21
+ * Register the user data exporter method
22
+ *
23
+ * @param array $exporters The exporter array.
24
+ * @return array $exporters The exporter array.
25
+ */
26
+ public static function register_wpjm_user_data_exporter( $exporters ) {
27
+ $exporters['wp-job-manager'] = array(
28
+ 'exporter_friendly_name' => __( 'WP Job Manager', 'wp-job-manager' ),
29
+ 'callback' => array( __CLASS__, 'user_data_exporter' ),
30
+ );
31
+ return $exporters;
32
+ }
33
+
34
+ /**
35
+ * Data exporter
36
+ *
37
+ * @param string $email_address User email address.
38
+ * @return array
39
+ */
40
+ public static function user_data_exporter( $email_address ) {
41
+ $user = get_user_by( 'email', $email_address );
42
+ if ( false === $user ) {
43
+ return;
44
+ }
45
+
46
+ $export_items = array();
47
+ $user_data_to_export = array();
48
+ $user_meta_keys = array(
49
+ '_company_logo' => __( 'Company Logo', 'wp-job-manager' ),
50
+ '_company_name' => __( 'Company Name', 'wp-job-manager' ),
51
+ '_company_website' => __( 'Company Website', 'wp-job-manager' ),
52
+ '_company_tagline' => __( 'Company Tagline', 'wp-job-manager' ),
53
+ '_company_twitter' => __( 'Company Twitter', 'wp-job-manager' ),
54
+ '_company_video' => __( 'Company Video', 'wp-job-manager' ),
55
+ );
56
+
57
+ foreach ( $user_meta_keys as $user_meta_key => $name ) {
58
+ $user_meta = get_user_meta( $user->ID, $user_meta_key, true );
59
+
60
+ if ( empty( $user_meta ) ) {
61
+ continue;
62
+ }
63
+
64
+ if ( '_company_logo' === $user_meta_key ) {
65
+ $user_meta = wp_get_attachment_url( $user_meta );
66
+ if ( false === $user_meta ) {
67
+ continue;
68
+ }
69
+ }
70
+
71
+ $user_data_to_export[] = array(
72
+ 'name' => $name,
73
+ 'value' => $user_meta,
74
+ );
75
+ }
76
+
77
+ $export_items[] = array(
78
+ 'group_id' => 'wpjm-user-data',
79
+ 'group_label' => __( 'WP Job Manager User Data', 'wp-job-manager' ),
80
+ 'item_id' => "wpjm-user-data-{$user->ID}",
81
+ 'data' => $user_data_to_export,
82
+ );
83
+
84
+ return array(
85
+ 'data' => $export_items,
86
+ 'done' => true,
87
+ );
88
+ }
89
+ }
includes/class-wp-job-manager-email-notifications.php CHANGED
@@ -1,7 +1,7 @@
1
  <?php
2
 
3
  if ( ! defined( 'ABSPATH' ) ) {
4
- exit; // Exit if accessed directly
5
  }
6
 
7
  /**
@@ -11,11 +11,13 @@ if ( ! defined( 'ABSPATH' ) ) {
11
  * @since 1.31.0
12
  */
13
  final class WP_Job_Manager_Email_Notifications {
14
- const EMAIL_SETTING_PREFIX = 'job_manager_email_';
15
- const EMAIL_SETTING_ENABLED = 'enabled';
16
  const EMAIL_SETTING_PLAIN_TEXT = 'plain_text';
17
 
18
  /**
 
 
19
  * @var array
20
  */
21
  private static $deferred_notifications = array();
@@ -26,8 +28,8 @@ final class WP_Job_Manager_Email_Notifications {
26
  * @static
27
  */
28
  public static function init() {
29
- add_action( 'job_manager_send_notification', array( __CLASS__, '_schedule_notification' ), 10, 2 );
30
- add_action( 'job_manager_email_init', array( __CLASS__, '_lazy_init' ) );
31
  add_action( 'job_manager_email_job_details', array( __CLASS__, 'output_job_details' ), 10, 4 );
32
  add_action( 'job_manager_email_header', array( __CLASS__, 'output_header' ), 10, 3 );
33
  add_action( 'job_manager_email_footer', array( __CLASS__, 'output_footer' ), 10, 3 );
@@ -55,10 +57,14 @@ final class WP_Job_Manager_Email_Notifications {
55
  /**
56
  * Sets up an email notification to be sent at the end of the script's execution.
57
  *
 
 
 
 
58
  * @param string $notification
59
  * @param array $args
60
  */
61
- public static function _schedule_notification( $notification, $args = array() ) {
62
  self::maybe_init();
63
 
64
  self::$deferred_notifications[] = array( $notification, $args );
@@ -71,7 +77,7 @@ final class WP_Job_Manager_Email_Notifications {
71
  *
72
  * @access private
73
  */
74
- public static function _send_deferred_notifications() {
75
  $email_notifications = self::get_email_notifications( true );
76
  foreach ( self::$deferred_notifications as $email ) {
77
  if (
@@ -81,9 +87,9 @@ final class WP_Job_Manager_Email_Notifications {
81
  continue;
82
  }
83
 
84
- $email_class = $email_notifications[ $email[0] ];
85
  $email_notification_key = $email[0];
86
- $email_args = is_array( $email[1] ) ? $email[1] : array();
87
 
88
  self::send_email( $email[0], new $email_class( $email_args, self::get_email_settings( $email_notification_key ) ) );
89
  }
@@ -111,8 +117,8 @@ final class WP_Job_Manager_Email_Notifications {
111
  *
112
  * @access private
113
  */
114
- public static function _lazy_init() {
115
- add_action( 'shutdown', array( __CLASS__, '_send_deferred_notifications' ) );
116
 
117
  include_once JOB_MANAGER_PLUGIN_DIR . '/includes/emails/class-wp-job-manager-email-admin-new-job.php';
118
  include_once JOB_MANAGER_PLUGIN_DIR . '/includes/emails/class-wp-job-manager-email-admin-updated-job.php';
@@ -131,9 +137,9 @@ final class WP_Job_Manager_Email_Notifications {
131
  *
132
  * @access private
133
  */
134
- public static function _clear_deferred_notifications() {
135
  if ( ! defined( 'PHPUNIT_WPJM_TESTSUITE' ) || ! PHPUNIT_WPJM_TESTSUITE ) {
136
- die( "This is just for use while testing" );
137
  }
138
  self::$deferred_notifications = array();
139
  }
@@ -155,9 +161,11 @@ final class WP_Job_Manager_Email_Notifications {
155
  * @param array $email_notifications All the email notifications to be registered.
156
  */
157
  $email_notification_classes = array_unique( apply_filters( 'job_manager_email_notifications', self::core_email_notifications() ) );
158
- $email_notifications = array();
159
 
160
  /**
 
 
161
  * @var WP_Job_Manager_Email $email_class
162
  */
163
  foreach ( $email_notification_classes as $email_class ) {
@@ -167,7 +175,7 @@ final class WP_Job_Manager_Email_Notifications {
167
  }
168
 
169
  // PHP 5.2: Using `call_user_func()` but `$email_class::get_key()` preferred.
170
- $email_notification_key = call_user_func( array( $email_class, 'get_key') );
171
  if (
172
  isset( $email_notifications[ $email_notification_key ] )
173
  || ( $enabled_notifications_only && ! self::is_email_notification_enabled( $email_notification_key ) )
@@ -231,7 +239,7 @@ final class WP_Job_Manager_Email_Notifications {
231
  if ( get_option( 'job_manager_enable_types' ) && wp_count_terms( 'job_listing_type' ) > 0 ) {
232
  $job_types = wpjm_get_the_job_types( $job );
233
  if ( ! empty( $job_types ) ) {
234
- $fields[ 'job_type' ] = array(
235
  'label' => __( 'Job type', 'wp-job-manager' ),
236
  'value' => implode( ', ', wp_list_pluck( $job_types, 'name' ) ),
237
  );
@@ -241,7 +249,7 @@ final class WP_Job_Manager_Email_Notifications {
241
  if ( get_option( 'job_manager_enable_categories' ) && wp_count_terms( 'job_listing_category' ) > 0 ) {
242
  $job_categories = wpjm_get_the_job_categories( $job );
243
  if ( ! empty( $job_categories ) ) {
244
- $fields[ 'job_category' ] = array(
245
  'label' => __( 'Job category', 'wp-job-manager' ),
246
  'value' => implode( ', ', wp_list_pluck( $job_categories, 'name' ) ),
247
  );
@@ -266,7 +274,7 @@ final class WP_Job_Manager_Email_Notifications {
266
 
267
  $job_expires = get_post_meta( $job->ID, '_job_expires', true );
268
  if ( ! empty( $job_expires ) ) {
269
- $job_expires_str = date_i18n( get_option( 'date_format' ), strtotime( $job_expires ) );
270
  $fields['job_expires'] = array(
271
  'label' => __( 'Listing expires', 'wp-job-manager' ),
272
  'value' => $job_expires_str,
@@ -344,9 +352,9 @@ final class WP_Job_Manager_Email_Notifications {
344
  * Checks for an alternative email template segment in the template path specified by the current email.
345
  * Useful to provide alternative email headers and footers for a specific WPJM extension plugin.
346
  *
347
- * @param string $email_notification_key Email notification key for email being sent.
348
- * @param string $template_name Name of the template to check
349
- * @param bool $plain_text True if the email is being sent as plain text.
350
  * @return bool|string Returns path to template path alternative or false if none exists.
351
  */
352
  private static function email_template_path_alternative( $email_notification_key, $template_name, $plain_text ) {
@@ -361,7 +369,7 @@ final class WP_Job_Manager_Email_Notifications {
361
  }
362
 
363
  $template_path = call_user_func( array( $email_class, 'get_template_path' ) );
364
- $template = self::locate_template_file( $template_name, $plain_text, $template_path, $template_default_path );
365
  if ( '' === $template ) {
366
  return false;
367
  }
@@ -385,7 +393,7 @@ final class WP_Job_Manager_Email_Notifications {
385
  /**
386
  * Add email notification settings for the job manager context.
387
  *
388
- * @param array $settings
389
  * @return array
390
  */
391
  public static function add_job_manager_email_settings( $settings ) {
@@ -401,17 +409,19 @@ final class WP_Job_Manager_Email_Notifications {
401
  */
402
  public static function add_email_settings( $settings, $context ) {
403
  $email_notifications = self::get_email_notifications( false );
404
- $email_settings = array();
405
 
406
  foreach ( $email_notifications as $email_notification_key => $email_class ) {
407
  $email_notification_context = call_user_func( array( $email_class, 'get_context' ) );
408
- if ( $context !== $email_notification_context ) { continue; }
 
 
409
 
410
  $email_settings[] = array(
411
- 'type' => 'multi_enable_expand',
412
- 'class' => 'email-setting-row no-separator',
413
- 'name' => self::EMAIL_SETTING_PREFIX . call_user_func( array( $email_class, 'get_key' ) ),
414
- 'enable_field' => array(
415
  'name' => self::EMAIL_SETTING_ENABLED,
416
  'cb_label' => call_user_func( array( $email_class, 'get_name' ) ),
417
  'desc' => call_user_func( array( $email_class, 'get_description' ) ),
@@ -485,7 +495,7 @@ final class WP_Job_Manager_Email_Notifications {
485
  public static function send_employer_expiring_notice() {
486
  self::maybe_init();
487
 
488
- $email_key = WP_Job_Manager_Email_Employer_Expiring_Job::get_key();
489
  if ( ! self::is_email_notification_enabled( $email_key ) ) {
490
  return;
491
  }
@@ -500,7 +510,7 @@ final class WP_Job_Manager_Email_Notifications {
500
  public static function send_admin_expiring_notice() {
501
  self::maybe_init();
502
 
503
- $email_key = WP_Job_Manager_Email_Admin_Expiring_Job::get_key();
504
  if ( ! self::is_email_notification_enabled( $email_key ) ) {
505
  return;
506
  }
@@ -537,15 +547,16 @@ final class WP_Job_Manager_Email_Notifications {
537
  global $wpdb;
538
 
539
  $notice_before_ts = current_time( 'timestamp' ) + ( DAY_IN_SECONDS * $days_notice );
540
- $job_ids_sql = $wpdb->prepare( "
 
541
  SELECT postmeta.post_id FROM {$wpdb->postmeta} as postmeta
542
  LEFT JOIN {$wpdb->posts} as posts ON postmeta.post_id = posts.ID
543
  WHERE postmeta.meta_key = '_job_expires'
544
  AND postmeta.meta_value = %s
545
  AND posts.post_status = 'publish'
546
  AND posts.post_type = 'job_listing'
547
- ", date( 'Y-m-d', $notice_before_ts ) );
548
- $job_ids = $wpdb->get_col( $job_ids_sql );
549
 
550
  if ( $job_ids ) {
551
  foreach ( $job_ids as $job_id ) {
@@ -561,8 +572,8 @@ final class WP_Job_Manager_Email_Notifications {
561
  * @return array
562
  */
563
  private static function get_email_setting_fields( $email_notification_key ) {
564
- $email_class = self::get_email_class( $email_notification_key );
565
- $core_settings = array(
566
  array(
567
  'name' => 'plain_text',
568
  'std' => '0',
@@ -585,7 +596,7 @@ final class WP_Job_Manager_Email_Notifications {
585
  * @return array
586
  */
587
  private static function get_email_settings( $email_notification_key ) {
588
- $option_name = self::EMAIL_SETTING_PREFIX . $email_notification_key;
589
  $option_value = get_option( $option_name );
590
  if ( empty( $option_value ) || ! is_array( $option_value ) ) {
591
  $option_value = array();
@@ -602,10 +613,10 @@ final class WP_Job_Manager_Email_Notifications {
602
  * @return array
603
  */
604
  private static function get_email_setting_defaults( $email_notification_key ) {
605
- $settings = self::get_email_setting_fields( $email_notification_key );
606
  $email_class = self::get_email_class( $email_notification_key );
607
 
608
- $defaults = array();
609
  $defaults[ self::EMAIL_SETTING_ENABLED ] = call_user_func( array( $email_class, 'is_default_enabled' ) ) ? '1' : '0';
610
 
611
  foreach ( $settings as $setting ) {
@@ -631,13 +642,15 @@ final class WP_Job_Manager_Email_Notifications {
631
  }
632
 
633
  /**
634
- * Returns the total number of deferred notifications to be sent. Used in unit tests.
 
 
635
  *
636
  * @access private
637
  *
638
  * @return int
639
  */
640
- public static function _get_deferred_notification_count() {
641
  return count( self::$deferred_notifications );
642
  }
643
 
@@ -654,8 +667,8 @@ final class WP_Job_Manager_Email_Notifications {
654
  return is_string( $email_class )
655
  && class_exists( $email_class )
656
  && is_subclass_of( $email_class, 'WP_Job_Manager_Email' )
657
- && false !== call_user_func( array( $email_class, 'get_key') )
658
- && false !== call_user_func( array( $email_class, 'get_name') );
659
  }
660
 
661
  /**
@@ -673,7 +686,7 @@ final class WP_Job_Manager_Email_Notifications {
673
  }
674
 
675
  $fields = array( 'to', 'from', 'subject', 'rich_content', 'plain_content', 'attachments', 'cc', 'headers' );
676
- $args = array();
677
  foreach ( $fields as $field ) {
678
  $method = 'get_' . $field;
679
 
@@ -744,9 +757,9 @@ final class WP_Job_Manager_Email_Notifications {
744
  do_action( 'job_manager_email_header', $email_notification_key, $args, $plain_text );
745
 
746
  if ( $plain_text ) {
747
- echo html_entity_decode( wptexturize( $args['plain_content'] ) );
748
  } else {
749
- echo wpautop( wptexturize( $args['rich_content'] ) );
750
  }
751
 
752
  /**
@@ -790,7 +803,7 @@ final class WP_Job_Manager_Email_Notifications {
790
  $emogrifier = new Emogrifier( $content, self::get_styles() );
791
  $content = $emogrifier->emogrify();
792
  } catch ( Exception $e ) {
793
- trigger_error( 'Unable to inject styles into email notification: ' . $e->getMessage() );
794
  }
795
  }
796
  return $content;
1
  <?php
2
 
3
  if ( ! defined( 'ABSPATH' ) ) {
4
+ exit; // Exit if accessed directly.
5
  }
6
 
7
  /**
11
  * @since 1.31.0
12
  */
13
  final class WP_Job_Manager_Email_Notifications {
14
+ const EMAIL_SETTING_PREFIX = 'job_manager_email_';
15
+ const EMAIL_SETTING_ENABLED = 'enabled';
16
  const EMAIL_SETTING_PLAIN_TEXT = 'plain_text';
17
 
18
  /**
19
+ * Notifications to be scheduled.
20
+ *
21
  * @var array
22
  */
23
  private static $deferred_notifications = array();
28
  * @static
29
  */
30
  public static function init() {
31
+ add_action( 'job_manager_send_notification', array( __CLASS__, 'schedule_notification' ), 10, 2 );
32
+ add_action( 'job_manager_email_init', array( __CLASS__, 'lazy_init' ) );
33
  add_action( 'job_manager_email_job_details', array( __CLASS__, 'output_job_details' ), 10, 4 );
34
  add_action( 'job_manager_email_header', array( __CLASS__, 'output_header' ), 10, 3 );
35
  add_action( 'job_manager_email_footer', array( __CLASS__, 'output_footer' ), 10, 3 );
57
  /**
58
  * Sets up an email notification to be sent at the end of the script's execution.
59
  *
60
+ * Do not call manually.
61
+ *
62
+ * @access private
63
+ *
64
  * @param string $notification
65
  * @param array $args
66
  */
67
+ public static function schedule_notification( $notification, $args = array() ) {
68
  self::maybe_init();
69
 
70
  self::$deferred_notifications[] = array( $notification, $args );
77
  *
78
  * @access private
79
  */
80
+ public static function send_deferred_notifications() {
81
  $email_notifications = self::get_email_notifications( true );
82
  foreach ( self::$deferred_notifications as $email ) {
83
  if (
87
  continue;
88
  }
89
 
90
+ $email_class = $email_notifications[ $email[0] ];
91
  $email_notification_key = $email[0];
92
+ $email_args = is_array( $email[1] ) ? $email[1] : array();
93
 
94
  self::send_email( $email[0], new $email_class( $email_args, self::get_email_settings( $email_notification_key ) ) );
95
  }
117
  *
118
  * @access private
119
  */
120
+ public static function lazy_init() {
121
+ add_action( 'shutdown', array( __CLASS__, 'send_deferred_notifications' ) );
122
 
123
  include_once JOB_MANAGER_PLUGIN_DIR . '/includes/emails/class-wp-job-manager-email-admin-new-job.php';
124
  include_once JOB_MANAGER_PLUGIN_DIR . '/includes/emails/class-wp-job-manager-email-admin-updated-job.php';
137
  *
138
  * @access private
139
  */
140
+ public static function clear_deferred_notifications() {
141
  if ( ! defined( 'PHPUNIT_WPJM_TESTSUITE' ) || ! PHPUNIT_WPJM_TESTSUITE ) {
142
+ die( 'This is just for use while testing' );
143
  }
144
  self::$deferred_notifications = array();
145
  }
161
  * @param array $email_notifications All the email notifications to be registered.
162
  */
163
  $email_notification_classes = array_unique( apply_filters( 'job_manager_email_notifications', self::core_email_notifications() ) );
164
+ $email_notifications = array();
165
 
166
  /**
167
+ * Email class in loop.
168
+ *
169
  * @var WP_Job_Manager_Email $email_class
170
  */
171
  foreach ( $email_notification_classes as $email_class ) {
175
  }
176
 
177
  // PHP 5.2: Using `call_user_func()` but `$email_class::get_key()` preferred.
178
+ $email_notification_key = call_user_func( array( $email_class, 'get_key' ) );
179
  if (
180
  isset( $email_notifications[ $email_notification_key ] )
181
  || ( $enabled_notifications_only && ! self::is_email_notification_enabled( $email_notification_key ) )
239
  if ( get_option( 'job_manager_enable_types' ) && wp_count_terms( 'job_listing_type' ) > 0 ) {
240
  $job_types = wpjm_get_the_job_types( $job );
241
  if ( ! empty( $job_types ) ) {
242
+ $fields['job_type'] = array(
243
  'label' => __( 'Job type', 'wp-job-manager' ),
244
  'value' => implode( ', ', wp_list_pluck( $job_types, 'name' ) ),
245
  );
249
  if ( get_option( 'job_manager_enable_categories' ) && wp_count_terms( 'job_listing_category' ) > 0 ) {
250
  $job_categories = wpjm_get_the_job_categories( $job );
251
  if ( ! empty( $job_categories ) ) {
252
+ $fields['job_category'] = array(
253
  'label' => __( 'Job category', 'wp-job-manager' ),
254
  'value' => implode( ', ', wp_list_pluck( $job_categories, 'name' ) ),
255
  );
274
 
275
  $job_expires = get_post_meta( $job->ID, '_job_expires', true );
276
  if ( ! empty( $job_expires ) ) {
277
+ $job_expires_str = date_i18n( get_option( 'date_format' ), strtotime( $job_expires ) );
278
  $fields['job_expires'] = array(
279
  'label' => __( 'Listing expires', 'wp-job-manager' ),
280
  'value' => $job_expires_str,
352
  * Checks for an alternative email template segment in the template path specified by the current email.
353
  * Useful to provide alternative email headers and footers for a specific WPJM extension plugin.
354
  *
355
+ * @param string $email_notification_key Email notification key for email being sent.
356
+ * @param string $template_name Name of the template to check.
357
+ * @param bool $plain_text True if the email is being sent as plain text.
358
  * @return bool|string Returns path to template path alternative or false if none exists.
359
  */
360
  private static function email_template_path_alternative( $email_notification_key, $template_name, $plain_text ) {
369
  }
370
 
371
  $template_path = call_user_func( array( $email_class, 'get_template_path' ) );
372
+ $template = self::locate_template_file( $template_name, $plain_text, $template_path, $template_default_path );
373
  if ( '' === $template ) {
374
  return false;
375
  }
393
  /**
394
  * Add email notification settings for the job manager context.
395
  *
396
+ * @param array $settings
397
  * @return array
398
  */
399
  public static function add_job_manager_email_settings( $settings ) {
409
  */
410
  public static function add_email_settings( $settings, $context ) {
411
  $email_notifications = self::get_email_notifications( false );
412
+ $email_settings = array();
413
 
414
  foreach ( $email_notifications as $email_notification_key => $email_class ) {
415
  $email_notification_context = call_user_func( array( $email_class, 'get_context' ) );
416
+ if ( $context !== $email_notification_context ) {
417
+ continue;
418
+ }
419
 
420
  $email_settings[] = array(
421
+ 'type' => 'multi_enable_expand',
422
+ 'class' => 'email-setting-row no-separator',
423
+ 'name' => self::EMAIL_SETTING_PREFIX . call_user_func( array( $email_class, 'get_key' ) ),
424
+ 'enable_field' => array(
425
  'name' => self::EMAIL_SETTING_ENABLED,
426
  'cb_label' => call_user_func( array( $email_class, 'get_name' ) ),
427
  'desc' => call_user_func( array( $email_class, 'get_description' ) ),
495
  public static function send_employer_expiring_notice() {
496
  self::maybe_init();
497
 
498
+ $email_key = WP_Job_Manager_Email_Employer_Expiring_Job::get_key();
499
  if ( ! self::is_email_notification_enabled( $email_key ) ) {
500
  return;
501
  }
510
  public static function send_admin_expiring_notice() {
511
  self::maybe_init();
512
 
513
+ $email_key = WP_Job_Manager_Email_Admin_Expiring_Job::get_key();
514
  if ( ! self::is_email_notification_enabled( $email_key ) ) {
515
  return;
516
  }
547
  global $wpdb;
548
 
549
  $notice_before_ts = current_time( 'timestamp' ) + ( DAY_IN_SECONDS * $days_notice );
550
+ $job_ids = $wpdb->get_col( $wpdb->prepare(
551
+ "
552
  SELECT postmeta.post_id FROM {$wpdb->postmeta} as postmeta
553
  LEFT JOIN {$wpdb->posts} as posts ON postmeta.post_id = posts.ID
554
  WHERE postmeta.meta_key = '_job_expires'
555
  AND postmeta.meta_value = %s
556
  AND posts.post_status = 'publish'
557
  AND posts.post_type = 'job_listing'
558
+ ", date( 'Y-m-d', $notice_before_ts )
559
+ ) );
560
 
561
  if ( $job_ids ) {
562
  foreach ( $job_ids as $job_id ) {
572
  * @return array
573
  */
574
  private static function get_email_setting_fields( $email_notification_key ) {
575
+ $email_class = self::get_email_class( $email_notification_key );
576
+ $core_settings = array(
577
  array(
578
  'name' => 'plain_text',
579
  'std' => '0',
596
  * @return array
597
  */
598
  private static function get_email_settings( $email_notification_key ) {
599
+ $option_name = self::EMAIL_SETTING_PREFIX . $email_notification_key;
600
  $option_value = get_option( $option_name );
601
  if ( empty( $option_value ) || ! is_array( $option_value ) ) {
602
  $option_value = array();
613
  * @return array
614
  */
615
  private static function get_email_setting_defaults( $email_notification_key ) {
616
+ $settings = self::get_email_setting_fields( $email_notification_key );
617
  $email_class = self::get_email_class( $email_notification_key );
618
 
619
+ $defaults = array();
620
  $defaults[ self::EMAIL_SETTING_ENABLED ] = call_user_func( array( $email_class, 'is_default_enabled' ) ) ? '1' : '0';
621
 
622
  foreach ( $settings as $setting ) {
642
  }
643
 
644
  /**
645
+ * Returns the total number of deferred notifications to be sent.
646
+ *
647
+ * Do not use. Used just in unit tests.
648
  *
649
  * @access private
650
  *
651
  * @return int
652
  */
653
+ public static function get_deferred_notification_count() {
654
  return count( self::$deferred_notifications );
655
  }
656
 
667
  return is_string( $email_class )
668
  && class_exists( $email_class )
669
  && is_subclass_of( $email_class, 'WP_Job_Manager_Email' )
670
+ && false !== call_user_func( array( $email_class, 'get_key' ) )
671
+ && false !== call_user_func( array( $email_class, 'get_name' ) );
672
  }
673
 
674
  /**
686
  }
687
 
688
  $fields = array( 'to', 'from', 'subject', 'rich_content', 'plain_content', 'attachments', 'cc', 'headers' );
689
+ $args = array();
690
  foreach ( $fields as $field ) {
691
  $method = 'get_' . $field;
692
 
757
  do_action( 'job_manager_email_header', $email_notification_key, $args, $plain_text );
758
 
759
  if ( $plain_text ) {
760
+ echo wp_kses_post( html_entity_decode( wptexturize( $args['plain_content'] ) ) );
761
  } else {
762
+ echo wp_kses_post( wpautop( wptexturize( $args['rich_content'] ) ) );
763
  }
764
 
765
  /**
803
  $emogrifier = new Emogrifier( $content, self::get_styles() );
804
  $content = $emogrifier->emogrify();
805
  } catch ( Exception $e ) {
806
+ trigger_error( 'Unable to inject styles into email notification: ' . $e->getMessage() ); // @codingStandardsIgnoreLine
807
  }
808
  }
809
  return $content;
includes/class-wp-job-manager-forms.php CHANGED
@@ -49,16 +49,16 @@ class WP_Job_Manager_Forms {
49
  * Load a form's class
50
  *
51
  * @param string $form_name
52
- * @return string class name on success, false on failure
53
  */
54
  private function load_form_class( $form_name ) {
55
  if ( ! class_exists( 'WP_Job_Manager_Form' ) ) {
56
- include( 'abstracts/abstract-wp-job-manager-form.php' );
57
  }
58
 
59
- // Now try to load the form_name
60
- $form_class = 'WP_Job_Manager_Form_' . str_replace( '-', '_', $form_name );
61
- $form_file = JOB_MANAGER_PLUGIN_DIR . '/includes/forms/class-wp-job-manager-form-' . $form_name . '.php';
62
 
63
  if ( class_exists( $form_class ) ) {
64
  return call_user_func( array( $form_class, 'instance' ) );
@@ -72,7 +72,7 @@ class WP_Job_Manager_Forms {
72
  include $form_file;
73
  }
74
 
75
- // Init the form
76
  return call_user_func( array( $form_class, 'instance' ) );
77
  }
78
 
@@ -80,11 +80,12 @@ class WP_Job_Manager_Forms {
80
  * Returns the form content.
81
  *
82
  * @param string $form_name
83
- * @param array $atts Optional passed attributes
84
  * @return string|null
85
  */
86
  public function get_form( $form_name, $atts = array() ) {
87
- if ( $form = $this->load_form_class( $form_name ) ) {
 
88
  ob_start();
89
  $form->output( $atts );
90
  return ob_get_clean();
49
  * Load a form's class
50
  *
51
  * @param string $form_name
52
+ * @return string class name on success, false on failure.
53
  */
54
  private function load_form_class( $form_name ) {
55
  if ( ! class_exists( 'WP_Job_Manager_Form' ) ) {
56
+ include 'abstracts/abstract-wp-job-manager-form.php';
57
  }
58
 
59
+ // Now try to load the form_name.
60
+ $form_class = 'WP_Job_Manager_Form_' . str_replace( '-', '_', $form_name );
61
+ $form_file = JOB_MANAGER_PLUGIN_DIR . '/includes/forms/class-wp-job-manager-form-' . $form_name . '.php';
62
 
63
  if ( class_exists( $form_class ) ) {
64
  return call_user_func( array( $form_class, 'instance' ) );
72
  include $form_file;
73
  }
74
 
75
+ // Init the form.
76
  return call_user_func( array( $form_class, 'instance' ) );
77
  }
78
 
80
  * Returns the form content.
81
  *
82
  * @param string $form_name
83
+ * @param array $atts Optional passed attributes.
84
  * @return string|null
85
  */
86
  public function get_form( $form_name, $atts = array() ) {
87
+ $form = $this->load_form_class( $form_name );
88
+ if ( $form ) {
89
  ob_start();
90
  $form->output( $atts );
91
  return ob_get_clean();
includes/class-wp-job-manager-geocode.php CHANGED
@@ -1,6 +1,8 @@
1
  <?php
2
 
3
- if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
 
 
4
 
5
  /**
6
  * Obtains Geolocation data for posted jobs from Google.
@@ -78,7 +80,7 @@ class WP_Job_Manager_Geocode {
78
  * @return boolean
79
  */
80
  public static function has_location_data( $job_id ) {
81
- return get_post_meta( $job_id, 'geolocated', true ) == 1;
82
  }
83
 
84
  /**
@@ -152,19 +154,19 @@ class WP_Job_Manager_Geocode {
152
  $api_key = apply_filters( 'job_manager_geolocation_api_key', '', $raw_address );
153
 
154
  if ( '' !== $api_key ) {
155
- $geocode_endpoint_url = add_query_arg( 'key', urlencode( $api_key ), $geocode_endpoint_url );
156
  }
157
 
158
- $geocode_endpoint_url = add_query_arg( 'address', urlencode( $raw_address ), $geocode_endpoint_url );
159
 
160
  $locale = get_locale();
161
  if ( $locale ) {
162
- $geocode_endpoint_url = add_query_arg( 'language', substr( $locale, 0, 2 ), $geocode_endpoint_url );
163
  }
164
 
165
  $region = apply_filters( 'job_manager_geolocation_region_cctld', '', $raw_address );
166
  if ( '' !== $region ) {
167
- $geocode_endpoint_url = add_query_arg( 'region', urlencode( $region ), $geocode_endpoint_url );
168
  }
169
 
170
  return $geocode_endpoint_url;
@@ -176,10 +178,18 @@ class WP_Job_Manager_Geocode {
176
  * Based on code by Eyal Fitoussi.
177
  *
178
  * @param string $raw_address
179
- * @return array|bool location data
 
180
  */
181
  public static function get_location_data( $raw_address ) {
182
- $invalid_chars = array( " " => "+", "," => "", "?" => "", "&" => "", "=" => "" , "#" => "" );
 
 
 
 
 
 
 
183
  $raw_address = trim( strtolower( str_replace( array_keys( $invalid_chars ), array_values( $invalid_chars ), $raw_address ) ) );
184
 
185
  if ( empty( $raw_address ) ) {
@@ -190,7 +200,7 @@ class WP_Job_Manager_Geocode {
190
  $geocoded_address = get_transient( $transient_name );
191
  $jm_geocode_over_query_limit = get_transient( 'jm_geocode_over_query_limit' );
192
 
193
- // Query limit reached - don't geocode for a while
194
  if ( $jm_geocode_over_query_limit && false === $geocoded_address ) {
195
  return false;
196
  }
@@ -202,41 +212,32 @@ class WP_Job_Manager_Geocode {
202
 
203
  try {
204
  if ( false === $geocoded_address || empty( $geocoded_address->results[0] ) ) {
205
- $result = wp_remote_get(
206
  $geocode_api_url,
207
  array(
208
  'timeout' => 5,
209
  'redirection' => 1,
210
  'httpversion' => '1.1',
211
  'user-agent' => 'WordPress/WP-Job-Manager-' . JOB_MANAGER_VERSION . '; ' . get_bloginfo( 'url' ),
212
- 'sslverify' => false
213
  )
214
  );
215
  $result = wp_remote_retrieve_body( $result );
216
  $geocoded_address = json_decode( $result );
217
 
218
  if ( $geocoded_address->status ) {
219
- switch ( $geocoded_address->status ) {
220
- case 'ZERO_RESULTS' :
221
- throw new Exception( __( "No results found", 'wp-job-manager' ) );
222
- break;
223
- case 'OVER_QUERY_LIMIT' :
224
- set_transient( 'jm_geocode_over_query_limit', 1, HOUR_IN_SECONDS );
225
- throw new Exception( __( "Query limit reached", 'wp-job-manager' ) );
226
- break;
227
- case 'OK' :
228
- if ( ! empty( $geocoded_address->results[0] ) ) {
229
- set_transient( $transient_name, $geocoded_address, DAY_IN_SECONDS * 7 );
230
- } else {
231
- throw new Exception( __( "Geocoding error", 'wp-job-manager' ) );
232
- }
233
- break;
234
- default :
235
- throw new Exception( __( "Geocoding error", 'wp-job-manager' ) );
236
- break;
237
  }
238
  } else {
239
- throw new Exception( __( "Geocoding error", 'wp-job-manager' ) );
240
  }
241
  }
242
  } catch ( Exception $e ) {
@@ -261,29 +262,29 @@ class WP_Job_Manager_Geocode {
261
 
262
  foreach ( $address_data as $data ) {
263
  switch ( $data->types[0] ) {
264
- case 'street_number' :
265
  $address['street_number'] = sanitize_text_field( $data->long_name );
266
- break;
267
- case 'route' :
268
- $address['street'] = sanitize_text_field( $data->long_name );
269
- break;
270
- case 'sublocality_level_1' :
271
- case 'locality' :
272
- case 'postal_town' :
273
- $address['city'] = sanitize_text_field( $data->long_name );
274
- break;
275
- case 'administrative_area_level_1' :
276
- case 'administrative_area_level_2' :
277
- $address['state_short'] = sanitize_text_field( $data->short_name );
278
- $address['state_long'] = sanitize_text_field( $data->long_name );
279
- break;
280
- case 'postal_code' :
281
- $address['postcode'] = sanitize_text_field( $data->long_name );
282
- break;
283
- case 'country' :
284
  $address['country_short'] = sanitize_text_field( $data->short_name );
285
  $address['country_long'] = sanitize_text_field( $data->long_name );
286
- break;
287
  }
288
  }
289
  }
1
  <?php
2
 
3
+ if ( ! defined( 'ABSPATH' ) ) {
4
+ exit; // Exit if accessed directly.
5
+ }
6
 
7
  /**
8
  * Obtains Geolocation data for posted jobs from Google.
80
  * @return boolean
81
  */
82
  public static function has_location_data( $job_id ) {
83
+ return 1 === intval( get_post_meta( $job_id, 'geolocated', true ) );
84
  }
85
 
86
  /**
154
  $api_key = apply_filters( 'job_manager_geolocation_api_key', '', $raw_address );
155
 
156
  if ( '' !== $api_key ) {
157
+ $geocode_endpoint_url = add_query_arg( 'key', rawurlencode( $api_key ), $geocode_endpoint_url );
158
  }
159
 
160
+ $geocode_endpoint_url = add_query_arg( 'address', rawurlencode( $raw_address ), $geocode_endpoint_url );
161
 
162
  $locale = get_locale();
163
  if ( $locale ) {
164
+ $geocode_endpoint_url = add_query_arg( 'language', substr( $locale, 0, 2 ), $geocode_endpoint_url );
165
  }
166
 
167
  $region = apply_filters( 'job_manager_geolocation_region_cctld', '', $raw_address );
168
  if ( '' !== $region ) {
169
+ $geocode_endpoint_url = add_query_arg( 'region', rawurlencode( $region ), $geocode_endpoint_url );
170
  }
171
 
172
  return $geocode_endpoint_url;
178
  * Based on code by Eyal Fitoussi.
179
  *
180
  * @param string $raw_address
181
+ * @return array|bool location data.
182
+ * @throws Exception After geocoding error.
183
  */
184
  public static function get_location_data( $raw_address ) {
185
+ $invalid_chars = array(
186
+ ' ' => '+',
187
+ ',' => '',
188
+ '?' => '',
189
+ '&' => '',
190
+ '=' => '',
191
+ '#' => '',
192
+ );
193
  $raw_address = trim( strtolower( str_replace( array_keys( $invalid_chars ), array_values( $invalid_chars ), $raw_address ) ) );
194
 
195
  if ( empty( $raw_address ) ) {
200
  $geocoded_address = get_transient( $transient_name );
201
  $jm_geocode_over_query_limit = get_transient( 'jm_geocode_over_query_limit' );
202
 
203
+ // Query limit reached - don't geocode for a while.
204
  if ( $jm_geocode_over_query_limit && false === $geocoded_address ) {
205
  return false;
206
  }
212
 
213
  try {
214
  if ( false === $geocoded_address || empty( $geocoded_address->results[0] ) ) {
215
+ $result = wp_remote_get(
216
  $geocode_api_url,
217
  array(
218
  'timeout' => 5,
219
  'redirection' => 1,
220
  'httpversion' => '1.1',
221
  'user-agent' => 'WordPress/WP-Job-Manager-' . JOB_MANAGER_VERSION . '; ' . get_bloginfo( 'url' ),
222
+ 'sslverify' => false,
223
  )
224
  );
225
  $result = wp_remote_retrieve_body( $result );
226
  $geocoded_address = json_decode( $result );
227
 
228
  if ( $geocoded_address->status ) {
229
+ if ( 'ZERO_RESULTS' === $geocoded_address->status ) {
230
+ throw new Exception( __( 'No results found', 'wp-job-manager' ) );
231
+ } elseif ( 'OVER_QUERY_LIMIT' === $geocoded_address->status ) {
232
+ set_transient( 'jm_geocode_over_query_limit', 1, HOUR_IN_SECONDS );
233
+ throw new Exception( __( 'Query limit reached', 'wp-job-manager' ) );
234
+ } elseif ( 'OK' === $geocoded_address->status && ! empty( $geocoded_address->results[0] ) ) {
235
+ set_transient( $transient_name, $geocoded_address, DAY_IN_SECONDS * 7 );
236
+ } else {
237
+ throw new Exception( __( 'Geocoding error', 'wp-job-manager' ) );
 
 
 
 
 
 
 
 
 
238
  }
239
  } else {
240
+ throw new Exception( __( 'Geocoding error', 'wp-job-manager' ) );
241
  }
242
  }
243
  } catch ( Exception $e ) {
262
 
263
  foreach ( $address_data as $data ) {
264
  switch ( $data->types[0] ) {
265
+ case 'street_number':
266
  $address['street_number'] = sanitize_text_field( $data->long_name );
267
+ break;
268
+ case 'route':
269
+ $address['street'] = sanitize_text_field( $data->long_name );
270
+ break;
271
+ case 'sublocality_level_1':
272
+ case 'locality':
273
+ case 'postal_town':
274
+ $address['city'] = sanitize_text_field( $data->long_name );
275
+ break;
276
+ case 'administrative_area_level_1':
277
+ case 'administrative_area_level_2':
278
+ $address['state_short'] = sanitize_text_field( $data->short_name );
279
+ $address['state_long'] = sanitize_text_field( $data->long_name );
280
+ break;
281
+ case 'postal_code':
282
+ $address['postcode'] = sanitize_text_field( $data->long_name );
283
+ break;
284
+ case 'country':
285
  $address['country_short'] = sanitize_text_field( $data->short_name );
286
  $address['country_long'] = sanitize_text_field( $data->long_name );
287
+ break;
288
  }
289
  }
290
  }
includes/class-wp-job-manager-install.php CHANGED
@@ -5,7 +5,7 @@ if ( ! defined( 'ABSPATH' ) ) {
5
  }
6
 
7
  /**
8
- * Handles the installation of the WP Job Manager plugin.s
9
  *
10
  * @package wp-job-manager
11
  * @since 1.0.0
@@ -21,23 +21,23 @@ class WP_Job_Manager_Install {
21
  self::init_user_roles();
22
  self::default_terms();
23
 
24
- // Redirect to setup screen for new installs
25
  if ( ! get_option( 'wp_job_manager_version' ) ) {
26
  set_transient( '_job_manager_activation_redirect', 1, HOUR_IN_SECONDS );
27
  }
28
 
29
- // Update featured posts ordering
30
  if ( version_compare( get_option( 'wp_job_manager_version', JOB_MANAGER_VERSION ), '1.22.0', '<' ) ) {
31
  $wpdb->query( "UPDATE {$wpdb->posts} p SET p.menu_order = 0 WHERE p.post_type='job_listing';" );
32
  $wpdb->query( "UPDATE {$wpdb->posts} p LEFT JOIN {$wpdb->postmeta} pm ON p.ID = pm.post_id SET p.menu_order = -1 WHERE pm.meta_key = '_featured' AND pm.meta_value='1' AND p.post_type='job_listing';" );
33
  }
34
 
35
- // Update default term meta with employment types
36
  if ( version_compare( get_option( 'wp_job_manager_version', JOB_MANAGER_VERSION ), '1.28.0', '<' ) ) {
37
  self::add_employment_types();
38
  }
39
 
40
- // Update legacy options
41
  if ( false === get_option( 'job_manager_submit_job_form_page_id', false ) && get_option( 'job_manager_submit_page_slug' ) ) {
42
  $page_id = get_page_by_path( get_option( 'job_manager_submit_page_slug' ) )->ID;
43
  update_option( 'job_manager_submit_job_form_page_id', $page_id );
@@ -58,15 +58,19 @@ class WP_Job_Manager_Install {
58
  global $wp_roles;
59
 
60
  if ( class_exists( 'WP_Roles' ) && ! isset( $wp_roles ) ) {
61
- $wp_roles = new WP_Roles();
62
  }
63
 
64
  if ( is_object( $wp_roles ) ) {
65
- add_role( 'employer', __( 'Employer', 'wp-job-manager' ), array(
66
- 'read' => true,
67
- 'edit_posts' => false,
68
- 'delete_posts' => false
69
- ) );
 
 
 
 
70
 
71
  $capabilities = self::get_core_capabilities();
72
 
@@ -85,28 +89,28 @@ class WP_Job_Manager_Install {
85
  */
86
  private static function get_core_capabilities() {
87
  return array(
88
- 'core' => array(
89
- 'manage_job_listings'
90
  ),
91
  'job_listing' => array(
92
- "edit_job_listing",
93
- "read_job_listing",
94
- "delete_job_listing",
95
- "edit_job_listings",
96
- "edit_others_job_listings",
97
- "publish_job_listings",
98
- "read_private_job_listings",
99
- "delete_job_listings",
100
- "delete_private_job_listings",
101
- "delete_published_job_listings",
102
- "delete_others_job_listings",
103
- "edit_private_job_listings",
104
- "edit_published_job_listings",
105
- "manage_job_listing_terms",
106
- "edit_job_listing_terms",
107
- "delete_job_listing_terms",
108
- "assign_job_listing_terms"
109
- )
110
  );
111
  }
112
 
@@ -114,7 +118,7 @@ class WP_Job_Manager_Install {
114
  * Sets up the default WP Job Manager terms.
115
  */
116
  private static function default_terms() {
117
- if ( get_option( 'job_manager_installed_terms' ) == 1 ) {
118
  return;
119
  }
120
 
@@ -143,22 +147,22 @@ class WP_Job_Manager_Install {
143
  private static function get_default_taxonomy_terms() {
144
  return array(
145
  'job_listing_type' => array(
146
- 'Full Time' => array(
147
  'employment_type' => 'FULL_TIME',
148
  ),
149
- 'Part Time' => array(
150
  'employment_type' => 'PART_TIME',
151
  ),
152
- 'Temporary' => array(
153
  'employment_type' => 'TEMPORARY',
154
  ),
155
- 'Freelance' => array(
156
  'employment_type' => 'CONTRACTOR',
157
  ),
158
  'Internship' => array(
159
  'employment_type' => 'INTERN',
160
  ),
161
- )
162
  );
163
  }
164
 
@@ -167,7 +171,7 @@ class WP_Job_Manager_Install {
167
  */
168
  private static function add_employment_types() {
169
  $taxonomies = self::get_default_taxonomy_terms();
170
- $terms = $taxonomies['job_listing_type'];
171
 
172
  foreach ( $terms as $term => $meta ) {
173
  $term = get_term_by( 'slug', sanitize_title( $term ), 'job_listing_type' );
5
  }
6
 
7
  /**
8
+ * Handles the installation of the WP Job Manager plugin.
9
  *
10
  * @package wp-job-manager
11
  * @since 1.0.0
21
  self::init_user_roles();
22
  self::default_terms();
23
 
24
+ // Redirect to setup screen for new installs.
25
  if ( ! get_option( 'wp_job_manager_version' ) ) {
26
  set_transient( '_job_manager_activation_redirect', 1, HOUR_IN_SECONDS );
27
  }
28
 
29
+ // Update featured posts ordering.
30
  if ( version_compare( get_option( 'wp_job_manager_version', JOB_MANAGER_VERSION ), '1.22.0', '<' ) ) {
31
  $wpdb->query( "UPDATE {$wpdb->posts} p SET p.menu_order = 0 WHERE p.post_type='job_listing';" );
32
  $wpdb->query( "UPDATE {$wpdb->posts} p LEFT JOIN {$wpdb->postmeta} pm ON p.ID = pm.post_id SET p.menu_order = -1 WHERE pm.meta_key = '_featured' AND pm.meta_value='1' AND p.post_type='job_listing';" );
33
  }
34
 
35
+ // Update default term meta with employment types.
36
  if ( version_compare( get_option( 'wp_job_manager_version', JOB_MANAGER_VERSION ), '1.28.0', '<' ) ) {
37
  self::add_employment_types();
38
  }
39
 
40
+ // Update legacy options.
41
  if ( false === get_option( 'job_manager_submit_job_form_page_id', false ) && get_option( 'job_manager_submit_page_slug' ) ) {
42
  $page_id = get_page_by_path( get_option( 'job_manager_submit_page_slug' ) )->ID;
43
  update_option( 'job_manager_submit_job_form_page_id', $page_id );
58
  global $wp_roles;
59
 
60
  if ( class_exists( 'WP_Roles' ) && ! isset( $wp_roles ) ) {
61
+ $wp_roles = new WP_Roles(); // WPCS: override ok.
62
  }
63
 
64
  if ( is_object( $wp_roles ) ) {
65
+ add_role(
66
+ 'employer',
67
+ __( 'Employer', 'wp-job-manager' ),
68
+ array(
69
+ 'read' => true,
70
+ 'edit_posts' => false,
71
+ 'delete_posts' => false,
72
+ )
73
+ );
74
 
75
  $capabilities = self::get_core_capabilities();
76
 
89
  */
90
  private static function get_core_capabilities() {
91
  return array(
92
+ 'core' => array(
93
+ 'manage_job_listings',
94
  ),
95
  'job_listing' => array(
96
+ 'edit_job_listing',
97
+ 'read_job_listing',
98
+ 'delete_job_listing',
99
+ 'edit_job_listings',
100
+ 'edit_others_job_listings',
101
+ 'publish_job_listings',
102
+ 'read_private_job_listings',
103
+ 'delete_job_listings',
104
+ 'delete_private_job_listings',
105
+ 'delete_published_job_listings',
106
+ 'delete_others_job_listings',
107
+ 'edit_private_job_listings',
108
+ 'edit_published_job_listings',
109
+ 'manage_job_listing_terms',
110
+ 'edit_job_listing_terms',
111
+ 'delete_job_listing_terms',
112
+ 'assign_job_listing_terms',
113
+ ),
114
  );
115
  }
116
 
118
  * Sets up the default WP Job Manager terms.
119
  */
120
  private static function default_terms() {
121
+ if ( 1 === intval( get_option( 'job_manager_installed_terms' ) ) ) {
122
  return;
123
  }
124
 
147
  private static function get_default_taxonomy_terms() {
148
  return array(
149
  'job_listing_type' => array(
150
+ 'Full Time' => array(
151
  'employment_type' => 'FULL_TIME',
152
  ),
153
+ 'Part Time' => array(
154
  'employment_type' => 'PART_TIME',
155
  ),
156
+ 'Temporary' => array(
157
  'employment_type' => 'TEMPORARY',
158
  ),
159
+ 'Freelance' => array(
160
  'employment_type' => 'CONTRACTOR',
161
  ),
162
  'Internship' => array(
163
  'employment_type' => 'INTERN',
164
  ),
165
+ ),
166
  );
167
  }
168
 
171
  */
172
  private static function add_employment_types() {
173
  $taxonomies = self::get_default_taxonomy_terms();
174
+ $terms = $taxonomies['job_listing_type'];
175
 
176
  foreach ( $terms as $term => $meta ) {
177
  $term = get_term_by( 'slug', sanitize_title( $term ), 'job_listing_type' );
includes/class-wp-job-manager-post-types.php CHANGED
@@ -47,11 +47,11 @@ class WP_Job_Manager_Post_Types {
47
  add_action( 'wp_head', array( $this, 'noindex_expired_filled_job_listings' ) );
48
  add_action( 'wp_footer', array( $this, 'output_structured_data' ) );
49
 
50
- add_filter( 'the_job_description', 'wptexturize' );
51
- add_filter( 'the_job_description', 'convert_smilies' );
52
- add_filter( 'the_job_description', 'convert_chars' );
53
- add_filter( 'the_job_description', 'wpautop' );
54
- add_filter( 'the_job_description', 'shortcode_unautop' );
55
  add_filter( 'the_job_description', 'prepend_attachment' );
56
  if ( ! empty( $GLOBALS['wp_embed'] ) ) {
57
  add_filter( 'the_job_description', array( $GLOBALS['wp_embed'], 'run_shortcode' ), 8 );
@@ -68,7 +68,7 @@ class WP_Job_Manager_Post_Types {
68
 
69
  add_action( 'parse_query', array( $this, 'add_feed_query_args' ) );
70
 
71
- // Single job content
72
  $this->job_content_filter( true );
73
  }
74
 
@@ -76,8 +76,9 @@ class WP_Job_Manager_Post_Types {
76
  * Registers the custom post type and taxonomies.
77
  */
78
  public function register_post_types() {
79
- if ( post_type_exists( "job_listing" ) )
80
  return;
 
81
 
82
  $admin_capability = 'manage_job_listings';
83
 
@@ -87,107 +88,131 @@ class WP_Job_Manager_Post_Types {
87
  * Taxonomies
88
  */
89
  if ( get_option( 'job_manager_enable_categories' ) ) {
90
- $singular = __( 'Job category', 'wp-job-manager' );
91
- $plural = __( 'Job categories', 'wp-job-manager' );
92
 
93
  if ( current_theme_supports( 'job-manager-templates' ) ) {
94
- $rewrite = array(
95
  'slug' => $permalink_structure['category_rewrite_slug'],
96
  'with_front' => false,
97
- 'hierarchical' => false
98
  );
99
- $public = true;
100
  } else {
101
- $rewrite = false;
102
- $public = false;
103
  }
104
 
105
- register_taxonomy( "job_listing_category",
 
106
  apply_filters( 'register_taxonomy_job_listing_category_object_type', array( 'job_listing' ) ),
107
- apply_filters( 'register_taxonomy_job_listing_category_args', array(
108
- 'hierarchical' => true,
109
- 'update_count_callback' => '_update_post_term_count',
110
- 'label' => $plural,
111
- 'labels' => array(
112
- 'name' => $plural,
113
- 'singular_name' => $singular,
114
- 'menu_name' => ucwords( $plural ),
115
- 'search_items' => sprintf( __( 'Search %s', 'wp-job-manager' ), $plural ),
116
- 'all_items' => sprintf( __( 'All %s', 'wp-job-manager' ), $plural ),
117
- 'parent_item' => sprintf( __( 'Parent %s', 'wp-job-manager' ), $singular ),
118
- 'parent_item_colon' => sprintf( __( 'Parent %s:', 'wp-job-manager' ), $singular ),
119
- 'edit_item' => sprintf( __( 'Edit %s', 'wp-job-manager' ), $singular ),
120
- 'update_item' => sprintf( __( 'Update %s', 'wp-job-manager' ), $singular ),
121
- 'add_new_item' => sprintf( __( 'Add New %s', 'wp-job-manager' ), $singular ),
122
- 'new_item_name' => sprintf( __( 'New %s Name', 'wp-job-manager' ), $singular )
123
- ),
124
- 'show_ui' => true,
125
- 'show_tagcloud' => false,
126
- 'public' => $public,
127
- 'capabilities' => array(
128
- 'manage_terms' => $admin_capability,
129
- 'edit_terms' => $admin_capability,
130
- 'delete_terms' => $admin_capability,
131
- 'assign_terms' => $admin_capability,
132
- ),
133
- 'rewrite' => $rewrite,
134
- ) )
 
 
 
 
 
 
 
 
 
 
 
135
  );
136
  }
137
 
138
  if ( get_option( 'job_manager_enable_types' ) ) {
139
- $singular = __( 'Job type', 'wp-job-manager' );
140
- $plural = __( 'Job types', 'wp-job-manager' );
141
 
142
  if ( current_theme_supports( 'job-manager-templates' ) ) {
143
- $rewrite = array(
144
  'slug' => $permalink_structure['type_rewrite_slug'],
145
  'with_front' => false,
146
- 'hierarchical' => false
147
  );
148
- $public = true;
149
  } else {
150
- $rewrite = false;
151
- $public = false;
152
  }
153
 
154
- register_taxonomy( "job_listing_type",
 
155
  apply_filters( 'register_taxonomy_job_listing_type_object_type', array( 'job_listing' ) ),
156
- apply_filters( 'register_taxonomy_job_listing_type_args', array(
157
- 'hierarchical' => true,
158
- 'label' => $plural,
159
- 'labels' => array(
160
- 'name' => $plural,
161
- 'singular_name' => $singular,
162
- 'menu_name' => ucwords( $plural ),
163
- 'search_items' => sprintf( __( 'Search %s', 'wp-job-manager' ), $plural ),
164
- 'all_items' => sprintf( __( 'All %s', 'wp-job-manager' ), $plural ),
165
- 'parent_item' => sprintf( __( 'Parent %s', 'wp-job-manager' ), $singular ),
166
- 'parent_item_colon' => sprintf( __( 'Parent %s:', 'wp-job-manager' ), $singular ),
167
- 'edit_item' => sprintf( __( 'Edit %s', 'wp-job-manager' ), $singular ),
168
- 'update_item' => sprintf( __( 'Update %s', 'wp-job-manager' ), $singular ),
169
- 'add_new_item' => sprintf( __( 'Add New %s', 'wp-job-manager' ), $singular ),
170
- 'new_item_name' => sprintf( __( 'New %s Name', 'wp-job-manager' ), $singular )
171
- ),
172
- 'show_ui' => true,
173
- 'show_tagcloud' => false,
174
- 'public' => $public,
175
- 'capabilities' => array(
176
- 'manage_terms' => $admin_capability,
177
- 'edit_terms' => $admin_capability,
178
- 'delete_terms' => $admin_capability,
179
- 'assign_terms' => $admin_capability,
180
- ),
181
- 'rewrite' => $rewrite,
182
- ) )
 
 
 
 
 
 
 
 
 
 
 
183
  );
184
  }
185
 
186
  /**
187
  * Post types
188
  */
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.
@@ -202,50 +227,66 @@ class WP_Job_Manager_Post_Types {
202
  $has_archive = false;
203
  }
204
 
205
- $rewrite = array(
206
  'slug' => $permalink_structure['job_rewrite_slug'],
207
  'with_front' => false,
208
  'feeds' => true,
209
- 'pages' => false
210
  );
211
 
212
- register_post_type( "job_listing",
213
- apply_filters( "register_post_type_job_listing", array(
214
- 'labels' => array(
215
- 'name' => $plural,
216
- 'singular_name' => $singular,
217
- 'menu_name' => __( 'Job Listings', 'wp-job-manager' ),
218
- 'all_items' => sprintf( __( 'All %s', 'wp-job-manager' ), $plural ),
219
- 'add_new' => __( 'Add New', 'wp-job-manager' ),
220
- 'add_new_item' => sprintf( __( 'Add %s', 'wp-job-manager' ), $singular ),
221
- 'edit' => __( 'Edit', 'wp-job-manager' ),
222
- 'edit_item' => sprintf( __( 'Edit %s', 'wp-job-manager' ), $singular ),
223
- 'new_item' => sprintf( __( 'New %s', 'wp-job-manager' ), $singular ),
224
- 'view' => sprintf( __( 'View %s', 'wp-job-manager' ), $singular ),
225
- 'view_item' => sprintf( __( 'View %s', 'wp-job-manager' ), $singular ),
226
- 'search_items' => sprintf( __( 'Search %s', 'wp-job-manager' ), $plural ),
227
- 'not_found' => sprintf( __( 'No %s found', 'wp-job-manager' ), $plural ),
228
- 'not_found_in_trash' => sprintf( __( 'No %s found in trash', 'wp-job-manager' ), $plural ),
229
- 'parent' => sprintf( __( 'Parent %s', 'wp-job-manager' ), $singular ),
230
- 'featured_image' => __( 'Company Logo', 'wp-job-manager' ),
231
- 'set_featured_image' => __( 'Set company logo', 'wp-job-manager' ),
232
- 'remove_featured_image' => __( 'Remove company logo', 'wp-job-manager' ),
233
- 'use_featured_image' => __( 'Use as company logo', 'wp-job-manager' ),
234
- ),
235
- 'description' => sprintf( __( 'This is where you can create and manage %s.', 'wp-job-manager' ), $plural ),
236
- 'public' => true,
237
- 'show_ui' => true,
238
- 'capability_type' => 'job_listing',
239
- 'map_meta_cap' => true,
240
- 'publicly_queryable' => true,
241
- 'exclude_from_search' => false,
242
- 'hierarchical' => false,
243
- 'rewrite' => $rewrite,
244
- 'query_var' => true,
245
- 'supports' => array( 'title', 'editor', 'custom-fields', 'publicize', 'thumbnail' ),
246
- 'has_archive' => $has_archive,
247
- 'show_in_nav_menus' => false
248
- ) )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
249
  );
250
 
251
  /**
@@ -256,23 +297,31 @@ class WP_Job_Manager_Post_Types {
256
  /**
257
  * Post status
258
  */
259
- register_post_status( 'expired', array(
260
- 'label' => _x( 'Expired', 'post status', 'wp-job-manager' ),
261
- 'public' => true,
262
- 'protected' => true,
263
- 'exclude_from_search' => true,
264
- 'show_in_admin_all_list' => true,
265
- 'show_in_admin_status_list' => true,
266
- 'label_count' => _n_noop( 'Expired <span class="count">(%s)</span>', 'Expired <span class="count">(%s)</span>', 'wp-job-manager' ),
267
- ) );
268
- register_post_status( 'preview', array(
269
- 'label' => _x( 'Preview', 'post status', 'wp-job-manager' ),
270
- 'public' => false,
271
- 'exclude_from_search' => true,
272
- 'show_in_admin_all_list' => false,
273
- 'show_in_admin_status_list' => true,
274
- 'label_count' => _n_noop( 'Preview <span class="count">(%s)</span>', 'Preview <span class="count">(%s)</span>', 'wp-job-manager' ),
275
- ) );
 
 
 
 
 
 
 
 
276
  }
277
 
278
  /**
@@ -283,18 +332,18 @@ class WP_Job_Manager_Post_Types {
283
 
284
  $pending_jobs = WP_Job_Manager_Cache_Helper::get_listings_count();
285
 
286
- // No need to go further if no pending jobs, menu is not set, or is not an array
287
- if( empty( $pending_jobs ) || empty( $menu ) || ! is_array( $menu ) ){
288
  return;
289
  }
290
 
291
- // Try to pull menu_name from post type object to support themes/plugins that change the menu string
292
  $post_type = get_post_type_object( 'job_listing' );
293
- $plural = isset( $post_type->labels, $post_type->labels->menu_name ) ? $post_type->labels->menu_name : __( 'Job Listings', 'wp-job-manager' );
294
 
295
  foreach ( $menu as $key => $menu_item ) {
296
  if ( strpos( $menu_item[0], $plural ) === 0 ) {
297
- $menu[ $key ][0] .= " <span class='awaiting-mod update-plugins count-{$pending_jobs}'><span class='pending-count'>" . number_format_i18n( $pending_jobs ) . "</span></span>" ;
298
  break;
299
  }
300
  }
@@ -354,7 +403,7 @@ class WP_Job_Manager_Post_Types {
354
  'posts_per_page' => isset( $_GET['posts_per_page'] ) ? absint( $_GET['posts_per_page'] ) : 10,
355
  'paged' => absint( get_query_var( 'paged', 1 ) ),
356
  'tax_query' => array(),
357
- 'meta_query' => array()
358
  );
359
 
360
  if ( ! empty( $_GET['search_location'] ) ) {
@@ -364,7 +413,7 @@ class WP_Job_Manager_Post_Types {
364
  $location_search[] = array(
365
  'key' => $meta_key,
366
  'value' => sanitize_text_field( $_GET['search_location'] ),
367
- 'compare' => 'like'
368
  );
369
  }
370
  $query_args['meta_query'][] = $location_search;
@@ -374,20 +423,20 @@ class WP_Job_Manager_Post_Types {
374
  $query_args['tax_query'][] = array(
375
  'taxonomy' => 'job_listing_type',
376
  'field' => 'slug',
377
- 'terms' => explode( ',', sanitize_text_field( $_GET['job_types'] ) ) + array( 0 )
378
  );
379
  }
380
 
381
  if ( ! empty( $_GET['job_categories'] ) ) {
382
- $cats = explode( ',', sanitize_text_field( $_GET['job_categories'] ) ) + array( 0 );
383
- $field = is_numeric( $cats ) ? 'term_id' : 'slug';
384
- $operator = 'all' === get_option( 'job_manager_category_filter_type', 'all' ) && sizeof( $args['search_categories'] ) > 1 ? 'AND' : 'IN';
385
  $query_args['tax_query'][] = array(
386
  'taxonomy' => 'job_listing_category',
387
  'field' => $field,
388
  'terms' => $cats,
389
- 'include_children' => $operator !== 'AND' ,
390
- 'operator' => $operator
391
  );
392
  }
393
 
@@ -405,7 +454,7 @@ class WP_Job_Manager_Post_Types {
405
  unset( $query_args['tax_query'] );
406
  }
407
 
408
- query_posts( apply_filters( 'job_feed_args', $query_args ) );
409
  add_action( 'rss2_ns', array( $this, 'job_feed_namespace' ) );
410
  add_action( 'rss2_item', array( $this, 'job_feed_item' ) );
411
  do_feed_rss2( false );
@@ -419,7 +468,7 @@ class WP_Job_Manager_Post_Types {
419
  */
420
  public function add_feed_query_args( $wp ) {
421
 
422
- // Let's leave if not the job feed
423
  if ( ! isset( $wp->query_vars['feed'] ) || 'job_feed' !== $wp->query_vars['feed'] ) {
424
  return;
425
  }
@@ -441,27 +490,27 @@ class WP_Job_Manager_Post_Types {
441
  * Adds a custom namespace to the job feed.
442
  */
443
  public function job_feed_namespace() {
444
- echo 'xmlns:job_listing="' . site_url() . '"' . "\n";
445
  }
446
 
447
  /**
448
  * Adds custom data to the job feed.
449
  */
450
  public function job_feed_item() {
451
- $post_id = get_the_ID();
452
- $location = get_the_job_location( $post_id );
453
- $company = get_the_company_name( $post_id );
454
- $job_types = wpjm_get_the_job_types( $post_id );
455
 
456
  if ( $location ) {
457
- echo "<job_listing:location><![CDATA[" . esc_html( $location ) . "]]></job_listing:location>\n";
458
  }
459
  if ( ! empty( $job_types ) ) {
460
  $job_types_names = implode( ', ', wp_list_pluck( $job_types, 'name' ) );
461
- echo "<job_listing:job_type><![CDATA[" . esc_html( $job_types_names ) . "]]></job_listing:job_type>\n";
462
  }
463
  if ( $company ) {
464
- echo "<job_listing:company><![CDATA[" . esc_html( $company ) . "]]></job_listing:company>\n";
465
  }
466
 
467
  /**
@@ -478,34 +527,40 @@ class WP_Job_Manager_Post_Types {
478
  public function check_for_expired_jobs() {
479
  global $wpdb;
480
 
481
- // Change status to expired
482
- $job_ids = $wpdb->get_col( $wpdb->prepare( "
483
- SELECT postmeta.post_id FROM {$wpdb->postmeta} as postmeta
484
- LEFT JOIN {$wpdb->posts} as posts ON postmeta.post_id = posts.ID
485
- WHERE postmeta.meta_key = '_job_expires'
486
- AND postmeta.meta_value > 0
487
- AND postmeta.meta_value < %s
488
- AND posts.post_status = 'publish'
489
- AND posts.post_type = 'job_listing'
490
- ", date( 'Y-m-d', current_time( 'timestamp' ) ) ) );
 
 
 
491
 
492
  if ( $job_ids ) {
493
  foreach ( $job_ids as $job_id ) {
494
- $job_data = array();
495
- $job_data['ID'] = $job_id;
496
  $job_data['post_status'] = 'expired';
497
  wp_update_post( $job_data );
498
  }
499
  }
500
 
501
- // Delete old expired jobs
502
  if ( apply_filters( 'job_manager_delete_expired_jobs', false ) ) {
503
- $job_ids = $wpdb->get_col( $wpdb->prepare( "
504
- SELECT posts.ID FROM {$wpdb->posts} as posts
505
- WHERE posts.post_type = 'job_listing'
506
- AND posts.post_modified < %s
507
- AND posts.post_status = 'expired'
508
- ", date( 'Y-m-d', strtotime( '-' . apply_filters( 'job_manager_delete_expired_jobs_days', 30 ) . ' days', current_time( 'timestamp' ) ) ) ) );
 
 
 
509
 
510
  if ( $job_ids ) {
511
  foreach ( $job_ids as $job_id ) {
@@ -521,13 +576,16 @@ class WP_Job_Manager_Post_Types {
521
  public function delete_old_previews() {
522
  global $wpdb;
523
 
524
- // Delete old expired jobs
525
- $job_ids = $wpdb->get_col( $wpdb->prepare( "
526
- SELECT posts.ID FROM {$wpdb->posts} as posts
527
- WHERE posts.post_type = 'job_listing'
528
- AND posts.post_modified < %s
529
- AND posts.post_status = 'preview'
530
- ", date( 'Y-m-d', strtotime( '-30 days', current_time( 'timestamp' ) ) ) ) );
 
 
 
531
 
532
  if ( $job_ids ) {
533
  foreach ( $job_ids as $job_id ) {
@@ -554,11 +612,11 @@ class WP_Job_Manager_Post_Types {
554
  * @param WP_Post $post
555
  */
556
  public function set_expiry( $post ) {
557
- if ( $post->post_type !== 'job_listing' ) {
558
  return;
559
  }
560
 
561
- // See if it is already set
562
  if ( metadata_exists( 'post', $post->ID, '_job_expires' ) ) {
563
  $expires = get_post_meta( $post->ID, '_job_expires', true );
564
  if ( $expires && strtotime( $expires ) < current_time( 'timestamp' ) ) {
@@ -566,18 +624,17 @@ class WP_Job_Manager_Post_Types {
566
  }
567
  }
568
 
569
- // See if the user has set the expiry manually:
570
- if ( ! empty( $_POST[ '_job_expires' ] ) ) {
571
- update_post_meta( $post->ID, '_job_expires', date( 'Y-m-d', strtotime( sanitize_text_field( $_POST[ '_job_expires' ] ) ) ) );
572
-
573
- // No manual setting? Lets generate a date if there isn't already one
574
- } elseif ( false == isset( $expires ) ) {
575
  $expires = calculate_job_expiry( $post->ID );
576
  update_post_meta( $post->ID, '_job_expires', $expires );
577
 
578
- // In case we are saving a post, ensure post data is updated so the field is not overridden
579
- if ( isset( $_POST[ '_job_expires' ] ) ) {
580
- $_POST[ '_job_expires' ] = $expires;
581
  }
582
  }
583
  }
@@ -631,16 +688,19 @@ class WP_Job_Manager_Post_Types {
631
  switch_to_locale( get_locale() );
632
  }
633
 
634
- $permalinks = wp_parse_args( (array) get_option( 'wpjm_permalinks', array() ), array(
635
- 'job_base' => '',
636
- 'category_base' => '',
637
- 'type_base' => '',
638
- ) );
 
 
 
639
 
640
  // Ensure rewrite slugs are set.
641
- $permalinks['job_rewrite_slug'] = untrailingslashit( empty( $permalinks['job_base'] ) ? _x( 'job', 'Job permalink - resave permalinks after changing this', 'wp-job-manager' ) : $permalinks['job_base'] );
642
  $permalinks['category_rewrite_slug'] = untrailingslashit( empty( $permalinks['category_base'] ) ? _x( 'job-category', 'Job category slug - resave permalinks after changing this', 'wp-job-manager' ) : $permalinks['category_base'] );
643
- $permalinks['type_rewrite_slug'] = untrailingslashit( empty( $permalinks['type_base'] ) ? _x( 'job-type', 'Job type slug - resave permalinks after changing this', 'wp-job-manager' ) : $permalinks['type_base'] );
644
 
645
  // Restore the original locale.
646
  if ( function_exists( 'restore_current_locale' ) && did_action( 'admin_init' ) ) {
@@ -674,12 +734,12 @@ class WP_Job_Manager_Post_Types {
674
  public function update_post_meta( $meta_id, $object_id, $meta_key, $meta_value ) {
675
  if ( 'job_listing' === get_post_type( $object_id ) ) {
676
  switch ( $meta_key ) {
677
- case '_job_location' :
678
  $this->maybe_update_geolocation_data( $meta_id, $object_id, $meta_key, $meta_value );
679
- break;
680
- case '_featured' :
681
  $this->maybe_update_menu_order( $meta_id, $object_id, $meta_key, $meta_value );
682
- break;
683
  }
684
  }
685
  }
@@ -687,9 +747,9 @@ class WP_Job_Manager_Post_Types {
687
  /**
688
  * Generates location data if a post is updated.
689
  *
690
- * @param int $meta_id (Unused)
691
  * @param int $object_id
692
- * @param string $meta_key (Unused)
693
  * @param mixed $meta_value
694
  */
695
  public function maybe_update_geolocation_data( $meta_id, $object_id, $meta_key, $meta_value ) {
@@ -699,18 +759,29 @@ class WP_Job_Manager_Post_Types {
699
  /**
700
  * Maybe sets menu_order if the featured status of a job is changed.
701
  *
702
- * @param int $meta_id (Unused)
703
  * @param int $object_id
704
- * @param string $meta_key (Unused)
705
  * @param mixed $meta_value
706
  */
707
  public function maybe_update_menu_order( $meta_id, $object_id, $meta_key, $meta_value ) {
708
  global $wpdb;
709
 
710
- if ( '1' == $meta_value ) {
711
- $wpdb->update( $wpdb->posts, array( 'menu_order' => -1 ), array( 'ID' => $object_id ) );
 
 
 
 
712
  } else {
713
- $wpdb->update( $wpdb->posts, array( 'menu_order' => 0 ), array( 'ID' => $object_id, 'menu_order' => -1 ) );
 
 
 
 
 
 
 
714
  }
715
 
716
  clean_post_cache( $object_id );
47
  add_action( 'wp_head', array( $this, 'noindex_expired_filled_job_listings' ) );
48
  add_action( 'wp_footer', array( $this, 'output_structured_data' ) );
49
 
50
+ add_filter( 'the_job_description', 'wptexturize' );
51
+ add_filter( 'the_job_description', 'convert_smilies' );
52
+ add_filter( 'the_job_description', 'convert_chars' );
53
+ add_filter( 'the_job_description', 'wpautop' );
54
+ add_filter( 'the_job_description', 'shortcode_unautop' );
55
  add_filter( 'the_job_description', 'prepend_attachment' );
56
  if ( ! empty( $GLOBALS['wp_embed'] ) ) {
57
  add_filter( 'the_job_description', array( $GLOBALS['wp_embed'], 'run_shortcode' ), 8 );
68
 
69
  add_action( 'parse_query', array( $this, 'add_feed_query_args' ) );
70
 
71
+ // Single job content.
72
  $this->job_content_filter( true );
73
  }
74
 
76
  * Registers the custom post type and taxonomies.
77
  */
78
  public function register_post_types() {
79
+ if ( post_type_exists( 'job_listing' ) ) {
80
  return;
81
+ }
82
 
83
  $admin_capability = 'manage_job_listings';
84
 
88
  * Taxonomies
89
  */
90
  if ( get_option( 'job_manager_enable_categories' ) ) {
91
+ $singular = __( 'Job category', 'wp-job-manager' );
92
+ $plural = __( 'Job categories', 'wp-job-manager' );
93
 
94
  if ( current_theme_supports( 'job-manager-templates' ) ) {
95
+ $rewrite = array(
96
  'slug' => $permalink_structure['category_rewrite_slug'],
97
  'with_front' => false,
98
+ 'hierarchical' => false,
99
  );
100
+ $public = true;
101
  } else {
102
+ $rewrite = false;
103
+ $public = false;
104
  }
105
 
106
+ register_taxonomy(
107
+ 'job_listing_category',
108
  apply_filters( 'register_taxonomy_job_listing_category_object_type', array( 'job_listing' ) ),
109
+ apply_filters(
110
+ 'register_taxonomy_job_listing_category_args',
111
+ array(
112
+ 'hierarchical' => true,
113
+ 'update_count_callback' => '_update_post_term_count',
114
+ 'label' => $plural,
115
+ 'labels' => array(
116
+ 'name' => $plural,
117
+ 'singular_name' => $singular,
118
+ 'menu_name' => ucwords( $plural ),
119
+ // translators: Placeholder %s is the plural label of the job listing category taxonomy type.
120
+ 'search_items' => sprintf( __( 'Search %s', 'wp-job-manager' ), $plural ),
121
+ // translators: Placeholder %s is the plural label of the job listing category taxonomy type.
122
+ 'all_items' => sprintf( __( 'All %s', 'wp-job-manager' ), $plural ),
123
+ // translators: Placeholder %s is the singular label of the job listing category taxonomy type.
124
+ 'parent_item' => sprintf( __( 'Parent %s', 'wp-job-manager' ), $singular ),
125
+ // translators: Placeholder %s is the singular label of the job listing category taxonomy type.
126
+ 'parent_item_colon' => sprintf( __( 'Parent %s:', 'wp-job-manager' ), $singular ),
127
+ // translators: Placeholder %s is the singular label of the job listing category taxonomy type.
128
+ 'edit_item' => sprintf( __( 'Edit %s', 'wp-job-manager' ), $singular ),
129
+ // translators: Placeholder %s is the singular label of the job listing category taxonomy type.
130
+ 'update_item' => sprintf( __( 'Update %s', 'wp-job-manager' ), $singular ),
131
+ // translators: Placeholder %s is the singular label of the job listing category taxonomy type.
132
+ 'add_new_item' => sprintf( __( 'Add New %s', 'wp-job-manager' ), $singular ),
133
+ // translators: Placeholder %s is the singular label of the job listing category taxonomy type.
134
+ 'new_item_name' => sprintf( __( 'New %s Name', 'wp-job-manager' ), $singular ),
135
+ ),
136
+ 'show_ui' => true,
137
+ 'show_tagcloud' => false,
138
+ 'public' => $public,
139
+ 'capabilities' => array(
140
+ 'manage_terms' => $admin_capability,
141
+ 'edit_terms' => $admin_capability,
142
+ 'delete_terms' => $admin_capability,
143
+ 'assign_terms' => $admin_capability,
144
+ ),
145
+ 'rewrite' => $rewrite,
146
+ )
147
+ )
148
  );
149
  }
150
 
151
  if ( get_option( 'job_manager_enable_types' ) ) {
152
+ $singular = __( 'Job type', 'wp-job-manager' );
153
+ $plural = __( 'Job types', 'wp-job-manager' );
154
 
155
  if ( current_theme_supports( 'job-manager-templates' ) ) {
156
+ $rewrite = array(
157
  'slug' => $permalink_structure['type_rewrite_slug'],
158
  'with_front' => false,
159
+ 'hierarchical' => false,
160
  );
161
+ $public = true;
162
  } else {
163
+ $rewrite = false;
164
+ $public = false;
165
  }
166
 
167
+ register_taxonomy(
168
+ 'job_listing_type',
169
  apply_filters( 'register_taxonomy_job_listing_type_object_type', array( 'job_listing' ) ),
170
+ apply_filters(
171
+ 'register_taxonomy_job_listing_type_args',
172
+ array(
173
+ 'hierarchical' => true,
174
+ 'label' => $plural,
175
+ 'labels' => array(
176
+ 'name' => $plural,
177
+ 'singular_name' => $singular,
178
+ 'menu_name' => ucwords( $plural ),
179
+ // translators: Placeholder %s is the plural label of the job listing job type taxonomy type.
180
+ 'search_items' => sprintf( __( 'Search %s', 'wp-job-manager' ), $plural ),
181
+ // translators: Placeholder %s is the plural label of the job listing job type taxonomy type.
182
+ 'all_items' => sprintf( __( 'All %s', 'wp-job-manager' ), $plural ),
183
+ // translators: Placeholder %s is the singular label of the job listing job type taxonomy type.
184
+ 'parent_item' => sprintf( __( 'Parent %s', 'wp-job-manager' ), $singular ),
185
+ // translators: Placeholder %s is the singular label of the job listing job type taxonomy type.
186
+ 'parent_item_colon' => sprintf( __( 'Parent %s:', 'wp-job-manager' ), $singular ),
187
+ // translators: Placeholder %s is the singular label of the job listing job type taxonomy type.
188
+ 'edit_item' => sprintf( __( 'Edit %s', 'wp-job-manager' ), $singular ),
189
+ // translators: Placeholder %s is the singular label of the job listing job type taxonomy type.
190
+ 'update_item' => sprintf( __( 'Update %s', 'wp-job-manager' ), $singular ),
191
+ // translators: Placeholder %s is the singular label of the job listing job type taxonomy type.
192
+ 'add_new_item' => sprintf( __( 'Add New %s', 'wp-job-manager' ), $singular ),
193
+ // translators: Placeholder %s is the singular label of the job listing job type taxonomy type.
194
+ 'new_item_name' => sprintf( __( 'New %s Name', 'wp-job-manager' ), $singular ),
195
+ ),
196
+ 'show_ui' => true,
197
+ 'show_tagcloud' => false,
198
+ 'public' => $public,
199
+ 'capabilities' => array(
200
+ 'manage_terms' => $admin_capability,
201
+ 'edit_terms' => $admin_capability,
202
+ 'delete_terms' => $admin_capability,
203
+ 'assign_terms' => $admin_capability,
204
+ ),
205
+ 'rewrite' => $rewrite,
206
+ )
207
+ )
208
  );
209
  }
210
 
211
  /**
212
  * Post types
213
  */
214
+ $singular = __( 'Job', 'wp-job-manager' );
215
+ $plural = __( 'Jobs', 'wp-job-manager' );
216
 
217
  /**
218
  * Set whether to add archive page support when registering the job listing post type.
227
  $has_archive = false;
228
  }
229
 
230
+ $rewrite = array(
231
  'slug' => $permalink_structure['job_rewrite_slug'],
232
  'with_front' => false,
233
  'feeds' => true,
234
+ 'pages' => false,
235
  );
236
 
237
+ register_post_type(
238
+ 'job_listing',
239
+ apply_filters(
240
+ 'register_post_type_job_listing',
241
+ array(
242
+ 'labels' => array(
243
+ 'name' => $plural,
244
+ 'singular_name' => $singular,
245
+ 'menu_name' => __( 'Job Listings', 'wp-job-manager' ),
246
+ // translators: Placeholder %s is the plural label of the job listing post type.
247
+ 'all_items' => sprintf( __( 'All %s', 'wp-job-manager' ), $plural ),
248
+ 'add_new' => __( 'Add New', 'wp-job-manager' ),
249
+ // translators: Placeholder %s is the singular label of the job listing post type.
250
+ 'add_new_item' => sprintf( __( 'Add %s', 'wp-job-manager' ), $singular ),
251
+ 'edit' => __( 'Edit', 'wp-job-manager' ),
252
+ // translators: Placeholder %s is the singular label of the job listing post type.
253
+ 'edit_item' => sprintf( __( 'Edit %s', 'wp-job-manager' ), $singular ),
254
+ // translators: Placeholder %s is the singular label of the job listing post type.
255
+ 'new_item' => sprintf( __( 'New %s', 'wp-job-manager' ), $singular ),
256
+ // translators: Placeholder %s is the singular label of the job listing post type.
257
+ 'view' => sprintf( __( 'View %s', 'wp-job-manager' ), $singular ),
258
+ // translators: Placeholder %s is the singular label of the job listing post type.
259
+ 'view_item' => sprintf( __( 'View %s', 'wp-job-manager' ), $singular ),
260
+ // translators: Placeholder %s is the singular label of the job listing post type.
261
+ 'search_items' => sprintf( __( 'Search %s', 'wp-job-manager' ), $plural ),
262
+ // translators: Placeholder %s is the singular label of the job listing post type.
263
+ 'not_found' => sprintf( __( 'No %s found', 'wp-job-manager' ), $plural ),
264
+ // translators: Placeholder %s is the plural label of the job listing post type.
265
+ 'not_found_in_trash' => sprintf( __( 'No %s found in trash', 'wp-job-manager' ), $plural ),
266
+ // translators: Placeholder %s is the singular label of the job listing post type.
267
+ 'parent' => sprintf( __( 'Parent %s', 'wp-job-manager' ), $singular ),
268
+ 'featured_image' => __( 'Company Logo', 'wp-job-manager' ),
269
+ 'set_featured_image' => __( 'Set company logo', 'wp-job-manager' ),
270
+ 'remove_featured_image' => __( 'Remove company logo', 'wp-job-manager' ),
271
+ 'use_featured_image' => __( 'Use as company logo', 'wp-job-manager' ),
272
+ ),
273
+ // translators: Placeholder %s is the plural label of the job listing post type.
274
+ 'description' => sprintf( __( 'This is where you can create and manage %s.', 'wp-job-manager' ), $plural ),
275
+ 'public' => true,
276
+ 'show_ui' => true,
277
+ 'capability_type' => 'job_listing',
278
+ 'map_meta_cap' => true,
279
+ 'publicly_queryable' => true,
280
+ 'exclude_from_search' => false,
281
+ 'hierarchical' => false,
282
+ 'rewrite' => $rewrite,
283
+ 'query_var' => true,
284
+ 'supports' => array( 'title', 'editor', 'custom-fields', 'publicize', 'thumbnail' ),
285
+ 'has_archive' => $has_archive,
286
+ 'show_in_nav_menus' => false,
287
+ 'delete_with_user' => true,
288
+ )
289
+ )
290
  );
291
 
292
  /**
297
  /**
298
  * Post status
299
  */
300
+ register_post_status(
301
+ 'expired',
302
+ array(
303
+ 'label' => _x( 'Expired', 'post status', 'wp-job-manager' ),
304
+ 'public' => true,
305
+ 'protected' => true,
306
+ 'exclude_from_search' => true,
307
+ 'show_in_admin_all_list' => true,
308
+ 'show_in_admin_status_list' => true,
309
+ // translators: Placeholder %s is the number of expired posts of this type.
310
+ 'label_count' => _n_noop( 'Expired <span class="count">(%s)</span>', 'Expired <span class="count">(%s)</span>', 'wp-job-manager' ),
311
+ )
312
+ );
313
+ register_post_status(
314
+ 'preview',
315
+ array(
316
+ 'label' => _x( 'Preview', 'post status', 'wp-job-manager' ),
317
+ 'public' => false,
318
+ 'exclude_from_search' => true,
319
+ 'show_in_admin_all_list' => false,
320
+ 'show_in_admin_status_list' => true,
321
+ // translators: Placeholder %s is the number of posts in a preview state.
322
+ 'label_count' => _n_noop( 'Preview <span class="count">(%s)</span>', 'Preview <span class="count">(%s)</span>', 'wp-job-manager' ),
323
+ )
324
+ );
325
  }
326
 
327
  /**
332
 
333
  $pending_jobs = WP_Job_Manager_Cache_Helper::get_listings_count();
334
 
335
+ // No need to go further if no pending jobs, menu is not set, or is not an array.
336
+ if ( empty( $pending_jobs ) || empty( $menu ) || ! is_array( $menu ) ) {
337
  return;
338
  }
339
 
340
+ // Try to pull menu_name from post type object to support themes/plugins that change the menu string.
341
  $post_type = get_post_type_object( 'job_listing' );
342
+ $plural = isset( $post_type->labels, $post_type->labels->menu_name ) ? $post_type->labels->menu_name : __( 'Job Listings', 'wp-job-manager' );
343
 
344
  foreach ( $menu as $key => $menu_item ) {
345
  if ( strpos( $menu_item[0], $plural ) === 0 ) {
346
+ $menu[ $key ][0] .= " <span class='awaiting-mod update-plugins count-" . esc_attr( $pending_jobs ) . "'><span class='pending-count'>" . absint( number_format_i18n( $pending_jobs ) ) . '</span></span>'; // WPCS: override ok.
347
  break;
348
  }
349
  }
403
  'posts_per_page' => isset( $_GET['posts_per_page'] ) ? absint( $_GET['posts_per_page'] ) : 10,
404
  'paged' => absint( get_query_var( 'paged', 1 ) ),
405
  'tax_query' => array(),
406
+ 'meta_query' => array(),
407
  );
408
 
409
  if ( ! empty( $_GET['search_location'] ) ) {
413
  $location_search[] = array(
414
  'key' => $meta_key,
415
  'value' => sanitize_text_field( $_GET['search_location'] ),
416
+ 'compare' => 'like',
417
  );
418
  }
419
  $query_args['meta_query'][] = $location_search;
423
  $query_args['tax_query'][] = array(
424
  'taxonomy' => 'job_listing_type',
425
  'field' => 'slug',
426
+ 'terms' => explode( ',', sanitize_text_field( $_GET['job_types'] ) ) + array( 0 ),
427
  );
428
  }
429
 
430
  if ( ! empty( $_GET['job_categories'] ) ) {
431
+ $cats = explode( ',', sanitize_text_field( $_GET['job_categories'] ) ) + array( 0 );
432
+ $field = is_numeric( $cats ) ? 'term_id' : 'slug';
433
+ $operator = 'all' === get_option( 'job_manager_category_filter_type', 'all' ) && count( $cats ) > 1 ? 'AND' : 'IN';
434
  $query_args['tax_query'][] = array(
435
  'taxonomy' => 'job_listing_category',
436
  'field' => $field,
437
  'terms' => $cats,
438
+ 'include_children' => 'AND' !== $operator,
439
+ 'operator' => $operator,
440
  );
441
  }
442
 
454
  unset( $query_args['tax_query'] );
455
  }
456
 
457
+ query_posts( apply_filters( 'job_feed_args', $query_args ) ); // phpcs:ignore WordPress.WP.DiscouragedFunctions
458
  add_action( 'rss2_ns', array( $this, 'job_feed_namespace' ) );
459
  add_action( 'rss2_item', array( $this, 'job_feed_item' ) );
460
  do_feed_rss2( false );
468
  */
469
  public function add_feed_query_args( $wp ) {
470
 
471
+ // Let's leave if not the job feed.
472
  if ( ! isset( $wp->query_vars['feed'] ) || 'job_feed' !== $wp->query_vars['feed'] ) {
473
  return;
474
  }
490
  * Adds a custom namespace to the job feed.
491
  */
492
  public function job_feed_namespace() {
493
+ echo 'xmlns:job_listing="' . esc_url( site_url() ) . '"' . "\n";
494
  }
495
 
496
  /**
497
  * Adds custom data to the job feed.
498
  */
499
  public function job_feed_item() {
500
+ $post_id = get_the_ID();
501
+ $location = get_the_job_location( $post_id );
502
+ $company = get_the_company_name( $post_id );
503
+ $job_types = wpjm_get_the_job_types( $post_id );
504
 
505
  if ( $location ) {
506
+ echo '<job_listing:location><![CDATA[' . esc_html( $location ) . "]]></job_listing:location>\n";
507
  }
508
  if ( ! empty( $job_types ) ) {
509
  $job_types_names = implode( ', ', wp_list_pluck( $job_types, 'name' ) );
510
+ echo '<job_listing:job_type><![CDATA[' . esc_html( $job_types_names ) . "]]></job_listing:job_type>\n";
511
  }
512
  if ( $company ) {
513
+ echo '<job_listing:company><![CDATA[' . esc_html( $company ) . "]]></job_listing:company>\n";
514
  }
515
 
516
  /**
527
  public function check_for_expired_jobs() {
528
  global $wpdb;
529
 
530
+ // Change status to expired.
531
+ $job_ids = $wpdb->get_col(
532
+ $wpdb->prepare( "
533
+ SELECT postmeta.post_id FROM {$wpdb->postmeta} as postmeta
534
+ LEFT JOIN {$wpdb->posts} as posts ON postmeta.post_id = posts.ID
535
+ WHERE postmeta.meta_key = '_job_expires'
536
+ AND postmeta.meta_value > 0
537
+ AND postmeta.meta_value < %s
538
+ AND posts.post_status = 'publish'
539
+ AND posts.post_type = 'job_listing'",
540
+ date( 'Y-m-d', current_time( 'timestamp' ) )
541
+ )
542
+ );
543
 
544
  if ( $job_ids ) {
545
  foreach ( $job_ids as $job_id ) {
546
+ $job_data = array();
547
+ $job_data['ID'] = $job_id;
548
  $job_data['post_status'] = 'expired';
549
  wp_update_post( $job_data );
550
  }
551
  }
552
 
553
+ // Delete old expired jobs.
554
  if ( apply_filters( 'job_manager_delete_expired_jobs', false ) ) {
555
+ $job_ids = $wpdb->get_col(
556
+ $wpdb->prepare( "
557
+ SELECT posts.ID FROM {$wpdb->posts} as posts
558
+ WHERE posts.post_type = 'job_listing'
559
+ AND posts.post_modified < %s
560
+ AND posts.post_status = 'expired'",
561
+ date( 'Y-m-d', strtotime( '-' . apply_filters( 'job_manager_delete_expired_jobs_days', 30 ) . ' days', current_time( 'timestamp' ) ) )
562
+ )
563
+ );
564
 
565
  if ( $job_ids ) {
566
  foreach ( $job_ids as $job_id ) {
576
  public function delete_old_previews() {
577
  global $wpdb;
578
 
579
+ // Delete old expired jobs.
580
+ $job_ids = $wpdb->get_col(
581
+ $wpdb->prepare( "
582
+ SELECT posts.ID FROM {$wpdb->posts} as posts
583
+ WHERE posts.post_type = 'job_listing'
584
+ AND posts.post_modified < %s
585
+ AND posts.post_status = 'preview'",
586
+ date( 'Y-m-d', strtotime( '-30 days', current_time( 'timestamp' ) ) )
587
+ )
588
+ );
589
 
590
  if ( $job_ids ) {
591
  foreach ( $job_ids as $job_id ) {
612
  * @param WP_Post $post
613
  */
614
  public function set_expiry( $post ) {
615
+ if ( 'job_listing' !== $post->post_type ) {
616
  return;
617
  }
618
 
619
+ // See if it is already set.
620
  if ( metadata_exists( 'post', $post->ID, '_job_expires' ) ) {
621
  $expires = get_post_meta( $post->ID, '_job_expires', true );
622
  if ( $expires && strtotime( $expires ) < current_time( 'timestamp' ) ) {
624
  }
625
  }
626
 
627
+ // See if the user has set the expiry manually.
628
+ if ( ! empty( $_POST['_job_expires'] ) ) {
629
+ update_post_meta( $post->ID, '_job_expires', date( 'Y-m-d', strtotime( sanitize_text_field( $_POST['_job_expires'] ) ) ) );
630
+ } elseif ( ! isset( $expires ) ) {
631
+ // No manual setting? Lets generate a date if there isn't already one.
 
632
  $expires = calculate_job_expiry( $post->ID );
633
  update_post_meta( $post->ID, '_job_expires', $expires );
634
 
635
+ // In case we are saving a post, ensure post data is updated so the field is not overridden.
636
+ if ( isset( $_POST['_job_expires'] ) ) {
637
+ $_POST['_job_expires'] = $expires;
638
  }
639
  }
640
  }
688
  switch_to_locale( get_locale() );
689
  }
690
 
691
+ $permalinks = wp_parse_args(
692
+ (array) get_option( 'wpjm_permalinks', array() ),
693
+ array(
694
+ 'job_base' => '',
695
+ 'category_base' => '',
696
+ 'type_base' => '',
697
+ )
698
+ );
699
 
700
  // Ensure rewrite slugs are set.
701
+ $permalinks['job_rewrite_slug'] = untrailingslashit( empty( $permalinks['job_base'] ) ? _x( 'job', 'Job permalink - resave permalinks after changing this', 'wp-job-manager' ) : $permalinks['job_base'] );
702
  $permalinks['category_rewrite_slug'] = untrailingslashit( empty( $permalinks['category_base'] ) ? _x( 'job-category', 'Job category slug - resave permalinks after changing this', 'wp-job-manager' ) : $permalinks['category_base'] );
703
+ $permalinks['type_rewrite_slug'] = untrailingslashit( empty( $permalinks['type_base'] ) ? _x( 'job-type', 'Job type slug - resave permalinks after changing this', 'wp-job-manager' ) : $permalinks['type_base'] );
704
 
705
  // Restore the original locale.
706
  if ( function_exists( 'restore_current_locale' ) && did_action( 'admin_init' ) ) {
734
  public function update_post_meta( $meta_id, $object_id, $meta_key, $meta_value ) {
735
  if ( 'job_listing' === get_post_type( $object_id ) ) {
736
  switch ( $meta_key ) {
737
+ case '_job_location':
738
  $this->maybe_update_geolocation_data( $meta_id, $object_id, $meta_key, $meta_value );
739
+ break;
740
+ case '_featured':
741
  $this->maybe_update_menu_order( $meta_id, $object_id, $meta_key, $meta_value );
742
+ break;
743
  }
744
  }
745
  }
747
  /**
748
  * Generates location data if a post is updated.
749
  *
750
+ * @param int $meta_id (Unused).
751
  * @param int $object_id
752
+ * @param string $meta_key (Unused).
753
  * @param mixed $meta_value
754
  */
755
  public function maybe_update_geolocation_data( $meta_id, $object_id, $meta_key, $meta_value ) {
759
  /**
760
  * Maybe sets menu_order if the featured status of a job is changed.
761
  *
762
+ * @param int $meta_id (Unused).
763
  * @param int $object_id
764
+ * @param string $meta_key (Unused).
765
  * @param mixed $meta_value
766
  */
767
  public function maybe_update_menu_order( $meta_id, $object_id, $meta_key, $meta_value ) {
768
  global $wpdb;
769
 
770
+ if ( 1 === intval( $meta_value ) ) {
771
+ $wpdb->update(
772
+ $wpdb->posts,
773
+ array( 'menu_order' => -1 ),
774
+ array( 'ID' => $object_id )
775
+ );
776
  } else {
777
+ $wpdb->update(
778
+ $wpdb->posts,
779
+ array( 'menu_order' => 0 ),
780
+ array(
781
+ 'ID' => $object_id,
782
+ 'menu_order' => -1,
783
+ )
784
+ );
785
  }
786
 
787
  clean_post_cache( $object_id );
includes/class-wp-job-manager-shortcodes.php CHANGED
@@ -1,6 +1,8 @@
1
  <?php
2
 
3
- if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
 
 
4
 
5
  /**
6
  * Handles the shortcodes for WP Job Manager.
@@ -63,7 +65,7 @@ class WP_Job_Manager_Shortcodes {
63
  public function shortcode_action_handler() {
64
  global $post;
65
 
66
- if ( is_page() && has_shortcode($post->post_content, 'job_dashboard' ) ) {
67
  $this->job_dashboard_handler();
68
  }
69
  }
@@ -80,6 +82,8 @@ class WP_Job_Manager_Shortcodes {
80
 
81
  /**
82
  * Handles actions on job dashboard.
 
 
83
  */
84
  public function job_dashboard_handler() {
85
  if ( ! empty( $_REQUEST['action'] ) && ! empty( $_REQUEST['_wpnonce'] ) && wp_verify_nonce( $_REQUEST['_wpnonce'], 'job_manager_my_job_actions' ) ) {
@@ -88,47 +92,51 @@ class WP_Job_Manager_Shortcodes {
88
  $job_id = absint( $_REQUEST['job_id'] );
89
 
90
  try {
91
- // Get Job
92
- $job = get_post( $job_id );
93
 
94
- // Check ownership
95
  if ( ! job_manager_user_can_edit_job( $job_id ) ) {
96
  throw new Exception( __( 'Invalid ID', 'wp-job-manager' ) );
97
  }
98
 
99
  switch ( $action ) {
100
- case 'mark_filled' :
101
- // Check status
102
- if ( $job->_filled == 1 )
103
  throw new Exception( __( 'This position has already been filled', 'wp-job-manager' ) );
 
104
 
105
- // Update
106
  update_post_meta( $job_id, '_filled', 1 );
107
 
108
- // Message
109
- $this->job_dashboard_message = '<div class="job-manager-message">' . sprintf( __( '%s has been filled', 'wp-job-manager' ), wpjm_get_the_job_title( $job ) ) . '</div>';
 
110
  break;
111
- case 'mark_not_filled' :
112
- // Check status
113
- if ( $job->_filled != 1 ) {
114
  throw new Exception( __( 'This position is not filled', 'wp-job-manager' ) );
115
  }
116
 
117
- // Update
118
  update_post_meta( $job_id, '_filled', 0 );
119
 
120
- // Message
121
- $this->job_dashboard_message = '<div class="job-manager-message">' . sprintf( __( '%s has been marked as not filled', 'wp-job-manager' ), wpjm_get_the_job_title( $job ) ) . '</div>';
 
122
  break;
123
- case 'delete' :
124
- // Trash it
125
  wp_trash_post( $job_id );
126
 
127
- // Message
128
- $this->job_dashboard_message = '<div class="job-manager-message">' . sprintf( __( '%s has been deleted', 'wp-job-manager' ), wpjm_get_the_job_title( $job ) ) . '</div>';
 
129
 
130
  break;
131
- case 'duplicate' :
132
  if ( ! job_manager_get_permalink( 'submit_job_form' ) ) {
133
  throw new Exception( __( 'Missing submission page.', 'wp-job-manager' ) );
134
  }
@@ -141,25 +149,38 @@ class WP_Job_Manager_Shortcodes {
141
  }
142
 
143
  break;
144
- case 'relist' :
145
  if ( ! job_manager_get_permalink( 'submit_job_form' ) ) {
146
  throw new Exception( __( 'Missing submission page.', 'wp-job-manager' ) );
147
  }
148
 
149
- // redirect to post page
150
  wp_redirect( add_query_arg( array( 'job_id' => absint( $job_id ) ), job_manager_get_permalink( 'submit_job_form' ) ) );
151
  exit;
152
-
153
- break;
154
- default :
155
  do_action( 'job_manager_job_dashboard_do_action_' . $action, $job_id );
156
  break;
157
  }
158
 
159
  do_action( 'job_manager_my_job_do_action', $action, $job_id );
160
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
161
  } catch ( Exception $e ) {
162
- $this->job_dashboard_message = '<div class="job-manager-error">' . $e->getMessage() . '</div>';
163
  }
164
  }
165
  }
@@ -177,9 +198,12 @@ class WP_Job_Manager_Shortcodes {
177
  return ob_get_clean();
178
  }
179
 
180
- extract( shortcode_atts( array(
181
- 'posts_per_page' => '25',
182
- ), $atts ) );
 
 
 
183
 
184
  wp_enqueue_script( 'wp-job-manager-job-dashboard' );
185
 
@@ -189,7 +213,7 @@ class WP_Job_Manager_Shortcodes {
189
  if ( ! empty( $_REQUEST['action'] ) ) {
190
  $action = sanitize_title( $_REQUEST['action'] );
191
 
192
- // Show alternative content if a plugin wants to
193
  if ( has_action( 'job_manager_job_dashboard_content_' . $action ) ) {
194
  do_action( 'job_manager_job_dashboard_content_' . $action, $atts );
195
 
@@ -197,30 +221,43 @@ class WP_Job_Manager_Shortcodes {
197
  }
198
  }
199
 
200
- // ....If not show the job dashboard
201
- $args = apply_filters( 'job_manager_get_dashboard_jobs_args', array(
202
- 'post_type' => 'job_listing',
203
- 'post_status' => array( 'publish', 'expired', 'pending' ),
204
- 'ignore_sticky_posts' => 1,
205
- 'posts_per_page' => $posts_per_page,
206
- 'offset' => ( max( 1, get_query_var('paged') ) - 1 ) * $posts_per_page,
207
- 'orderby' => 'date',
208
- 'order' => 'desc',
209
- 'author' => get_current_user_id()
210
- ) );
 
 
 
211
 
212
- $jobs = new WP_Query;
213
 
214
- echo $this->job_dashboard_message;
215
 
216
- $job_dashboard_columns = apply_filters( 'job_manager_job_dashboard_columns', array(
217
- 'job_title' => __( 'Title', 'wp-job-manager' ),
218
- 'filled' => __( 'Filled?', 'wp-job-manager' ),
219
- 'date' => __( 'Date Posted', 'wp-job-manager' ),
220
- 'expires' => __( 'Listing Expires', 'wp-job-manager' )
221
- ) );
 
 
 
222
 
223
- get_job_manager_template( 'job-dashboard.php', array( 'jobs' => $jobs->query( $args ), 'max_num_pages' => $jobs->max_num_pages, 'job_dashboard_columns' => $job_dashboard_columns ) );
 
 
 
 
 
 
 
224
 
225
  return ob_get_clean();
226
  }
@@ -231,7 +268,7 @@ class WP_Job_Manager_Shortcodes {
231
  public function edit_job() {
232
  global $job_manager;
233
 
234
- echo $job_manager->forms->get_form( 'edit-job' );
235
  }
236
 
237
  /**
@@ -243,145 +280,162 @@ class WP_Job_Manager_Shortcodes {
243
  public function output_jobs( $atts ) {
244
  ob_start();
245
 
246
- extract( $atts = shortcode_atts( apply_filters( 'job_manager_output_jobs_defaults', array(
247
- 'per_page' => get_option( 'job_manager_per_page' ),
248
- 'orderby' => 'featured',
249
- 'order' => 'DESC',
250
-
251
- // Filters + cats
252
- 'show_filters' => true,
253
- 'show_categories' => true,
254
- 'show_category_multiselect' => get_option( 'job_manager_enable_default_category_multiselect', false ),
255
- 'show_pagination' => false,
256
- 'show_more' => true,
257
-
258
- // Limit what jobs are shown based on category, post status, and type
259
- 'categories' => '',
260
- 'job_types' => '',
261
- 'post_status' => '',
262
- 'featured' => null, // True to show only featured, false to hide featured, leave null to show both.
263
- 'filled' => null, // True to show only filled, false to hide filled, leave null to show both/use the settings.
264
-
265
- // Default values for filters
266
- 'location' => '',
267
- 'keywords' => '',
268
- 'selected_category' => '',
269
- 'selected_job_types' => implode( ',', array_values( get_job_listing_types( 'id=>slug' ) ) ),
270
- ) ), $atts ) );
 
 
 
 
 
271
 
272
  if ( ! get_option( 'job_manager_enable_categories' ) ) {
273
- $show_categories = false;
274
  }
275
 
276
- // String and bool handling
277
- $show_filters = $this->string_to_bool( $show_filters );
278
- $show_categories = $this->string_to_bool( $show_categories );
279
- $show_category_multiselect = $this->string_to_bool( $show_category_multiselect );
280
- $show_more = $this->string_to_bool( $show_more );
281
- $show_pagination = $this->string_to_bool( $show_pagination );
282
 
283
- if ( ! is_null( $featured ) ) {
284
- $featured = ( is_bool( $featured ) && $featured ) || in_array( $featured, array( '1', 'true', 'yes' ) ) ? true : false;
285
  }
286
 
287
- if ( ! is_null( $filled ) ) {
288
- $filled = ( is_bool( $filled ) && $filled ) || in_array( $filled, array( '1', 'true', 'yes' ) ) ? true : false;
289
  }
290
 
291
- // Array handling
292
- $categories = is_array( $categories ) ? $categories : array_filter( array_map( 'trim', explode( ',', $categories ) ) );
293
- $job_types = is_array( $job_types ) ? $job_types : array_filter( array_map( 'trim', explode( ',', $job_types ) ) );
294
- $post_status = is_array( $post_status ) ? $post_status : array_filter( array_map( 'trim', explode( ',', $post_status ) ) );
295
- $selected_job_types = is_array( $selected_job_types ) ? $selected_job_types : array_filter( array_map( 'trim', explode( ',', $selected_job_types ) ) );
296
 
297
- // Get keywords and location from querystring if set
298
  if ( ! empty( $_GET['search_keywords'] ) ) {
299
- $keywords = sanitize_text_field( $_GET['search_keywords'] );
300
  }
301
  if ( ! empty( $_GET['search_location'] ) ) {
302
- $location = sanitize_text_field( $_GET['search_location'] );
303
  }
304
  if ( ! empty( $_GET['search_category'] ) ) {
305
- $selected_category = sanitize_text_field( $_GET['search_category'] );
306
  }
307
 
308
- $data_attributes = array(
309
- 'location' => $location,
310
- 'keywords' => $keywords,
311
- 'show_filters' => $show_filters ? 'true' : 'false',
312
- 'show_pagination' => $show_pagination ? 'true' : 'false',
313
- 'per_page' => $per_page,
314
- 'orderby' => $orderby,
315
- 'order' => $order,
316
- 'categories' => implode( ',', $categories ),
317
  );
318
- if ( $show_filters ) {
319
-
320
- get_job_manager_template( 'job-filters.php', array( 'per_page' => $per_page, 'orderby' => $orderby, 'order' => $order, 'show_categories' => $show_categories, 'categories' => $categories, 'selected_category' => $selected_category, 'job_types' => $job_types, 'atts' => $atts, 'location' => $location, 'keywords' => $keywords, 'selected_job_types' => $selected_job_types, 'show_category_multiselect' => $show_category_multiselect ) );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
321
 
322
  get_job_manager_template( 'job-listings-start.php' );
323
  get_job_manager_template( 'job-listings-end.php' );
324
 
325
- if ( ! $show_pagination && $show_more ) {
326
- echo '<a class="load_more_jobs" href="#" style="display:none;"><strong>' . __( 'Load more listings', 'wp-job-manager' ) . '</strong></a>';
327
  }
328
-
329
  } else {
330
- $jobs = get_job_listings( apply_filters( 'job_manager_output_jobs_args', array(
331
- 'search_location' => $location,
332
- 'search_keywords' => $keywords,
333
- 'post_status' => $post_status,
334
- 'search_categories' => $categories,
335
- 'job_types' => $job_types,
336
- 'orderby' => $orderby,
337
- 'order' => $order,
338
- 'posts_per_page' => $per_page,
339
- 'featured' => $featured,
340
- 'filled' => $filled
341
- ) ) );
342
-
343
- if ( ! empty( $job_types ) ) {
344
- $data_attributes[ 'job_types' ] = implode( ',', $job_types );
 
 
 
 
 
345
  }
346
 
347
- if ( $jobs->have_posts() ) : ?>
348
-
349
- <?php get_job_manager_template( 'job-listings-start.php' ); ?>
350
-
351
- <?php while ( $jobs->have_posts() ) : $jobs->the_post(); ?>
352
- <?php get_job_manager_template_part( 'content', 'job_listing' ); ?>
353
- <?php endwhile; ?>
354
-
355
- <?php get_job_manager_template( 'job-listings-end.php' ); ?>
356
-
357
- <?php if ( $jobs->found_posts > $per_page && $show_more ) : ?>
358
-
359
- <?php wp_enqueue_script( 'wp-job-manager-ajax-filters' ); ?>
360
-
361
- <?php if ( $show_pagination ) : ?>
362
- <?php echo get_job_listing_pagination( $jobs->max_num_pages ); ?>
363
- <?php else : ?>
364
- <a class="load_more_jobs" href="#"><strong><?php _e( 'Load more listings', 'wp-job-manager' ); ?></strong></a>
365
- <?php endif; ?>
366
-
367
- <?php endif; ?>
368
-
369
- <?php else :
370
  do_action( 'job_manager_output_jobs_no_results' );
371
- endif;
372
-
373
  wp_reset_postdata();
374
  }
375
 
376
  $data_attributes_string = '';
377
- if ( ! is_null( $featured ) ) {
378
- $data_attributes[ 'featured' ] = $featured ? 'true' : 'false';
379
  }
380
- if ( ! is_null( $filled ) ) {
381
- $data_attributes[ 'filled' ] = $filled ? 'true' : 'false';
382
  }
383
- if ( ! empty( $post_status ) ) {
384
- $data_attributes[ 'post_status' ] = implode( ',', $post_status );
385
  }
386
  foreach ( $data_attributes as $key => $value ) {
387
  $data_attributes_string .= 'data-' . esc_attr( $key ) . '="' . esc_attr( $value ) . '" ';
@@ -406,7 +460,7 @@ class WP_Job_Manager_Shortcodes {
406
  * @return bool
407
  */
408
  public function string_to_bool( $value ) {
409
- return ( is_bool( $value ) && $value ) || in_array( $value, array( '1', 'true', 'yes' ) ) ? true : false;
410
  }
411
 
412
  /**
@@ -415,12 +469,17 @@ class WP_Job_Manager_Shortcodes {
415
  * @param array $atts
416
  */
417
  public function job_filter_job_types( $atts ) {
418
- extract( $atts );
419
-
420
- $job_types = array_filter( array_map( 'trim', explode( ',', $job_types ) ) );
421
- $selected_job_types = array_filter( array_map( 'trim', explode( ',', $selected_job_types ) ) );
422
-
423
- get_job_manager_template( 'job-filter-job-types.php', array( 'job_types' => $job_types, 'atts' => $atts, 'selected_job_types' => $selected_job_types ) );
 
 
 
 
 
424
  }
425
 
426
  /**
@@ -437,11 +496,13 @@ class WP_Job_Manager_Shortcodes {
437
  * @return string|null
438
  */
439
  public function output_job( $atts ) {
440
- extract( shortcode_atts( array(
441
- 'id' => '',
442
- ), $atts ) );
 
 
443
 
444
- if ( ! $id ) {
445
  return;
446
  }
447
 
@@ -450,22 +511,18 @@ class WP_Job_Manager_Shortcodes {
450
  $args = array(
451
  'post_type' => 'job_listing',
452
  'post_status' => 'publish',
453
- 'p' => $id
454
  );
455
 
456
  $jobs = new WP_Query( $args );
457
 
458
- if ( $jobs->have_posts() ) : ?>
459
-
460
- <?php while ( $jobs->have_posts() ) : $jobs->the_post(); ?>
461
-
462
- <h1><?php wpjm_the_job_title(); ?></h1>
463
-
464
- <?php get_job_manager_template_part( 'content-single', 'job_listing' ); ?>
465
-
466
- <?php endwhile; ?>
467
-
468
- <?php endif;
469
 
470
  wp_reset_postdata();
471
 
@@ -479,50 +536,50 @@ class WP_Job_Manager_Shortcodes {
479
  * @return string
480
  */
481
  public function output_job_summary( $atts ) {
482
- extract( shortcode_atts( array(
483
- 'id' => '',
484
- 'width' => '250px',
485
- 'align' => 'left',
486
- 'featured' => null, // True to show only featured, false to hide featured, leave null to show both (when leaving out id)
487
- 'limit' => 1
488
- ), $atts ) );
 
 
489
 
490
  ob_start();
491
 
492
  $args = array(
493
  'post_type' => 'job_listing',
494
- 'post_status' => 'publish'
495
  );
496
 
497
- if ( ! $id ) {
498
- $args['posts_per_page'] = $limit;
499
  $args['orderby'] = 'rand';
500
- if ( ! is_null( $featured ) ) {
501
- $args['meta_query'] = array( array(
502
- 'key' => '_featured',
503
- 'value' => '1',
504
- 'compare' => $featured ? '=' : '!='
505
- ) );
 
 
506
  }
507
  } else {
508
- $args['p'] = absint( $id );
509
  }
510
 
511
  $jobs = new WP_Query( $args );
512
 
513
- if ( $jobs->have_posts() ) : ?>
514
-
515
- <?php while ( $jobs->have_posts() ) : $jobs->the_post(); ?>
516
-
517
- <div class="job_summary_shortcode align<?php echo $align ?>" style="width: <?php echo $width ? $width : auto; ?>">
518
-
519
- <?php get_job_manager_template_part( 'content-summary', 'job_listing' ); ?>
520
-
521
- </div>
522
-
523
- <?php endwhile; ?>
524
-
525
- <?php endif;
526
 
527
  wp_reset_postdata();
528
 
@@ -536,15 +593,18 @@ class WP_Job_Manager_Shortcodes {
536
  * @return string
537
  */
538
  public function output_job_apply( $atts ) {
539
- extract( shortcode_atts( array(
540
- 'id' => ''
541
- ), $atts ) );
 
 
 
542
 
543
  ob_start();
544
 
545
  $args = array(
546
  'post_type' => 'job_listing',
547
- 'post_status' => 'publish'
548
  );
549
 
550
  if ( ! $id ) {
@@ -555,28 +615,20 @@ class WP_Job_Manager_Shortcodes {
555
 
556
  $jobs = new WP_Query( $args );
557
 
558
- if ( $jobs->have_posts() ) : ?>
559
-
560
- <?php while ( $jobs->have_posts() ) :
561
  $jobs->the_post();
562
  $apply = get_the_job_application_method();
563
- ?>
564
-
565
- <?php do_action( 'job_manager_before_job_apply_' . absint( $id ) ); ?>
566
-
567
- <?php if ( apply_filters( 'job_manager_show_job_apply_' . absint( $id ), true ) ) : ?>
568
- <div class="job-manager-application-wrapper">
569
- <?php do_action( 'job_manager_application_details_' . $apply->type, $apply ); ?>
570
- </div>
571
- <?php endif; ?>
572
-
573
- <?php do_action( 'job_manager_after_job_apply_' . absint( $id ) ); ?>
574
-
575
- <?php endwhile; ?>
576
-
577
- <?php endif;
578
-
579
- wp_reset_postdata();
580
 
581
  return ob_get_clean();
582
  }
1
  <?php
2
 
3
+ if ( ! defined( 'ABSPATH' ) ) {
4
+ exit; // Exit if accessed directly.
5
+ }
6
 
7
  /**
8
  * Handles the shortcodes for WP Job Manager.
65
  public function shortcode_action_handler() {
66
  global $post;
67
 
68
+ if ( is_page() && has_shortcode( $post->post_content, 'job_dashboard' ) ) {
69
  $this->job_dashboard_handler();
70
  }
71
  }
82
 
83
  /**
84
  * Handles actions on job dashboard.
85
+ *
86
+ * @throws Exception On action handling error.
87
  */
88
  public function job_dashboard_handler() {
89
  if ( ! empty( $_REQUEST['action'] ) && ! empty( $_REQUEST['_wpnonce'] ) && wp_verify_nonce( $_REQUEST['_wpnonce'], 'job_manager_my_job_actions' ) ) {
92
  $job_id = absint( $_REQUEST['job_id'] );
93
 
94
  try {
95
+ // Get Job.
96
+ $job = get_post( $job_id );
97
 
98
+ // Check ownership.
99
  if ( ! job_manager_user_can_edit_job( $job_id ) ) {
100
  throw new Exception( __( 'Invalid ID', 'wp-job-manager' ) );
101
  }
102
 
103
  switch ( $action ) {
104
+ case 'mark_filled':
105
+ // Check status.
106
+ if ( 1 === intval( $job->_filled ) ) {
107
  throw new Exception( __( 'This position has already been filled', 'wp-job-manager' ) );
108
+ }
109
 
110
+ // Update.
111
  update_post_meta( $job_id, '_filled', 1 );
112
 
113
+ // Message.
114
+ // translators: Placeholder %s is the job listing title.
115
+ $this->job_dashboard_message = '<div class="job-manager-message">' . esc_html( sprintf( __( '%s has been filled', 'wp-job-manager' ), wpjm_get_the_job_title( $job ) ) ) . '</div>';
116
  break;
117
+ case 'mark_not_filled':
118
+ // Check status.
119
+ if ( 1 !== intval( $job->_filled ) ) {
120
  throw new Exception( __( 'This position is not filled', 'wp-job-manager' ) );
121
  }
122
 
123
+ // Update.
124
  update_post_meta( $job_id, '_filled', 0 );
125
 
126
+ // Message.
127
+ // translators: Placeholder %s is the job listing title.
128
+ $this->job_dashboard_message = '<div class="job-manager-message">' . esc_html( sprintf( __( '%s has been marked as not filled', 'wp-job-manager' ), wpjm_get_the_job_title( $job ) ) ) . '</div>';
129
  break;
130
+ case 'delete':
131
+ // Trash it.
132
  wp_trash_post( $job_id );
133
 
134
+ // Message.
135
+ // translators: Placeholder %s is the job listing title.
136
+ $this->job_dashboard_message = '<div class="job-manager-message">' . esc_html( sprintf( __( '%s has been deleted', 'wp-job-manager' ), wpjm_get_the_job_title( $job ) ) ) . '</div>';
137
 
138
  break;
139
+ case 'duplicate':
140
  if ( ! job_manager_get_permalink( 'submit_job_form' ) ) {
141
  throw new Exception( __( 'Missing submission page.', 'wp-job-manager' ) );
142
  }
149
  }
150
 
151
  break;
152
+ case 'relist':
153
  if ( ! job_manager_get_permalink( 'submit_job_form' ) ) {
154
  throw new Exception( __( 'Missing submission page.', 'wp-job-manager' ) );
155
  }
156
 
157
+ // redirect to post page.
158
  wp_redirect( add_query_arg( array( 'job_id' => absint( $job_id ) ), job_manager_get_permalink( 'submit_job_form' ) ) );
159
  exit;
160
+ default:
 
 
161
  do_action( 'job_manager_job_dashboard_do_action_' . $action, $job_id );
162
  break;
163
  }
164
 
165
  do_action( 'job_manager_my_job_do_action', $action, $job_id );
166
 
167
+ /**
168
+ * Set a success message for a custom dashboard action handler.
169
+ *
170
+ * When left empty, no success message will be shown.
171
+ *
172
+ * @since 1.31.1
173
+ *
174
+ * @param string $message Text for the success message. Default: empty string.
175
+ * @param string $action The name of the custom action.
176
+ * @param int $job_id The ID for the job that's been altered.
177
+ */
178
+ $success_message = apply_filters( 'job_manager_job_dashboard_success_message', '', $action, $job_id );
179
+ if ( $success_message ) {
180
+ $this->job_dashboard_message = '<div class="job-manager-message">' . $success_message . '</div>';
181
+ }
182
  } catch ( Exception $e ) {
183
+ $this->job_dashboard_message = '<div class="job-manager-error">' . wp_kses_post( $e->getMessage() ) . '</div>';
184
  }
185
  }
186
  }
198
  return ob_get_clean();
199
  }
200
 
201
+ $new_atts = shortcode_atts(
202
+ array(
203
+ 'posts_per_page' => '25',
204
+ ), $atts
205
+ );
206
+ $posts_per_page = $new_atts['posts_per_page'];
207
 
208
  wp_enqueue_script( 'wp-job-manager-job-dashboard' );
209
 
213
  if ( ! empty( $_REQUEST['action'] ) ) {
214
  $action = sanitize_title( $_REQUEST['action'] );
215
 
216
+ // Show alternative content if a plugin wants to.
217
  if ( has_action( 'job_manager_job_dashboard_content_' . $action ) ) {
218
  do_action( 'job_manager_job_dashboard_content_' . $action, $atts );
219
 
221
  }
222
  }
223
 
224
+ // ....If not show the job dashboard.
225
+ $args = apply_filters(
226
+ 'job_manager_get_dashboard_jobs_args',
227
+ array(
228
+ 'post_type' => 'job_listing',
229
+ 'post_status' => array( 'publish', 'expired', 'pending' ),
230
+ 'ignore_sticky_posts' => 1,
231
+ 'posts_per_page' => $posts_per_page,
232
+ 'offset' => ( max( 1, get_query_var( 'paged' ) ) - 1 ) * $posts_per_page,
233
+ 'orderby' => 'date',
234
+ 'order' => 'desc',
235
+ 'author' => get_current_user_id(),
236
+ )
237
+ );
238
 
239
+ $jobs = new WP_Query();
240
 
241
+ echo wp_kses_post( $this->job_dashboard_message );
242
 
243
+ $job_dashboard_columns = apply_filters(
244
+ 'job_manager_job_dashboard_columns',
245
+ array(
246
+ 'job_title' => __( 'Title', 'wp-job-manager' ),
247
+ 'filled' => __( 'Filled?', 'wp-job-manager' ),
248
+ 'date' => __( 'Date Posted', 'wp-job-manager' ),
249
+ 'expires' => __( 'Listing Expires', 'wp-job-manager' ),
250
+ )
251
+ );
252
 
253
+ get_job_manager_template(
254
+ 'job-dashboard.php',
255
+ array(
256
+ 'jobs' => $jobs->query( $args ),
257
+ 'max_num_pages' => $jobs->max_num_pages,
258
+ 'job_dashboard_columns' => $job_dashboard_columns,
259
+ )
260
+ );
261
 
262
  return ob_get_clean();
263
  }
268
  public function edit_job() {
269
  global $job_manager;
270
 
271
+ echo $job_manager->forms->get_form( 'edit-job' ); // WPCS: XSS ok.
272
  }
273
 
274
  /**
280
  public function output_jobs( $atts ) {
281
  ob_start();
282
 
283
+ $atts = shortcode_atts(
284
+ apply_filters(
285
+ 'job_manager_output_jobs_defaults',
286
+ array(
287
+ 'per_page' => get_option( 'job_manager_per_page' ),
288
+ 'orderby' => 'featured',
289
+ 'order' => 'DESC',
290
+
291
+ // Filters + cats.
292
+ 'show_filters' => true,
293
+ 'show_categories' => true,
294
+ 'show_category_multiselect' => get_option( 'job_manager_enable_default_category_multiselect', false ),
295
+ 'show_pagination' => false,
296
+ 'show_more' => true,
297
+
298
+ // Limit what jobs are shown based on category, post status, and type.
299
+ 'categories' => '',
300
+ 'job_types' => '',
301
+ 'post_status' => '',
302
+ 'featured' => null, // True to show only featured, false to hide featured, leave null to show both.
303
+ 'filled' => null, // True to show only filled, false to hide filled, leave null to show both/use the settings.
304
+
305
+ // Default values for filters.
306
+ 'location' => '',
307
+ 'keywords' => '',
308
+ 'selected_category' => '',
309
+ 'selected_job_types' => implode( ',', array_values( get_job_listing_types( 'id=>slug' ) ) ),
310
+ )
311
+ ), $atts
312
+ );
313
 
314
  if ( ! get_option( 'job_manager_enable_categories' ) ) {
315
+ $atts['show_categories'] = false;
316
  }
317
 
318
+ // String and bool handling.
319
+ $atts['show_filters'] = $this->string_to_bool( $atts['show_filters'] );
320
+ $atts['show_categories'] = $this->string_to_bool( $atts['show_categories'] );
321
+ $atts['show_category_multiselect'] = $this->string_to_bool( $atts['show_category_multiselect'] );
322
+ $atts['show_more'] = $this->string_to_bool( $atts['show_more'] );
323
+ $atts['show_pagination'] = $this->string_to_bool( $atts['show_pagination'] );
324
 
325
+ if ( ! is_null( $atts['featured'] ) ) {
326
+ $atts['featured'] = ( is_bool( $atts['featured'] ) && $atts['featured'] ) || in_array( $atts['featured'], array( 1, '1', 'true', 'yes' ), true );
327
  }
328
 
329
+ if ( ! is_null( $atts['filled'] ) ) {
330
+ $atts['filled'] = ( is_bool( $atts['filled'] ) && $atts['filled'] ) || in_array( $atts['filled'], array( 1, '1', 'true', 'yes' ), true );
331
  }
332
 
333
+ // Array handling.
334
+ $atts['categories'] = is_array( $atts['categories'] ) ? $atts['categories'] : array_filter( array_map( 'trim', explode( ',', $atts['categories'] ) ) );
335
+ $atts['job_types'] = is_array( $atts['job_types'] ) ? $atts['job_types'] : array_filter( array_map( 'trim', explode( ',', $atts['job_types'] ) ) );
336
+ $atts['post_status'] = is_array( $atts['post_status'] ) ? $atts['post_status'] : array_filter( array_map( 'trim', explode( ',', $atts['post_status'] ) ) );
337
+ $atts['selected_job_types'] = is_array( $atts['selected_job_types'] ) ? $atts['selected_job_types'] : array_filter( array_map( 'trim', explode( ',', $atts['selected_job_types'] ) ) );
338
 
339
+ // Get keywords and location from querystring if set.
340
  if ( ! empty( $_GET['search_keywords'] ) ) {
341
+ $atts['keywords'] = sanitize_text_field( $_GET['search_keywords'] );
342
  }
343
  if ( ! empty( $_GET['search_location'] ) ) {
344
+ $atts['location'] = sanitize_text_field( $_GET['search_location'] );
345
  }
346
  if ( ! empty( $_GET['search_category'] ) ) {
347
+ $atts['selected_category'] = sanitize_text_field( $_GET['search_category'] );
348
  }
349
 
350
+ $data_attributes = array(
351
+ 'location' => $atts['location'],
352
+ 'keywords' => $atts['keywords'],
353
+ 'show_filters' => $atts['show_filters'] ? 'true' : 'false',
354
+ 'show_pagination' => $atts['show_pagination'] ? 'true' : 'false',
355
+ 'per_page' => $atts['per_page'],
356
+ 'orderby' => $atts['orderby'],
357
+ 'order' => $atts['order'],
358
+ 'categories' => implode( ',', $atts['categories'] ),
359
  );
360
+ if ( $atts['show_filters'] ) {
361
+
362
+ get_job_manager_template(
363
+ 'job-filters.php',
364
+ array(
365
+ 'per_page' => $atts['per_page'],
366
+ 'orderby' => $atts['orderby'],
367
+ 'order' => $atts['order'],
368
+ 'show_categories' => $atts['show_categories'],
369
+ 'categories' => $atts['categories'],
370
+ 'selected_category' => $atts['selected_category'],
371
+ 'job_types' => $atts['job_types'],
372
+ 'atts' => $atts,
373
+ 'location' => $atts['location'],
374
+ 'keywords' => $atts['keywords'],
375
+ 'selected_job_types' => $atts['selected_job_types'],
376
+ 'show_category_multiselect' => $atts['show_category_multiselect'],
377
+ )
378
+ );
379
 
380
  get_job_manager_template( 'job-listings-start.php' );
381
  get_job_manager_template( 'job-listings-end.php' );
382
 
383
+ if ( ! $atts['show_pagination'] && $atts['show_more'] ) {
384
+ echo '<a class="load_more_jobs" href="#" style="display:none;"><strong>' . esc_html__( 'Load more listings', 'wp-job-manager' ) . '</strong></a>';
385
  }
 
386
  } else {
387
+ $jobs = get_job_listings(
388
+ apply_filters(
389
+ 'job_manager_output_jobs_args',
390
+ array(
391
+ 'search_location' => $atts['location'],
392
+ 'search_keywords' => $atts['keywords'],
393
+ 'post_status' => $atts['post_status'],
394
+ 'search_categories' => $atts['categories'],
395
+ 'job_types' => $atts['job_types'],
396
+ 'orderby' => $atts['orderby'],
397
+ 'order' => $atts['order'],
398
+ 'posts_per_page' => $atts['per_page'],
399
+ 'featured' => $atts['featured'],
400
+ 'filled' => $atts['filled'],
401
+ )
402
+ )
403
+ );
404
+
405
+ if ( ! empty( $atts['job_types'] ) ) {
406
+ $data_attributes['job_types'] = implode( ',', $atts['job_types'] );
407
  }
408
 
409
+ if ( $jobs->have_posts() ) {
410
+ get_job_manager_template( 'job-listings-start.php' );
411
+ while ( $jobs->have_posts() ) {
412
+ $jobs->the_post();
413
+ get_job_manager_template_part( 'content', 'job_listing' );
414
+ }
415
+ get_job_manager_template( 'job-listings-end.php' );
416
+ if ( $jobs->found_posts > $atts['per_page'] && $atts['show_more'] ) {
417
+ wp_enqueue_script( 'wp-job-manager-ajax-filters' );
418
+ if ( $atts['show_pagination'] ) {
419
+ echo get_job_listing_pagination( $jobs->max_num_pages ); // WPCS: XSS ok.
420
+ } else {
421
+ echo '<a class="load_more_jobs" href="#"><strong>' . esc_html__( 'Load more listings', 'wp-job-manager' ) . '</strong></a>';
422
+ }
423
+ }
424
+ } else {
 
 
 
 
 
 
 
425
  do_action( 'job_manager_output_jobs_no_results' );
426
+ }
 
427
  wp_reset_postdata();
428
  }
429
 
430
  $data_attributes_string = '';
431
+ if ( ! is_null( $atts['featured'] ) ) {
432
+ $data_attributes['featured'] = $atts['featured'] ? 'true' : 'false';
433
  }
434
+ if ( ! is_null( $atts['filled'] ) ) {
435
+ $data_attributes['filled'] = $atts['filled'] ? 'true' : 'false';
436
  }
437
+ if ( ! empty( $atts['post_status'] ) ) {
438
+ $data_attributes['post_status'] = implode( ',', $atts['post_status'] );
439
  }
440
  foreach ( $data_attributes as $key => $value ) {
441
  $data_attributes_string .= 'data-' . esc_attr( $key ) . '="' . esc_attr( $value ) . '" ';
460
  * @return bool
461
  */
462
  public function string_to_bool( $value ) {
463
+ return ( is_bool( $value ) && $value ) || in_array( $value, array( 1, '1', 'true', 'yes' ), true );
464
  }
465
 
466
  /**
469
  * @param array $atts
470
  */
471
  public function job_filter_job_types( $atts ) {
472
+ $job_types = is_array( $atts['job_types'] ) ? $atts['job_types'] : array_filter( array_map( 'trim', explode( ',', $atts['job_types'] ) ) );
473
+ $selected_job_types = is_array( $atts['selected_job_types'] ) ? $atts['selected_job_types'] : array_filter( array_map( 'trim', explode( ',', $atts['selected_job_types'] ) ) );
474
+
475
+ get_job_manager_template(
476
+ 'job-filter-job-types.php',
477
+ array(
478
+ 'job_types' => $job_types,
479
+ 'atts' => $atts,
480
+ 'selected_job_types' => $selected_job_types,
481
+ )
482
+ );
483
  }
484
 
485
  /**
496
  * @return string|null
497
  */
498
  public function output_job( $atts ) {
499
+ $atts = shortcode_atts(
500
+ array(
501
+ 'id' => '',
502
+ ), $atts
503
+ );
504
 
505
+ if ( ! $atts['id'] ) {
506
  return;
507
  }
508
 
511
  $args = array(
512
  'post_type' => 'job_listing',
513
  'post_status' => 'publish',
514
+ 'p' => $atts['id'],
515
  );
516
 
517
  $jobs = new WP_Query( $args );
518
 
519
+ if ( $jobs->have_posts() ) {
520
+ while ( $jobs->have_posts() ) {
521
+ $jobs->the_post();
522
+ echo '<h1>' . esc_html( wpjm_get_the_job_title() ) . '</h1>';
523
+ get_job_manager_template_part( 'content-single', 'job_listing' );
524
+ }
525
+ }
 
 
 
 
526
 
527
  wp_reset_postdata();
528
 
536
  * @return string
537
  */
538
  public function output_job_summary( $atts ) {
539
+ $atts = shortcode_atts(
540
+ array(
541
+ 'id' => '',
542
+ 'width' => '250px',
543
+ 'align' => 'left',
544
+ 'featured' => null, // True to show only featured, false to hide featured, leave null to show both (when leaving out id).
545
+ 'limit' => 1,
546
+ ), $atts
547
+ );
548
 
549
  ob_start();
550
 
551
  $args = array(
552
  'post_type' => 'job_listing',
553
+ 'post_status' => 'publish',
554
  );
555
 
556
+ if ( ! $atts['id'] ) {
557
+ $args['posts_per_page'] = $atts['limit'];
558
  $args['orderby'] = 'rand';
559
+ if ( ! is_null( $atts['featured'] ) ) {
560
+ $args['meta_query'] = array(
561
+ array(
562
+ 'key' => '_featured',
563
+ 'value' => '1',
564
+ 'compare' => $atts['featured'] ? '=' : '!=',
565
+ ),
566
+ );
567
  }
568
  } else {
569
+ $args['p'] = absint( $atts['id'] );
570
  }
571
 
572
  $jobs = new WP_Query( $args );
573
 
574
+ if ( $jobs->have_posts() ) {
575
+ while ( $jobs->have_posts() ) {
576
+ $jobs->the_post();
577
+ $width = $atts['width'] ? $atts['width'] : 'auto';
578
+ echo '<div class="job_summary_shortcode align' . esc_attr( $atts['align'] ) . '" style="width: ' . esc_attr( $width ) . '">';
579
+ get_job_manager_template_part( 'content-summary', 'job_listing' );
580
+ echo '</div>';
581
+ }
582
+ }
 
 
 
 
583
 
584
  wp_reset_postdata();
585
 
593
  * @return string
594
  */
595
  public function output_job_apply( $atts ) {
596
+ $new_atts = shortcode_atts(
597
+ array(
598
+ 'id' => '',
599
+ ), $atts
600
+ );
601
+ $id = $new_atts['id'];
602
 
603
  ob_start();
604
 
605
  $args = array(
606
  'post_type' => 'job_listing',
607
+ 'post_status' => 'publish',
608
  );
609
 
610
  if ( ! $id ) {
615
 
616
  $jobs = new WP_Query( $args );
617
 
618
+ if ( $jobs->have_posts() ) {
619
+ while ( $jobs->have_posts() ) {
 
620
  $jobs->the_post();
621
  $apply = get_the_job_application_method();
622
+ do_action( 'job_manager_before_job_apply_' . absint( $id ) );
623
+ if ( apply_filters( 'job_manager_show_job_apply_' . absint( $id ), true ) ) {
624
+ echo '<div class="job-manager-application-wrapper">';
625
+ do_action( 'job_manager_application_details_' . $apply->type, $apply );
626
+ echo '</div>';
627
+ }
628
+ do_action( 'job_manager_after_job_apply_' . absint( $id ) );
629
+ }
630
+ wp_reset_postdata();
631
+ }
 
 
 
 
 
 
 
632
 
633
  return ob_get_clean();
634
  }
includes/class-wp-job-manager-usage-tracking-data.php CHANGED
@@ -58,16 +58,8 @@ class WP_Job_Manager_Usage_Tracking_Data {
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
  }
@@ -180,7 +172,7 @@ class WP_Job_Manager_Usage_Tracking_Data {
180
  *
181
  * @param string $job_type Job type to search for.
182
  *
183
- * @return array Number of published or expired jobs for a particular job type.
184
  **/
185
  private static function get_jobs_by_type_count( $job_type ) {
186
  $query = new WP_Query(
@@ -231,7 +223,7 @@ class WP_Job_Manager_Usage_Tracking_Data {
231
  *
232
  * @since 1.30.0
233
  *
234
- * @return array Number of job listings associated with at least one job type.
235
  **/
236
  private static function get_job_type_count() {
237
  $query = new WP_Query(
@@ -259,18 +251,20 @@ class WP_Job_Manager_Usage_Tracking_Data {
259
  * @return int the number of job listings.
260
  */
261
  private static function get_jobs_count_with_meta( $meta_key ) {
262
- $query = new WP_Query( array(
263
- 'post_type' => 'job_listing',
264
- 'post_status' => array( 'publish', 'expired' ),
265
- 'fields' => 'ids',
266
- 'meta_query' => array(
267
- array(
268
- 'key' => $meta_key,
269
- 'value' => '[^[:space:]]',
270
- 'compare' => 'REGEXP',
 
 
271
  ),
272
- ),
273
- ) );
274
 
275
  return $query->found_posts;
276
  }
@@ -284,17 +278,19 @@ class WP_Job_Manager_Usage_Tracking_Data {
284
  * @return int the number of job listings.
285
  */
286
  private static function get_jobs_count_with_checked_meta( $meta_key ) {
287
- $query = new WP_Query( array(
288
- 'post_type' => 'job_listing',
289
- 'post_status' => array( 'publish', 'expired' ),
290
- 'fields' => 'ids',
291
- 'meta_query' => array(
292
- array(
293
- 'key' => $meta_key,
294
- 'value' => '1',
 
 
295
  ),
296
- ),
297
- ) );
298
 
299
  return $query->found_posts;
300
  }
@@ -305,12 +301,14 @@ class WP_Job_Manager_Usage_Tracking_Data {
305
  * @return int the number of job listings.
306
  */
307
  private static function get_jobs_by_guests() {
308
- $query = new WP_Query( array(
309
- 'post_type' => 'job_listing',
310
- 'post_status' => array( 'publish', 'expired' ),
311
- 'fields' => 'ids',
312
- 'author__in' => array( 0 ),
313
- ) );
 
 
314
 
315
  return $query->found_posts;
316
  }
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_part_time' => self::get_jobs_by_type_count( 'part-time' ),
 
 
 
 
 
62
  'jobs_temp' => self::get_jobs_by_type_count( 'temporary' ),
 
63
  'jobs_by_guests' => self::get_jobs_by_guests(),
64
  );
65
  }
172
  *
173
  * @param string $job_type Job type to search for.
174
  *
175
+ * @return int Number of published or expired jobs for a particular job type.
176
  **/
177
  private static function get_jobs_by_type_count( $job_type ) {
178
  $query = new WP_Query(
223
  *
224
  * @since 1.30.0
225
  *
226
+ * @return int Number of job listings associated with at least one job type.
227
  **/
228
  private static function get_job_type_count() {
229
  $query = new WP_Query(
251
  * @return int the number of job listings.
252
  */
253
  private static function get_jobs_count_with_meta( $meta_key ) {
254
+ $query = new WP_Query(
255
+ array(
256
+ 'post_type' => 'job_listing',
257
+ 'post_status' => array( 'publish', 'expired' ),
258
+ 'fields' => 'ids',
259
+ 'meta_query' => array(
260
+ array(
261
+ 'key' => $meta_key,
262
+ 'value' => '[^[:space:]]',
263
+ 'compare' => 'REGEXP',
264
+ ),
265
  ),
266
+ )
267
+ );
268
 
269
  return $query->found_posts;
270
  }
278
  * @return int the number of job listings.
279
  */
280
  private static function get_jobs_count_with_checked_meta( $meta_key ) {
281
+ $query = new WP_Query(
282
+ array(
283
+ 'post_type' => 'job_listing',
284
+ 'post_status' => array( 'publish', 'expired' ),
285
+ 'fields' => 'ids',
286
+ 'meta_query' => array(
287
+ array(
288
+ 'key' => $meta_key,
289
+ 'value' => '1',
290
+ ),
291
  ),
292
+ )
293
+ );
294
 
295
  return $query->found_posts;
296
  }
301
  * @return int the number of job listings.
302
  */
303
  private static function get_jobs_by_guests() {
304
+ $query = new WP_Query(
305
+ array(
306
+ 'post_type' => 'job_listing',
307
+ 'post_status' => array( 'publish', 'expired' ),
308
+ 'fields' => 'ids',
309
+ 'author__in' => array( 0 ),
310
+ )
311
+ );
312
 
313
  return $query->found_posts;
314
  }
includes/class-wp-job-manager-usage-tracking.php CHANGED
@@ -4,17 +4,20 @@ 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
 
@@ -27,45 +30,96 @@ class WP_Job_Manager_Usage_Tracking extends WP_Job_Manager_Usage_Tracking_Base {
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;
@@ -89,14 +143,28 @@ class WP_Job_Manager_Usage_Tracking extends WP_Job_Manager_Usage_Tracking_Base {
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
 
@@ -113,10 +181,16 @@ class WP_Job_Manager_Usage_Tracking extends WP_Job_Manager_Usage_Tracking_Base {
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,
@@ -131,10 +205,13 @@ class WP_Job_Manager_Usage_Tracking extends WP_Job_Manager_Usage_Tracking_Base {
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 );
4
  exit;
5
  }
6
 
7
+ require 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
+ /**
19
+ * WP_Job_Manager_Usage_Tracking constructor.
20
+ */
21
  protected function __construct() {
22
  parent::__construct();
23
 
30
  }
31
  }
32
 
33
+ /**
34
  * Implementation for abstract functions.
35
  */
36
 
37
+ /**
38
+ * Return the instance of this class.
39
+ *
40
+ * @return object
41
+ */
42
  public static function get_instance() {
43
  return self::get_instance_for_subclass( get_class() );
44
  }
45
 
46
+ /**
47
+ * Get prefix for the usage data setting.
48
+ *
49
+ * @return string
50
+ */
51
  protected function get_prefix() {
52
  return 'job_manager';
53
  }
54
 
55
+ /**
56
+ * Get prefix for the event sent for usage tracking.
57
+ *
58
+ * @return string
59
+ */
60
  protected function get_event_prefix() {
61
  return 'wpjm';
62
  }
63
 
64
+ /**
65
+ * Get the text domain used in the plugin.
66
+ *
67
+ * @return string
68
+ */
69
  protected function get_text_domain() {
70
  return 'wp-job-manager';
71
  }
72
 
73
+ /**
74
+ * Get the status of usage tracking.
75
+ *
76
+ * @return bool
77
+ */
78
  public function get_tracking_enabled() {
79
  return get_option( self::WPJM_SETTING_NAME ) || false;
80
  }
81
 
82
+ /**
83
+ * Set whether or not usage tracking is enabled.
84
+ *
85
+ * @param bool $enable
86
+ */
87
  public function set_tracking_enabled( $enable ) {
88
  update_option( self::WPJM_SETTING_NAME, $enable );
89
  }
90
 
91
+ /**
92
+ * Check if the current user can manage usage tracking settings.
93
+ *
94
+ * @return bool
95
+ */
96
  protected function current_user_can_manage_tracking() {
97
  return current_user_can( 'manage_options' );
98
  }
99
 
100
+ /**
101
+ * Get the text to show in the opt-in dialog.
102
+ *
103
+ * @return string
104
+ */
105
  protected function opt_in_dialog_text() {
106
+ return sprintf(
107
+ // translators: Placeholder %s is a URL to the document on wpjobmanager.com with info on usage tracking.
108
+ __(
109
+ 'We\'d love if you helped us make WP Job Manager better by allowing us to collect
110
+ <a href="%s" target="_blank">usage tracking data</a>. No sensitive information is
111
+ collected, and you can opt out at any time.',
112
+ 'wp-job-manager'
113
+ ), self::WPJM_TRACKING_INFO_URL
114
+ );
115
  }
116
 
117
+ /**
118
+ * Check if we should track the status of a plugin.
119
+ *
120
+ * @param string $plugin_slug
121
+ * @return bool
122
+ */
123
  protected function do_track_plugin( $plugin_slug ) {
124
  if ( 1 === preg_match( '/^wp-job-manager/', $plugin_slug ) ) {
125
  return true;
143
  * Public functions.
144
  */
145
 
146
+ /**
147
+ * Hide the opt-in for enabling usage tracking.
148
+ **/
149
+ public function hide_tracking_opt_in() { // phpcs:ignore Generic.CodeAnalysis.UselessOverridingMethod
150
  parent::hide_tracking_opt_in();
151
  }
152
 
153
+ /**
154
+ * Allowed html tags, used by wp_kses, for the translated opt-in dialog
155
+ * text.
156
+ *
157
+ * @return array the html tags.
158
+ **/
159
+ public function opt_in_dialog_text_allowed_html() { // phpcs:ignore Generic.CodeAnalysis.UselessOverridingMethod
160
  return parent::opt_in_dialog_text_allowed_html();
161
  }
162
 
163
+ /**
164
+ * Get the opt-in text.
165
+ *
166
+ * @return string
167
+ */
168
  public function opt_in_checkbox_text() {
169
  return sprintf(
170
 
181
  }
182
 
183
 
184
+ /**
185
  * Hooks.
186
  */
187
 
188
+ /**
189
+ * Add tracking setting field to general settings.
190
+ *
191
+ * @param array $fields
192
+ * @return array
193
+ */
194
  public function add_setting_field( $fields ) {
195
  $fields['general'][1][] = array(
196
  'name' => self::WPJM_SETTING_NAME,
205
  }
206
 
207
 
208
+ /**
209
  * Helpers.
210
  */
211
 
212
+ /**
213
+ * Clear options used for usage tracking.
214
+ */
215
  public function clear_options() {
216
  delete_option( self::WPJM_SETTING_NAME );
217
  delete_option( $this->hide_tracking_opt_in_option_name );
includes/class-wp-job-manager-widget.php CHANGED
@@ -83,7 +83,7 @@ class WP_Job_Manager_Widget extends WP_Widget {
83
  }
84
 
85
  if ( isset( $cache[ $args['widget_id'] ] ) ) {
86
- echo $cache[ $args['widget_id'] ];
87
  return true;
88
  }
89
 
@@ -151,33 +151,41 @@ class WP_Job_Manager_Widget extends WP_Widget {
151
  $value = isset( $instance[ $key ] ) ? $instance[ $key ] : $setting['std'];
152
 
153
  switch ( $setting['type'] ) {
154
- case 'text' :
155
  ?>
156
  <p>
157
- <label for="<?php echo $this->get_field_id( $key ); ?>"><?php echo $setting['label']; ?></label>
158
- <input class="widefat" id="<?php echo esc_attr( $this->get_field_id( $key ) ); ?>" name="<?php echo $this->get_field_name( $key ); ?>" type="text" value="<?php echo esc_attr( $value ); ?>" />
159
  </p>
160
  <?php
161
- break;
162
- case 'number' :
163
  ?>
164
  <p>
165
- <label for="<?php echo $this->get_field_id( $key ); ?>"><?php echo $setting['label']; ?></label>
166
- <input class="widefat" id="<?php echo esc_attr( $this->get_field_id( $key ) ); ?>" name="<?php echo $this->get_field_name( $key ); ?>" type="number" step="<?php echo esc_attr( $setting['step'] ); ?>" min="<?php echo esc_attr( $setting['min'] ); ?>" max="<?php echo esc_attr( $setting['max'] ); ?>" value="<?php echo esc_attr( $value ); ?>" />
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
  }
83
  }
84
 
85
  if ( isset( $cache[ $args['widget_id'] ] ) ) {
86
+ echo $cache[ $args['widget_id'] ]; // WPCS: XSS ok.
87
  return true;
88
  }
89
 
151
  $value = isset( $instance[ $key ] ) ? $instance[ $key ] : $setting['std'];
152
 
153
  switch ( $setting['type'] ) {
154
+ case 'text':
155
  ?>
156
  <p>
157
+ <label for="<?php echo esc_attr( $this->get_field_id( $key ) ); ?>"><?php echo esc_html( $setting['label'] ); ?></label>
158
+ <input class="widefat" id="<?php echo esc_attr( $this->get_field_id( $key ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( $key ) ); ?>" type="text" value="<?php echo esc_attr( $value ); ?>" />
159
  </p>
160
  <?php
161
+ break;
162
+ case 'number':
163
  ?>
164
  <p>
165
+ <label for="<?php echo esc_attr( $this->get_field_id( $key ) ); ?>"><?php echo esc_html( $setting['label'] ); ?></label>
166
+ <input class="widefat" id="<?php echo esc_attr( $this->get_field_id( $key ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( $key ) ); ?>" type="number" step="<?php echo esc_attr( $setting['step'] ); ?>" min="<?php echo esc_attr( $setting['min'] ); ?>" max="<?php echo esc_attr( $setting['max'] ); ?>" value="<?php echo esc_attr( $value ); ?>" />
167
  </p>
168
  <?php
169
+ break;
170
+ case 'select':
171
  ?>
172
  <p>
173
+ <label for="<?php echo esc_attr( $this->get_field_id( $key ) ); ?>"><?php echo esc_html( $setting['label'] ); ?></label>
174
+ <select class="widefat" id="<?php echo esc_attr( $this->get_field_id( $key ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( $key ) ); ?>">
175
+ <?php foreach ( $setting['options'] as $option_key => $option_label ) : ?>
176
+ <option value="<?php echo esc_attr( $option_key ); ?>" <?php selected( $value, $option_key ); ?>><?php echo esc_html( $option_label ); ?></option>
177
  <?php endforeach; ?></select>
178
  </p>
179
  <?php
180
+ break;
181
+ case 'checkbox':
182
+ ?>
183
+ <p>
184
+ <label for="<?php echo esc_attr( $this->get_field_id( $key ) ); ?>"><?php echo esc_html( $setting['label'] ); ?></label>
185
+ <input class="checkbox" id="<?php echo esc_attr( $this->get_field_id( $key ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( $key ) ); ?>" type="checkbox" value="1" <?php checked( $value, 1 ); ?> />
186
+ </p>
187
+ <?php
188
+ break;
189
  }
190
  }
191
  }
includes/emails/class-wp-job-manager-email-admin-expiring-job.php CHANGED
@@ -1,7 +1,7 @@
1
  <?php
2
 
3
  if ( ! defined( 'ABSPATH' ) ) {
4
- exit; // Exit if accessed directly
5
  }
6
 
7
  /**
1
  <?php
2
 
3
  if ( ! defined( 'ABSPATH' ) ) {
4
+ exit; // Exit if accessed directly.
5
  }
6
 
7
  /**
includes/emails/class-wp-job-manager-email-admin-new-job.php CHANGED
@@ -1,7 +1,7 @@
1
  <?php
2
 
3
  if ( ! defined( 'ABSPATH' ) ) {
4
- exit; // Exit if accessed directly
5
  }
6
 
7
  /**
@@ -49,9 +49,13 @@ class WP_Job_Manager_Email_Admin_New_Job extends WP_Job_Manager_Email_Template {
49
  $args = $this->get_args();
50
 
51
  /**
 
 
52
  * @var WP_Post $job
53
  */
54
  $job = $args['job'];
 
 
55
  return sprintf( __( 'New Job Listing Submitted: %s', 'wp-job-manager' ), $job->post_title );
56
  }
57
 
1
  <?php
2
 
3
  if ( ! defined( 'ABSPATH' ) ) {
4
+ exit; // Exit if accessed directly.
5
  }
6
 
7
  /**
49
  $args = $this->get_args();
50
 
51
  /**
52
+ * Job listing post object.
53
+ *
54
  * @var WP_Post $job
55
  */
56
  $job = $args['job'];
57
+
58
+ // translators: Placeholder %s is the job listing post title.
59
  return sprintf( __( 'New Job Listing Submitted: %s', 'wp-job-manager' ), $job->post_title );
60
  }
61
 
includes/emails/class-wp-job-manager-email-admin-updated-job.php CHANGED
@@ -1,7 +1,7 @@
1
  <?php
2
 
3
  if ( ! defined( 'ABSPATH' ) ) {
4
- exit; // Exit if accessed directly
5
  }
6
 
7
  /**
@@ -49,9 +49,13 @@ class WP_Job_Manager_Email_Admin_Updated_Job extends WP_Job_Manager_Email_Templa
49
  $args = $this->get_args();
50
 
51
  /**
 
 
52
  * @var WP_Post $job
53
  */
54
  $job = $args['job'];
 
 
55
  return sprintf( __( 'Job Listing Updated: %s', 'wp-job-manager' ), $job->post_title );
56
  }
57
 
1
  <?php
2
 
3
  if ( ! defined( 'ABSPATH' ) ) {
4
+ exit; // Exit if accessed directly.
5
  }
6
 
7
  /**
49
  $args = $this->get_args();
50
 
51
  /**
52
+ * Job listing post object.
53
+ *
54
  * @var WP_Post $job
55
  */
56
  $job = $args['job'];
57
+
58
+ // translators: Placeholder %s is the job listing post title.
59
  return sprintf( __( 'Job Listing Updated: %s', 'wp-job-manager' ), $job->post_title );
60
  }
61
 
includes/emails/class-wp-job-manager-email-employer-expiring-job.php CHANGED
@@ -1,7 +1,7 @@
1
  <?php
2
 
3
  if ( ! defined( 'ABSPATH' ) ) {
4
- exit; // Exit if accessed directly
5
  }
6
 
7
  /**
@@ -12,7 +12,7 @@ if ( ! defined( 'ABSPATH' ) ) {
12
  * @extends WP_Job_Manager_Email
13
  */
14
  class WP_Job_Manager_Email_Employer_Expiring_Job extends WP_Job_Manager_Email_Template {
15
- const SETTING_NOTICE_PERIOD_NAME = 'notice_period_days';
16
  const SETTING_NOTICE_PERIOD_DEFAULT = '1';
17
 
18
  /**
@@ -65,9 +65,13 @@ class WP_Job_Manager_Email_Employer_Expiring_Job extends WP_Job_Manager_Email_Te
65
  $args = $this->get_args();
66
 
67
  /**
 
 
68
  * @var WP_Post $job
69
  */
70
  $job = $args['job'];
 
 
71
  return sprintf( __( 'Job Listing Expiring: %s', 'wp-job-manager' ), $job->post_title );
72
  }
73
 
@@ -93,7 +97,7 @@ class WP_Job_Manager_Email_Employer_Expiring_Job extends WP_Job_Manager_Email_Te
93
  /**
94
  * Expand arguments as necessary for the generation of the email.
95
  *
96
- * @param $args
97
  * @return mixed
98
  */
99
  protected function prepare_args( $args ) {
@@ -101,8 +105,8 @@ class WP_Job_Manager_Email_Employer_Expiring_Job extends WP_Job_Manager_Email_Te
101
 
102
  if ( isset( $args['job'] ) ) {
103
  $args['expiring_today'] = false;
104
- $today = date( 'Y-m-d', current_time( 'timestamp' ) );
105
- $expiring_date = date( 'Y-m-d', strtotime( $args['job']->_job_expires ) );
106
  if ( ! empty( $args['job']->_job_expires ) && $today === $expiring_date ) {
107
  $args['expiring_today'] = true;
108
  }
@@ -117,7 +121,7 @@ class WP_Job_Manager_Email_Employer_Expiring_Job extends WP_Job_Manager_Email_Te
117
  * @return array
118
  */
119
  public static function get_setting_fields() {
120
- $fields = parent::get_setting_fields();
121
  $fields[] = array(
122
  'name' => self::SETTING_NOTICE_PERIOD_NAME,
123
  'std' => self::SETTING_NOTICE_PERIOD_DEFAULT,
1
  <?php
2
 
3
  if ( ! defined( 'ABSPATH' ) ) {
4
+ exit; // Exit if accessed directly.
5
  }
6
 
7
  /**
12
  * @extends WP_Job_Manager_Email
13
  */
14
  class WP_Job_Manager_Email_Employer_Expiring_Job extends WP_Job_Manager_Email_Template {
15
+ const SETTING_NOTICE_PERIOD_NAME = 'notice_period_days';
16
  const SETTING_NOTICE_PERIOD_DEFAULT = '1';
17
 
18
  /**
65
  $args = $this->get_args();
66
 
67
  /**
68
+ * Job listing post object.
69
+ *
70
  * @var WP_Post $job
71
  */
72
  $job = $args['job'];
73
+
74
+ // translators: Placeholder %s is the job listing post title.
75
  return sprintf( __( 'Job Listing Expiring: %s', 'wp-job-manager' ), $job->post_title );
76
  }
77
 
97
  /**
98
  * Expand arguments as necessary for the generation of the email.
99
  *
100
+ * @param array $args
101
  * @return mixed
102
  */
103
  protected function prepare_args( $args ) {
105
 
106
  if ( isset( $args['job'] ) ) {
107
  $args['expiring_today'] = false;
108
+ $today = date( 'Y-m-d', current_time( 'timestamp' ) );
109
+ $expiring_date = date( 'Y-m-d', strtotime( $args['job']->_job_expires ) );
110
  if ( ! empty( $args['job']->_job_expires ) && $today === $expiring_date ) {
111
  $args['expiring_today'] = true;
112
  }
121
  * @return array
122
  */
123
  public static function get_setting_fields() {
124
+ $fields = parent::get_setting_fields();
125
  $fields[] = array(
126
  'name' => self::SETTING_NOTICE_PERIOD_NAME,
127
  'std' => self::SETTING_NOTICE_PERIOD_DEFAULT,
includes/forms/class-wp-job-manager-form-edit-job.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
 
3
- include_once( 'class-wp-job-manager-form-submit-job.php' );
4
 
5
  /**
6
  * Handles the editing of Job Listings from the public facing frontend (from within `[job_dashboard]` shortcode).
@@ -19,11 +19,15 @@ class WP_Job_Manager_Form_Edit_Job extends WP_Job_Manager_Form_Submit_Job {
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;
@@ -51,9 +55,9 @@ class WP_Job_Manager_Form_Edit_Job extends WP_Job_Manager_Form_Submit_Job {
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
 
@@ -69,16 +73,16 @@ class WP_Job_Manager_Form_Edit_Job extends WP_Job_Manager_Form_Submit_Job {
69
  }
70
 
71
  /**
72
- * output function.
73
  *
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
  }
@@ -90,7 +94,7 @@ class WP_Job_Manager_Form_Edit_Job extends WP_Job_Manager_Form_Submit_Job {
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
  }
96
 
@@ -130,19 +134,24 @@ class WP_Job_Manager_Form_Edit_Job extends WP_Job_Manager_Form_Submit_Job {
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,
135
- 'job_id' => $this->get_job_id(),
136
- 'action' => $this->get_action(),
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
  /**
145
- * Submit Step is posted
 
 
146
  */
147
  public function submit_handler() {
148
  if ( empty( $_POST['submit_job'] ) ) {
@@ -151,12 +160,13 @@ class WP_Job_Manager_Form_Edit_Job extends WP_Job_Manager_Form_Submit_Job {
151
 
152
  try {
153
 
154
- // Get posted values
155
  $values = $this->get_posted_fields();
156
 
157
- // Validate required
158
- if ( is_wp_error( ( $return = $this->validate_fields( $values ) ) ) ) {
159
- throw new Exception( $return->get_error_message() );
 
160
  }
161
 
162
  $save_post_status = '';
@@ -165,13 +175,13 @@ class WP_Job_Manager_Form_Edit_Job extends WP_Job_Manager_Form_Submit_Job {
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
 
1
  <?php
2
 
3
+ require_once 'class-wp-job-manager-form-submit-job.php';
4
 
5
  /**
6
  * Handles the editing of Job Listings from the public facing frontend (from within `[job_dashboard]` shortcode).
19
  public $form_name = 'edit-job';
20
 
21
  /**
22
+ * Messaged shown on save.
23
+ *
24
  * @var bool|string
25
  */
26
  private $save_message = false;
27
 
28
  /**
29
+ * Message shown on error.
30
+ *
31
  * @var bool|string
32
  */
33
  private $save_error = false;
55
  */
56
  public function __construct() {
57
  add_action( 'wp', array( $this, 'submit_handler' ) );
58
+ $this->job_id = ! empty( $_REQUEST['job_id'] ) ? absint( $_REQUEST['job_id'] ) : 0;
59
 
60
+ if ( ! job_manager_user_can_edit_job( $this->job_id ) ) {
61
  $this->job_id = 0;
62
  }
63
 
73
  }
74
 
75
  /**
76
+ * Output function.
77
  *
78
  * @param array $atts
79
  */
80
  public function output( $atts = array() ) {
81
  if ( ! empty( $this->save_message ) ) {
82
+ echo '<div class="job-manager-message">' . wp_kses_post( $this->save_message ) . '</div>';
83
  }
84
  if ( ! empty( $this->save_error ) ) {
85
+ echo '<div class="job-manager-error">' . wp_kses_post( $this->save_error ) . '</div>';
86
  }
87
  $this->submit();
88
  }
94
  $job = get_post( $this->job_id );
95
 
96
  if ( empty( $this->job_id ) ) {
97
+ echo wp_kses_post( wpautop( __( 'Invalid listing', 'wp-job-manager' ) ) );
98
  return;
99
  }
100
 
134
 
135
  $save_button_text = apply_filters( 'update_job_form_submit_button_text', $save_button_text );
136
 
137
+ get_job_manager_template(
138
+ 'job-submit.php',
139
+ array(
140
+ 'form' => $this->form_name,
141
+ 'job_id' => $this->get_job_id(),
142
+ 'action' => $this->get_action(),
143
+ 'job_fields' => $this->get_fields( 'job' ),
144
+ 'company_fields' => $this->get_fields( 'company' ),
145
+ 'step' => $this->get_step(),
146
+ 'submit_button_text' => $save_button_text,
147
+ )
148
+ );
149
  }
150
 
151
  /**
152
+ * Submit Step is posted.
153
+ *
154
+ * @throws Exception When invalid fields are submitted.
155
  */
156
  public function submit_handler() {
157
  if ( empty( $_POST['submit_job'] ) ) {
160
 
161
  try {
162
 
163
+ // Get posted values.
164
  $values = $this->get_posted_fields();
165
 
166
+ // Validate required.
167
+ $validation_result = $this->validate_fields( $values );
168
+ if ( is_wp_error( $validation_result ) ) {
169
+ throw new Exception( $validation_result->get_error_message() );
170
  }
171
 
172
  $save_post_status = '';
175
  }
176
  $original_post_status = get_post_status( $this->job_id );
177
 
178
+ // Update the job.
179
  $this->save_job( $values['job']['job_title'], $values['job']['job_description'], $save_post_status, $values, false );
180
  $this->update_job_data( $values );
181
 
182
+ // Successful.
183
  $save_message = __( 'Your changes have been saved.', 'wp-job-manager' );
184
+ $post_status = get_post_status( $this->job_id );
185
 
186
  update_post_meta( $this->job_id, '_job_edited', time() );
187
 
includes/forms/class-wp-job-manager-form-submit-job.php CHANGED
@@ -62,36 +62,39 @@ class WP_Job_Manager_Form_Submit_Job extends WP_Job_Manager_Form {
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(
67
- 'name' => __( 'Submit Details', 'wp-job-manager' ),
68
- 'view' => array( $this, 'submit' ),
69
- 'handler' => array( $this, 'submit_handler' ),
70
- 'priority' => 10
 
 
 
 
 
 
 
 
 
 
 
 
 
71
  ),
72
- 'preview' => array(
73
- 'name' => __( 'Preview', 'wp-job-manager' ),
74
- 'view' => array( $this, 'preview' ),
75
- 'handler' => array( $this, 'preview_handler' ),
76
- 'priority' => 20
77
- ),
78
- 'done' => array(
79
- 'name' => __( 'Done', 'wp-job-manager' ),
80
- 'view' => array( $this, 'done' ),
81
- 'priority' => 30
82
  )
83
- ) );
84
 
85
  uasort( $this->steps, array( $this, 'sort_by_priority' ) );
86
 
87
- // Get step/job
88
  if ( isset( $_POST['step'] ) ) {
89
- $this->step = is_numeric( $_POST['step'] ) ? max( absint( $_POST['step'] ), 0 ) : array_search( $_POST['step'], array_keys( $this->steps ) );
90
  } elseif ( ! empty( $_GET['step'] ) ) {
91
- $this->step = is_numeric( $_GET['step'] ) ? max( absint( $_GET['step'] ), 0 ) : array_search( $_GET['step'], array_keys( $this->steps ) );
92
  }
93
 
94
- $this->job_id = ! empty( $_REQUEST[ 'job_id' ] ) ? absint( $_REQUEST[ 'job_id' ] ) : 0;
95
 
96
  if ( ! job_manager_user_can_edit_job( $this->job_id ) ) {
97
  $this->job_id = 0;
@@ -99,17 +102,17 @@ class WP_Job_Manager_Form_Submit_Job extends WP_Job_Manager_Form {
99
 
100
  // Allow resuming from cookie.
101
  $this->resume_edit = false;
102
- if ( ! isset( $_GET[ 'new' ] ) && ( 'before' === get_option( 'job_manager_paid_listings_flow' ) || ! $this->job_id ) && ! empty( $_COOKIE['wp-job-manager-submitting-job-id'] ) && ! empty( $_COOKIE['wp-job-manager-submitting-job-key'] ) ) {
103
  $job_id = absint( $_COOKIE['wp-job-manager-submitting-job-id'] );
104
  $job_status = get_post_status( $job_id );
105
 
106
  if ( ( 'preview' === $job_status || 'pending_payment' === $job_status ) && get_post_meta( $job_id, '_submitting_key', true ) === $_COOKIE['wp-job-manager-submitting-job-key'] ) {
107
- $this->job_id = $job_id;
108
  $this->resume_edit = get_post_meta( $job_id, '_submitting_key', true );
109
  }
110
  }
111
 
112
- // Load job details
113
  if ( $this->job_id ) {
114
  $job_status = get_post_status( $this->job_id );
115
  if ( 'expired' === $job_status ) {
@@ -117,7 +120,7 @@ class WP_Job_Manager_Form_Submit_Job extends WP_Job_Manager_Form {
117
  $this->job_id = 0;
118
  $this->step = 0;
119
  }
120
- } elseif ( ! in_array( $job_status, apply_filters( 'job_manager_valid_submit_job_statuses', array( 'preview' ) ) ) ) {
121
  $this->job_id = 0;
122
  $this->step = 0;
123
  }
@@ -143,21 +146,21 @@ class WP_Job_Manager_Form_Submit_Job extends WP_Job_Manager_Form {
143
 
144
  $allowed_application_method = get_option( 'job_manager_allowed_application_method', '' );
145
  switch ( $allowed_application_method ) {
146
- case 'email' :
147
  $application_method_label = __( 'Application email', 'wp-job-manager' );
148
  $application_method_placeholder = __( 'you@yourdomain.com', 'wp-job-manager' );
149
  $application_method_sanitizer = 'email';
150
- break;
151
- case 'url' :
152
  $application_method_label = __( 'Application URL', 'wp-job-manager' );
153
  $application_method_placeholder = __( 'http://', 'wp-job-manager' );
154
  $application_method_sanitizer = 'url';
155
- break;
156
- default :
157
  $application_method_label = __( 'Application email/URL', 'wp-job-manager' );
158
  $application_method_placeholder = __( 'Enter an email address or website URL', 'wp-job-manager' );
159
  $application_method_sanitizer = 'url_or_email';
160
- break;
161
  }
162
 
163
  if ( job_manager_multi_job_type() ) {
@@ -165,117 +168,120 @@ class WP_Job_Manager_Form_Submit_Job extends WP_Job_Manager_Form {
165
  } else {
166
  $job_type = 'term-select';
167
  }
168
- $this->fields = apply_filters( 'submit_job_form_fields', array(
169
- 'job' => array(
170
- 'job_title' => array(
171
- 'label' => __( 'Job Title', 'wp-job-manager' ),
172
- 'type' => 'text',
173
- 'required' => true,
174
- 'placeholder' => '',
175
- 'priority' => 1
176
- ),
177
- 'job_location' => array(
178
- 'label' => __( 'Location', 'wp-job-manager' ),
179
- 'description' => __( 'Leave this blank if the location is not important', 'wp-job-manager' ),
180
- 'type' => 'text',
181
- 'required' => false,
182
- 'placeholder' => __( 'e.g. "London"', 'wp-job-manager' ),
183
- 'priority' => 2
184
- ),
185
- 'job_type' => array(
186
- 'label' => __( 'Job type', 'wp-job-manager' ),
187
- 'type' => $job_type,
188
- 'required' => true,
189
- 'placeholder' => __( 'Choose job type&hellip;', 'wp-job-manager' ),
190
- 'priority' => 3,
191
- 'default' => 'full-time',
192
- 'taxonomy' => 'job_listing_type'
193
- ),
194
- 'job_category' => array(
195
- 'label' => __( 'Job category', 'wp-job-manager' ),
196
- 'type' => 'term-multiselect',
197
- 'required' => true,
198
- 'placeholder' => '',
199
- 'priority' => 4,
200
- 'default' => '',
201
- 'taxonomy' => 'job_listing_category'
202
- ),
203
- 'job_description' => array(
204
- 'label' => __( 'Description', 'wp-job-manager' ),
205
- 'type' => 'wp-editor',
206
- 'required' => true,
207
- 'priority' => 5
208
- ),
209
- 'application' => array(
210
- 'label' => $application_method_label,
211
- 'type' => 'text',
212
- 'sanitizer' => $application_method_sanitizer,
213
- 'required' => true,
214
- 'placeholder' => $application_method_placeholder,
215
- 'priority' => 6
216
- )
217
- ),
218
- 'company' => array(
219
- 'company_name' => array(
220
- 'label' => __( 'Company name', 'wp-job-manager' ),
221
- 'type' => 'text',
222
- 'required' => true,
223
- 'placeholder' => __( 'Enter the name of the company', 'wp-job-manager' ),
224
- 'priority' => 1
225
- ),
226
- 'company_website' => array(
227
- 'label' => __( 'Website', 'wp-job-manager' ),
228
- 'type' => 'text',
229
- 'sanitizer' => 'url',
230
- 'required' => false,
231
- 'placeholder' => __( 'http://', 'wp-job-manager' ),
232
- 'priority' => 2
233
  ),
234
- 'company_tagline' => array(
235
- 'label' => __( 'Tagline', 'wp-job-manager' ),
236
- 'type' => 'text',
237
- 'required' => false,
238
- 'placeholder' => __( 'Briefly describe your company', 'wp-job-manager' ),
239
- 'maxlength' => 64,
240
- 'priority' => 3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
241
  ),
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
249
- ),
250
- 'company_twitter' => array(
251
- 'label' => __( 'Twitter username', 'wp-job-manager' ),
252
- 'type' => 'text',
253
- 'required' => false,
254
- 'placeholder' => __( '@yourcompany', 'wp-job-manager' ),
255
- 'priority' => 5
256
- ),
257
- 'company_logo' => array(
258
- 'label' => __( 'Logo', 'wp-job-manager' ),
259
- 'type' => 'file',
260
- 'required' => false,
261
- 'placeholder' => '',
262
- 'priority' => 6,
263
- 'ajax' => true,
264
- 'multiple' => false,
265
- 'allowed_mime_types' => array(
266
- 'jpg' => 'image/jpeg',
267
- 'jpeg' => 'image/jpeg',
268
- 'gif' => 'image/gif',
269
- 'png' => 'image/png'
270
- )
271
- )
272
  )
273
- ) );
274
 
275
- if ( ! get_option( 'job_manager_enable_categories' ) || wp_count_terms( 'job_listing_category' ) == 0 ) {
276
  unset( $this->fields['job']['job_category'] );
277
  }
278
- if ( ! get_option( 'job_manager_enable_types' ) || wp_count_terms( 'job_listing_type' ) == 0 ) {
279
  unset( $this->fields['job']['job_type'] );
280
  }
281
  }
@@ -296,16 +302,17 @@ class WP_Job_Manager_Form_Submit_Job extends WP_Job_Manager_Form {
296
  * Validates the posted fields.
297
  *
298
  * @param array $values
299
- * @throws Exception Uploaded file is not a valid mime-type or other validation error
300
- * @return bool|WP_Error True on success, WP_Error on failure
301
  */
302
  protected function validate_fields( $values ) {
303
  foreach ( $this->fields as $group_key => $group_fields ) {
304
  foreach ( $group_fields as $key => $field ) {
305
  if ( $field['required'] && empty( $values[ $group_key ][ $key ] ) ) {
 
306
  return new WP_Error( 'validation-error', sprintf( __( '%s is a required field', 'wp-job-manager' ), $field['label'] ) );
307
  }
308
- if ( ! empty( $field['taxonomy'] ) && in_array( $field['type'], array( 'term-checklist', 'term-select', 'term-multiselect' ) ) ) {
309
  if ( is_array( $values[ $group_key ][ $key ] ) ) {
310
  $check_value = $values[ $group_key ][ $key ];
311
  } else {
@@ -313,6 +320,7 @@ class WP_Job_Manager_Form_Submit_Job extends WP_Job_Manager_Form {
313
  }
314
  foreach ( $check_value as $term ) {
315
  if ( ! term_exists( $term, $field['taxonomy'] ) ) {
 
316
  return new WP_Error( 'validation-error', sprintf( __( '%s is invalid', 'wp-job-manager' ), $field['label'] ) );
317
  }
318
  }
@@ -328,8 +336,9 @@ class WP_Job_Manager_Form_Submit_Job extends WP_Job_Manager_Form {
328
  $file_url = current( explode( '?', $file_url ) );
329
  $file_info = wp_check_filetype( $file_url );
330
 
331
- if ( ! is_numeric( $file_url ) && $file_info && ! in_array( $file_info['type'], $field['allowed_mime_types'] ) ) {
332
- throw new Exception( sprintf( __( '"%s" (filetype %s) needs to be one of the following file types: %s', 'wp-job-manager' ), $field['label'], $file_info['ext'], implode( ', ', array_keys( $field['allowed_mime_types'] ) ) ) );
 
333
  }
334
  }
335
  }
@@ -337,18 +346,18 @@ class WP_Job_Manager_Form_Submit_Job extends WP_Job_Manager_Form {
337
  }
338
  }
339
 
340
- // Application method
341
  if ( isset( $values['job']['application'] ) && ! empty( $values['job']['application'] ) ) {
342
- $allowed_application_method = get_option( 'job_manager_allowed_application_method', '' );
343
  $values['job']['application'] = str_replace( ' ', '+', $values['job']['application'] );
344
  switch ( $allowed_application_method ) {
345
- case 'email' :
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:' ) ) {
353
  $values['job']['application'] = 'http://' . $values['job']['application'];
354
  }
@@ -356,9 +365,9 @@ class WP_Job_Manager_Form_Submit_Job extends WP_Job_Manager_Form {
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
362
  if ( ! strstr( $values['job']['application'], 'http:' ) && ! strstr( $values['job']['application'], 'https:' ) ) {
363
  $values['job']['application'] = 'http://' . $values['job']['application'];
364
  }
@@ -380,9 +389,9 @@ class WP_Job_Manager_Form_Submit_Job extends WP_Job_Manager_Form {
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' ) );
@@ -396,10 +405,14 @@ class WP_Job_Manager_Form_Submit_Job extends WP_Job_Manager_Form {
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
 
@@ -423,40 +436,40 @@ class WP_Job_Manager_Form_Submit_Job extends WP_Job_Manager_Form {
423
  public function submit() {
424
  $this->init_fields();
425
 
426
- // Load data if neccessary
427
  if ( $this->job_id ) {
428
  $job = get_post( $this->job_id );
429
  foreach ( $this->fields as $group_key => $group_fields ) {
430
  foreach ( $group_fields as $key => $field ) {
431
  switch ( $key ) {
432
- case 'job_title' :
433
  $this->fields[ $group_key ][ $key ]['value'] = $job->post_title;
434
- break;
435
- case 'job_description' :
436
  $this->fields[ $group_key ][ $key ]['value'] = $job->post_content;
437
- break;
438
- case 'job_type' :
439
  $this->fields[ $group_key ][ $key ]['value'] = wp_get_object_terms( $job->ID, 'job_listing_type', array( 'fields' => 'ids' ) );
440
  if ( ! job_manager_multi_job_type() ) {
441
  $this->fields[ $group_key ][ $key ]['value'] = current( $this->fields[ $group_key ][ $key ]['value'] );
442
  }
443
- break;
444
- case 'job_category' :
445
  $this->fields[ $group_key ][ $key ]['value'] = wp_get_object_terms( $job->ID, 'job_listing_category', array( 'fields' => 'ids' ) );
446
- break;
447
- case 'company_logo' :
448
  $this->fields[ $group_key ][ $key ]['value'] = has_post_thumbnail( $job->ID ) ? get_post_thumbnail_id( $job->ID ) : get_post_meta( $job->ID, '_' . $key, true );
449
- break;
450
  default:
451
  $this->fields[ $group_key ][ $key ]['value'] = get_post_meta( $job->ID, '_' . $key, true );
452
- break;
453
  }
454
  }
455
  }
456
 
457
  $this->fields = apply_filters( 'submit_job_form_fields_get_job_data', $this->fields, $job );
458
 
459
- // Get user meta
460
  } elseif ( is_user_logged_in() && empty( $_POST['submit_job'] ) ) {
461
  if ( ! empty( $this->fields['company'] ) ) {
462
  foreach ( $this->fields['company'] as $key => $field ) {
@@ -465,8 +478,8 @@ class WP_Job_Manager_Form_Submit_Job extends WP_Job_Manager_Form {
465
  }
466
  if ( ! empty( $this->fields['job']['application'] ) ) {
467
  $allowed_application_method = get_option( 'job_manager_allowed_application_method', '' );
468
- if ( $allowed_application_method !== 'url' ) {
469
- $current_user = wp_get_current_user();
470
  $this->fields['job']['application']['value'] = $current_user->user_email;
471
  }
472
  }
@@ -474,39 +487,45 @@ class WP_Job_Manager_Form_Submit_Job extends WP_Job_Manager_Form {
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(),
480
- 'resume_edit' => $this->resume_edit,
481
- 'action' => $this->get_action(),
482
- 'job_fields' => $this->get_fields( 'job' ),
483
- 'company_fields' => $this->get_fields( 'company' ),
484
- 'step' => $this->get_step(),
485
- 'submit_button_text' => apply_filters( 'submit_job_form_submit_button_text', __( 'Preview', 'wp-job-manager' ) )
486
- ) );
 
 
 
487
  }
488
 
489
  /**
490
  * Handles the submission of form data.
 
 
491
  */
492
  public function submit_handler() {
493
  try {
494
- // Init fields
495
  $this->init_fields();
496
 
497
- // Get posted values
498
  $values = $this->get_posted_fields();
499
 
500
  if ( empty( $_POST['submit_job'] ) ) {
501
  return;
502
  }
503
 
504
- // Validate required
505
- if ( is_wp_error( ( $return = $this->validate_fields( $values ) ) ) ) {
506
- throw new Exception( $return->get_error_message() );
 
507
  }
508
 
509
- // Account creation
510
  if ( ! is_user_logged_in() ) {
511
  $create_account = false;
512
 
@@ -532,6 +551,7 @@ class WP_Job_Manager_Form_Submit_Job extends WP_Job_Manager_Form {
532
  if ( ! wpjm_validate_new_password( $_POST['create_account_password'] ) ) {
533
  $password_hint = wpjm_get_password_rules_hint();
534
  if ( $password_hint ) {
 
535
  throw new Exception( sprintf( __( 'Invalid Password: %s', 'wp-job-manager' ), $password_hint ) );
536
  } else {
537
  throw new Exception( __( 'Password is not valid.', 'wp-job-manager' ) );
@@ -540,12 +560,14 @@ class WP_Job_Manager_Form_Submit_Job extends WP_Job_Manager_Form {
540
  }
541
 
542
  if ( ! empty( $_POST['create_account_email'] ) ) {
543
- $create_account = wp_job_manager_create_account( array(
544
- 'username' => ( job_manager_generate_username_from_email() || empty( $_POST['create_account_username'] ) ) ? '' : $_POST['create_account_username'],
545
- 'password' => ( wpjm_use_standard_password_setup_email() || empty( $_POST['create_account_password'] ) ) ? '' : $_POST['create_account_password'],
546
- 'email' => $_POST['create_account_email'],
547
- 'role' => get_option( 'job_manager_registration_role' ),
548
- ) );
 
 
549
  }
550
  }
551
 
@@ -558,11 +580,11 @@ class WP_Job_Manager_Form_Submit_Job extends WP_Job_Manager_Form {
558
  throw new Exception( __( 'You must be signed in to post a new listing.', 'wp-job-manager' ) );
559
  }
560
 
561
- // Update the job
562
  $this->save_job( $values['job']['job_title'], $values['job']['job_description'], $this->job_id ? '' : 'preview', $values );
563
  $this->update_job_data( $values );
564
 
565
- // Successful, show next step
566
  $this->step ++;
567
 
568
  } catch ( Exception $e ) {
@@ -585,23 +607,23 @@ class WP_Job_Manager_Form_Submit_Job extends WP_Job_Manager_Form {
585
  'post_title' => $post_title,
586
  'post_content' => $post_content,
587
  'post_type' => 'job_listing',
588
- 'comment_status' => 'closed'
589
  );
590
 
591
  if ( $update_slug ) {
592
- $job_slug = array();
593
 
594
- // Prepend with company name
595
  if ( apply_filters( 'submit_job_form_prefix_post_name_with_company', true ) && ! empty( $values['company']['company_name'] ) ) {
596
  $job_slug[] = $values['company']['company_name'];
597
  }
598
 
599
- // Prepend location
600
  if ( apply_filters( 'submit_job_form_prefix_post_name_with_location', true ) && ! empty( $values['job']['job_location'] ) ) {
601
  $job_slug[] = $values['job']['job_location'];
602
  }
603
 
604
- // Prepend with job type
605
  if ( apply_filters( 'submit_job_form_prefix_post_name_with_job_type', true ) && ! empty( $values['job']['job_type'] ) ) {
606
  if ( ! job_manager_multi_job_type() ) {
607
  $job_slug[] = $values['job']['job_type'];
@@ -649,11 +671,11 @@ class WP_Job_Manager_Form_Submit_Job extends WP_Job_Manager_Form {
649
  * Creates a file attachment.
650
  *
651
  * @param string $attachment_url
652
- * @return int attachment id
653
  */
654
  protected function create_attachment( $attachment_url ) {
655
- include_once( ABSPATH . 'wp-admin/includes/image.php' );
656
- include_once( ABSPATH . 'wp-admin/includes/media.php' );
657
 
658
  $upload_dir = wp_upload_dir();
659
  $attachment_url = str_replace( array( $upload_dir['baseurl'], WP_CONTENT_URL, site_url( '/' ) ), array( $upload_dir['basedir'], WP_CONTENT_DIR, ABSPATH ), $attachment_url );
@@ -662,15 +684,16 @@ class WP_Job_Manager_Form_Submit_Job extends WP_Job_Manager_Form {
662
  return 0;
663
  }
664
 
665
- $attachment = array(
666
  'post_title' => wpjm_get_the_job_title( $this->job_id ),
667
  'post_content' => '',
668
  'post_status' => 'inherit',
669
  'post_parent' => $this->job_id,
670
- 'guid' => $attachment_url
671
  );
672
 
673
- if ( $info = wp_check_filetype( $attachment_url ) ) {
 
674
  $attachment['post_mime_type'] = $info['type'];
675
  }
676
 
@@ -690,16 +713,16 @@ class WP_Job_Manager_Form_Submit_Job extends WP_Job_Manager_Form {
690
  * @param array $values
691
  */
692
  protected function update_job_data( $values ) {
693
- // Set defaults
694
  add_post_meta( $this->job_id, '_filled', 0, true );
695
  add_post_meta( $this->job_id, '_featured', 0, true );
696
 
697
  $maybe_attach = array();
698
 
699
- // Loop fields and save meta and term data
700
  foreach ( $this->fields as $group_key => $group_fields ) {
701
  foreach ( $group_fields as $key => $field ) {
702
- // Save taxonomies
703
  if ( ! empty( $field['taxonomy'] ) ) {
704
  if ( is_array( $values[ $group_key ][ $key ] ) ) {
705
  wp_set_object_terms( $this->job_id, $values[ $group_key ][ $key ], $field['taxonomy'], false );
@@ -707,7 +730,7 @@ class WP_Job_Manager_Form_Submit_Job extends WP_Job_Manager_Form {
707
  wp_set_object_terms( $this->job_id, array( $values[ $group_key ][ $key ] ), $field['taxonomy'], false );
708
  }
709
 
710
- // Company logo is a featured image
711
  } elseif ( 'company_logo' === $key ) {
712
  $attachment_id = is_numeric( $values[ $group_key ][ $key ] ) ? absint( $values[ $group_key ][ $key ] ) : $this->create_attachment( $values[ $group_key ][ $key ] );
713
  if ( empty( $attachment_id ) ) {
@@ -717,11 +740,11 @@ class WP_Job_Manager_Form_Submit_Job extends WP_Job_Manager_Form {
717
  }
718
  update_user_meta( get_current_user_id(), '_company_logo', $attachment_id );
719
 
720
- // Save meta data
721
  } else {
722
  update_post_meta( $this->job_id, '_' . $key, $values[ $group_key ][ $key ] );
723
 
724
- // Handle attachments
725
  if ( 'file' === $field['type'] ) {
726
  if ( is_array( $values[ $group_key ][ $key ] ) ) {
727
  foreach ( $values[ $group_key ][ $key ] as $file_url ) {
@@ -737,25 +760,25 @@ class WP_Job_Manager_Form_Submit_Job extends WP_Job_Manager_Form {
737
 
738
  $maybe_attach = array_filter( $maybe_attach );
739
 
740
- // Handle attachments
741
- if ( sizeof( $maybe_attach ) && apply_filters( 'job_manager_attach_uploaded_files', true ) ) {
742
- // Get attachments
743
  $attachments = get_posts( 'post_parent=' . $this->job_id . '&post_type=attachment&fields=ids&numberposts=-1' );
744
  $attachment_urls = array();
745
 
746
- // Loop attachments already attached to the job
747
  foreach ( $attachments as $attachment_id ) {
748
  $attachment_urls[] = wp_get_attachment_url( $attachment_id );
749
  }
750
 
751
  foreach ( $maybe_attach as $attachment_url ) {
752
- if ( ! in_array( $attachment_url, $attachment_urls ) ) {
753
  $this->create_attachment( $attachment_url );
754
  }
755
  }
756
  }
757
 
758
- // And user meta to save time in future
759
  if ( is_user_logged_in() ) {
760
  update_user_meta( get_current_user_id(), '_company_name', isset( $values['company']['company_name'] ) ? $values['company']['company_name'] : '' );
761
  update_user_meta( get_current_user_id(), '_company_website', isset( $values['company']['company_website'] ) ? $values['company']['company_website'] : '' );
@@ -775,14 +798,17 @@ class WP_Job_Manager_Form_Submit_Job extends WP_Job_Manager_Form {
775
 
776
  if ( $this->job_id ) {
777
  $job_preview = true;
778
- $post = get_post( $this->job_id );
779
  $post->post_status = 'preview';
780
 
781
  setup_postdata( $post );
782
 
783
- get_job_manager_template( 'job-preview.php', array(
784
- 'form' => $this
785
- ) );
 
 
 
786
 
787
  wp_reset_postdata();
788
  }
@@ -796,20 +822,20 @@ class WP_Job_Manager_Form_Submit_Job extends WP_Job_Manager_Form {
796
  return;
797
  }
798
 
799
- // Edit = show submit form again
800
  if ( ! empty( $_POST['edit_job'] ) ) {
801
  $this->step --;
802
  }
803
 
804
- // Continue = change job status then show next screen
805
  if ( ! empty( $_POST['continue'] ) ) {
806
  $job = get_post( $this->job_id );
807
 
808
- if ( in_array( $job->post_status, array( 'preview', 'expired' ) ) ) {
809
- // Reset expiry
810
  delete_post_meta( $job->ID, '_job_expires' );
811
 
812
- // Update job listing
813
  $update_job = array();
814
  $update_job['ID'] = $job->ID;
815
  $update_job['post_status'] = apply_filters( 'submit_job_post_status', get_option( 'job_manager_submission_requires_approval' ) ? 'pending' : 'publish', $job );
62
  add_action( 'submit_job_form_validate_fields', array( $this, 'validate_recaptcha_field' ) );
63
  }
64
 
65
+ $this->steps = (array) apply_filters(
66
+ 'submit_job_steps',
67
+ array(
68
+ 'submit' => array(
69
+ 'name' => __( 'Submit Details', 'wp-job-manager' ),
70
+ 'view' => array( $this, 'submit' ),
71
+ 'handler' => array( $this, 'submit_handler' ),
72
+ 'priority' => 10,
73
+ ),
74
+ 'preview' => array(
75
+ 'name' => __( 'Preview', 'wp-job-manager' ),
76
+ 'view' => array( $this, 'preview' ),
77
+ 'handler' => array( $this, 'preview_handler' ),
78
+ 'priority' => 20,
79
+ ),
80
+ 'done' => array(
81
+ 'name' => __( 'Done', 'wp-job-manager' ),
82
+ 'view' => array( $this, 'done' ),
83
+ 'priority' => 30,
84
  ),
 
 
 
 
 
 
 
 
 
 
85
  )
86
+ );
87
 
88
  uasort( $this->steps, array( $this, 'sort_by_priority' ) );
89
 
90
+ // Get step/job.
91
  if ( isset( $_POST['step'] ) ) {
92
+ $this->step = is_numeric( $_POST['step'] ) ? max( absint( $_POST['step'] ), 0 ) : array_search( intval( $_POST['step'] ), array_keys( $this->steps ), true );
93
  } elseif ( ! empty( $_GET['step'] ) ) {
94
+ $this->step = is_numeric( $_GET['step'] ) ? max( absint( $_GET['step'] ), 0 ) : array_search( intval( $_GET['step'] ), array_keys( $this->steps ), true );
95
  }
96
 
97
+ $this->job_id = ! empty( $_REQUEST['job_id'] ) ? absint( $_REQUEST['job_id'] ) : 0;
98
 
99
  if ( ! job_manager_user_can_edit_job( $this->job_id ) ) {
100
  $this->job_id = 0;
102
 
103
  // Allow resuming from cookie.
104
  $this->resume_edit = false;
105
+ if ( ! isset( $_GET['new'] ) && ( 'before' === get_option( 'job_manager_paid_listings_flow' ) || ! $this->job_id ) && ! empty( $_COOKIE['wp-job-manager-submitting-job-id'] ) && ! empty( $_COOKIE['wp-job-manager-submitting-job-key'] ) ) {
106
  $job_id = absint( $_COOKIE['wp-job-manager-submitting-job-id'] );
107
  $job_status = get_post_status( $job_id );
108
 
109
  if ( ( 'preview' === $job_status || 'pending_payment' === $job_status ) && get_post_meta( $job_id, '_submitting_key', true ) === $_COOKIE['wp-job-manager-submitting-job-key'] ) {
110
+ $this->job_id = $job_id;
111
  $this->resume_edit = get_post_meta( $job_id, '_submitting_key', true );
112
  }
113
  }
114
 
115
+ // Load job details.
116
  if ( $this->job_id ) {
117
  $job_status = get_post_status( $this->job_id );
118
  if ( 'expired' === $job_status ) {
120
  $this->job_id = 0;
121
  $this->step = 0;
122
  }
123
+ } elseif ( ! in_array( $job_status, apply_filters( 'job_manager_valid_submit_job_statuses', array( 'preview' ) ), true ) ) {
124
  $this->job_id = 0;
125
  $this->step = 0;
126
  }
146
 
147
  $allowed_application_method = get_option( 'job_manager_allowed_application_method', '' );
148
  switch ( $allowed_application_method ) {
149
+ case 'email':
150
  $application_method_label = __( 'Application email', 'wp-job-manager' );
151
  $application_method_placeholder = __( 'you@yourdomain.com', 'wp-job-manager' );
152
  $application_method_sanitizer = 'email';
153
+ break;
154
+ case 'url':
155
  $application_method_label = __( 'Application URL', 'wp-job-manager' );
156
  $application_method_placeholder = __( 'http://', 'wp-job-manager' );
157
  $application_method_sanitizer = 'url';
158
+ break;
159
+ default:
160
  $application_method_label = __( 'Application email/URL', 'wp-job-manager' );
161
  $application_method_placeholder = __( 'Enter an email address or website URL', 'wp-job-manager' );
162
  $application_method_sanitizer = 'url_or_email';
163
+ break;
164
  }
165
 
166
  if ( job_manager_multi_job_type() ) {
168
  } else {
169
  $job_type = 'term-select';
170
  }
171
+ $this->fields = apply_filters(
172
+ 'submit_job_form_fields',
173
+ array(
174
+ 'job' => array(
175
+ 'job_title' => array(
176
+ 'label' => __( 'Job Title', 'wp-job-manager' ),
177
+ 'type' => 'text',
178
+ 'required' => true,
179
+ 'placeholder' => '',
180
+ 'priority' => 1,
181
+ ),
182
+ 'job_location' => array(
183
+ 'label' => __( 'Location', 'wp-job-manager' ),
184
+ 'description' => __( 'Leave this blank if the location is not important', 'wp-job-manager' ),
185
+ 'type' => 'text',
186
+ 'required' => false,
187
+ 'placeholder' => __( 'e.g. "London"', 'wp-job-manager' ),
188
+ 'priority' => 2,
189
+ ),
190
+ 'job_type' => array(
191
+ 'label' => __( 'Job type', 'wp-job-manager' ),
192
+ 'type' => $job_type,
193
+ 'required' => true,
194
+ 'placeholder' => __( 'Choose job type&hellip;', 'wp-job-manager' ),
195
+ 'priority' => 3,
196
+ 'default' => 'full-time',
197
+ 'taxonomy' => 'job_listing_type',
198
+ ),
199
+ 'job_category' => array(
200
+ 'label' => __( 'Job category', 'wp-job-manager' ),
201
+ 'type' => 'term-multiselect',
202
+ 'required' => true,
203
+ 'placeholder' => '',
204
+ 'priority' => 4,
205
+ 'default' => '',
206
+ 'taxonomy' => 'job_listing_category',
207
+ ),
208
+ 'job_description' => array(
209
+ 'label' => __( 'Description', 'wp-job-manager' ),
210
+ 'type' => 'wp-editor',
211
+ 'required' => true,
212
+ 'priority' => 5,
213
+ ),
214
+ 'application' => array(
215
+ 'label' => $application_method_label,
216
+ 'type' => 'text',
217
+ 'sanitizer' => $application_method_sanitizer,
218
+ 'required' => true,
219
+ 'placeholder' => $application_method_placeholder,
220
+ 'priority' => 6,
221
+ ),
 
 
 
 
 
 
 
 
 
 
 
 
 
 
222
  ),
223
+ 'company' => array(
224
+ 'company_name' => array(
225
+ 'label' => __( 'Company name', 'wp-job-manager' ),
226
+ 'type' => 'text',
227
+ 'required' => true,
228
+ 'placeholder' => __( 'Enter the name of the company', 'wp-job-manager' ),
229
+ 'priority' => 1,
230
+ ),
231
+ 'company_website' => array(
232
+ 'label' => __( 'Website', 'wp-job-manager' ),
233
+ 'type' => 'text',
234
+ 'sanitizer' => 'url',
235
+ 'required' => false,
236
+ 'placeholder' => __( 'http://', 'wp-job-manager' ),
237
+ 'priority' => 2,
238
+ ),
239
+ 'company_tagline' => array(
240
+ 'label' => __( 'Tagline', 'wp-job-manager' ),
241
+ 'type' => 'text',
242
+ 'required' => false,
243
+ 'placeholder' => __( 'Briefly describe your company', 'wp-job-manager' ),
244
+ 'maxlength' => 64,
245
+ 'priority' => 3,
246
+ ),
247
+ 'company_video' => array(
248
+ 'label' => __( 'Video', 'wp-job-manager' ),
249
+ 'type' => 'text',
250
+ 'sanitizer' => 'url',
251
+ 'required' => false,
252
+ 'placeholder' => __( 'A link to a video about your company', 'wp-job-manager' ),
253
+ 'priority' => 4,
254
+ ),
255
+ 'company_twitter' => array(
256
+ 'label' => __( 'Twitter username', 'wp-job-manager' ),
257
+ 'type' => 'text',
258
+ 'required' => false,
259
+ 'placeholder' => __( '@yourcompany', 'wp-job-manager' ),
260
+ 'priority' => 5,
261
+ ),
262
+ 'company_logo' => array(
263
+ 'label' => __( 'Logo', 'wp-job-manager' ),
264
+ 'type' => 'file',
265
+ 'required' => false,
266
+ 'placeholder' => '',
267
+ 'priority' => 6,
268
+ 'ajax' => true,
269
+ 'multiple' => false,
270
+ 'allowed_mime_types' => array(
271
+ 'jpg' => 'image/jpeg',
272
+ 'jpeg' => 'image/jpeg',
273
+ 'gif' => 'image/gif',
274
+ 'png' => 'image/png',
275
+ ),
276
+ ),
277
  ),
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
278
  )
279
+ );
280
 
281
+ if ( ! get_option( 'job_manager_enable_categories' ) || 0 === intval( wp_count_terms( 'job_listing_category' ) ) ) {
282
  unset( $this->fields['job']['job_category'] );
283
  }
284
+ if ( ! get_option( 'job_manager_enable_types' ) || 0 === intval( wp_count_terms( 'job_listing_type' ) ) ) {
285
  unset( $this->fields['job']['job_type'] );
286
  }
287
  }
302
  * Validates the posted fields.
303
  *
304
  * @param array $values
305
+ * @return bool|WP_Error True on success, WP_Error on failure.
306
+ * @throws Exception Uploaded file is not a valid mime-type or other validation error.
307
  */
308
  protected function validate_fields( $values ) {
309
  foreach ( $this->fields as $group_key => $group_fields ) {
310
  foreach ( $group_fields as $key => $field ) {
311
  if ( $field['required'] && empty( $values[ $group_key ][ $key ] ) ) {
312
+ // translators: Placeholder %s is the label for the required field.
313
  return new WP_Error( 'validation-error', sprintf( __( '%s is a required field', 'wp-job-manager' ), $field['label'] ) );
314
  }
315
+ if ( ! empty( $field['taxonomy'] ) && in_array( $field['type'], array( 'term-checklist', 'term-select', 'term-multiselect' ), true ) ) {
316
  if ( is_array( $values[ $group_key ][ $key ] ) ) {
317
  $check_value = $values[ $group_key ][ $key ];
318
  } else {
320
  }
321
  foreach ( $check_value as $term ) {
322
  if ( ! term_exists( $term, $field['taxonomy'] ) ) {
323
+ // translators: Placeholder %s is the field label that is did not validate.
324
  return new WP_Error( 'validation-error', sprintf( __( '%s is invalid', 'wp-job-manager' ), $field['label'] ) );
325
  }
326
  }
336
  $file_url = current( explode( '?', $file_url ) );
337
  $file_info = wp_check_filetype( $file_url );
338
 
339
+ if ( ! is_numeric( $file_url ) && $file_info && ! in_array( $file_info['type'], $field['allowed_mime_types'], true ) ) {
340
+ // translators: Placeholder %1$s is field label; %2$s is the file mime type; %3$s is the allowed mime-types.
341
+ throw new Exception( sprintf( __( '"%1$s" (filetype %2$s) needs to be one of the following file types: %3$s', 'wp-job-manager' ), $field['label'], $file_info['ext'], implode( ', ', array_keys( $field['allowed_mime_types'] ) ) ) );
342
  }
343
  }
344
  }
346
  }
347
  }
348
 
349
+ // Application method.
350
  if ( isset( $values['job']['application'] ) && ! empty( $values['job']['application'] ) ) {
351
+ $allowed_application_method = get_option( 'job_manager_allowed_application_method', '' );
352
  $values['job']['application'] = str_replace( ' ', '+', $values['job']['application'] );
353
  switch ( $allowed_application_method ) {
354
+ case 'email':
355
  if ( ! is_email( $values['job']['application'] ) ) {
356
  throw new Exception( __( 'Please enter a valid application email address', 'wp-job-manager' ) );
357
  }
358
  break;
359
+ case 'url':
360
+ // Prefix http if needed.
361
  if ( ! strstr( $values['job']['application'], 'http:' ) && ! strstr( $values['job']['application'], 'https:' ) ) {
362
  $values['job']['application'] = 'http://' . $values['job']['application'];
363
  }
365
  throw new Exception( __( 'Please enter a valid application URL', 'wp-job-manager' ) );
366
  }
367
  break;
368
+ default:
369
  if ( ! is_email( $values['job']['application'] ) ) {
370
+ // Prefix http if needed.
371
  if ( ! strstr( $values['job']['application'], 'http:' ) && ! strstr( $values['job']['application'], 'https:' ) ) {
372
  $values['job']['application'] = 'http://' . $values['job']['application'];
373
  }
389
  wp_enqueue_script( 'wp-job-manager-job-submission' );
390
  wp_enqueue_style( 'wp-job-manager-job-submission', JOB_MANAGER_PLUGIN_URL . '/assets/css/job-submission.css', array(), JOB_MANAGER_VERSION );
391
 
392
+ // Register datepicker JS. It will be enqueued if needed when a date.
393
  // field is rendered.
394
+ 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 );
395
 
396
  // Localize scripts after the fields are rendered.
397
  add_action( 'submit_job_form_end', array( $this, 'localize_job_form_scripts' ) );
405
  if ( function_exists( 'wp_localize_jquery_ui_datepicker' ) ) {
406
  wp_localize_jquery_ui_datepicker();
407
  } else {
408
+ wp_localize_script(
409
+ 'wp-job-manager-datepicker',
410
+ 'job_manager_datepicker',
411
+ array(
412
+ /* translators: jQuery date format, see http://api.jqueryui.com/datepicker/#utility-formatDate */
413
+ 'date_format' => _x( 'yy-mm-dd', 'Date format for jQuery datepicker.', 'wp-job-manager' ),
414
+ )
415
+ );
416
  }
417
  }
418
 
436
  public function submit() {
437
  $this->init_fields();
438
 
439
+ // Load data if neccessary.
440
  if ( $this->job_id ) {
441
  $job = get_post( $this->job_id );
442
  foreach ( $this->fields as $group_key => $group_fields ) {
443
  foreach ( $group_fields as $key => $field ) {
444
  switch ( $key ) {
445
+ case 'job_title':
446
  $this->fields[ $group_key ][ $key ]['value'] = $job->post_title;
447
+ break;
448
+ case 'job_description':
449
  $this->fields[ $group_key ][ $key ]['value'] = $job->post_content;
450
+ break;
451
+ case 'job_type':
452
  $this->fields[ $group_key ][ $key ]['value'] = wp_get_object_terms( $job->ID, 'job_listing_type', array( 'fields' => 'ids' ) );
453
  if ( ! job_manager_multi_job_type() ) {
454
  $this->fields[ $group_key ][ $key ]['value'] = current( $this->fields[ $group_key ][ $key ]['value'] );
455
  }
456
+ break;
457
+ case 'job_category':
458
  $this->fields[ $group_key ][ $key ]['value'] = wp_get_object_terms( $job->ID, 'job_listing_category', array( 'fields' => 'ids' ) );
459
+ break;
460
+ case 'company_logo':
461
  $this->fields[ $group_key ][ $key ]['value'] = has_post_thumbnail( $job->ID ) ? get_post_thumbnail_id( $job->ID ) : get_post_meta( $job->ID, '_' . $key, true );
462
+ break;
463
  default:
464
  $this->fields[ $group_key ][ $key ]['value'] = get_post_meta( $job->ID, '_' . $key, true );
465
+ break;
466
  }
467
  }
468
  }
469
 
470
  $this->fields = apply_filters( 'submit_job_form_fields_get_job_data', $this->fields, $job );
471
 
472
+ // Get user meta.
473
  } elseif ( is_user_logged_in() && empty( $_POST['submit_job'] ) ) {
474
  if ( ! empty( $this->fields['company'] ) ) {
475
  foreach ( $this->fields['company'] as $key => $field ) {
478
  }
479
  if ( ! empty( $this->fields['job']['application'] ) ) {
480
  $allowed_application_method = get_option( 'job_manager_allowed_application_method', '' );
481
+ if ( 'url' !== $allowed_application_method ) {
482
+ $current_user = wp_get_current_user();
483
  $this->fields['job']['application']['value'] = $current_user->user_email;
484
  }
485
  }
487
  }
488
 
489
  $this->enqueue_job_form_assets();
490
+ get_job_manager_template(
491
+ 'job-submit.php',
492
+ array(
493
+ 'form' => $this->form_name,
494
+ 'job_id' => $this->get_job_id(),
495
+ 'resume_edit' => $this->resume_edit,
496
+ 'action' => $this->get_action(),
497
+ 'job_fields' => $this->get_fields( 'job' ),
498
+ 'company_fields' => $this->get_fields( 'company' ),
499
+ 'step' => $this->get_step(),
500
+ 'submit_button_text' => apply_filters( 'submit_job_form_submit_button_text', __( 'Preview', 'wp-job-manager' ) ),
501
+ )
502
+ );
503
  }
504
 
505
  /**
506
  * Handles the submission of form data.
507
+ *
508
+ * @throws Exception On validation error.
509
  */
510
  public function submit_handler() {
511
  try {
512
+ // Init fields.
513
  $this->init_fields();
514
 
515
+ // Get posted values.
516
  $values = $this->get_posted_fields();
517
 
518
  if ( empty( $_POST['submit_job'] ) ) {
519
  return;
520
  }
521
 
522
+ // Validate required.
523
+ $validation_status = $this->validate_fields( $values );
524
+ if ( is_wp_error( $validation_status ) ) {
525
+ throw new Exception( $validation_status->get_error_message() );
526
  }
527
 
528
+ // Account creation.
529
  if ( ! is_user_logged_in() ) {
530
  $create_account = false;
531
 
551
  if ( ! wpjm_validate_new_password( $_POST['create_account_password'] ) ) {
552
  $password_hint = wpjm_get_password_rules_hint();
553
  if ( $password_hint ) {
554
+ // translators: Placeholder %s is the password hint.
555
  throw new Exception( sprintf( __( 'Invalid Password: %s', 'wp-job-manager' ), $password_hint ) );
556
  } else {
557
  throw new Exception( __( 'Password is not valid.', 'wp-job-manager' ) );
560
  }
561
 
562
  if ( ! empty( $_POST['create_account_email'] ) ) {
563
+ $create_account = wp_job_manager_create_account(
564
+ array(
565
+ 'username' => ( job_manager_generate_username_from_email() || empty( $_POST['create_account_username'] ) ) ? '' : $_POST['create_account_username'],
566
+ 'password' => ( wpjm_use_standard_password_setup_email() || empty( $_POST['create_account_password'] ) ) ? '' : $_POST['create_account_password'],
567
+ 'email' => $_POST['create_account_email'],
568
+ 'role' => get_option( 'job_manager_registration_role' ),
569
+ )
570
+ );
571
  }
572
  }
573
 
580
  throw new Exception( __( 'You must be signed in to post a new listing.', 'wp-job-manager' ) );
581
  }
582
 
583
+ // Update the job.
584
  $this->save_job( $values['job']['job_title'], $values['job']['job_description'], $this->job_id ? '' : 'preview', $values );
585
  $this->update_job_data( $values );
586
 
587
+ // Successful, show next step.
588
  $this->step ++;
589
 
590
  } catch ( Exception $e ) {
607
  'post_title' => $post_title,
608
  'post_content' => $post_content,
609
  'post_type' => 'job_listing',
610
+ 'comment_status' => 'closed',
611
  );
612
 
613
  if ( $update_slug ) {
614
+ $job_slug = array();
615
 
616
+ // Prepend with company name.
617
  if ( apply_filters( 'submit_job_form_prefix_post_name_with_company', true ) && ! empty( $values['company']['company_name'] ) ) {
618
  $job_slug[] = $values['company']['company_name'];
619
  }
620
 
621
+ // Prepend location.
622
  if ( apply_filters( 'submit_job_form_prefix_post_name_with_location', true ) && ! empty( $values['job']['job_location'] ) ) {
623
  $job_slug[] = $values['job']['job_location'];
624
  }
625
 
626
+ // Prepend with job type.
627
  if ( apply_filters( 'submit_job_form_prefix_post_name_with_job_type', true ) && ! empty( $values['job']['job_type'] ) ) {
628
  if ( ! job_manager_multi_job_type() ) {
629
  $job_slug[] = $values['job']['job_type'];
671
  * Creates a file attachment.
672
  *
673
  * @param string $attachment_url
674
+ * @return int attachment id.
675
  */
676
  protected function create_attachment( $attachment_url ) {
677
+ include_once ABSPATH . 'wp-admin/includes/image.php';
678
+ include_once ABSPATH . 'wp-admin/includes/media.php';
679
 
680
  $upload_dir = wp_upload_dir();
681
  $attachment_url = str_replace( array( $upload_dir['baseurl'], WP_CONTENT_URL, site_url( '/' ) ), array( $upload_dir['basedir'], WP_CONTENT_DIR, ABSPATH ), $attachment_url );
684
  return 0;
685
  }
686
 
687
+ $attachment = array(
688
  'post_title' => wpjm_get_the_job_title( $this->job_id ),
689
  'post_content' => '',
690
  'post_status' => 'inherit',
691
  'post_parent' => $this->job_id,
692
+ 'guid' => $attachment_url,
693
  );
694
 
695
+ $info = wp_check_filetype( $attachment_url );
696
+ if ( $info ) {
697
  $attachment['post_mime_type'] = $info['type'];
698
  }
699
 
713
  * @param array $values
714
  */
715
  protected function update_job_data( $values ) {
716
+ // Set defaults.
717
  add_post_meta( $this->job_id, '_filled', 0, true );
718
  add_post_meta( $this->job_id, '_featured', 0, true );
719
 
720
  $maybe_attach = array();
721
 
722
+ // Loop fields and save meta and term data.
723
  foreach ( $this->fields as $group_key => $group_fields ) {
724
  foreach ( $group_fields as $key => $field ) {
725
+ // Save taxonomies.
726
  if ( ! empty( $field['taxonomy'] ) ) {
727
  if ( is_array( $values[ $group_key ][ $key ] ) ) {
728
  wp_set_object_terms( $this->job_id, $values[ $group_key ][ $key ], $field['taxonomy'], false );
730
  wp_set_object_terms( $this->job_id, array( $values[ $group_key ][ $key ] ), $field['taxonomy'], false );
731
  }
732
 
733
+ // Company logo is a featured image.
734
  } elseif ( 'company_logo' === $key ) {
735
  $attachment_id = is_numeric( $values[ $group_key ][ $key ] ) ? absint( $values[ $group_key ][ $key ] ) : $this->create_attachment( $values[ $group_key ][ $key ] );
736
  if ( empty( $attachment_id ) ) {
740
  }
741
  update_user_meta( get_current_user_id(), '_company_logo', $attachment_id );
742
 
743
+ // Save meta data.
744
  } else {
745
  update_post_meta( $this->job_id, '_' . $key, $values[ $group_key ][ $key ] );
746
 
747
+ // Handle attachments.
748
  if ( 'file' === $field['type'] ) {
749
  if ( is_array( $values[ $group_key ][ $key ] ) ) {
750
  foreach ( $values[ $group_key ][ $key ] as $file_url ) {
760
 
761
  $maybe_attach = array_filter( $maybe_attach );
762
 
763
+ // Handle attachments.
764
+ if ( count( $maybe_attach ) && apply_filters( 'job_manager_attach_uploaded_files', true ) ) {
765
+ // Get attachments.
766
  $attachments = get_posts( 'post_parent=' . $this->job_id . '&post_type=attachment&fields=ids&numberposts=-1' );
767
  $attachment_urls = array();
768
 
769
+ // Loop attachments already attached to the job.
770
  foreach ( $attachments as $attachment_id ) {
771
  $attachment_urls[] = wp_get_attachment_url( $attachment_id );
772
  }
773
 
774
  foreach ( $maybe_attach as $attachment_url ) {
775
+ if ( ! in_array( $attachment_url, $attachment_urls, true ) ) {
776
  $this->create_attachment( $attachment_url );
777
  }
778
  }
779
  }
780
 
781
+ // And user meta to save time in future.
782
  if ( is_user_logged_in() ) {
783
  update_user_meta( get_current_user_id(), '_company_name', isset( $values['company']['company_name'] ) ? $values['company']['company_name'] : '' );
784
  update_user_meta( get_current_user_id(), '_company_website', isset( $values['company']['company_website'] ) ? $values['company']['company_website'] : '' );
798
 
799
  if ( $this->job_id ) {
800
  $job_preview = true;
801
+ $post = get_post( $this->job_id ); // WPCS: override ok.
802
  $post->post_status = 'preview';
803
 
804
  setup_postdata( $post );
805
 
806
+ get_job_manager_template(
807
+ 'job-preview.php',
808
+ array(
809
+ 'form' => $this,
810
+ )
811
+ );
812
 
813
  wp_reset_postdata();
814
  }
822
  return;
823
  }
824
 
825
+ // Edit = show submit form again.
826
  if ( ! empty( $_POST['edit_job'] ) ) {
827
  $this->step --;
828
  }
829
 
830
+ // Continue = change job status then show next screen.
831
  if ( ! empty( $_POST['continue'] ) ) {
832
  $job = get_post( $this->job_id );
833
 
834
+ if ( in_array( $job->post_status, array( 'preview', 'expired' ), true ) ) {
835
+ // Reset expiry.
836
  delete_post_meta( $job->ID, '_job_expires' );
837
 
838
+ // Update job listing.
839
  $update_job = array();
840
  $update_job['ID'] = $job->ID;
841
  $update_job['post_status'] = apply_filters( 'submit_job_post_status', get_option( 'job_manager_submission_requires_approval' ) ? 'pending' : 'publish', $job );
includes/helper/class-wp-job-manager-helper-api.php CHANGED
@@ -37,10 +37,10 @@ class WP_Job_Manager_Helper_API {
37
  * Sends and receives data to and from the server API
38
  *
39
  * @param array|string $args
40
- * @return object|bool $response
41
  */
42
  public function plugin_update_check( $args ) {
43
- $args = wp_parse_args( $args );
44
  $args['wc-api'] = 'wp_plugin_licencing_update_api';
45
  $args['request'] = 'pluginupdatecheck';
46
  return $this->request( $args );
@@ -50,10 +50,10 @@ class WP_Job_Manager_Helper_API {
50
  * Sends and receives data to and from the server API
51
  *
52
  * @param array|string $args
53
- * @return object $response
54
  */
55
  public function plugin_information( $args ) {
56
- $args = wp_parse_args( $args );
57
  $args['wc-api'] = 'wp_plugin_licencing_update_api';
58
  $args['request'] = 'plugininformation';
59
  return $this->request( $args );
@@ -66,10 +66,10 @@ class WP_Job_Manager_Helper_API {
66
  * @return boolean|string JSON response or false if failed.
67
  */
68
  public function activate( $args ) {
69
- $args = wp_parse_args( $args );
70
  $args['wc-api'] = 'wp_plugin_licencing_activation_api';
71
  $args['request'] = 'activate';
72
- $response = $this->request( $args, true );
73
  if ( false === $response ) {
74
  return false;
75
  }
@@ -83,10 +83,10 @@ class WP_Job_Manager_Helper_API {
83
  * @return boolean|string JSON response or false if failed.
84
  */
85
  public function deactivate( $args ) {
86
- $args = wp_parse_args( $args );
87
  $args['wc-api'] = 'wp_plugin_licencing_activation_api';
88
  $args['request'] = 'deactivate';
89
- $response = $this->request( $args, false );
90
  if ( false === $response ) {
91
  return false;
92
  }
@@ -112,30 +112,33 @@ class WP_Job_Manager_Helper_API {
112
  );
113
 
114
  $args = wp_parse_args( $args, $defaults );
115
- $request = wp_safe_remote_get( $this->get_api_base_url() . '?' . http_build_query( $args, '', '&' ), array(
116
- 'timeout' => 10,
117
- 'headers' => array(
118
- 'Accept' => 'application/json',
119
- ),
120
- ) );
 
 
 
121
 
122
  if ( is_wp_error( $request ) || 200 !== wp_remote_retrieve_response_code( $request ) ) {
123
  if ( $return_error ) {
124
  if ( is_wp_error( $request ) ) {
125
  return array(
126
  'error_code' => $request->get_error_code(),
127
- 'error' => $request->get_error_message(),
128
  );
129
  }
130
  return array(
131
  'error_code' => wp_remote_retrieve_response_code( $request ),
132
- 'error' => 'Error code: ' . wp_remote_retrieve_response_code( $request ),
133
  );
134
  }
135
  return false;
136
  }
137
 
138
- $response = @json_decode( wp_remote_retrieve_body( $request ), true );
139
 
140
  if ( is_array( $response ) ) {
141
  return $response;
@@ -163,7 +166,7 @@ class WP_Job_Manager_Helper_API {
163
  */
164
  private function get_api_base_url() {
165
  if ( defined( 'JOB_MANAGER_VERSION' )
166
- && defined( 'JOB_MANAGER_DEV_API_BASE_URL')
167
  && '-dev' === substr( JOB_MANAGER_VERSION, -4 )
168
  ) {
169
  return JOB_MANAGER_DEV_API_BASE_URL;
37
  * Sends and receives data to and from the server API
38
  *
39
  * @param array|string $args
40
+ * @return object|bool $response.
41
  */
42
  public function plugin_update_check( $args ) {
43
+ $args = wp_parse_args( $args );
44
  $args['wc-api'] = 'wp_plugin_licencing_update_api';
45
  $args['request'] = 'pluginupdatecheck';
46
  return $this->request( $args );
50
  * Sends and receives data to and from the server API
51
  *
52
  * @param array|string $args
53
+ * @return object $response.
54
  */
55
  public function plugin_information( $args ) {
56
+ $args = wp_parse_args( $args );
57
  $args['wc-api'] = 'wp_plugin_licencing_update_api';
58
  $args['request'] = 'plugininformation';
59
  return $this->request( $args );
66
  * @return boolean|string JSON response or false if failed.
67
  */
68
  public function activate( $args ) {
69
+ $args = wp_parse_args( $args );
70
  $args['wc-api'] = 'wp_plugin_licencing_activation_api';
71
  $args['request'] = 'activate';
72
+ $response = $this->request( $args, true );
73
  if ( false === $response ) {
74
  return false;
75
  }
83
  * @return boolean|string JSON response or false if failed.
84
  */
85
  public function deactivate( $args ) {
86
+ $args = wp_parse_args( $args );
87
  $args['wc-api'] = 'wp_plugin_licencing_activation_api';
88
  $args['request'] = 'deactivate';
89
+ $response = $this->request( $args, false );
90
  if ( false === $response ) {
91
  return false;
92
  }
112
  );
113
 
114
  $args = wp_parse_args( $args, $defaults );
115
+ $request = wp_safe_remote_get(
116
+ $this->get_api_base_url() . '?' . http_build_query( $args, '', '&' ),
117
+ array(
118
+ 'timeout' => 10,
119
+ 'headers' => array(
120
+ 'Accept' => 'application/json',
121
+ ),
122
+ )
123
+ );
124
 
125
  if ( is_wp_error( $request ) || 200 !== wp_remote_retrieve_response_code( $request ) ) {
126
  if ( $return_error ) {
127
  if ( is_wp_error( $request ) ) {
128
  return array(
129
  'error_code' => $request->get_error_code(),
130
+ 'error' => $request->get_error_message(),
131
  );
132
  }
133
  return array(
134
  'error_code' => wp_remote_retrieve_response_code( $request ),
135
+ 'error' => 'Error code: ' . wp_remote_retrieve_response_code( $request ),
136
  );
137
  }
138
  return false;
139
  }
140
 
141
+ $response = json_decode( wp_remote_retrieve_body( $request ), true );
142
 
143
  if ( is_array( $response ) ) {
144
  return $response;
166
  */
167
  private function get_api_base_url() {
168
  if ( defined( 'JOB_MANAGER_VERSION' )
169
+ && defined( 'JOB_MANAGER_DEV_API_BASE_URL' )
170
  && '-dev' === substr( JOB_MANAGER_VERSION, -4 )
171
  ) {
172
  return JOB_MANAGER_DEV_API_BASE_URL;
includes/helper/class-wp-job-manager-helper-options.php CHANGED
@@ -103,6 +103,7 @@ class WP_Job_Manager_Helper_Options {
103
  /**
104
  * Update the master option.
105
  *
 
106
  * @return bool
107
  */
108
  private static function update_master_option( $value ) {
103
  /**
104
  * Update the master option.
105
  *
106
+ * @param array $value Master license container array.
107
  * @return bool
108
  */
109
  private static function update_master_option( $value ) {
includes/helper/class-wp-job-manager-helper.php CHANGED
@@ -1,7 +1,7 @@
1
  <?php
2
 
3
  if ( ! defined( 'ABSPATH' ) ) {
4
- exit; // Exit if accessed directly
5
  }
6
 
7
  /**
@@ -12,11 +12,15 @@ if ( ! defined( 'ABSPATH' ) ) {
12
  */
13
  class WP_Job_Manager_Helper {
14
  /**
 
 
15
  * @var array Messages when updating licences.
16
  */
17
  protected $licence_messages = array();
18
 
19
  /**
 
 
20
  * @var WP_Job_Manager_Helper_API
21
  */
22
  protected $api;
@@ -30,6 +34,8 @@ class WP_Job_Manager_Helper {
30
  private static $_instance = null;
31
 
32
  /**
 
 
33
  * @var bool
34
  * @since 1.29.1
35
  */
@@ -53,8 +59,8 @@ class WP_Job_Manager_Helper {
53
  * Loads the class, runs on init.
54
  */
55
  public function init() {
56
- include_once( dirname( __FILE__ ) . '/class-wp-job-manager-helper-options.php' );
57
- include_once( dirname( __FILE__ ) . '/class-wp-job-manager-helper-api.php' );
58
 
59
  $this->api = WP_Job_Manager_Helper_API::instance();
60
 
@@ -85,7 +91,7 @@ class WP_Job_Manager_Helper {
85
  private function handle_admin_request() {
86
  if ( ! empty( $_GET['dismiss-wpjm-licence-notice'] ) ) {
87
  $product_plugins = $this->get_installed_plugins();
88
- $product_slug = sanitize_text_field( $_GET['dismiss-wpjm-licence-notice'] );
89
  if ( isset( $product_plugins[ $product_slug ] ) ) {
90
  WP_Job_Manager_Helper_Options::update( $product_slug, 'hide_key_notice', true );
91
  }
@@ -106,14 +112,14 @@ class WP_Job_Manager_Helper {
106
 
107
  // We only want to show the notices on the plugins page and main job listing admin page.
108
  $screen = get_current_screen();
109
- if ( null === $screen || ! in_array( $screen->id, array( 'plugins', 'edit-job_listing' ) ) ) {
110
  return false;
111
  }
112
 
113
  $dev_version_loc = strpos( JOB_MANAGER_VERSION, '-dev' );
114
  if (
115
  false !== $dev_version_loc
116
- && $minimum_required_core_version === substr( JOB_MANAGER_VERSION, 0, $dev_version_loc )
117
  ) {
118
  return false;
119
  }
@@ -129,13 +135,15 @@ class WP_Job_Manager_Helper {
129
  * @return array
130
  */
131
  public function check_for_updates( $check_for_updates_data ) {
132
- // Set version variables
133
  foreach ( $this->get_installed_plugins() as $product_slug => $plugin_data ) {
134
- if ( $response = $this->get_plugin_version( $plugin_data['_filename'] ) ) {
135
- // If there is a new version, modify the transient to reflect an update is available
136
- if ( $response !== false && isset( $response['new_version'] ) && version_compare( $response['new_version'], $plugin_data['Version'], '>' ) ) {
137
- $check_for_updates_data->response[ $plugin_data['_filename'] ] = (object) $response;
138
- }
 
 
139
  }
140
  }
141
  return $check_for_updates_data;
@@ -154,22 +162,24 @@ class WP_Job_Manager_Helper {
154
  return false;
155
  }
156
  $product_slug = $plugin_data['_product_slug'];
157
- $licence = $this->get_plugin_licence( $product_slug );
158
  if ( ! $licence || empty( $licence['licence_key'] ) ) {
159
  return false;
160
  }
161
 
162
- $response = $this->api->plugin_update_check( array(
163
- 'plugin_name' => $plugin_data['Name'],
164
- 'version' => $plugin_data['Version'],
165
- 'api_product_id' => $product_slug,
166
- 'licence_key' => $licence['licence_key'],
167
- 'email' => $licence['email'],
168
- ) );
 
 
169
 
170
  $this->handle_api_errors( $product_slug, $response );
171
 
172
- // Set version variables
173
  if ( ! empty( $response ) ) {
174
  return $response;
175
  }
@@ -212,9 +222,9 @@ class WP_Job_Manager_Helper {
212
  /**
213
  * Fetches the plugin information for WPJM plugins.
214
  *
215
- * @param false|object|array $response The result object or array. Default false.
216
- * @param string $action The type of information being requested from the Plugin Install API.
217
- * @param object $args Plugin API arguments.
218
  *
219
  * @return false|object|array
220
  */
@@ -227,7 +237,8 @@ class WP_Job_Manager_Helper {
227
  return $response;
228
  }
229
 
230
- if ( ( $plugin_info = $this->get_plugin_info( $args->slug ) ) ) {
 
231
  $response = (object) $plugin_info;
232
  }
233
 
@@ -247,20 +258,20 @@ class WP_Job_Manager_Helper {
247
  return $actions;
248
  }
249
  $product_slug = $plugin['_product_slug'];
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';
262
  }
263
- $actions[] = '<a class="' . $css_class . '" href="' . esc_url( admin_url( 'edit.php?post_type=job_listing&page=job-manager-addons&section=helper' ) ) . '">' . $manage_licence_label . '</a>';
264
  return $actions;
265
  }
266
 
@@ -312,7 +323,7 @@ class WP_Job_Manager_Helper {
312
  /**
313
  * Returns the plugin data for plugin with a `WPJM-Product` tag by plugin filename.
314
  *
315
- * @param $plugin_filename
316
  * @return bool|array
317
  */
318
  private function get_licence_managed_plugin( $plugin_filename ) {
@@ -331,21 +342,21 @@ class WP_Job_Manager_Helper {
331
  * @return array|bool
332
  */
333
  public function get_plugin_licence( $product_slug ) {
334
- $licence_key = WP_Job_Manager_Helper_Options::get( $product_slug, 'licence_key' );
335
  $activation_email = WP_Job_Manager_Helper_Options::get( $product_slug, 'email' );
336
- $errors = WP_Job_Manager_Helper_Options::get( $product_slug, 'errors' );
337
 
338
  return array(
339
  'licence_key' => $licence_key,
340
- 'email' => $activation_email,
341
- 'errors' => $errors,
342
  );
343
  }
344
 
345
  /**
346
  * Adds newly recognized data header in WordPress plugin files.
347
  *
348
- * @params array $headers
349
  * @return array
350
  */
351
  public function extra_headers( $headers ) {
@@ -356,12 +367,12 @@ class WP_Job_Manager_Helper {
356
  /**
357
  * Returns list of installed WPJM plugins with managed licenses indexed by product ID.
358
  *
359
- * @param bool $active_only Only return active plugins
360
  * @return array
361
  */
362
  protected function get_installed_plugins( $active_only = true ) {
363
  if ( ! function_exists( 'get_plugins' ) ) {
364
- require_once( ABSPATH . 'wp-admin/includes/plugin.php' );
365
  }
366
 
367
  /**
@@ -378,16 +389,16 @@ class WP_Job_Manager_Helper {
378
  }
379
 
380
  $wpjm_plugins = array();
381
- $plugins = get_plugins();
382
 
383
  foreach ( $plugins as $filename => $data ) {
384
  if ( empty( $data['WPJM-Product'] ) || ( true === $active_only && ! is_plugin_active( $filename ) ) ) {
385
  continue;
386
  }
387
 
388
- $data['_filename'] = $filename;
389
- $data['_product_slug'] = $data['WPJM-Product'];
390
- $data['_type'] = 'plugin';
391
  $wpjm_plugins[ $data['WPJM-Product'] ] = $data;
392
  }
393
 
@@ -405,7 +416,7 @@ class WP_Job_Manager_Helper {
405
  $this->handle_request();
406
  }
407
  $licenced_plugins = $this->get_installed_plugins();
408
- include_once( dirname( __FILE__ ) . '/views/html-licences.php' );
409
  }
410
 
411
  /**
@@ -413,16 +424,16 @@ class WP_Job_Manager_Helper {
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
  }
@@ -449,7 +460,7 @@ class WP_Job_Manager_Helper {
449
  $this->add_error( $product_slug, __( 'Please enter a valid license key and email address in order to activate this plugin\'s license.', 'wp-job-manager' ) );
450
  break;
451
  }
452
- $email = sanitize_email( $_POST['email'] );
453
  $licence_key = sanitize_text_field( $_POST['licence_key'] );
454
  $this->activate_licence( $product_slug, $licence_key, $email );
455
  break;
@@ -467,11 +478,13 @@ class WP_Job_Manager_Helper {
467
  * @param string $email
468
  */
469
  private function activate_licence( $product_slug, $licence_key, $email ) {
470
- $response = $this->api->activate( array(
471
- 'api_product_id' => $product_slug,
472
- 'licence_key' => $licence_key,
473
- 'email' => $email,
474
- ) );
 
 
475
 
476
  if ( false === $response ) {
477
  $this->add_error( $product_slug, __( 'Connection failed to the License Key API server - possible server issue.', 'wp-job-manager' ) );
@@ -499,11 +512,13 @@ class WP_Job_Manager_Helper {
499
  $this->add_error( $product_slug, __( 'license is not active.', 'wp-job-manager' ) );
500
  return;
501
  }
502
- $this->api->deactivate( array(
503
- 'api_product_id' => $product_slug,
504
- 'licence_key' => $licence['licence_key'],
505
- 'email' => $licence['email'],
506
- ) );
 
 
507
 
508
  WP_Job_Manager_Helper_Options::delete( $product_slug, 'licence_key' );
509
  WP_Job_Manager_Helper_Options::delete( $product_slug, 'email' );
@@ -525,7 +540,7 @@ class WP_Job_Manager_Helper {
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
 
@@ -572,7 +587,7 @@ class WP_Job_Manager_Helper {
572
  $this->licence_messages[ $product_slug ] = array();
573
  }
574
  $this->licence_messages[ $product_slug ][] = array(
575
- 'type' => $type,
576
  'message' => $message,
577
  );
578
  }
1
  <?php
2
 
3
  if ( ! defined( 'ABSPATH' ) ) {
4
+ exit; // Exit if accessed directly.
5
  }
6
 
7
  /**
12
  */
13
  class WP_Job_Manager_Helper {
14
  /**
15
+ * License messages to display to the user.
16
+ *
17
  * @var array Messages when updating licences.
18
  */
19
  protected $licence_messages = array();
20
 
21
  /**
22
+ * API object.
23
+ *
24
  * @var WP_Job_Manager_Helper_API
25
  */
26
  protected $api;
34
  private static $_instance = null;
35
 
36
  /**
37
+ * True if the plugin cache has already been cleared.
38
+ *
39
  * @var bool
40
  * @since 1.29.1
41
  */
59
  * Loads the class, runs on init.
60
  */
61
  public function init() {
62
+ include_once dirname( __FILE__ ) . '/class-wp-job-manager-helper-options.php';
63
+ include_once dirname( __FILE__ ) . '/class-wp-job-manager-helper-api.php';
64
 
65
  $this->api = WP_Job_Manager_Helper_API::instance();
66
 
91
  private function handle_admin_request() {
92
  if ( ! empty( $_GET['dismiss-wpjm-licence-notice'] ) ) {
93
  $product_plugins = $this->get_installed_plugins();
94
+ $product_slug = sanitize_text_field( $_GET['dismiss-wpjm-licence-notice'] );
95
  if ( isset( $product_plugins[ $product_slug ] ) ) {
96
  WP_Job_Manager_Helper_Options::update( $product_slug, 'hide_key_notice', true );
97
  }
112
 
113
  // We only want to show the notices on the plugins page and main job listing admin page.
114
  $screen = get_current_screen();
115
+ if ( null === $screen || ! in_array( $screen->id, array( 'plugins', 'edit-job_listing' ), true ) ) {
116
  return false;
117
  }
118
 
119
  $dev_version_loc = strpos( JOB_MANAGER_VERSION, '-dev' );
120
  if (
121
  false !== $dev_version_loc
122
+ && substr( JOB_MANAGER_VERSION, 0, $dev_version_loc ) === $minimum_required_core_version
123
  ) {
124
  return false;
125
  }
135
  * @return array
136
  */
137
  public function check_for_updates( $check_for_updates_data ) {
138
+ // Set version variables.
139
  foreach ( $this->get_installed_plugins() as $product_slug => $plugin_data ) {
140
+ $response = $this->get_plugin_version( $plugin_data['_filename'] );
141
+ // If there is a new version, modify the transient to reflect an update is available.
142
+ if ( $response
143
+ && isset( $response['new_version'] )
144
+ && version_compare( $response['new_version'], $plugin_data['Version'], '>' )
145
+ ) {
146
+ $check_for_updates_data->response[ $plugin_data['_filename'] ] = (object) $response;
147
  }
148
  }
149
  return $check_for_updates_data;
162
  return false;
163
  }
164
  $product_slug = $plugin_data['_product_slug'];
165
+ $licence = $this->get_plugin_licence( $product_slug );
166
  if ( ! $licence || empty( $licence['licence_key'] ) ) {
167
  return false;
168
  }
169
 
170
+ $response = $this->api->plugin_update_check(
171
+ array(
172
+ 'plugin_name' => $plugin_data['Name'],
173
+ 'version' => $plugin_data['Version'],
174
+ 'api_product_id' => $product_slug,
175
+ 'licence_key' => $licence['licence_key'],
176
+ 'email' => $licence['email'],
177
+ )
178
+ );
179
 
180
  $this->handle_api_errors( $product_slug, $response );
181
 
182
+ // Set version variables.
183
  if ( ! empty( $response ) ) {
184
  return $response;
185
  }
222
  /**
223
  * Fetches the plugin information for WPJM plugins.
224
  *
225
+ * @param false|object|array $response The result object or array. Default false.
226
+ * @param string $action The type of information being requested from the Plugin Install API.
227
+ * @param object $args Plugin API arguments.
228
  *
229
  * @return false|object|array
230
  */
237
  return $response;
238
  }
239
 
240
+ $plugin_info = $this->get_plugin_info( $args->slug );
241
+ if ( $plugin_info ) {
242
  $response = (object) $plugin_info;
243
  }
244
 
258
  return $actions;
259
  }
260
  $product_slug = $plugin['_product_slug'];
261
+ $licence = $this->get_plugin_licence( $product_slug );
262
+ $css_class = '';
263
  if ( $licence && ! empty( $licence['licence_key'] ) ) {
264
  if ( ! empty( $licence['errors'] ) ) {
265
  $manage_licence_label = __( 'Manage License (Requires Attention)', 'wp-job-manager' );
266
+ $css_class = 'wpjm-activate-licence-link';
267
  } else {
268
  $manage_licence_label = __( 'Manage License', 'wp-job-manager' );
269
  }
270
  } else {
271
  $manage_licence_label = __( 'Activate License', 'wp-job-manager' );
272
+ $css_class = 'wpjm-activate-licence-link';
273
  }
274
+ $actions[] = '<a class="' . esc_attr( $css_class ) . '" href="' . esc_url( admin_url( 'edit.php?post_type=job_listing&page=job-manager-addons&section=helper' ) ) . '">' . esc_html( $manage_licence_label ) . '</a>';
275
  return $actions;
276
  }
277
 
323
  /**
324
  * Returns the plugin data for plugin with a `WPJM-Product` tag by plugin filename.
325
  *
326
+ * @param string $plugin_filename
327
  * @return bool|array
328
  */
329
  private function get_licence_managed_plugin( $plugin_filename ) {
342
  * @return array|bool
343
  */
344
  public function get_plugin_licence( $product_slug ) {
345
+ $licence_key = WP_Job_Manager_Helper_Options::get( $product_slug, 'licence_key' );
346
  $activation_email = WP_Job_Manager_Helper_Options::get( $product_slug, 'email' );
347
+ $errors = WP_Job_Manager_Helper_Options::get( $product_slug, 'errors' );
348
 
349
  return array(
350
  'licence_key' => $licence_key,
351
+ 'email' => $activation_email,
352
+ 'errors' => $errors,
353
  );
354
  }
355
 
356
  /**
357
  * Adds newly recognized data header in WordPress plugin files.
358
  *
359
+ * @param array $headers
360
  * @return array
361
  */
362
  public function extra_headers( $headers ) {
367
  /**
368
  * Returns list of installed WPJM plugins with managed licenses indexed by product ID.
369
  *
370
+ * @param bool $active_only Only return active plugins.
371
  * @return array
372
  */
373
  protected function get_installed_plugins( $active_only = true ) {
374
  if ( ! function_exists( 'get_plugins' ) ) {
375
+ require_once ABSPATH . 'wp-admin/includes/plugin.php';
376
  }
377
 
378
  /**
389
  }
390
 
391
  $wpjm_plugins = array();
392
+ $plugins = get_plugins();
393
 
394
  foreach ( $plugins as $filename => $data ) {
395
  if ( empty( $data['WPJM-Product'] ) || ( true === $active_only && ! is_plugin_active( $filename ) ) ) {
396
  continue;
397
  }
398
 
399
+ $data['_filename'] = $filename;
400
+ $data['_product_slug'] = $data['WPJM-Product'];
401
+ $data['_type'] = 'plugin';
402
  $wpjm_plugins[ $data['WPJM-Product'] ] = $data;
403
  }
404
 
416
  $this->handle_request();
417
  }
418
  $licenced_plugins = $this->get_installed_plugins();
419
+ include_once dirname( __FILE__ ) . '/views/html-licences.php';
420
  }
421
 
422
  /**
424
  */
425
  public function licence_error_notices() {
426
  $screen = get_current_screen();
427
+ if ( null === $screen || in_array( $screen->id, array( 'job_listing_page_job-manager-addons' ), true ) ) {
428
  return;
429
  }
430
+ foreach ( $this->get_installed_plugins() as $product_slug => $plugin_data ) {
431
  $licence = $this->get_plugin_licence( $product_slug );
432
  if ( ! WP_Job_Manager_Helper_Options::get( $product_slug, 'hide_key_notice' ) ) {
433
+ if ( empty( $licence['licence_key'] ) ) {
434
+ include 'views/html-licence-key-notice.php';
435
+ } elseif ( ! empty( $licence['errors'] ) ) {
436
+ include 'views/html-licence-key-error.php';
437
  }
438
  }
439
  }
460
  $this->add_error( $product_slug, __( 'Please enter a valid license key and email address in order to activate this plugin\'s license.', 'wp-job-manager' ) );
461
  break;
462
  }
463
+ $email = sanitize_email( $_POST['email'] );
464
  $licence_key = sanitize_text_field( $_POST['licence_key'] );
465
  $this->activate_licence( $product_slug, $licence_key, $email );
466
  break;
478
  * @param string $email
479
  */
480
  private function activate_licence( $product_slug, $licence_key, $email ) {
481
+ $response = $this->api->activate(
482
+ array(
483
+ 'api_product_id' => $product_slug,
484
+ 'licence_key' => $licence_key,
485
+ 'email' => $email,
486
+ )
487
+ );
488
 
489
  if ( false === $response ) {
490
  $this->add_error( $product_slug, __( 'Connection failed to the License Key API server - possible server issue.', 'wp-job-manager' ) );
512
  $this->add_error( $product_slug, __( 'license is not active.', 'wp-job-manager' ) );
513
  return;
514
  }
515
+ $this->api->deactivate(
516
+ array(
517
+ 'api_product_id' => $product_slug,
518
+ 'licence_key' => $licence['licence_key'],
519
+ 'email' => $licence['email'],
520
+ )
521
+ );
522
 
523
  WP_Job_Manager_Helper_Options::delete( $product_slug, 'licence_key' );
524
  WP_Job_Manager_Helper_Options::delete( $product_slug, 'email' );
540
  return;
541
  }
542
 
543
+ $errors = ! empty( $response['errors'] ) ? $response['errors'] : array();
544
  $allowed_errors = array( 'no_activation', 'expired_key', 'expiring_soon' );
545
  $ignored_errors = array_diff( array_keys( $errors ), $allowed_errors );
546
 
587
  $this->licence_messages[ $product_slug ] = array();
588
  }
589
  $this->licence_messages[ $product_slug ][] = array(
590
+ 'type' => $type,
591
  'message' => $message,
592
  );
593
  }
includes/helper/views/html-licence-key-error.php CHANGED
@@ -1,9 +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>
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 esc_html_e( 'Hide notice', 'wp-job-manager' ); ?></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/helper/views/html-licence-key-notice.php CHANGED
@@ -1,9 +1,9 @@
1
  <?php
2
  if ( ! defined( 'ABSPATH' ) ) {
3
- exit; // Exit if accessed directly
4
  }
5
  ?>
6
  <div class="updated">
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( '<a href="%s">Please enter your license key</a> to get updates for "%s".', esc_url( admin_url( 'edit.php?post_type=job_listing&page=job-manager-addons&section=helper#' . sanitize_title( $product_slug . '_row' ) ) ), esc_html( $plugin_data['Name'] ) ); ?></p>
9
  </div>
1
  <?php
2
  if ( ! defined( 'ABSPATH' ) ) {
3
+ exit; // Exit if accessed directly.
4
  }
5
  ?>
6
  <div class="updated">
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 esc_html_e( 'Hide notice', 'wp-job-manager' ); ?></a></p>
8
  <p><?php printf( '<a href="%s">Please enter your license key</a> to get updates for "%s".', esc_url( admin_url( 'edit.php?post_type=job_listing&page=job-manager-addons&section=helper#' . sanitize_title( $product_slug . '_row' ) ) ), esc_html( $plugin_data['Name'] ) ); ?></p>
9
  </div>
includes/helper/views/html-licences.php CHANGED
@@ -1,81 +1,81 @@
1
  <?php
2
  if ( ! defined( 'ABSPATH' ) ) {
3
- exit; // Exit if accessed directly
4
  }
5
  ?>
6
- <h1 class="screen-reader-text"><?php _e( 'Licenses', 'wp-job-manager' ); ?></h1>
7
  <div class="wpjm-licences">
8
  <?php if ( ! empty( $licenced_plugins ) ) : ?>
9
- <?php foreach ( $licenced_plugins as $product_slug => $plugin_data ) : ?>
10
- <?php
11
- $licence = WP_Job_Manager_Helper::get_plugin_licence( $product_slug );
12
- ?>
13
  <div class="licence-row">
14
  <div class="plugin-info">
15
- <?php echo $plugin_data['Name']; ?>
16
  <div class="plugin-author">
17
  <?php
18
  $author = $plugin_data['Author'];
19
- if ( !empty( $plugin_data['AuthorURI'] ) ) {
20
- $author = '<a href="' . $plugin_data['AuthorURI'] . '">' . $plugin_data['Author'] . '</a>';
21
  }
22
- echo $author;
23
  ?>
24
  </div>
25
  </div>
26
  <div class="plugin-licence">
27
  <?php
28
- $notices = WP_Job_Manager_Helper::get_messages( $product_slug );
29
- if ( empty( $notices) && ! empty( $licence['errors'] ) ) {
30
- $notices = array();
31
- foreach ( $licence['errors'] as $key => $error ) {
32
- $notices[] = array(
33
- 'type' => 'error',
34
- 'message' => $error,
35
- );
36
- }
37
- }
38
- foreach ( $notices as $message ) {
39
- echo '<div class="notice inline notice-'. esc_attr( $message['type'] ) .'"><p>'. wp_kses_post( $message['message'] ) . '</p></div>';
40
  }
 
 
 
 
41
  ?>
42
  <form method="post">
43
  <?php wp_nonce_field( 'wpjm-manage-licence' ); ?>
44
  <?php
45
  if ( ! empty( $licence['licence_key'] ) && ! empty( $licence['email'] ) ) {
46
  ?>
47
- <input type="hidden" id="<?php echo sanitize_title( $product_slug ); ?>_action" name="action" value="deactivate"/>
48
- <input type="hidden" id="<?php echo sanitize_title( $product_slug ); ?>_plugin" name="product_slug" value="<?php echo esc_attr( $product_slug ); ?>"/>
49
 
50
- <label for="<?php echo sanitize_title( $product_slug ); ?>_licence_key"><?php _e( 'License' ); ?>:
51
- <input type="text" disabled="disabled" id="<?php echo sanitize_title( $product_slug ); ?>_licence_key" name="licence_key" placeholder="XXXX-XXXX-XXXX-XXXX" value="<?php echo esc_attr( $licence['licence_key'] ); ?>"/>
52
  </label>
53
- <label for="<?php echo sanitize_title( $product_slug ); ?>_email"><?php _e( 'Email' ); ?>:
54
- <input type="email" disabled="disabled" id="<?php echo sanitize_title( $product_slug ); ?>_email" name="email" placeholder="Email address" value="<?php echo esc_attr( $licence['email'] ); ?>"/>
55
  </label>
56
 
57
- <input type="submit" class="button" name="submit" value="<?php _e( 'Deactivate License' ); ?>" />
58
  <?php
59
- } else { // licence is not active
60
  ?>
61
- <input type="hidden" id="<?php echo sanitize_title( $product_slug ); ?>_action" name="action" value="activate"/>
62
- <input type="hidden" id="<?php echo sanitize_title( $product_slug ); ?>_plugin" name="product_slug" value="<?php echo esc_attr( $product_slug ); ?>"/>
63
- <label for="<?php echo sanitize_title( $product_slug ); ?>_licence_key"><?php _e( 'License' ); ?>:
64
- <input type="text" id="<?php echo sanitize_title( $product_slug ); ?>_licence_key" name="licence_key" placeholder="XXXX-XXXX-XXXX-XXXX"/>
65
  </label>
66
- <label for="<?php echo sanitize_title( $product_slug ); ?>_email"><?php _e( 'Email' ); ?>:
67
- <input type="email" id="<?php echo sanitize_title( $product_slug ); ?>_email" name="email" placeholder="Email address" value="<?php echo esc_attr( get_option( 'admin_email' ) ); ?>"/>
68
  </label>
69
- <input type="submit" class="button" name="submit" value="<?php _e( 'Activate License' ); ?>" />
70
  <?php
71
- } // end if : else licence is not active
72
  ?>
73
  </form>
74
  </div>
75
  </div>
76
  <?php endforeach; ?>
77
- <div class="notice notice-info inline"><p><?php printf( 'Lost your license key? <a href="%s">Retrieve it here</a>.', esc_url( 'https://wpjobmanager.com/lost-licence-key/' ) ); ?></p></div>
78
- <?php else: ?>
79
- <div class="notice notice-warning inline"><p><?php _e( 'No plugins are activated that have licenses managed by WP Job Manager.', 'wp-job-manager' ); ?></p></div>
80
  <?php endif; ?>
81
  </div>
1
  <?php
2
  if ( ! defined( 'ABSPATH' ) ) {
3
+ exit; // Exit if accessed directly.
4
  }
5
  ?>
6
+ <h1 class="screen-reader-text"><?php esc_html_e( 'Licenses', 'wp-job-manager' ); ?></h1>
7
  <div class="wpjm-licences">
8
  <?php if ( ! empty( $licenced_plugins ) ) : ?>
9
+ <?php foreach ( $licenced_plugins as $product_slug => $plugin_data ) : ?>
10
+ <?php
11
+ $licence = WP_Job_Manager_Helper::get_plugin_licence( $product_slug );
12
+ ?>
13
  <div class="licence-row">
14
  <div class="plugin-info">
15
+ <?php echo esc_html( $plugin_data['Name'] ); ?>
16
  <div class="plugin-author">
17
  <?php
18
  $author = $plugin_data['Author'];
19
+ if ( ! empty( $plugin_data['AuthorURI'] ) ) {
20
+ $author = '<a href="' . esc_url( $plugin_data['AuthorURI'] ) . '">' . wp_kses_post( $plugin_data['Author'] ) . '</a>';
21
  }
22
+ echo wp_kses_post( $author );
23
  ?>
24
  </div>
25
  </div>
26
  <div class="plugin-licence">
27
  <?php
28
+ $notices = WP_Job_Manager_Helper::get_messages( $product_slug );
29
+ if ( empty( $notices ) && ! empty( $licence['errors'] ) ) {
30
+ $notices = array();
31
+ foreach ( $licence['errors'] as $key => $error ) {
32
+ $notices[] = array(
33
+ 'type' => 'error',
34
+ 'message' => $error,
35
+ );
 
 
 
 
36
  }
37
+ }
38
+ foreach ( $notices as $message ) {
39
+ echo '<div class="notice inline notice-' . esc_attr( $message['type'] ) . '"><p>' . wp_kses_post( $message['message'] ) . '</p></div>';
40
+ }
41
  ?>
42
  <form method="post">
43
  <?php wp_nonce_field( 'wpjm-manage-licence' ); ?>
44
  <?php
45
  if ( ! empty( $licence['licence_key'] ) && ! empty( $licence['email'] ) ) {
46
  ?>
47
+ <input type="hidden" id="<?php echo esc_attr( sanitize_title( $product_slug ) ); ?>_action" name="action" value="deactivate"/>
48
+ <input type="hidden" id="<?php echo esc_attr( sanitize_title( $product_slug ) ); ?>_plugin" name="product_slug" value="<?php echo esc_attr( $product_slug ); ?>"/>
49
 
50
+ <label for="<?php echo esc_attr( sanitize_title( $product_slug ) ); ?>_licence_key"><?php esc_html_e( 'License', 'wp-job-manager' ); ?>:
51
+ <input type="text" disabled="disabled" id="<?php echo esc_attr( sanitize_title( $product_slug ) ); ?>_licence_key" name="licence_key" placeholder="XXXX-XXXX-XXXX-XXXX" value="<?php echo esc_attr( $licence['licence_key'] ); ?>"/>
52
  </label>
53
+ <label for="<?php echo esc_attr( sanitize_title( $product_slug ) ); ?>_email"><?php esc_html_e( 'Email', 'wp-job-manager' ); ?>:
54
+ <input type="email" disabled="disabled" id="<?php echo esc_attr( sanitize_title( $product_slug ) ); ?>_email" name="email" placeholder="Email address" value="<?php echo esc_attr( $licence['email'] ); ?>"/>
55
  </label>
56
 
57
+ <input type="submit" class="button" name="submit" value="<?php esc_attr_e( 'Deactivate License', 'wp-job-manager' ); ?>" />
58
  <?php
59
+ } else { // licence is not active.
60
  ?>
61
+ <input type="hidden" id="<?php echo esc_attr( sanitize_title( $product_slug ) ); ?>_action" name="action" value="activate"/>
62
+ <input type="hidden" id="<?php echo esc_attr( sanitize_title( $product_slug ) ); ?>_plugin" name="product_slug" value="<?php echo esc_attr( $product_slug ); ?>"/>
63
+ <label for="<?php echo esc_attr( sanitize_title( $product_slug ) ); ?>_licence_key"><?php esc_html_e( 'License', 'wp-job-manager' ); ?>:
64
+ <input type="text" id="<?php echo esc_attr( sanitize_title( $product_slug ) ); ?>_licence_key" name="licence_key" placeholder="XXXX-XXXX-XXXX-XXXX"/>
65
  </label>
66
+ <label for="<?php echo esc_attr( sanitize_title( $product_slug ) ); ?>_email"><?php esc_html_e( 'Email', 'wp-job-manager' ); ?>:
67
+ <input type="email" id="<?php echo esc_attr( sanitize_title( $product_slug ) ); ?>_email" name="email" placeholder="Email address" value="<?php echo esc_attr( get_option( 'admin_email' ) ); ?>"/>
68
  </label>
69
+ <input type="submit" class="button" name="submit" value="<?php esc_attr_e( 'Activate License', 'wp-job-manager' ); ?>" />
70
  <?php
71
+ } // end if : else licence is not active.
72
  ?>
73
  </form>
74
  </div>
75
  </div>
76
  <?php endforeach; ?>
77
+ <div class="notice notice-info inline"><p><?php printf( 'Lost your license key? <a href="%s">Retrieve it here</a>.', 'https://wpjobmanager.com/lost-licence-key/' ); ?></p></div>
78
+ <?php else : ?>
79
+ <div class="notice notice-warning inline"><p><?php esc_html_e( 'No plugins are activated that have licenses managed by WP Job Manager.', 'wp-job-manager' ); ?></p></div>
80
  <?php endif; ?>
81
  </div>
includes/rest-api/class-wp-job-manager-controllers-status.php CHANGED
@@ -32,7 +32,9 @@ class WP_Job_Manager_Controllers_Status extends WP_Job_Manager_REST_Controller_M
32
  * Index handler
33
  *
34
  * @param WP_REST_Request $request The request.
 
35
  * @return WP_REST_Response
 
36
  */
37
  public function index( $request ) {
38
  $params = $request->get_params();
@@ -52,7 +54,7 @@ class WP_Job_Manager_Controllers_Status extends WP_Job_Manager_REST_Controller_M
52
  return $this->not_found( __( 'Not Found', 'wp-job-manager' ) );
53
  }
54
 
55
- $dto = $this->prepare_dto( $configuration );
56
  $keys = $filter->get( 'keys' );
57
  if ( empty( $keys ) ) {
58
  return $this->ok( $dto );
@@ -74,7 +76,7 @@ class WP_Job_Manager_Controllers_Status extends WP_Job_Manager_REST_Controller_M
74
  * @return WP_REST_Response
75
  */
76
  public function show( $request ) {
77
- $key = $request->get_param( 'key' );
78
  $configuration = $this->get_model_prototype()
79
  ->get_data_store()
80
  ->get_entity( null );
@@ -93,17 +95,17 @@ class WP_Job_Manager_Controllers_Status extends WP_Job_Manager_REST_Controller_M
93
  * @return WP_REST_Response
94
  */
95
  public function update( $request ) {
96
- $key = $request->get_param( 'key' );
97
  $value = $request->get_param( 'value' );
98
  if ( ! isset( $value ) ) {
99
  if ( ! function_exists( 'json_decode' ) ) {
100
  include_once ABSPATH . WPINC . 'compat.php';
101
  }
102
- $body = $request->get_body();
103
  $value = json_decode( $body, true );
104
  }
105
  $thing_to_update = array(
106
- $key => $value,
107
  );
108
 
109
  $configuration = $this->get_model_prototype()
32
  * Index handler
33
  *
34
  * @param WP_REST_Request $request The request.
35
+ *
36
  * @return WP_REST_Response
37
+ * @throws WP_Job_Manager_REST_Exception Thrown during error while processing of request.
38
  */
39
  public function index( $request ) {
40
  $params = $request->get_params();
54
  return $this->not_found( __( 'Not Found', 'wp-job-manager' ) );
55
  }
56
 
57
+ $dto = $this->prepare_dto( $configuration );
58
  $keys = $filter->get( 'keys' );
59
  if ( empty( $keys ) ) {
60
  return $this->ok( $dto );
76
  * @return WP_REST_Response
77
  */
78
  public function show( $request ) {
79
+ $key = $request->get_param( 'key' );
80
  $configuration = $this->get_model_prototype()
81
  ->get_data_store()
82
  ->get_entity( null );
95
  * @return WP_REST_Response
96
  */
97
  public function update( $request ) {
98
+ $key = $request->get_param( 'key' );
99
  $value = $request->get_param( 'value' );
100
  if ( ! isset( $value ) ) {
101
  if ( ! function_exists( 'json_decode' ) ) {
102
  include_once ABSPATH . WPINC . 'compat.php';
103
  }
104
+ $body = $request->get_body();
105
  $value = json_decode( $body, true );
106
  }
107
  $thing_to_update = array(
108
+ $key => $value,
109
  );
110
 
111
  $configuration = $this->get_model_prototype()
includes/rest-api/class-wp-job-manager-data-stores-status.php CHANGED
@@ -20,6 +20,7 @@ class WP_Job_Manager_Data_Stores_Status extends WP_Job_Manager_REST_Data_Store_A
20
  *
21
  * @param WP_Job_Manager_REST_Interfaces_Model|null $filter A filter.
22
  * @return WP_Job_Manager_REST_Model_Collection
 
23
  */
24
  public function get_entities( $filter = null ) {
25
  return new WP_Job_Manager_REST_Model_Collection( array( $this->get_entity( null ) ) );
@@ -29,12 +30,14 @@ class WP_Job_Manager_Data_Stores_Status extends WP_Job_Manager_REST_Data_Store_A
29
  * Get a Model Using it's unique identifier
30
  *
31
  * @param mixed $id The id of the entity.
 
32
  * @return WP_Job_Manager_REST_Interfaces_Model
 
33
  */
34
  public function get_entity( $id ) {
35
  $should_run_page_setup = (bool) get_transient( '_job_manager_activation_redirect' );
36
- $params = array(
37
- 'run_page_setup' => $should_run_page_setup,
38
  );
39
  return $this->get_model_prototype()->create( $params );
40
  }
20
  *
21
  * @param WP_Job_Manager_REST_Interfaces_Model|null $filter A filter.
22
  * @return WP_Job_Manager_REST_Model_Collection
23
+ * @throws WP_Job_Manager_REST_Exception Thrown during error while processing of request.
24
  */
25
  public function get_entities( $filter = null ) {
26
  return new WP_Job_Manager_REST_Model_Collection( array( $this->get_entity( null ) ) );
30
  * Get a Model Using it's unique identifier
31
  *
32
  * @param mixed $id The id of the entity.
33
+ *
34
  * @return WP_Job_Manager_REST_Interfaces_Model
35
+ * @throws WP_Job_Manager_REST_Exception Thrown during error while processing of request.
36
  */
37
  public function get_entity( $id ) {
38
  $should_run_page_setup = (bool) get_transient( '_job_manager_activation_redirect' );
39
+ $params = array(
40
+ 'run_page_setup' => $should_run_page_setup,
41
  );
42
  return $this->get_model_prototype()->create( $params );
43
  }
includes/rest-api/class-wp-job-manager-filters-status.php CHANGED
@@ -23,10 +23,10 @@ class WP_Job_Manager_Filters_Status extends WP_Job_Manager_REST_Model {
23
  public function declare_fields() {
24
  $env = $this->get_environment();
25
  return array(
26
- $env->field( 'keys', 'The status keys to return' )
27
- ->with_type( $env->type( 'array:string' ) )
28
- ->with_before_set( 'explode_keys' )
29
- ->with_default( array() ),
30
  );
31
  }
32
 
23
  public function declare_fields() {
24
  $env = $this->get_environment();
25
  return array(
26
+ $env->field( 'keys', 'The status keys to return' )
27
+ ->with_type( $env->type( 'array:string' ) )
28
+ ->with_before_set( 'explode_keys' )
29
+ ->with_default( array() ),
30
  );
31
  }
32
 
includes/rest-api/class-wp-job-manager-models-job-listings-custom-fields.php CHANGED
@@ -21,7 +21,7 @@ class WP_Job_Manager_Models_Job_Listings_Custom_Fields extends WP_Job_Manager_RE
21
  * @throws WP_Job_Manager_REST_Exception Exc.
22
  */
23
  public function declare_fields() {
24
- $env = $this->get_environment();
25
  $current_user = wp_get_current_user();
26
 
27
  $declarations = array(
21
  * @throws WP_Job_Manager_REST_Exception Exc.
22
  */
23
  public function declare_fields() {
24
+ $env = $this->get_environment();
25
  $current_user = wp_get_current_user();
26
 
27
  $declarations = array(
includes/rest-api/class-wp-job-manager-models-job-types-custom-fields.php CHANGED
@@ -26,13 +26,14 @@ class WP_Job_Manager_Models_Job_Types_Custom_Fields extends WP_Job_Manager_REST_
26
  * Declare Fields
27
  *
28
  * @return array
 
29
  */
30
  public function declare_fields() {
31
- $env = $this->get_environment();
32
- $employment_types = wpjm_job_listing_employment_type_options();
33
  self::$accepted_employment_types = array_keys( $employment_types );
34
  return array(
35
- $env->field( 'employment_type', __( 'Employment Type', 'wp-job-manager' ) )
36
  ->with_kind( WP_Job_Manager_REST_Field_Declaration::META )
37
  ->with_type( $env->type( 'string' ) )
38
  ->with_choices( self::$accepted_employment_types ),
@@ -43,15 +44,20 @@ class WP_Job_Manager_Models_Job_Types_Custom_Fields extends WP_Job_Manager_REST_
43
  * Validate this
44
  *
45
  * @return bool|WP_Error
 
46
  */
47
  public function validate() {
48
  $employment_type = $this->get( 'employment_type' );
49
  if ( ! empty( $employment_type ) && ! in_array( $employment_type, self::$accepted_employment_types, true ) ) {
50
- return new WP_Error('invalid_employment_type', __( 'Invalid Employment Type', 'wp-job-manager' ), array(
51
- 'input' => $employment_type,
52
- 'acceptable_values' => self::$accepted_employment_types,
53
- 'status' => 400,
54
- ) );
 
 
 
 
55
  }
56
  return parent::validate();
57
  }
26
  * Declare Fields
27
  *
28
  * @return array
29
+ * @throws WP_Job_Manager_REST_Exception Thrown during error while processing of request.
30
  */
31
  public function declare_fields() {
32
+ $env = $this->get_environment();
33
+ $employment_types = wpjm_job_listing_employment_type_options();
34
  self::$accepted_employment_types = array_keys( $employment_types );
35
  return array(
36
+ $env->field( 'employment_type', esc_html__( 'Employment Type', 'wp-job-manager' ) )
37
  ->with_kind( WP_Job_Manager_REST_Field_Declaration::META )
38
  ->with_type( $env->type( 'string' ) )
39
  ->with_choices( self::$accepted_employment_types ),
44
  * Validate this
45
  *
46
  * @return bool|WP_Error
47
+ * @throws WP_Job_Manager_REST_Exception Thrown during error while processing of request.
48
  */
49
  public function validate() {
50
  $employment_type = $this->get( 'employment_type' );
51
  if ( ! empty( $employment_type ) && ! in_array( $employment_type, self::$accepted_employment_types, true ) ) {
52
+ return new WP_Error(
53
+ 'invalid_employment_type',
54
+ esc_html__( 'Invalid Employment Type', 'wp-job-manager' ),
55
+ array(
56
+ 'input' => $employment_type,
57
+ 'acceptable_values' => self::$accepted_employment_types,
58
+ 'status' => 400,
59
+ )
60
+ );
61
  }
62
  return parent::validate();
63
  }
includes/rest-api/class-wp-job-manager-models-settings.php CHANGED
@@ -48,6 +48,8 @@ class WP_Job_Manager_Models_Settings extends WP_Job_Manager_REST_Model_Settings
48
  * @param WP_Job_Manager_REST_Field_Declaration_Builder $field_builder The field builder.
49
  * @param array $field_data The field data.
50
  * @param WP_Job_Manager_REST_Environment $env The definition.
 
 
51
  */
52
  protected function on_field_setup( $field_name, $field_builder, $field_data, $env ) {
53
  if ( in_array( $field_name, self::get_fields_requiring_page_id_validation(), true ) ) {
@@ -94,9 +96,9 @@ class WP_Job_Manager_Models_Settings extends WP_Job_Manager_REST_Model_Settings
94
  self::$fields_requiring_page_id_validation = (array) apply_filters(
95
  'wpjm_rest_api_settings_fields_requiring_page_id_validation',
96
  array(
97
- 'job_manager_submit_job_form_page_id',
98
- 'job_manager_job_dashboard_page_id',
99
- 'job_manager_jobs_page_id',
100
  )
101
  );
102
  }
48
  * @param WP_Job_Manager_REST_Field_Declaration_Builder $field_builder The field builder.
49
  * @param array $field_data The field data.
50
  * @param WP_Job_Manager_REST_Environment $env The definition.
51
+ *
52
+ * @throws WP_Job_Manager_REST_Exception Thrown during error while processing of request.
53
  */
54
  protected function on_field_setup( $field_name, $field_builder, $field_data, $env ) {
55
  if ( in_array( $field_name, self::get_fields_requiring_page_id_validation(), true ) ) {
96
  self::$fields_requiring_page_id_validation = (array) apply_filters(
97
  'wpjm_rest_api_settings_fields_requiring_page_id_validation',
98
  array(
99
+ 'job_manager_submit_job_form_page_id',
100
+ 'job_manager_job_dashboard_page_id',
101
+ 'job_manager_jobs_page_id',
102
  )
103
  );
104
  }
includes/rest-api/class-wp-job-manager-models-status.php CHANGED
@@ -25,8 +25,8 @@ class WP_Job_Manager_Models_Status extends WP_Job_Manager_REST_Model
25
  public function declare_fields() {
26
  $env = $this->get_environment();
27
  return array(
28
- $env->field( 'run_page_setup', 'Should we run page setup' )
29
- ->with_type( $env->type( 'boolean' ) ),
30
  );
31
  }
32
 
25
  public function declare_fields() {
26
  $env = $this->get_environment();
27
  return array(
28
+ $env->field( 'run_page_setup', 'Should we run page setup' )
29
+ ->with_type( $env->type( 'boolean' ) ),
30
  );
31
  }
32
 
includes/rest-api/class-wp-job-manager-registrable-job-listings.php CHANGED
@@ -59,9 +59,9 @@ class WP_Job_Manager_Registrable_Job_Listings implements WP_Job_Manager_REST_Int
59
  * @param string $rest_field_name The REST field name.
60
  */
61
  public function __construct( $object_to_extend, $model_class, $rest_field_name ) {
62
- $this->model_class = $model_class;
63
  $this->object_to_extend = $object_to_extend;
64
- $this->rest_field_name = $rest_field_name;
65
  }
66
 
67
  /**
@@ -72,7 +72,7 @@ class WP_Job_Manager_Registrable_Job_Listings implements WP_Job_Manager_REST_Int
72
  *
73
  * @return bool|WP_Error true if valid otherwise error.
74
  */
75
- function register( $environment ) {
76
  global $wp_post_types;
77
  $post_type_name = $this->object_to_extend;
78
  if ( ! isset( $wp_post_types[ $post_type_name ] ) ) {
@@ -84,20 +84,24 @@ class WP_Job_Manager_Registrable_Job_Listings implements WP_Job_Manager_REST_Int
84
  }
85
 
86
  // Optionally customize the rest_base or controller class.
87
- $wp_post_types[ $post_type_name ]->show_in_rest = true;
88
- $wp_post_types[ $post_type_name ]->rest_base = 'job-listings';
89
  $wp_post_types[ $post_type_name ]->rest_controller_class = 'WP_REST_Posts_Controller';
90
 
91
- $this->environment = $environment;
92
  $this->model_factory = $this->environment->model( $this->model_class );
93
  if ( ! $this->model_factory ) {
94
  return new WP_Error( 'model-not-found' );
95
  }
96
- register_rest_field( $this->object_to_extend, $this->rest_field_name, array(
97
- 'get_callback' => array( $this, 'get_fields' ),
98
- 'update_callback' => array( $this, 'update_fields' ),
99
- 'schema' => $this->get_item_schema(),
100
- ) );
 
 
 
 
101
 
102
  return true;
103
  }
@@ -108,9 +112,9 @@ class WP_Job_Manager_Registrable_Job_Listings implements WP_Job_Manager_REST_Int
108
  * @return array
109
  */
110
  public function get_item_schema() {
111
- $fields = $this->model_factory->get_fields();
112
  $properties = array();
113
- $required = array();
114
  foreach ( $fields as $field_declaration ) {
115
  /**
116
  * Our declaration
@@ -123,9 +127,9 @@ class WP_Job_Manager_Registrable_Job_Listings implements WP_Job_Manager_REST_Int
123
  }
124
  }
125
  $schema = array(
126
- '$schema' => 'http://json-schema.org/schema#',
127
- 'title' => $this->model_factory->get_name(),
128
- 'type' => 'object',
129
  'properties' => (array) apply_filters( 'mixtape_rest_api_schema_properties', $properties, $this->model_factory ),
130
  );
131
 
@@ -157,7 +161,7 @@ class WP_Job_Manager_Registrable_Job_Listings implements WP_Job_Manager_REST_Int
157
  }
158
 
159
  $object_id = absint( $object['id'] );
160
- $model = $this->get_model( $object_id );
161
  return $model->to_dto();
162
  }
163
 
@@ -166,21 +170,23 @@ class WP_Job_Manager_Registrable_Job_Listings implements WP_Job_Manager_REST_Int
166
  *
167
  * @param int $object_id Object ID.
168
  * @return WP_Job_Manager_REST_Interfaces_Model
169
- * @throws WP_Job_Manager_REST_Exception On Error.
170
  */
171
  private function get_model( $object_id ) {
172
  $data = array();
173
  foreach ( $this->model_factory->get_fields() as $field_declaration ) {
174
  $field_name = $field_declaration->get_name();
175
  if ( metadata_exists( 'post', $object_id, $field_name ) ) {
176
- $meta = get_post_meta( $object_id, $field_name, true );
177
  $data[ $field_name ] = $meta;
178
  }
179
  }
180
 
181
- return $this->model_factory->create( $data, array(
182
- 'deserialize' => true,
183
- ) );
 
 
 
184
  }
185
 
186
  /**
@@ -204,7 +210,7 @@ class WP_Job_Manager_Registrable_Job_Listings implements WP_Job_Manager_REST_Int
204
  return null;
205
  }
206
 
207
- $object_id = absint( $object->ID );
208
  $existing_model = $this->get_model( $object_id );
209
 
210
  $updated = $existing_model->update_from_array( $data );
59
  * @param string $rest_field_name The REST field name.
60
  */
61
  public function __construct( $object_to_extend, $model_class, $rest_field_name ) {
62
+ $this->model_class = $model_class;
63
  $this->object_to_extend = $object_to_extend;
64
+ $this->rest_field_name = $rest_field_name;
65
  }
66
 
67
  /**
72
  *
73
  * @return bool|WP_Error true if valid otherwise error.
74
  */
75
+ public function register( $environment ) {
76
  global $wp_post_types;
77
  $post_type_name = $this->object_to_extend;
78
  if ( ! isset( $wp_post_types[ $post_type_name ] ) ) {
84
  }
85
 
86
  // Optionally customize the rest_base or controller class.
87
+ $wp_post_types[ $post_type_name ]->show_in_rest = true;
88
+ $wp_post_types[ $post_type_name ]->rest_base = 'job-listings';
89
  $wp_post_types[ $post_type_name ]->rest_controller_class = 'WP_REST_Posts_Controller';
90
 
91
+ $this->environment = $environment;
92
  $this->model_factory = $this->environment->model( $this->model_class );
93
  if ( ! $this->model_factory ) {
94
  return new WP_Error( 'model-not-found' );
95
  }
96
+ register_rest_field(
97
+ $this->object_to_extend,
98
+ $this->rest_field_name,
99
+ array(
100
+ 'get_callback' => array( $this, 'get_fields' ),
101
+ 'update_callback' => array( $this, 'update_fields' ),
102
+ 'schema' => $this->get_item_schema(),
103
+ )
104
+ );
105
 
106
  return true;
107
  }
112
  * @return array
113
  */
114
  public function get_item_schema() {
115
+ $fields = $this->model_factory->get_fields();
116
  $properties = array();
117
+ $required = array();
118
  foreach ( $fields as $field_declaration ) {
119
  /**
120
  * Our declaration
127
  }
128
  }
129
  $schema = array(
130
+ '$schema' => 'http://json-schema.org/schema#',
131
+ 'title' => $this->model_factory->get_name(),
132
+ 'type' => 'object',
133
  'properties' => (array) apply_filters( 'mixtape_rest_api_schema_properties', $properties, $this->model_factory ),
134
  );
135
 
161
  }
162
 
163
  $object_id = absint( $object['id'] );
164
+ $model = $this->get_model( $object_id );
165
  return $model->to_dto();
166
  }
167
 
170
  *
171
  * @param int $object_id Object ID.
172
  * @return WP_Job_Manager_REST_Interfaces_Model
 
173
  */
174
  private function get_model( $object_id ) {
175
  $data = array();
176
  foreach ( $this->model_factory->get_fields() as $field_declaration ) {
177
  $field_name = $field_declaration->get_name();
178
  if ( metadata_exists( 'post', $object_id, $field_name ) ) {
179
+ $meta = get_post_meta( $object_id, $field_name, true );
180
  $data[ $field_name ] = $meta;
181
  }
182
  }
183
 
184
+ return $this->model_factory->create(
185
+ $data,
186
+ array(
187
+ 'deserialize' => true,
188
+ )
189
+ );
190
  }
191
 
192
  /**
210
  return null;
211
  }
212
 
213
+ $object_id = absint( $object->ID );
214
  $existing_model = $this->get_model( $object_id );
215
 
216
  $updated = $existing_model->update_from_array( $data );
includes/rest-api/class-wp-job-manager-registrable-taxonomy-type.php CHANGED
@@ -48,7 +48,7 @@ abstract class WP_Job_Manager_Registrable_Taxonomy_Type implements WP_Job_Manage
48
  * @return string Class name for the taxonomy type's model.
49
  */
50
  abstract public function get_model_class_name();
51
-
52
  /**
53
  * Register Job Categories
54
  *
@@ -60,7 +60,7 @@ abstract class WP_Job_Manager_Registrable_Taxonomy_Type implements WP_Job_Manage
60
  public function register( $environment ) {
61
  global $wp_taxonomies;
62
 
63
- $taxonomy_type = $this->get_taxonomy_type();
64
  $this->rest_field_name = 'fields';
65
 
66
  if ( ! isset( $wp_taxonomies[ $taxonomy_type ] ) ) {
@@ -72,18 +72,22 @@ abstract class WP_Job_Manager_Registrable_Taxonomy_Type implements WP_Job_Manage
72
  }
73
 
74
  $wp_taxonomies[ $taxonomy_type ]->show_in_rest = true;
75
- $wp_taxonomies[ $taxonomy_type ]->rest_base = $this->get_rest_base();
76
 
77
  $this->model_prototype = $environment->model( $this->get_model_class_name() );
78
 
79
  if ( ! $this->model_prototype ) {
80
  return new WP_Error( 'model-not-found' );
81
  }
82
- register_rest_field( $taxonomy_type, $this->rest_field_name, array(
83
- 'get_callback' => array( $this, 'get_taxonomy_term' ),
84
- 'update_callback' => array( $this, 'update_taxonomy_term' ),
85
- 'schema' => $this->get_item_schema(),
86
- ) );
 
 
 
 
87
 
88
  return true;
89
  }
@@ -94,9 +98,9 @@ abstract class WP_Job_Manager_Registrable_Taxonomy_Type implements WP_Job_Manage
94
  * @return array
95
  */
96
  public function get_item_schema() {
97
- $fields = $this->model_prototype->get_fields();
98
  $properties = array();
99
- $required = array();
100
  foreach ( $fields as $field_declaration ) {
101
  /**
102
  * Our declaration
@@ -109,9 +113,9 @@ abstract class WP_Job_Manager_Registrable_Taxonomy_Type implements WP_Job_Manage
109
  }
110
  }
111
  $schema = array(
112
- '$schema' => 'http://json-schema.org/schema#',
113
- 'title' => $this->model_prototype->get_name(),
114
- 'type' => 'object',
115
  'properties' => (array) apply_filters( 'mixtape_rest_api_schema_properties', $properties, $this->model_prototype ),
116
  );
117
 
@@ -143,7 +147,7 @@ abstract class WP_Job_Manager_Registrable_Taxonomy_Type implements WP_Job_Manage
143
  }
144
 
145
  $object_id = absint( $object['id'] );
146
- $model = $this->get_model( $object_id );
147
  return $model->to_dto();
148
  }
149
 
@@ -159,20 +163,23 @@ abstract class WP_Job_Manager_Registrable_Taxonomy_Type implements WP_Job_Manage
159
  foreach ( $this->model_prototype->get_fields( WP_Job_Manager_REST_Field_Declaration::META ) as $field_declaration ) {
160
  $field_name = $field_declaration->get_name();
161
  if ( metadata_exists( 'term', $object_id, $field_name ) ) {
162
- $meta = get_term_meta( $object_id, $field_name, true );
163
  $data[ $field_name ] = $meta;
164
  }
165
  }
166
 
167
- return $this->model_prototype->create( $data, array(
168
- 'deserialize' => true,
169
- ) );
 
 
 
170
  }
171
 
172
  /**
173
  * Our Reader.
174
  *
175
- * @param mixed $data Data.
176
  * @param object $object Object.
177
  * @param string $field_name Field Name.
178
  * @param WP_REST_Request $request Request.
@@ -195,12 +202,15 @@ abstract class WP_Job_Manager_Registrable_Taxonomy_Type implements WP_Job_Manage
195
  }
196
 
197
  $rest_base = $this->get_rest_base();
198
- $term_id = absint( $object->term_id );
199
  if ( ! $term_id ) {
200
  // No way to update this. Bail.
201
- return new WP_Error( $rest_base . '-error-invalid-id', $rest_base . '-error-invalid-id', array(
202
- 'status' => 400,
203
- ) );
 
 
 
204
  }
205
  $existing_model = $this->get_model( $term_id );
206
 
48
  * @return string Class name for the taxonomy type's model.
49
  */
50
  abstract public function get_model_class_name();
51
+
52
  /**
53
  * Register Job Categories
54
  *
60
  public function register( $environment ) {
61
  global $wp_taxonomies;
62
 
63
+ $taxonomy_type = $this->get_taxonomy_type();
64
  $this->rest_field_name = 'fields';
65
 
66
  if ( ! isset( $wp_taxonomies[ $taxonomy_type ] ) ) {
72
  }
73
 
74
  $wp_taxonomies[ $taxonomy_type ]->show_in_rest = true;
75
+ $wp_taxonomies[ $taxonomy_type ]->rest_base = $this->get_rest_base();
76
 
77
  $this->model_prototype = $environment->model( $this->get_model_class_name() );
78
 
79
  if ( ! $this->model_prototype ) {
80
  return new WP_Error( 'model-not-found' );
81
  }
82
+ register_rest_field(
83
+ $taxonomy_type,
84
+ $this->rest_field_name,
85
+ array(
86
+ 'get_callback' => array( $this, 'get_taxonomy_term' ),
87
+ 'update_callback' => array( $this, 'update_taxonomy_term' ),
88
+ 'schema' => $this->get_item_schema(),
89
+ )
90
+ );
91
 
92
  return true;
93
  }
98
  * @return array
99
  */
100
  public function get_item_schema() {
101
+ $fields = $this->model_prototype->get_fields();
102
  $properties = array();
103
+ $required = array();
104
  foreach ( $fields as $field_declaration ) {
105
  /**
106
  * Our declaration
113
  }
114
  }
115
  $schema = array(
116
+ '$schema' => 'http://json-schema.org/schema#',
117
+ 'title' => $this->model_prototype->get_name(),
118
+ 'type' => 'object',
119
  'properties' => (array) apply_filters( 'mixtape_rest_api_schema_properties', $properties, $this->model_prototype ),
120
  );
121
 
147
  }
148
 
149
  $object_id = absint( $object['id'] );
150
+ $model = $this->get_model( $object_id );
151
  return $model->to_dto();
152
  }
153
 
163
  foreach ( $this->model_prototype->get_fields( WP_Job_Manager_REST_Field_Declaration::META ) as $field_declaration ) {
164
  $field_name = $field_declaration->get_name();
165
  if ( metadata_exists( 'term', $object_id, $field_name ) ) {
166
+ $meta = get_term_meta( $object_id, $field_name, true );
167
  $data[ $field_name ] = $meta;
168
  }
169
  }
170
 
171
+ return $this->model_prototype->create(
172
+ $data,
173
+ array(
174
+ 'deserialize' => true,
175
+ )
176
+ );
177
  }
178
 
179
  /**
180
  * Our Reader.
181
  *
182
+ * @param mixed $data Data.
183
  * @param object $object Object.
184
  * @param string $field_name Field Name.
185
  * @param WP_REST_Request $request Request.
202
  }
203
 
204
  $rest_base = $this->get_rest_base();
205
+ $term_id = absint( $object->term_id );
206
  if ( ! $term_id ) {
207
  // No way to update this. Bail.
208
+ return new WP_Error(
209
+ $rest_base . '-error-invalid-id', $rest_base . '-error-invalid-id',
210
+ array(
211
+ 'status' => 400,
212
+ )
213
+ );
214
  }
215
  $existing_model = $this->get_model( $term_id );
216
 
includes/rest-api/class-wp-job-manager-rest-api.php CHANGED
@@ -39,9 +39,9 @@ class WP_Job_Manager_REST_API {
39
  * @param string $base_dir The base dir.
40
  */
41
  public function __construct( $base_dir ) {
42
- $this->base_dir = trailingslashit( $base_dir );
43
  $this->is_rest_api_enabled = defined( 'WPJM_REST_API_ENABLED' ) && ( true === constant( 'WPJM_REST_API_ENABLED' ) );
44
- $file = $this->base_dir . 'lib/wpjm_rest/class-wp-job-manager-rest-bootstrap.php';
45
  if ( file_exists( $file ) && $this->is_rest_api_enabled ) {
46
  include_once $file;
47
  $this->wpjm_rest_api = WP_Job_Manager_REST_Bootstrap::create();
@@ -79,6 +79,8 @@ class WP_Job_Manager_REST_API {
79
  * Define our REST API Models and Controllers
80
  *
81
  * @param WP_Job_Manager_REST_Environment $env The Environment.
 
 
82
  */
83
  public function define_api( $env ) {
84
  if ( ! is_a( $env, 'WP_Job_Manager_REST_Environment' ) ) {
@@ -112,10 +114,13 @@ class WP_Job_Manager_REST_API {
112
  $env->rest_api( 'wpjm/v1' )
113
  ->add_endpoint( new WP_Job_Manager_REST_Controller_Settings( '/settings', 'WP_Job_Manager_Models_Settings' ) )
114
  ->add_endpoint( new WP_Job_Manager_Controllers_Status( '/status', 'WP_Job_Manager_Models_Status' ) );
115
- $env->add_registrable( new WP_Job_Manager_Registrable_Job_Listings(
116
- 'job_listing',
117
- 'WP_Job_Manager_Models_Job_Listings_Custom_Fields',
118
- 'fields' ) );
 
 
 
119
  $env->add_registrable( new WP_Job_Manager_Registrable_Job_Types() );
120
  $env->add_registrable( new WP_Job_Manager_Registrable_Job_Categories() );
121
  }
39
  * @param string $base_dir The base dir.
40
  */
41
  public function __construct( $base_dir ) {
42
+ $this->base_dir = trailingslashit( $base_dir );
43
  $this->is_rest_api_enabled = defined( 'WPJM_REST_API_ENABLED' ) && ( true === constant( 'WPJM_REST_API_ENABLED' ) );
44
+ $file = $this->base_dir . 'lib/wpjm_rest/class-wp-job-manager-rest-bootstrap.php';
45
  if ( file_exists( $file ) && $this->is_rest_api_enabled ) {
46
  include_once $file;
47
  $this->wpjm_rest_api = WP_Job_Manager_REST_Bootstrap::create();
79
  * Define our REST API Models and Controllers
80
  *
81
  * @param WP_Job_Manager_REST_Environment $env The Environment.
82
+ *
83
+ * @throws WP_Job_Manager_REST_Exception Thrown during error while processing of request.
84
  */
85
  public function define_api( $env ) {
86
  if ( ! is_a( $env, 'WP_Job_Manager_REST_Environment' ) ) {
114
  $env->rest_api( 'wpjm/v1' )
115
  ->add_endpoint( new WP_Job_Manager_REST_Controller_Settings( '/settings', 'WP_Job_Manager_Models_Settings' ) )
116
  ->add_endpoint( new WP_Job_Manager_Controllers_Status( '/status', 'WP_Job_Manager_Models_Status' ) );
117
+ $env->add_registrable(
118
+ new WP_Job_Manager_Registrable_Job_Listings(
119
+ 'job_listing',
120
+ 'WP_Job_Manager_Models_Job_Listings_Custom_Fields',
121
+ 'fields'
122
+ )
123
+ );
124
  $env->add_registrable( new WP_Job_Manager_Registrable_Job_Types() );
125
  $env->add_registrable( new WP_Job_Manager_Registrable_Job_Categories() );
126
  }
includes/widgets/class-wp-job-manager-widget-featured-jobs.php CHANGED
@@ -17,17 +17,19 @@ class WP_Job_Manager_Widget_Featured_Jobs extends WP_Job_Manager_Widget {
17
  public function __construct() {
18
  global $wp_post_types;
19
 
 
 
20
  $this->widget_cssclass = 'job_manager widget_featured_jobs';
21
  $this->widget_description = __( 'Display a list of featured listings on your site.', 'wp-job-manager' );
22
  $this->widget_id = 'widget_featured_jobs';
23
- $this->widget_name = sprintf( __( 'Featured %s', 'wp-job-manager' ), $wp_post_types['job_listing']->labels->name );
24
  $this->settings = array(
25
- 'title' => array(
26
  'type' => 'text',
 
27
  'std' => sprintf( __( 'Featured %s', 'wp-job-manager' ), $wp_post_types['job_listing']->labels->name ),
28
  'label' => __( 'Title', 'wp-job-manager' ),
29
  ),
30
- 'number' => array(
31
  'type' => 'number',
32
  'step' => 1,
33
  'min' => 1,
@@ -36,27 +38,27 @@ class WP_Job_Manager_Widget_Featured_Jobs extends WP_Job_Manager_Widget {
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
  }
61
 
62
  /**
@@ -77,28 +79,36 @@ class WP_Job_Manager_Widget_Featured_Jobs extends WP_Job_Manager_Widget {
77
 
78
  ob_start();
79
 
80
- extract( $args );
81
- $titleInstance = esc_attr( $instance['title'] );
82
- $number = absint( $instance['number'] );
83
- $orderby = esc_attr( $instance['orderby'] );
84
- $order = esc_attr( $instance['order'] );
85
- $title = apply_filters( 'widget_title', $titleInstance, $instance, $this->id_base );
86
- $jobs = get_job_listings( array(
87
- 'posts_per_page' => $number,
88
- 'orderby' => $orderby,
89
- 'order' => $order,
90
- 'featured' => true,
91
- ) );
 
92
 
93
  if ( $jobs->have_posts() ) : ?>
94
 
95
- <?php echo $before_widget; ?>
96
 
97
- <?php if ( $title ) { echo $before_title . $title . $after_title;} ?>
 
 
 
 
98
 
99
  <ul class="job_listings">
100
 
101
- <?php while ( $jobs->have_posts() ) : $jobs->the_post(); ?>
 
 
 
102
 
103
  <?php get_job_manager_template_part( 'content-widget', 'job_listing' ); ?>
104
 
@@ -106,19 +116,20 @@ class WP_Job_Manager_Widget_Featured_Jobs extends WP_Job_Manager_Widget {
106
 
107
  </ul>
108
 
109
- <?php echo $after_widget; ?>
110
 
111
  <?php else : ?>
112
 
113
  <?php get_job_manager_template_part( 'content-widget', 'no-jobs-found' ); ?>
114
 
115
- <?php endif;
 
116
 
117
  wp_reset_postdata();
118
 
119
  $content = ob_get_clean();
120
 
121
- echo $content;
122
 
123
  $this->cache_widget( $args, $content );
124
  }
17
  public function __construct() {
18
  global $wp_post_types;
19
 
20
+ // translators: Placeholder %s is the plural label for the job listing post type.
21
+ $this->widget_name = sprintf( __( 'Featured %s', 'wp-job-manager' ), $wp_post_types['job_listing']->labels->name );
22
  $this->widget_cssclass = 'job_manager widget_featured_jobs';
23
  $this->widget_description = __( 'Display a list of featured listings on your site.', 'wp-job-manager' );
24
  $this->widget_id = 'widget_featured_jobs';
 
25
  $this->settings = array(
26
+ 'title' => array(
27
  'type' => 'text',
28
+ // translators: Placeholder %s is the plural label for the job listing post type.
29
  'std' => sprintf( __( 'Featured %s', 'wp-job-manager' ), $wp_post_types['job_listing']->labels->name ),
30
  'label' => __( 'Title', 'wp-job-manager' ),
31
  ),
32
+ 'number' => array(
33
  'type' => 'number',
34
  'step' => 1,
35
  'min' => 1,
38
  'label' => __( 'Number of listings to show', 'wp-job-manager' ),
39
  ),
40
  'orderby' => array(
41
+ 'type' => 'select',
42
+ 'std' => 'date',
43
+ 'label' => __( 'Sort By', 'wp-job-manager' ),
44
  'options' => array(
45
+ 'date' => __( 'Date', 'wp-job-manager' ),
46
+ 'title' => __( 'Title', 'wp-job-manager' ),
47
+ 'author' => __( 'Author', 'wp-job-manager' ),
48
+ 'rand_featured' => __( 'Random', 'wp-job-manager' ),
49
  ),
50
  ),
51
+ 'order' => array(
52
+ 'type' => 'select',
53
+ 'std' => 'DESC',
54
+ 'label' => __( 'Sort Direction', 'wp-job-manager' ),
55
  'options' => array(
56
+ 'ASC' => __( 'Ascending', 'wp-job-manager' ),
57
+ 'DESC' => __( 'Descending', 'wp-job-manager' ),
58
  ),
59
  ),
60
  );
61
+ parent::__construct();
62
  }
63
 
64
  /**
79
 
80
  ob_start();
81
 
82
+ $title_instance = esc_attr( $instance['title'] );
83
+ $number = absint( $instance['number'] );
84
+ $orderby = esc_attr( $instance['orderby'] );
85
+ $order = esc_attr( $instance['order'] );
86
+ $title = apply_filters( 'widget_title', $title_instance, $instance, $this->id_base );
87
+ $jobs = get_job_listings(
88
+ array(
89
+ 'posts_per_page' => $number,
90
+ 'orderby' => $orderby,
91
+ 'order' => $order,
92
+ 'featured' => true,
93
+ )
94
+ );
95
 
96
  if ( $jobs->have_posts() ) : ?>
97
 
98
+ <?php echo $args['before_widget']; // WPCS: XSS ok. ?>
99
 
100
+ <?php
101
+ if ( $title ) {
102
+ echo $args['before_title'] . esc_html( $title ) . $args['after_title']; // WPCS: XSS ok.
103
+ }
104
+ ?>
105
 
106
  <ul class="job_listings">
107
 
108
+ <?php
109
+ while ( $jobs->have_posts() ) :
110
+ $jobs->the_post();
111
+ ?>
112
 
113
  <?php get_job_manager_template_part( 'content-widget', 'job_listing' ); ?>
114
 
116
 
117
  </ul>
118
 
119
+ <?php echo $args['after_widget']; // WPCS: XSS ok. ?>
120
 
121
  <?php else : ?>
122
 
123
  <?php get_job_manager_template_part( 'content-widget', 'no-jobs-found' ); ?>
124
 
125
+ <?php
126
+ endif;
127
 
128
  wp_reset_postdata();
129
 
130
  $content = ob_get_clean();
131
 
132
+ echo $content; // WPCS: XSS ok.
133
 
134
  $this->cache_widget( $args, $content );
135
  }
includes/widgets/class-wp-job-manager-widget-recent-jobs.php CHANGED
@@ -17,27 +17,29 @@ class WP_Job_Manager_Widget_Recent_Jobs extends WP_Job_Manager_Widget {
17
  public function __construct() {
18
  global $wp_post_types;
19
 
 
 
20
  $this->widget_cssclass = 'job_manager widget_recent_jobs';
21
  $this->widget_description = __( 'Display a list of recent listings on your site, optionally matching a keyword and location.', 'wp-job-manager' );
22
  $this->widget_id = 'widget_recent_jobs';
23
- $this->widget_name = sprintf( __( 'Recent %s', 'wp-job-manager' ), $wp_post_types['job_listing']->labels->name );
24
  $this->settings = array(
25
- 'title' => array(
26
  'type' => 'text',
 
27
  'std' => sprintf( __( 'Recent %s', 'wp-job-manager' ), $wp_post_types['job_listing']->labels->name ),
28
  'label' => __( 'Title', 'wp-job-manager' ),
29
  ),
30
- 'keyword' => array(
31
  'type' => 'text',
32
  'std' => '',
33
  'label' => __( 'Keyword', 'wp-job-manager' ),
34
  ),
35
- 'location' => array(
36
  'type' => 'text',
37
  'std' => '',
38
  'label' => __( 'Location', 'wp-job-manager' ),
39
  ),
40
- 'number' => array(
41
  'type' => 'number',
42
  'step' => 1,
43
  'min' => 1,
@@ -45,8 +47,14 @@ class WP_Job_Manager_Widget_Recent_Jobs extends WP_Job_Manager_Widget {
45
  'std' => 10,
46
  'label' => __( 'Number of listings to show', 'wp-job-manager' ),
47
  ),
 
 
 
 
 
48
  );
49
- $this->register();
 
50
  }
51
 
52
  /**
@@ -67,17 +75,18 @@ class WP_Job_Manager_Widget_Recent_Jobs extends WP_Job_Manager_Widget {
67
 
68
  ob_start();
69
 
70
- extract( $args );
71
-
72
- $title = apply_filters( 'widget_title', $instance['title'], $instance, $this->id_base );
73
- $number = absint( $instance['number'] );
74
- $jobs = get_job_listings( array(
75
- 'search_location' => $instance['location'],
76
- 'search_keywords' => $instance['keyword'],
77
- 'posts_per_page' => $number,
78
- 'orderby' => 'date',
79
- 'order' => 'DESC',
80
- ) );
 
81
 
82
  /**
83
  * Runs before Recent Jobs widget content.
@@ -92,27 +101,35 @@ class WP_Job_Manager_Widget_Recent_Jobs extends WP_Job_Manager_Widget {
92
 
93
  if ( $jobs->have_posts() ) : ?>
94
 
95
- <?php echo $before_widget; ?>
96
 
97
- <?php if ( $title ) { echo $before_title . $title . $after_title;} ?>
 
 
 
 
98
 
99
  <ul class="job_listings">
100
 
101
- <?php while ( $jobs->have_posts() ) : $jobs->the_post(); ?>
 
 
 
102
 
103
- <?php get_job_manager_template_part( 'content-widget', 'job_listing' ); ?>
104
 
105
  <?php endwhile; ?>
106
 
107
  </ul>
108
 
109
- <?php echo $after_widget; ?>
110
 
111
  <?php else : ?>
112
 
113
  <?php get_job_manager_template_part( 'content-widget', 'no-jobs-found' ); ?>
114
 
115
- <?php endif;
 
116
 
117
  /**
118
  * Runs after Recent Jobs widget content.
@@ -129,7 +146,7 @@ class WP_Job_Manager_Widget_Recent_Jobs extends WP_Job_Manager_Widget {
129
 
130
  $content = ob_get_clean();
131
 
132
- echo $content;
133
 
134
  $this->cache_widget( $args, $content );
135
  }
17
  public function __construct() {
18
  global $wp_post_types;
19
 
20
+ // translators: Placeholder %s is the plural label for the job listing post type.
21
+ $this->widget_name = sprintf( __( 'Recent %s', 'wp-job-manager' ), $wp_post_types['job_listing']->labels->name );
22
  $this->widget_cssclass = 'job_manager widget_recent_jobs';
23
  $this->widget_description = __( 'Display a list of recent listings on your site, optionally matching a keyword and location.', 'wp-job-manager' );
24
  $this->widget_id = 'widget_recent_jobs';
 
25
  $this->settings = array(
26
+ 'title' => array(
27
  'type' => 'text',
28
+ // translators: Placeholder %s is the plural label for the job listing post type.
29
  'std' => sprintf( __( 'Recent %s', 'wp-job-manager' ), $wp_post_types['job_listing']->labels->name ),
30
  'label' => __( 'Title', 'wp-job-manager' ),
31
  ),
32
+ 'keyword' => array(
33
  'type' => 'text',
34
  'std' => '',
35
  'label' => __( 'Keyword', 'wp-job-manager' ),
36
  ),
37
+ 'location' => array(
38
  'type' => 'text',
39
  'std' => '',
40
  'label' => __( 'Location', 'wp-job-manager' ),
41
  ),
42
+ 'number' => array(
43
  'type' => 'number',
44
  'step' => 1,
45
  'min' => 1,
47
  'std' => 10,
48
  'label' => __( 'Number of listings to show', 'wp-job-manager' ),
49
  ),
50
+ 'show_logo' => array(
51
+ 'type' => 'checkbox',
52
+ 'std' => 0,
53
+ 'label' => esc_html__( 'Show Company Logo', 'wp-job-manager' ),
54
+ ),
55
  );
56
+
57
+ parent::__construct();
58
  }
59
 
60
  /**
75
 
76
  ob_start();
77
 
78
+ $title = apply_filters( 'widget_title', $instance['title'], $instance, $this->id_base );
79
+ $number = absint( $instance['number'] );
80
+ $jobs = get_job_listings(
81
+ array(
82
+ 'search_location' => $instance['location'],
83
+ 'search_keywords' => $instance['keyword'],
84
+ 'posts_per_page' => $number,
85
+ 'orderby' => 'date',
86
+ 'order' => 'DESC',
87
+ )
88
+ );
89
+ $show_logo = absint( $instance['show_logo'] );
90
 
91
  /**
92
  * Runs before Recent Jobs widget content.
101
 
102
  if ( $jobs->have_posts() ) : ?>
103
 
104
+ <?php echo $args['before_widget']; // WPCS: XSS ok. ?>
105
 
106
+ <?php
107
+ if ( $title ) {
108
+ echo $args['before_title'] . esc_html( $title ) . $args['after_title']; // WPCS: XSS ok.
109
+ }
110
+ ?>
111
 
112
  <ul class="job_listings">
113
 
114
+ <?php
115
+ while ( $jobs->have_posts() ) :
116
+ $jobs->the_post();
117
+ ?>
118
 
119
+ <?php get_job_manager_template( 'content-widget-job_listing.php', array( 'show_logo' => $instance['show_logo'] ) ); ?>
120
 
121
  <?php endwhile; ?>
122
 
123
  </ul>
124
 
125
+ <?php echo $args['after_widget']; // WPCS: XSS ok. ?>
126
 
127
  <?php else : ?>
128
 
129
  <?php get_job_manager_template_part( 'content-widget', 'no-jobs-found' ); ?>
130
 
131
+ <?php
132
+ endif;
133
 
134
  /**
135
  * Runs after Recent Jobs widget content.
146
 
147
  $content = ob_get_clean();
148
 
149
+ echo $content; // WPCS: XSS ok.
150
 
151
  $this->cache_widget( $args, $content );
152
  }
languages/wp-job-manager.pot CHANGED
@@ -2,765 +2,814 @@
2
  # This file is distributed under the GPL2+.
3
  msgid ""
4
  msgstr ""
5
- "Project-Id-Version: WP Job Manager 1.31.0\n"
6
  "Report-Msgid-Bugs-To: https://github.com/Automattic/WP-Job-Manager/issues\n"
7
- "POT-Creation-Date: 2018-04-26 10:23:25+00:00\n"
8
  "MIME-Version: 1.0\n"
9
  "Content-Type: text/plain; charset=utf-8\n"
10
  "Content-Transfer-Encoding: 8bit\n"
11
  "PO-Revision-Date: 2018-MO-DA HO:MI+ZONE\n"
12
  "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
13
  "Language-Team: LANGUAGE <EMAIL@ADDRESS>\n"
14
- "X-Generator: grunt-wp-i18n 0.5.4\n"
15
 
16
- #: includes/3rd-party/wpml.php:82
17
  msgid "Page Not Set"
18
  msgstr ""
19
 
20
- #: includes/3rd-party/wpml.php:94
 
 
21
  msgid "<a href=\"%s\">Switch to primary language</a> to edit this setting."
22
  msgstr ""
23
 
24
- #: includes/abstracts/abstract-wp-job-manager-form.php:312
25
- #: includes/abstracts/abstract-wp-job-manager-form.php:325
 
 
26
  msgid "\"%s\" check failed. Please try again."
27
  msgstr ""
28
 
29
- #: includes/admin/class-wp-job-manager-addons.php:111
30
- #: includes/admin/class-wp-job-manager-admin.php:146
31
  #: includes/admin/views/html-admin-page-addons.php:2
32
  msgid "WP Job Manager Add-ons"
33
  msgstr ""
34
 
35
- #: includes/admin/class-wp-job-manager-addons.php:113
36
  #: includes/helper/views/html-licences.php:6
37
  msgid "Licenses"
38
  msgstr ""
39
 
40
- #: includes/admin/class-wp-job-manager-admin.php:86
 
 
41
  msgid ""
42
  "<strong>WP Job Manager</strong> requires a more recent version of "
43
  "WordPress. <a href=\"%s\">Please update WordPresse</a> to avoid issues."
44
  msgstr ""
45
 
46
- #: includes/admin/class-wp-job-manager-admin.php:97
 
 
47
  msgid "<a href=\"%s\" style=\"color: red\">WordPress Update Required</a>"
48
  msgstr ""
49
 
50
- #: includes/admin/class-wp-job-manager-admin.php:143
51
  msgid "Settings"
52
  msgstr ""
53
 
54
- #: includes/admin/class-wp-job-manager-admin.php:146
55
  msgid "Add-ons"
56
  msgstr ""
57
 
58
- #: includes/admin/class-wp-job-manager-cpt.php:74
 
 
59
  msgid "Approve %s"
60
  msgstr ""
61
 
62
- #: includes/admin/class-wp-job-manager-cpt.php:75
 
 
63
  msgid "%s approved"
64
  msgstr ""
65
 
66
- #: includes/admin/class-wp-job-manager-cpt.php:79
 
 
67
  msgid "Expire %s"
68
  msgstr ""
69
 
70
- #: includes/admin/class-wp-job-manager-cpt.php:80
 
 
71
  msgid "%s expired"
72
  msgstr ""
73
 
74
- #: includes/admin/class-wp-job-manager-cpt.php:84
 
 
75
  msgid "Mark %s Filled"
76
  msgstr ""
77
 
78
- #: includes/admin/class-wp-job-manager-cpt.php:85
 
 
79
  msgid "%s marked as filled"
80
  msgstr ""
81
 
82
- #: includes/admin/class-wp-job-manager-cpt.php:89
 
 
83
  msgid "Mark %s Not Filled"
84
  msgstr ""
85
 
86
- #: includes/admin/class-wp-job-manager-cpt.php:90
 
 
87
  msgid "%s marked as not filled"
88
  msgstr ""
89
 
90
- #: includes/admin/class-wp-job-manager-cpt.php:302
91
  msgid "Select category"
92
  msgstr ""
93
 
94
- #: includes/admin/class-wp-job-manager-cpt.php:326
95
  msgid "Select Filled"
96
  msgstr ""
97
 
98
- #: includes/admin/class-wp-job-manager-cpt.php:330
99
  msgid "Filled"
100
  msgstr ""
101
 
102
- #: includes/admin/class-wp-job-manager-cpt.php:334
103
  msgid "Not Filled"
104
  msgstr ""
105
 
106
- #: includes/admin/class-wp-job-manager-cpt.php:342
107
  msgid "Select Featured"
108
  msgstr ""
109
 
110
- #: includes/admin/class-wp-job-manager-cpt.php:346
111
  msgid "Featured"
112
  msgstr ""
113
 
114
- #: includes/admin/class-wp-job-manager-cpt.php:350
115
  msgid "Not Featured"
116
  msgstr ""
117
 
118
- #: includes/admin/class-wp-job-manager-cpt.php:396
119
- #: includes/admin/class-wp-job-manager-cpt.php:440
120
  msgid "Position"
121
  msgstr ""
122
 
123
- #: includes/admin/class-wp-job-manager-cpt.php:411
124
- msgid "%s updated. <a href=\"%s\">View</a>"
 
 
125
  msgstr ""
126
 
127
- #: includes/admin/class-wp-job-manager-cpt.php:412
128
  msgid "Custom field updated."
129
  msgstr ""
130
 
131
- #: includes/admin/class-wp-job-manager-cpt.php:413
132
  msgid "Custom field deleted."
133
  msgstr ""
134
 
135
- #: includes/admin/class-wp-job-manager-cpt.php:414
 
136
  msgid "%s updated."
137
  msgstr ""
138
 
139
- #: includes/admin/class-wp-job-manager-cpt.php:415
140
- msgid "%s restored to revision from %s"
 
 
141
  msgstr ""
142
 
143
- #: includes/admin/class-wp-job-manager-cpt.php:416
144
- msgid "%s published. <a href=\"%s\">View</a>"
 
 
145
  msgstr ""
146
 
147
- #: includes/admin/class-wp-job-manager-cpt.php:417
 
 
148
  msgid "%s saved."
149
  msgstr ""
150
 
151
- #: includes/admin/class-wp-job-manager-cpt.php:418
152
- msgid "%s submitted. <a target=\"_blank\" href=\"%s\">Preview</a>"
 
 
153
  msgstr ""
154
 
155
- #: includes/admin/class-wp-job-manager-cpt.php:419
 
 
156
  msgid ""
157
- "%s scheduled for: <strong>%1$s</strong>. <a target=\"_blank\" "
158
- "href=\"%2$s\">Preview</a>"
159
  msgstr ""
160
 
161
- #: includes/admin/class-wp-job-manager-cpt.php:421
162
- msgid "%s draft updated. <a target=\"_blank\" href=\"%s\">Preview</a>"
 
 
163
  msgstr ""
164
 
165
- #: includes/admin/class-wp-job-manager-cpt.php:441
166
  msgid "Type"
167
  msgstr ""
168
 
169
- #: includes/admin/class-wp-job-manager-cpt.php:442
170
- #: includes/admin/class-wp-job-manager-writepanels.php:55
171
- #: includes/class-wp-job-manager-email-notifications.php:226
172
- #: includes/forms/class-wp-job-manager-form-submit-job.php:178
173
- #: includes/widgets/class-wp-job-manager-widget-recent-jobs.php:38
174
  #: templates/job-filters.php:35 templates/job-filters.php:36
175
  msgid "Location"
176
  msgstr ""
177
 
178
- #: includes/admin/class-wp-job-manager-cpt.php:443
179
  msgid "Status"
180
  msgstr ""
181
 
182
- #: includes/admin/class-wp-job-manager-cpt.php:444
183
  msgid "Posted"
184
  msgstr ""
185
 
186
- #: includes/admin/class-wp-job-manager-cpt.php:445
187
  msgid "Expires"
188
  msgstr ""
189
 
190
- #: includes/admin/class-wp-job-manager-cpt.php:446
191
- #: includes/admin/class-wp-job-manager-settings.php:154
192
  msgid "Categories"
193
  msgstr ""
194
 
195
- #: includes/admin/class-wp-job-manager-cpt.php:447
196
  msgid "Featured?"
197
  msgstr ""
198
 
199
- #: includes/admin/class-wp-job-manager-cpt.php:448
200
- #: includes/class-wp-job-manager-shortcodes.php:218
201
  msgid "Filled?"
202
  msgstr ""
203
 
204
- #: includes/admin/class-wp-job-manager-cpt.php:449
205
  msgid "Actions"
206
  msgstr ""
207
 
208
- #: includes/admin/class-wp-job-manager-cpt.php:513
 
209
  msgid "ID: %d"
210
  msgstr ""
211
 
212
- #: includes/admin/class-wp-job-manager-cpt.php:543
 
213
  msgid "by a guest"
214
  msgstr ""
215
 
216
- #: includes/admin/class-wp-job-manager-cpt.php:543
217
  msgid "by %s"
218
  msgstr ""
219
 
220
- #: includes/admin/class-wp-job-manager-cpt.php:561
221
  msgid "Approve"
222
  msgstr ""
223
 
224
- #: includes/admin/class-wp-job-manager-cpt.php:569
225
- #: includes/admin/class-wp-job-manager-writepanels.php:257
226
- #: includes/admin/class-wp-job-manager-writepanels.php:260
227
- #: includes/admin/class-wp-job-manager-writepanels.php:263
228
  msgid "View"
229
  msgstr ""
230
 
231
- #: includes/admin/class-wp-job-manager-cpt.php:576
232
- #: includes/class-wp-job-manager-post-types.php:221
233
  #: templates/job-dashboard.php:52 templates/job-dashboard.php:70
234
  msgid "Edit"
235
  msgstr ""
236
 
237
- #: includes/admin/class-wp-job-manager-cpt.php:583
238
  #: templates/job-dashboard.php:75
239
  msgid "Delete"
240
  msgstr ""
241
 
242
- #: includes/admin/class-wp-job-manager-permalink-settings.php:55
243
  msgid "Job base"
244
  msgstr ""
245
 
246
- #: includes/admin/class-wp-job-manager-permalink-settings.php:62
247
  msgid "Job category base"
248
  msgstr ""
249
 
250
- #: includes/admin/class-wp-job-manager-permalink-settings.php:69
251
  msgid "Job type base"
252
  msgstr ""
253
 
254
- #: includes/admin/class-wp-job-manager-settings.php:82
255
  msgid "General"
256
  msgstr ""
257
 
258
- #: includes/admin/class-wp-job-manager-settings.php:87
259
  msgid "Date Format"
260
  msgstr ""
261
 
262
- #: includes/admin/class-wp-job-manager-settings.php:88
263
  msgid ""
264
  "Choose how you want the published date for jobs to be displayed on the "
265
  "front-end."
266
  msgstr ""
267
 
268
- #: includes/admin/class-wp-job-manager-settings.php:91
269
  msgid "Relative to the current date (e.g., 1 day, 1 week, 1 month ago)"
270
  msgstr ""
271
 
272
- #: includes/admin/class-wp-job-manager-settings.php:92
273
  msgid "Default date format as defined in Settings"
274
  msgstr ""
275
 
276
- #: includes/admin/class-wp-job-manager-settings.php:98
277
  msgid "Google Maps API Key"
278
  msgstr ""
279
 
280
- #: includes/admin/class-wp-job-manager-settings.php:99
 
281
  msgid ""
282
  "Google requires an API key to retrieve location information for job "
283
  "listings. Acquire an API key from the <a href=\"%s\">Google Maps API "
284
  "developer site</a>."
285
  msgstr ""
286
 
287
- #: includes/admin/class-wp-job-manager-settings.php:105
288
  msgid "Delete Data On Uninstall"
289
  msgstr ""
290
 
291
- #: includes/admin/class-wp-job-manager-settings.php:106
292
  msgid ""
293
  "Delete WP Job Manager data when the plugin is deleted. Once removed, this "
294
  "data cannot be restored."
295
  msgstr ""
296
 
297
- #: includes/admin/class-wp-job-manager-settings.php:114
298
- #: includes/class-wp-job-manager-post-types.php:217
299
- #: includes/class-wp-job-manager-post-types.php:293
300
  msgid "Job Listings"
301
  msgstr ""
302
 
303
- #: includes/admin/class-wp-job-manager-settings.php:120
304
  msgid "Listings Per Page"
305
  msgstr ""
306
 
307
- #: includes/admin/class-wp-job-manager-settings.php:121
308
  msgid "Number of job listings to display per page."
309
  msgstr ""
310
 
311
- #: includes/admin/class-wp-job-manager-settings.php:127
312
  msgid "Filled Positions"
313
  msgstr ""
314
 
315
- #: includes/admin/class-wp-job-manager-settings.php:128
316
  msgid "Hide filled positions"
317
  msgstr ""
318
 
319
- #: includes/admin/class-wp-job-manager-settings.php:129
320
  msgid "Filled positions will not display in your archives."
321
  msgstr ""
322
 
323
- #: includes/admin/class-wp-job-manager-settings.php:136
324
  msgid "Hide Expired Listings"
325
  msgstr ""
326
 
327
- #: includes/admin/class-wp-job-manager-settings.php:137
328
  msgid "Hide expired listings in job archives/search"
329
  msgstr ""
330
 
331
- #: includes/admin/class-wp-job-manager-settings.php:138
332
  msgid "Expired job listings will not be searchable."
333
  msgstr ""
334
 
335
- #: includes/admin/class-wp-job-manager-settings.php:145
336
  msgid "Hide Expired Listings Content"
337
  msgstr ""
338
 
339
- #: includes/admin/class-wp-job-manager-settings.php:146
340
  msgid "Hide content in expired single job listings"
341
  msgstr ""
342
 
343
- #: includes/admin/class-wp-job-manager-settings.php:147
344
  msgid ""
345
  "Your site will display the titles of expired listings, but not the content "
346
  "of the listings. Otherwise, expired listings display their full content "
347
  "minus the application area."
348
  msgstr ""
349
 
350
- #: includes/admin/class-wp-job-manager-settings.php:155
351
  msgid "Enable listing categories"
352
  msgstr ""
353
 
354
- #: includes/admin/class-wp-job-manager-settings.php:156
355
  msgid ""
356
  "This lets users select from a list of categories when submitting a job. "
357
  "Note: an admin has to create categories before site users can select them."
358
  msgstr ""
359
 
360
- #: includes/admin/class-wp-job-manager-settings.php:163
361
  msgid "Multi-select Categories"
362
  msgstr ""
363
 
364
- #: includes/admin/class-wp-job-manager-settings.php:164
365
  msgid "Default to category multiselect"
366
  msgstr ""
367
 
368
- #: includes/admin/class-wp-job-manager-settings.php:165
369
  msgid ""
370
  "The category selection box will default to allowing multiple selections on "
371
  "the [jobs] shortcode. Without this, users will only be able to select a "
372
  "single category when submitting jobs."
373
  msgstr ""
374
 
375
- #: includes/admin/class-wp-job-manager-settings.php:172
376
  msgid "Category Filter Type"
377
  msgstr ""
378
 
379
- #: includes/admin/class-wp-job-manager-settings.php:173
380
  msgid ""
381
  "Determines the logic used to display jobs when selecting multiple "
382
  "categories."
383
  msgstr ""
384
 
385
- #: includes/admin/class-wp-job-manager-settings.php:176
386
  msgid "Jobs will be shown if within ANY selected category"
387
  msgstr ""
388
 
389
- #: includes/admin/class-wp-job-manager-settings.php:177
390
  msgid "Jobs will be shown if within ALL selected categories"
391
  msgstr ""
392
 
393
- #: includes/admin/class-wp-job-manager-settings.php:183
394
  msgid "Types"
395
  msgstr ""
396
 
397
- #: includes/admin/class-wp-job-manager-settings.php:184
398
  msgid "Enable listing types"
399
  msgstr ""
400
 
401
- #: includes/admin/class-wp-job-manager-settings.php:185
402
  msgid ""
403
  "This lets users select from a list of types when submitting a job. Note: an "
404
  "admin has to create types before site users can select them."
405
  msgstr ""
406
 
407
- #: includes/admin/class-wp-job-manager-settings.php:192
408
  msgid "Multi-select Listing Types"
409
  msgstr ""
410
 
411
- #: includes/admin/class-wp-job-manager-settings.php:193
412
  msgid "Allow multiple types for listings"
413
  msgstr ""
414
 
415
- #: includes/admin/class-wp-job-manager-settings.php:194
416
  msgid ""
417
  "This allows users to select more than one type when submitting a job. The "
418
  "metabox on the post editor and the selection box on the front-end job "
419
  "submission form will both reflect this."
420
  msgstr ""
421
 
422
- #: includes/admin/class-wp-job-manager-settings.php:201
423
  msgid "Job Submission"
424
  msgstr ""
425
 
426
- #: includes/admin/class-wp-job-manager-settings.php:206
427
  msgid "Account Required"
428
  msgstr ""
429
 
430
- #: includes/admin/class-wp-job-manager-settings.php:207
431
  msgid "Require an account to submit listings"
432
  msgstr ""
433
 
434
- #: includes/admin/class-wp-job-manager-settings.php:208
435
  msgid "Limits job listing submissions to registered, logged-in users."
436
  msgstr ""
437
 
438
- #: includes/admin/class-wp-job-manager-settings.php:215
439
  msgid "Account Creation"
440
  msgstr ""
441
 
442
- #: includes/admin/class-wp-job-manager-settings.php:216
443
  msgid "Enable account creation during submission"
444
  msgstr ""
445
 
446
- #: includes/admin/class-wp-job-manager-settings.php:217
447
  msgid ""
448
  "Includes account creation on the listing submission form, to allow "
449
  "non-registered users to create an account and submit a job listing "
450
  "simultaneously."
451
  msgstr ""
452
 
453
- #: includes/admin/class-wp-job-manager-settings.php:224
454
  msgid "Account Username"
455
  msgstr ""
456
 
457
- #: includes/admin/class-wp-job-manager-settings.php:225
458
  msgid "Generate usernames from email addresses"
459
  msgstr ""
460
 
461
- #: includes/admin/class-wp-job-manager-settings.php:226
462
  msgid ""
463
  "Automatically generates usernames for new accounts from the registrant's "
464
  "email address. If this is not enabled, a \"username\" field will display "
465
  "instead."
466
  msgstr ""
467
 
468
- #: includes/admin/class-wp-job-manager-settings.php:233
469
  msgid "Account Password"
470
  msgstr ""
471
 
472
- #: includes/admin/class-wp-job-manager-settings.php:234
473
  msgid "Email new users a link to set a password"
474
  msgstr ""
475
 
476
- #: includes/admin/class-wp-job-manager-settings.php:235
477
  msgid ""
478
  "Sends an email to the user with their username and a link to set their "
479
  "password. If this is not enabled, a \"password\" field will display "
480
  "instead, and their email address won't be verified."
481
  msgstr ""
482
 
483
- #: includes/admin/class-wp-job-manager-settings.php:242
484
  msgid "Account Role"
485
  msgstr ""
486
 
487
- #: includes/admin/class-wp-job-manager-settings.php:243
488
  msgid ""
489
  "Any new accounts created during submission will have this role. If you "
490
  "haven't enabled account creation during submission in the options above, "
491
  "your own method of assigning roles will apply."
492
  msgstr ""
493
 
494
- #: includes/admin/class-wp-job-manager-settings.php:250
495
  msgid "Moderate New Listings"
496
  msgstr ""
497
 
498
- #: includes/admin/class-wp-job-manager-settings.php:251
499
  msgid "Require admin approval of all new listing submissions"
500
  msgstr ""
501
 
502
- #: includes/admin/class-wp-job-manager-settings.php:252
503
  msgid ""
504
  "Sets all new submissions to \"pending.\" They will not appear on your site "
505
  "until an admin approves them."
506
  msgstr ""
507
 
508
- #: includes/admin/class-wp-job-manager-settings.php:259
509
  msgid "Allow Pending Edits"
510
  msgstr ""
511
 
512
- #: includes/admin/class-wp-job-manager-settings.php:260
513
  msgid "Allow editing of pending listings"
514
  msgstr ""
515
 
516
- #: includes/admin/class-wp-job-manager-settings.php:261
517
  msgid ""
518
  "Users can continue to edit pending listings until they are approved by an "
519
  "admin."
520
  msgstr ""
521
 
522
- #: includes/admin/class-wp-job-manager-settings.php:268
523
  msgid "Allow Published Edits"
524
  msgstr ""
525
 
526
- #: includes/admin/class-wp-job-manager-settings.php:269
527
  msgid "Allow editing of published listings"
528
  msgstr ""
529
 
530
- #: includes/admin/class-wp-job-manager-settings.php:270
531
  msgid ""
532
  "Choose whether published job listings can be edited and if edits require "
533
  "admin approval. When moderation is required, the original job listings will "
534
  "be unpublished while edits await admin approval."
535
  msgstr ""
536
 
537
- #: includes/admin/class-wp-job-manager-settings.php:273
538
  msgid "Users cannot edit"
539
  msgstr ""
540
 
541
- #: includes/admin/class-wp-job-manager-settings.php:274
542
  msgid "Users can edit without admin approval"
543
  msgstr ""
544
 
545
- #: includes/admin/class-wp-job-manager-settings.php:275
546
  msgid "Users can edit, but edits require admin approval"
547
  msgstr ""
548
 
549
- #: includes/admin/class-wp-job-manager-settings.php:282
550
  msgid "Listing Duration"
551
  msgstr ""
552
 
553
- #: includes/admin/class-wp-job-manager-settings.php:283
554
  msgid ""
555
  "Listings will display for the set number of days, then expire. Leave this "
556
  "field blank if you don't want listings to have an expiration date."
557
  msgstr ""
558
 
559
- #: includes/admin/class-wp-job-manager-settings.php:289
560
  msgid "Application Method"
561
  msgstr ""
562
 
563
- #: includes/admin/class-wp-job-manager-settings.php:290
564
  msgid ""
565
  "Choose the application method job listers will need to provide. Specify URL "
566
  "or email address only, or allow listers to choose which they prefer."
567
  msgstr ""
568
 
569
- #: includes/admin/class-wp-job-manager-settings.php:293
570
  msgid "Email address or website URL"
571
  msgstr ""
572
 
573
- #: includes/admin/class-wp-job-manager-settings.php:294
574
  msgid "Email addresses only"
575
  msgstr ""
576
 
577
- #: includes/admin/class-wp-job-manager-settings.php:295
578
  msgid "Website URLs only"
579
  msgstr ""
580
 
581
- #: includes/admin/class-wp-job-manager-settings.php:301
582
  msgid "reCAPTCHA"
583
  msgstr ""
584
 
585
- #: includes/admin/class-wp-job-manager-settings.php:305
586
  msgid "Are you human?"
587
  msgstr ""
588
 
589
- #: includes/admin/class-wp-job-manager-settings.php:307
590
  msgid "Field Label"
591
  msgstr ""
592
 
593
- #: includes/admin/class-wp-job-manager-settings.php:308
594
  msgid "The label used for the reCAPTCHA field on forms."
595
  msgstr ""
596
 
597
- #: includes/admin/class-wp-job-manager-settings.php:315
598
  msgid "Site Key"
599
  msgstr ""
600
 
601
- #: includes/admin/class-wp-job-manager-settings.php:316
 
602
  msgid ""
603
  "You can retrieve your site key from <a href=\"%s\">Google's reCAPTCHA admin "
604
  "dashboard</a>."
605
  msgstr ""
606
 
607
- #: includes/admin/class-wp-job-manager-settings.php:323
608
  msgid "Secret Key"
609
  msgstr ""
610
 
611
- #: includes/admin/class-wp-job-manager-settings.php:324
 
612
  msgid ""
613
  "You can retrieve your secret key from <a href=\"%s\">Google's reCAPTCHA "
614
  "admin dashboard</a>."
615
  msgstr ""
616
 
617
- #: includes/admin/class-wp-job-manager-settings.php:330
618
  msgid "Job Submission Form"
619
  msgstr ""
620
 
621
- #: includes/admin/class-wp-job-manager-settings.php:331
622
  msgid "Display a reCAPTCHA field on job submission form."
623
  msgstr ""
624
 
625
- #: includes/admin/class-wp-job-manager-settings.php:332
626
  msgid ""
627
  "This will help prevent bots from submitting job listings. You must have "
628
  "entered a valid site key and secret key above."
629
  msgstr ""
630
 
631
- #: includes/admin/class-wp-job-manager-settings.php:339
632
  msgid "Pages"
633
  msgstr ""
634
 
635
- #: includes/admin/class-wp-job-manager-settings.php:344
636
  msgid "Submit Job Form Page"
637
  msgstr ""
638
 
639
- #: includes/admin/class-wp-job-manager-settings.php:345
640
  msgid ""
641
  "Select the page where you've used the [submit_job_form] shortcode. This "
642
  "lets the plugin know the location of the form."
643
  msgstr ""
644
 
645
- #: includes/admin/class-wp-job-manager-settings.php:351
646
  msgid "Job Dashboard Page"
647
  msgstr ""
648
 
649
- #: includes/admin/class-wp-job-manager-settings.php:352
650
  msgid ""
651
  "Select the page where you've used the [job_dashboard] shortcode. This lets "
652
  "the plugin know the location of the dashboard."
653
  msgstr ""
654
 
655
- #: includes/admin/class-wp-job-manager-settings.php:358
656
  msgid "Job Listings Page"
657
  msgstr ""
658
 
659
- #: includes/admin/class-wp-job-manager-settings.php:359
660
  msgid ""
661
  "Select the page where you've used the [jobs] shortcode. This lets the "
662
  "plugin know the location of the job listings page."
663
  msgstr ""
664
 
665
- #: includes/admin/class-wp-job-manager-settings.php:405
666
  msgid "Settings successfully saved"
667
  msgstr ""
668
 
669
- #: includes/admin/class-wp-job-manager-settings.php:430
670
  msgid "Save Changes"
671
  msgstr ""
672
 
673
- #: includes/admin/class-wp-job-manager-settings.php:597
674
  msgid "--no page--"
675
  msgstr ""
676
 
677
- #: includes/admin/class-wp-job-manager-settings.php:602
678
  msgid "Select a page&hellip;"
679
  msgstr ""
680
 
681
- #: includes/admin/class-wp-job-manager-setup.php:51
682
  msgid "Setup"
683
  msgstr ""
684
 
685
- #: includes/admin/class-wp-job-manager-setup.php:203
686
  msgid "WP Job Manager Setup"
687
  msgstr ""
688
 
689
- #: includes/admin/class-wp-job-manager-setup.php:206
690
  msgid "1. Introduction"
691
  msgstr ""
692
 
693
- #: includes/admin/class-wp-job-manager-setup.php:207
694
  msgid "2. Page Setup"
695
  msgstr ""
696
 
697
- #: includes/admin/class-wp-job-manager-setup.php:208
698
  msgid "3. Done"
699
  msgstr ""
700
 
701
- #: includes/admin/class-wp-job-manager-setup.php:213
702
  msgid "Welcome to the Setup Wizard!"
703
  msgstr ""
704
 
705
- #: includes/admin/class-wp-job-manager-setup.php:215
706
  msgid ""
707
  "Thanks for installing <em>WP Job Manager</em>! Let's get your site ready to "
708
  "accept job listings."
709
  msgstr ""
710
 
711
- #: includes/admin/class-wp-job-manager-setup.php:216
712
  msgid ""
713
  "This setup wizard will walk you through the process of creating pages for "
714
  "job submissions, management, and listings."
715
  msgstr ""
716
 
717
- #: includes/admin/class-wp-job-manager-setup.php:217
 
718
  msgid ""
719
- "If you'd prefer to skip this and set up your pages manually, our "
720
- "%sdocumentation%s will walk you through each step."
721
  msgstr ""
722
 
723
- #: includes/admin/class-wp-job-manager-setup.php:225
724
  msgid "Start setup"
725
  msgstr ""
726
 
727
- #: includes/admin/class-wp-job-manager-setup.php:226
728
  msgid "Skip setup. I will set up the plugin manually."
729
  msgstr ""
730
 
731
- #: includes/admin/class-wp-job-manager-setup.php:233
732
  msgid "Page Setup"
733
  msgstr ""
734
 
735
- #: includes/admin/class-wp-job-manager-setup.php:235
736
  msgid ""
737
  "With WP Job Manager, employers and applicants can post, manage, and browse "
738
  "job listings right on your website. Tell us which of these common pages "
739
  "you'd like your site to have and we'll create and configure them for you."
740
  msgstr ""
741
 
742
- #: includes/admin/class-wp-job-manager-setup.php:236
 
 
743
  msgid ""
744
- "(These pages are created using %1$sshortcodes%2$s, which we take care of in "
745
- "this step. If you'd like to build these pages yourself or want to add one "
746
- "of these options to an existing page on your site, you can skip this step "
747
- "and take a look at %4$sshortcode documentation%2$s for detailed "
748
- "instructions.)"
 
 
749
  msgstr ""
750
 
751
- #: includes/admin/class-wp-job-manager-setup.php:244
752
  msgid "Page Title"
753
  msgstr ""
754
 
755
- #: includes/admin/class-wp-job-manager-setup.php:245
756
  msgid "Page Description"
757
  msgstr ""
758
 
759
- #: includes/admin/class-wp-job-manager-setup.php:246
760
  msgid "Content Shortcode"
761
  msgstr ""
762
 
763
- #: includes/admin/class-wp-job-manager-setup.php:254
764
  msgid ""
765
  "Creates a page that allows employers to post new jobs directly from a page "
766
  "on your website, instead of requiring them to log in to an admin area. If "
@@ -768,7 +817,7 @@ msgid ""
768
  "the admin dashboard only -- you can uncheck this setting."
769
  msgstr ""
770
 
771
- #: includes/admin/class-wp-job-manager-setup.php:262
772
  msgid ""
773
  "Creates a page that allows employers to manage their job listings directly "
774
  "from a page on your website, instead of requiring them to log in to an "
@@ -776,66 +825,70 @@ msgid ""
776
  "only, you can uncheck this setting."
777
  msgstr ""
778
 
779
- #: includes/admin/class-wp-job-manager-setup.php:269
780
  msgid "Creates a page where visitors can browse, search, and filter job listings."
781
  msgstr ""
782
 
783
- #: includes/admin/class-wp-job-manager-setup.php:277
784
  msgid "Skip this step"
785
  msgstr ""
786
 
787
- #: includes/admin/class-wp-job-manager-setup.php:287
788
  msgid "You're ready to start using WP Job Manager!"
789
  msgstr ""
790
 
791
- #: includes/admin/class-wp-job-manager-setup.php:289
792
  msgid "Wondering what to do now? Here are some of the most common next steps:"
793
  msgstr ""
794
 
795
- #: includes/admin/class-wp-job-manager-setup.php:292
796
  msgid "Tweak your settings"
797
  msgstr ""
798
 
799
- #: includes/admin/class-wp-job-manager-setup.php:293
800
  msgid "Add a job using the admin dashboard"
801
  msgstr ""
802
 
803
- #: includes/admin/class-wp-job-manager-setup.php:296
804
  msgid "View submitted job listings"
805
  msgstr ""
806
 
807
- #: includes/admin/class-wp-job-manager-setup.php:298
808
  msgid "Add job listings to a page using the [jobs] shortcode"
809
  msgstr ""
810
 
811
- #: includes/admin/class-wp-job-manager-setup.php:302
812
  msgid "Add a job via the front-end"
813
  msgstr ""
814
 
815
- #: includes/admin/class-wp-job-manager-setup.php:304
816
  msgid "Learn to use the front-end job submission board"
817
  msgstr ""
818
 
819
- #: includes/admin/class-wp-job-manager-setup.php:308
820
  msgid "View the job dashboard"
821
  msgstr ""
822
 
823
- #: includes/admin/class-wp-job-manager-setup.php:310
824
  msgid "Learn to use the front-end job dashboard"
825
  msgstr ""
826
 
827
- #: includes/admin/class-wp-job-manager-setup.php:314
 
 
828
  msgid ""
829
- "If you need help, you can find more detail in our %1$ssupport "
830
- "documentation%2$s or post your question on the %3$sWP Job Manager support "
831
- "forums%2$s. Happy hiring!"
 
 
832
  msgstr ""
833
 
834
- #: includes/admin/class-wp-job-manager-setup.php:317
835
  msgid "Support WP Job Manager's Ongoing Development"
836
  msgstr ""
837
 
838
- #: includes/admin/class-wp-job-manager-setup.php:318
839
  msgid ""
840
  "There are lots of ways you can support open source software projects like "
841
  "this one: contributing code, fixing a bug, assisting with non-English "
@@ -843,156 +896,165 @@ msgid ""
843
  "spread the word. We appreciate your support!"
844
  msgstr ""
845
 
846
- #: includes/admin/class-wp-job-manager-setup.php:320
847
  msgid "Leave a positive review"
848
  msgstr ""
849
 
850
- #: includes/admin/class-wp-job-manager-setup.php:321
851
  msgid "Contribute a localization"
852
  msgstr ""
853
 
854
- #: includes/admin/class-wp-job-manager-setup.php:322
855
  msgid "Contribute code or report a bug"
856
  msgstr ""
857
 
858
- #: includes/admin/class-wp-job-manager-setup.php:323
859
  msgid "Help other users on the forums"
860
  msgstr ""
861
 
862
  #: includes/admin/class-wp-job-manager-taxonomy-meta.php:78
863
- #: includes/admin/class-wp-job-manager-taxonomy-meta.php:100
864
- #: includes/admin/class-wp-job-manager-taxonomy-meta.php:118
865
- #: includes/rest-api/class-wp-job-manager-models-job-types-custom-fields.php:35
866
  msgid "Employment Type"
867
  msgstr ""
868
 
869
- #: includes/admin/class-wp-job-manager-writepanels.php:56
870
- #: includes/forms/class-wp-job-manager-form-submit-job.php:182
871
  msgid "e.g. \"London\""
872
  msgstr ""
873
 
874
- #: includes/admin/class-wp-job-manager-writepanels.php:57
875
  #: includes/rest-api/class-wp-job-manager-models-job-listings-custom-fields.php:28
876
  msgid "Leave this blank if the location is not important."
877
  msgstr ""
878
 
879
- #: includes/admin/class-wp-job-manager-writepanels.php:61
880
  #: includes/rest-api/class-wp-job-manager-models-job-listings-custom-fields.php:32
881
  msgid "Application Email or URL"
882
  msgstr ""
883
 
884
- #: includes/admin/class-wp-job-manager-writepanels.php:62
885
  msgid "URL or email which applicants use to apply"
886
  msgstr ""
887
 
888
- #: includes/admin/class-wp-job-manager-writepanels.php:63
889
  msgid ""
890
  "This field is required for the \"application\" area to appear beneath the "
891
  "listing."
892
  msgstr ""
893
 
894
- #: includes/admin/class-wp-job-manager-writepanels.php:68
 
895
  #: includes/rest-api/class-wp-job-manager-models-job-listings-custom-fields.php:37
896
  msgid "Company Name"
897
  msgstr ""
898
 
899
- #: includes/admin/class-wp-job-manager-writepanels.php:73
 
900
  #: includes/rest-api/class-wp-job-manager-models-job-listings-custom-fields.php:41
901
  msgid "Company Website"
902
  msgstr ""
903
 
904
- #: includes/admin/class-wp-job-manager-writepanels.php:78
 
905
  #: includes/rest-api/class-wp-job-manager-models-job-listings-custom-fields.php:45
906
  msgid "Company Tagline"
907
  msgstr ""
908
 
909
- #: includes/admin/class-wp-job-manager-writepanels.php:79
910
  msgid "Brief description about the company"
911
  msgstr ""
912
 
913
- #: includes/admin/class-wp-job-manager-writepanels.php:83
 
914
  #: includes/rest-api/class-wp-job-manager-models-job-listings-custom-fields.php:49
915
  msgid "Company Twitter"
916
  msgstr ""
917
 
918
- #: includes/admin/class-wp-job-manager-writepanels.php:88
 
919
  #: includes/rest-api/class-wp-job-manager-models-job-listings-custom-fields.php:53
920
  msgid "Company Video"
921
  msgstr ""
922
 
923
- #: includes/admin/class-wp-job-manager-writepanels.php:89
924
  msgid "URL to the company video"
925
  msgstr ""
926
 
927
- #: includes/admin/class-wp-job-manager-writepanels.php:94
928
  #: includes/rest-api/class-wp-job-manager-models-job-listings-custom-fields.php:57
929
  msgid "Position Filled"
930
  msgstr ""
931
 
932
- #: includes/admin/class-wp-job-manager-writepanels.php:97
933
  msgid "Filled listings will no longer accept applications."
934
  msgstr ""
935
 
936
- #: includes/admin/class-wp-job-manager-writepanels.php:102
937
  #: includes/rest-api/class-wp-job-manager-models-job-listings-custom-fields.php:64
938
  msgid "Featured Listing"
939
  msgstr ""
940
 
941
- #: includes/admin/class-wp-job-manager-writepanels.php:104
942
  msgid ""
943
  "Featured listings will be sticky during searches, and can be styled "
944
  "differently."
945
  msgstr ""
946
 
947
- #: includes/admin/class-wp-job-manager-writepanels.php:109
948
  #: includes/rest-api/class-wp-job-manager-models-job-listings-custom-fields.php:68
949
  msgid "Listing Expiry Date"
950
  msgstr ""
951
 
952
- #: includes/admin/class-wp-job-manager-writepanels.php:118
953
- #: includes/class-wp-job-manager-email-notifications.php:280
954
  #: includes/rest-api/class-wp-job-manager-models-job-listings-custom-fields.php:75
955
  msgid "Posted by"
956
  msgstr ""
957
 
958
- #: includes/admin/class-wp-job-manager-writepanels.php:160
 
 
959
  msgid "%s Data"
960
  msgstr ""
961
 
962
- #: includes/admin/class-wp-job-manager-writepanels.php:200
963
  msgid "Most Used"
964
  msgstr ""
965
 
966
- #: includes/admin/class-wp-job-manager-writepanels.php:257
967
- #: includes/admin/class-wp-job-manager-writepanels.php:260
968
- #: includes/admin/class-wp-job-manager-writepanels.php:263
969
  msgid "Use file"
970
  msgstr ""
971
 
972
- #: includes/admin/class-wp-job-manager-writepanels.php:257
973
- #: includes/admin/class-wp-job-manager-writepanels.php:260
974
- #: includes/admin/class-wp-job-manager-writepanels.php:263
975
  msgid "Upload"
976
  msgstr ""
977
 
978
- #: includes/admin/class-wp-job-manager-writepanels.php:263
979
  msgid "Add file"
980
  msgstr ""
981
 
982
- #: includes/admin/class-wp-job-manager-writepanels.php:489
983
  msgid "Guest User"
984
  msgstr ""
985
 
986
- #: includes/admin/class-wp-job-manager-writepanels.php:491
987
  msgid "Change"
988
  msgstr ""
989
 
990
- #: includes/admin/class-wp-job-manager-writepanels.php:495
991
  msgid "Enter the ID of the user, or leave blank if submitted by a guest."
992
  msgstr ""
993
 
994
- #: includes/admin/class-wp-job-manager-writepanels.php:558
995
- msgid "%s was last modified by the user on %s."
 
 
996
  msgstr ""
997
 
998
  #: includes/admin/views/html-admin-page-addons.php:13
@@ -1003,259 +1065,327 @@ msgstr ""
1003
  msgid "No add-ons were found."
1004
  msgstr ""
1005
 
1006
- #: includes/class-wp-job-manager-ajax.php:170
 
1007
  msgid "Search completed. Found %d matching record."
1008
  msgid_plural "Search completed. Found %d matching records."
1009
  msgstr[0] ""
1010
  msgstr[1] ""
1011
 
1012
- #: includes/class-wp-job-manager-ajax.php:269
1013
  msgid "You must be logged in to upload files using this method."
1014
  msgstr ""
1015
 
1016
- #: includes/class-wp-job-manager-email-notifications.php:215
 
 
 
 
 
 
 
 
 
 
 
 
 
1017
  msgid "Job title"
1018
  msgstr ""
1019
 
1020
- #: includes/class-wp-job-manager-email-notifications.php:235
1021
- #: includes/class-wp-job-manager-post-types.php:139
1022
- #: includes/forms/class-wp-job-manager-form-submit-job.php:186
1023
  msgid "Job type"
1024
  msgstr ""
1025
 
1026
- #: includes/class-wp-job-manager-email-notifications.php:245
1027
- #: includes/class-wp-job-manager-post-types.php:90
1028
- #: includes/forms/class-wp-job-manager-form-submit-job.php:195
1029
  msgid "Job category"
1030
  msgstr ""
1031
 
1032
- #: includes/class-wp-job-manager-email-notifications.php:254
1033
- #: includes/forms/class-wp-job-manager-form-submit-job.php:220
1034
  msgid "Company name"
1035
  msgstr ""
1036
 
1037
- #: includes/class-wp-job-manager-email-notifications.php:262
1038
  msgid "Company website"
1039
  msgstr ""
1040
 
1041
- #: includes/class-wp-job-manager-email-notifications.php:271
1042
  msgid "Listing expires"
1043
  msgstr ""
1044
 
1045
- #: includes/class-wp-job-manager-email-notifications.php:427
1046
  msgid "Email Notifications"
1047
  msgstr ""
1048
 
1049
- #: includes/class-wp-job-manager-email-notifications.php:430
1050
  msgid "Select the email notifications to enable."
1051
  msgstr ""
1052
 
1053
- #: includes/class-wp-job-manager-email-notifications.php:569
1054
  msgid "Format"
1055
  msgstr ""
1056
 
1057
- #: includes/class-wp-job-manager-email-notifications.php:572
1058
  msgid "Send plain text email"
1059
  msgstr ""
1060
 
1061
- #: includes/class-wp-job-manager-email-notifications.php:573
1062
  msgid "Send rich text email"
1063
  msgstr ""
1064
 
1065
- #: includes/class-wp-job-manager-geocode.php:221
1066
  msgid "No results found"
1067
  msgstr ""
1068
 
1069
- #: includes/class-wp-job-manager-geocode.php:225
1070
  msgid "Query limit reached"
1071
  msgstr ""
1072
 
1073
- #: includes/class-wp-job-manager-geocode.php:231
1074
- #: includes/class-wp-job-manager-geocode.php:235
1075
- #: includes/class-wp-job-manager-geocode.php:239
1076
  msgid "Geocoding error"
1077
  msgstr ""
1078
 
1079
- #: includes/class-wp-job-manager-install.php:65
1080
  msgid "Employer"
1081
  msgstr ""
1082
 
1083
- #: includes/class-wp-job-manager-post-types.php:91
1084
  msgid "Job categories"
1085
  msgstr ""
1086
 
1087
- #: includes/class-wp-job-manager-post-types.php:115
1088
- #: includes/class-wp-job-manager-post-types.php:163
1089
- #: includes/class-wp-job-manager-post-types.php:226
 
 
 
 
 
 
1090
  msgid "Search %s"
1091
  msgstr ""
1092
 
1093
- #: includes/class-wp-job-manager-post-types.php:116
1094
- #: includes/class-wp-job-manager-post-types.php:164
1095
- #: includes/class-wp-job-manager-post-types.php:218
 
 
 
 
 
 
1096
  msgid "All %s"
1097
  msgstr ""
1098
 
1099
- #: includes/class-wp-job-manager-post-types.php:117
1100
- #: includes/class-wp-job-manager-post-types.php:165
1101
- #: includes/class-wp-job-manager-post-types.php:229
 
 
 
 
 
 
1102
  msgid "Parent %s"
1103
  msgstr ""
1104
 
1105
- #: includes/class-wp-job-manager-post-types.php:118
1106
- #: includes/class-wp-job-manager-post-types.php:166
 
 
 
 
1107
  msgid "Parent %s:"
1108
  msgstr ""
1109
 
1110
- #: includes/class-wp-job-manager-post-types.php:119
1111
- #: includes/class-wp-job-manager-post-types.php:167
1112
- #: includes/class-wp-job-manager-post-types.php:222
 
 
 
 
 
 
1113
  msgid "Edit %s"
1114
  msgstr ""
1115
 
1116
- #: includes/class-wp-job-manager-post-types.php:120
1117
- #: includes/class-wp-job-manager-post-types.php:168
 
 
 
 
1118
  msgid "Update %s"
1119
  msgstr ""
1120
 
1121
- #: includes/class-wp-job-manager-post-types.php:121
1122
- #: includes/class-wp-job-manager-post-types.php:169
 
 
 
 
1123
  msgid "Add New %s"
1124
  msgstr ""
1125
 
1126
- #: includes/class-wp-job-manager-post-types.php:122
1127
- #: includes/class-wp-job-manager-post-types.php:170
 
 
 
 
1128
  msgid "New %s Name"
1129
  msgstr ""
1130
 
1131
- #: includes/class-wp-job-manager-post-types.php:140
1132
  msgid "Job types"
1133
  msgstr ""
1134
 
1135
- #: includes/class-wp-job-manager-post-types.php:189
1136
  msgid "Job"
1137
  msgstr ""
1138
 
1139
- #: includes/class-wp-job-manager-post-types.php:190
1140
  msgid "Jobs"
1141
  msgstr ""
1142
 
1143
- #: includes/class-wp-job-manager-post-types.php:219
1144
  msgid "Add New"
1145
  msgstr ""
1146
 
1147
- #: includes/class-wp-job-manager-post-types.php:220
 
 
1148
  msgid "Add %s"
1149
  msgstr ""
1150
 
1151
- #: includes/class-wp-job-manager-post-types.php:223
 
 
1152
  msgid "New %s"
1153
  msgstr ""
1154
 
1155
- #: includes/class-wp-job-manager-post-types.php:224
1156
- #: includes/class-wp-job-manager-post-types.php:225
 
 
1157
  msgid "View %s"
1158
  msgstr ""
1159
 
1160
- #: includes/class-wp-job-manager-post-types.php:227
 
 
1161
  msgid "No %s found"
1162
  msgstr ""
1163
 
1164
- #: includes/class-wp-job-manager-post-types.php:228
 
 
1165
  msgid "No %s found in trash"
1166
  msgstr ""
1167
 
1168
- #: includes/class-wp-job-manager-post-types.php:230
1169
- msgid "Company Logo"
1170
- msgstr ""
1171
-
1172
- #: includes/class-wp-job-manager-post-types.php:231
1173
  msgid "Set company logo"
1174
  msgstr ""
1175
 
1176
- #: includes/class-wp-job-manager-post-types.php:232
1177
  msgid "Remove company logo"
1178
  msgstr ""
1179
 
1180
- #: includes/class-wp-job-manager-post-types.php:233
1181
  msgid "Use as company logo"
1182
  msgstr ""
1183
 
1184
- #: includes/class-wp-job-manager-post-types.php:235
 
 
1185
  msgid "This is where you can create and manage %s."
1186
  msgstr ""
1187
 
1188
- #: includes/class-wp-job-manager-post-types.php:266
 
1189
  msgid "Expired <span class=\"count\">(%s)</span>"
1190
  msgid_plural "Expired <span class=\"count\">(%s)</span>"
1191
  msgstr[0] ""
1192
  msgstr[1] ""
1193
 
1194
- #: includes/class-wp-job-manager-post-types.php:274
 
1195
  msgid "Preview <span class=\"count\">(%s)</span>"
1196
  msgid_plural "Preview <span class=\"count\">(%s)</span>"
1197
  msgstr[0] ""
1198
  msgstr[1] ""
1199
 
1200
- #: includes/class-wp-job-manager-shortcodes.php:96
1201
  msgid "Invalid ID"
1202
  msgstr ""
1203
 
1204
- #: includes/class-wp-job-manager-shortcodes.php:103
1205
  msgid "This position has already been filled"
1206
  msgstr ""
1207
 
1208
- #: includes/class-wp-job-manager-shortcodes.php:109
 
1209
  msgid "%s has been filled"
1210
  msgstr ""
1211
 
1212
- #: includes/class-wp-job-manager-shortcodes.php:114
1213
  msgid "This position is not filled"
1214
  msgstr ""
1215
 
1216
- #: includes/class-wp-job-manager-shortcodes.php:121
 
1217
  msgid "%s has been marked as not filled"
1218
  msgstr ""
1219
 
1220
- #: includes/class-wp-job-manager-shortcodes.php:128
 
1221
  msgid "%s has been deleted"
1222
  msgstr ""
1223
 
1224
- #: includes/class-wp-job-manager-shortcodes.php:133
1225
- #: includes/class-wp-job-manager-shortcodes.php:146
1226
  msgid "Missing submission page."
1227
  msgstr ""
1228
 
1229
- #: includes/class-wp-job-manager-shortcodes.php:217
1230
- #: includes/widgets/class-wp-job-manager-widget-featured-jobs.php:28
1231
- #: includes/widgets/class-wp-job-manager-widget-featured-jobs.php:44
1232
- #: includes/widgets/class-wp-job-manager-widget-recent-jobs.php:28
1233
  msgid "Title"
1234
  msgstr ""
1235
 
1236
- #: includes/class-wp-job-manager-shortcodes.php:219
1237
  msgid "Date Posted"
1238
  msgstr ""
1239
 
1240
- #: includes/class-wp-job-manager-shortcodes.php:220
1241
  msgid "Listing Expires"
1242
  msgstr ""
1243
 
1244
- #: includes/class-wp-job-manager-shortcodes.php:326
1245
- #: includes/class-wp-job-manager-shortcodes.php:364
1246
  msgid "Load more listings"
1247
  msgstr ""
1248
 
1249
- #: includes/class-wp-job-manager-usage-tracking.php:63
 
 
1250
  msgid ""
1251
  "We'd love if you helped us make WP Job Manager better by allowing us to "
1252
  "collect\n"
1253
- "\t\t\t<a href=\"%s\" target=\"_blank\">usage tracking data</a>.\n"
1254
- "\t\t\tNo sensitive information is collected, and you can opt out at any "
1255
- "time."
1256
  msgstr ""
1257
 
1258
- #: includes/class-wp-job-manager-usage-tracking.php:107
1259
  #. translators: the href tag contains the URL for the page telling users what
1260
  #. data WPJM tracks.
1261
  msgid ""
@@ -1264,8 +1394,8 @@ msgid ""
1264
  "\t\t\t\tNo sensitive information is collected."
1265
  msgstr ""
1266
 
1267
- #: includes/class-wp-job-manager-usage-tracking.php:126
1268
- #: lib/usage-tracking/class-usage-tracking-base.php:472
1269
  msgid "Enable Usage Tracking"
1270
  msgstr ""
1271
 
@@ -1287,7 +1417,8 @@ msgid ""
1287
  "frontend."
1288
  msgstr ""
1289
 
1290
- #: includes/emails/class-wp-job-manager-email-admin-new-job.php:55
 
1291
  msgid "New Job Listing Submitted: %s"
1292
  msgstr ""
1293
 
@@ -1301,7 +1432,8 @@ msgid ""
1301
  "frontend."
1302
  msgstr ""
1303
 
1304
- #: includes/emails/class-wp-job-manager-email-admin-updated-job.php:55
 
1305
  msgid "Job Listing Updated: %s"
1306
  msgstr ""
1307
 
@@ -1313,226 +1445,234 @@ msgstr ""
1313
  msgid "Send notices to employers before a job listing expires."
1314
  msgstr ""
1315
 
1316
- #: includes/emails/class-wp-job-manager-email-employer-expiring-job.php:71
 
1317
  msgid "Job Listing Expiring: %s"
1318
  msgstr ""
1319
 
1320
- #: includes/emails/class-wp-job-manager-email-employer-expiring-job.php:124
1321
  msgid "Notice Period"
1322
  msgstr ""
1323
 
1324
- #: includes/emails/class-wp-job-manager-email-employer-expiring-job.php:126
1325
  msgid "days"
1326
  msgstr ""
1327
 
1328
- #: includes/forms/class-wp-job-manager-form-edit-job.php:93
1329
  msgid "Invalid listing"
1330
  msgstr ""
1331
 
1332
- #: includes/forms/class-wp-job-manager-form-edit-job.php:125
1333
  msgid "Save changes"
1334
  msgstr ""
1335
 
1336
- #: includes/forms/class-wp-job-manager-form-edit-job.php:128
1337
  msgid "Submit changes for approval"
1338
  msgstr ""
1339
 
1340
- #: includes/forms/class-wp-job-manager-form-edit-job.php:173
1341
  msgid "Your changes have been saved."
1342
  msgstr ""
1343
 
1344
- #: includes/forms/class-wp-job-manager-form-edit-job.php:179
1345
  msgid "View &rarr;"
1346
  msgstr ""
1347
 
1348
- #: includes/forms/class-wp-job-manager-form-edit-job.php:181
1349
  msgid ""
1350
  "Your changes have been submitted and your listing will be visible again "
1351
  "once approved."
1352
  msgstr ""
1353
 
1354
- #: includes/forms/class-wp-job-manager-form-submit-job.php:67
1355
  msgid "Submit Details"
1356
  msgstr ""
1357
 
1358
- #: includes/forms/class-wp-job-manager-form-submit-job.php:73
1359
- #: includes/forms/class-wp-job-manager-form-submit-job.php:485
1360
  #: templates/job-preview.php:22
1361
  msgid "Preview"
1362
  msgstr ""
1363
 
1364
- #: includes/forms/class-wp-job-manager-form-submit-job.php:79
1365
  msgid "Done"
1366
  msgstr ""
1367
 
1368
- #: includes/forms/class-wp-job-manager-form-submit-job.php:147
1369
  msgid "Application email"
1370
  msgstr ""
1371
 
1372
- #: includes/forms/class-wp-job-manager-form-submit-job.php:148
1373
- #: wp-job-manager-template.php:703
1374
  msgid "you@yourdomain.com"
1375
  msgstr ""
1376
 
1377
- #: includes/forms/class-wp-job-manager-form-submit-job.php:152
1378
  msgid "Application URL"
1379
  msgstr ""
1380
 
1381
- #: includes/forms/class-wp-job-manager-form-submit-job.php:153
1382
- #: includes/forms/class-wp-job-manager-form-submit-job.php:231
1383
  msgid "http://"
1384
  msgstr ""
1385
 
1386
- #: includes/forms/class-wp-job-manager-form-submit-job.php:157
1387
  msgid "Application email/URL"
1388
  msgstr ""
1389
 
1390
- #: includes/forms/class-wp-job-manager-form-submit-job.php:158
1391
  msgid "Enter an email address or website URL"
1392
  msgstr ""
1393
 
1394
- #: includes/forms/class-wp-job-manager-form-submit-job.php:171
1395
  msgid "Job Title"
1396
  msgstr ""
1397
 
1398
- #: includes/forms/class-wp-job-manager-form-submit-job.php:179
1399
  msgid "Leave this blank if the location is not important"
1400
  msgstr ""
1401
 
1402
- #: includes/forms/class-wp-job-manager-form-submit-job.php:189
1403
  msgid "Choose job type&hellip;"
1404
  msgstr ""
1405
 
1406
- #: includes/forms/class-wp-job-manager-form-submit-job.php:204
1407
  msgid "Description"
1408
  msgstr ""
1409
 
1410
- #: includes/forms/class-wp-job-manager-form-submit-job.php:223
1411
  msgid "Enter the name of the company"
1412
  msgstr ""
1413
 
1414
- #: includes/forms/class-wp-job-manager-form-submit-job.php:227
1415
  #: templates/content-single-job_listing-company.php:30
1416
  msgid "Website"
1417
  msgstr ""
1418
 
1419
- #: includes/forms/class-wp-job-manager-form-submit-job.php:235
1420
  msgid "Tagline"
1421
  msgstr ""
1422
 
1423
- #: includes/forms/class-wp-job-manager-form-submit-job.php:238
1424
  msgid "Briefly describe your company"
1425
  msgstr ""
1426
 
1427
- #: includes/forms/class-wp-job-manager-form-submit-job.php:243
1428
  msgid "Video"
1429
  msgstr ""
1430
 
1431
- #: includes/forms/class-wp-job-manager-form-submit-job.php:247
1432
  msgid "A link to a video about your company"
1433
  msgstr ""
1434
 
1435
- #: includes/forms/class-wp-job-manager-form-submit-job.php:251
1436
  msgid "Twitter username"
1437
  msgstr ""
1438
 
1439
- #: includes/forms/class-wp-job-manager-form-submit-job.php:254
1440
  msgid "@yourcompany"
1441
  msgstr ""
1442
 
1443
- #: includes/forms/class-wp-job-manager-form-submit-job.php:258
1444
  msgid "Logo"
1445
  msgstr ""
1446
 
1447
- #: includes/forms/class-wp-job-manager-form-submit-job.php:306
 
1448
  msgid "%s is a required field"
1449
  msgstr ""
1450
 
1451
- #: includes/forms/class-wp-job-manager-form-submit-job.php:316
 
1452
  msgid "%s is invalid"
1453
  msgstr ""
1454
 
1455
- #: includes/forms/class-wp-job-manager-form-submit-job.php:332
1456
- #: wp-job-manager-functions.php:1257
1457
- msgid "\"%s\" (filetype %s) needs to be one of the following file types: %s"
 
 
 
 
1458
  msgstr ""
1459
 
1460
- #: includes/forms/class-wp-job-manager-form-submit-job.php:347
1461
  msgid "Please enter a valid application email address"
1462
  msgstr ""
1463
 
1464
- #: includes/forms/class-wp-job-manager-form-submit-job.php:356
1465
  msgid "Please enter a valid application URL"
1466
  msgstr ""
1467
 
1468
- #: includes/forms/class-wp-job-manager-form-submit-job.php:366
1469
  msgid "Please enter a valid application email address or URL"
1470
  msgstr ""
1471
 
1472
- #: includes/forms/class-wp-job-manager-form-submit-job.php:516
1473
  msgid "Please enter a username."
1474
  msgstr ""
1475
 
1476
- #: includes/forms/class-wp-job-manager-form-submit-job.php:520
1477
  msgid "Please enter a password."
1478
  msgstr ""
1479
 
1480
- #: includes/forms/class-wp-job-manager-form-submit-job.php:524
1481
  msgid "Please enter your email address."
1482
  msgstr ""
1483
 
1484
- #: includes/forms/class-wp-job-manager-form-submit-job.php:530
1485
  msgid "Passwords must match."
1486
  msgstr ""
1487
 
1488
- #: includes/forms/class-wp-job-manager-form-submit-job.php:535
 
1489
  msgid "Invalid Password: %s"
1490
  msgstr ""
1491
 
1492
- #: includes/forms/class-wp-job-manager-form-submit-job.php:537
1493
  msgid "Password is not valid."
1494
  msgstr ""
1495
 
1496
- #: includes/forms/class-wp-job-manager-form-submit-job.php:558
1497
  msgid "You must be signed in to post a new listing."
1498
  msgstr ""
1499
 
1500
- #: includes/helper/class-wp-job-manager-helper.php:254
1501
  msgid "Manage License (Requires Attention)"
1502
  msgstr ""
1503
 
1504
- #: includes/helper/class-wp-job-manager-helper.php:257
1505
  msgid "Manage License"
1506
  msgstr ""
1507
 
1508
- #: includes/helper/class-wp-job-manager-helper.php:260
1509
  #: includes/helper/views/html-licences.php:69
1510
  msgid "Activate License"
1511
  msgstr ""
1512
 
1513
- #: includes/helper/class-wp-job-manager-helper.php:449
1514
  msgid ""
1515
  "Please enter a valid license key and email address in order to activate "
1516
  "this plugin's license."
1517
  msgstr ""
1518
 
1519
- #: includes/helper/class-wp-job-manager-helper.php:477
1520
  msgid "Connection failed to the License Key API server - possible server issue."
1521
  msgstr ""
1522
 
1523
- #: includes/helper/class-wp-job-manager-helper.php:485
1524
  msgid "Plugin license has been activated."
1525
  msgstr ""
1526
 
1527
- #: includes/helper/class-wp-job-manager-helper.php:487
1528
  msgid "An unknown error occurred while attempting to activate the license"
1529
  msgstr ""
1530
 
1531
- #: includes/helper/class-wp-job-manager-helper.php:499
1532
  msgid "license is not active."
1533
  msgstr ""
1534
 
1535
- #: includes/helper/class-wp-job-manager-helper.php:513
1536
  msgid "Plugin license has been deactivated."
1537
  msgstr ""
1538
 
@@ -1559,92 +1699,100 @@ msgstr ""
1559
  msgid "No plugins are activated that have licenses managed by WP Job Manager."
1560
  msgstr ""
1561
 
1562
- #: includes/rest-api/class-wp-job-manager-controllers-status.php:52
1563
  msgid "Not Found"
1564
  msgstr ""
1565
 
1566
- #: includes/rest-api/class-wp-job-manager-models-job-types-custom-fields.php:50
1567
  msgid "Invalid Employment Type"
1568
  msgstr ""
1569
 
1570
- #: includes/rest-api/class-wp-job-manager-models-settings.php:72
1571
  msgid "Invalid page ID provided"
1572
  msgstr ""
1573
 
1574
  #: includes/widgets/class-wp-job-manager-widget-featured-jobs.php:21
1575
- msgid "Display a list of featured listings on your site."
 
 
 
1576
  msgstr ""
1577
 
1578
  #: includes/widgets/class-wp-job-manager-widget-featured-jobs.php:23
1579
- #: includes/widgets/class-wp-job-manager-widget-featured-jobs.php:27
1580
- msgid "Featured %s"
1581
  msgstr ""
1582
 
1583
- #: includes/widgets/class-wp-job-manager-widget-featured-jobs.php:36
1584
- #: includes/widgets/class-wp-job-manager-widget-recent-jobs.php:46
1585
  msgid "Number of listings to show"
1586
  msgstr ""
1587
 
1588
- #: includes/widgets/class-wp-job-manager-widget-featured-jobs.php:41
1589
  msgid "Sort By"
1590
  msgstr ""
1591
 
1592
- #: includes/widgets/class-wp-job-manager-widget-featured-jobs.php:43
1593
  msgid "Date"
1594
  msgstr ""
1595
 
1596
- #: includes/widgets/class-wp-job-manager-widget-featured-jobs.php:45
1597
  msgid "Author"
1598
  msgstr ""
1599
 
1600
- #: includes/widgets/class-wp-job-manager-widget-featured-jobs.php:46
1601
  msgid "Random"
1602
  msgstr ""
1603
 
1604
- #: includes/widgets/class-wp-job-manager-widget-featured-jobs.php:52
1605
  msgid "Sort Direction"
1606
  msgstr ""
1607
 
1608
- #: includes/widgets/class-wp-job-manager-widget-featured-jobs.php:54
1609
  msgid "Ascending"
1610
  msgstr ""
1611
 
1612
- #: includes/widgets/class-wp-job-manager-widget-featured-jobs.php:55
1613
  msgid "Descending"
1614
  msgstr ""
1615
 
1616
  #: includes/widgets/class-wp-job-manager-widget-recent-jobs.php:21
 
 
 
 
 
 
 
1617
  msgid ""
1618
  "Display a list of recent listings on your site, optionally matching a "
1619
  "keyword and location."
1620
  msgstr ""
1621
 
1622
- #: includes/widgets/class-wp-job-manager-widget-recent-jobs.php:23
1623
- #: includes/widgets/class-wp-job-manager-widget-recent-jobs.php:27
1624
- msgid "Recent %s"
1625
  msgstr ""
1626
 
1627
- #: includes/widgets/class-wp-job-manager-widget-recent-jobs.php:33
1628
- msgid "Keyword"
1629
  msgstr ""
1630
 
1631
- #: lib/usage-tracking/class-usage-tracking-base.php:333
1632
  msgid "Every Two Weeks"
1633
  msgstr ""
1634
 
1635
- #: lib/usage-tracking/class-usage-tracking-base.php:475
1636
  msgid "Disable Usage Tracking"
1637
  msgstr ""
1638
 
1639
- #: lib/usage-tracking/class-usage-tracking-base.php:481
1640
  msgid "Usage data enabled. Thank you!"
1641
  msgstr ""
1642
 
1643
- #: lib/usage-tracking/class-usage-tracking-base.php:484
1644
  msgid "Disabled usage tracking."
1645
  msgstr ""
1646
 
1647
- #: lib/usage-tracking/class-usage-tracking-base.php:487
1648
  msgid "Something went wrong. Please try again later."
1649
  msgstr ""
1650
 
@@ -1725,12 +1873,12 @@ msgid "This listing has expired."
1725
  msgstr ""
1726
 
1727
  #: templates/emails/admin-expiring-job.php:30
1728
- #: templates/emails/employer-expiring-job.php:30
1729
  msgid "The following job listing is expiring today from <a href=\"%s\">%s</a>."
1730
  msgstr ""
1731
 
1732
  #: templates/emails/admin-expiring-job.php:32
1733
- #: templates/emails/employer-expiring-job.php:32
1734
  msgid "The following job listing is expiring soon from <a href=\"%s\">%s</a>."
1735
  msgstr ""
1736
 
@@ -1738,51 +1886,51 @@ msgstr ""
1738
  msgid "Visit <a href=\"%s\">WordPress admin</a> to manage the listing."
1739
  msgstr ""
1740
 
1741
- #: templates/emails/admin-new-job.php:24
1742
  msgid "A new job listing has been submitted to <a href=\"%s\">%s</a>."
1743
  msgstr ""
1744
 
1745
- #: templates/emails/admin-new-job.php:27
1746
  #: templates/emails/plain/admin-new-job.php:26
1747
  msgid "It has been published and is now available to the public."
1748
  msgstr ""
1749
 
1750
- #: templates/emails/admin-new-job.php:30
1751
  msgid ""
1752
  "It is awaiting approval by an administrator in <a href=\"%s\">WordPress "
1753
  "admin</a>."
1754
  msgstr ""
1755
 
1756
- #: templates/emails/admin-updated-job.php:24
1757
  msgid "A job listing has been updated on <a href=\"%s\">%s</a>."
1758
  msgstr ""
1759
 
1760
- #: templates/emails/admin-updated-job.php:27
1761
  #: templates/emails/plain/admin-updated-job.php:26
1762
  msgid "The changes have been published and are now available to the public."
1763
  msgstr ""
1764
 
1765
- #: templates/emails/admin-updated-job.php:30
1766
  msgid ""
1767
  "The job listing is not publicly available until the changes are approved by "
1768
  "an administrator in the site's <a href=\"%s\">WordPress admin</a>."
1769
  msgstr ""
1770
 
1771
- #: templates/emails/employer-expiring-job.php:34
1772
  msgid "Visit the <a href=\"%s\">job listing dashboard</a> to manage the listing."
1773
  msgstr ""
1774
 
1775
- #: templates/emails/plain/admin-expiring-job.php:29
1776
  #: templates/emails/plain/employer-expiring-job.php:29
1777
  msgid "The following job listing is expiring today from %s (%s)."
1778
  msgstr ""
1779
 
1780
- #: templates/emails/plain/admin-expiring-job.php:31
1781
  #: templates/emails/plain/employer-expiring-job.php:31
1782
  msgid "The following job listing is expiring soon from %s (%s)."
1783
  msgstr ""
1784
 
1785
- #: templates/emails/plain/admin-expiring-job.php:34
1786
  msgid "Visit WordPress admin (%s) to manage the listing."
1787
  msgstr ""
1788
 
@@ -1813,12 +1961,12 @@ msgid "Maximum file size: %s."
1813
  msgstr ""
1814
 
1815
  #: templates/form-fields/multiselect-field.php:20
1816
- #: wp-job-manager-functions.php:1043
1817
  msgid "No results match"
1818
  msgstr ""
1819
 
1820
  #: templates/form-fields/multiselect-field.php:20
1821
- #: wp-job-manager-functions.php:1044
1822
  msgid "Select Some Options"
1823
  msgstr ""
1824
 
@@ -1911,130 +2059,140 @@ msgstr ""
1911
  msgid "Company Details"
1912
  msgstr ""
1913
 
1914
- #: templates/job-submitted.php:22
1915
  msgid "%s listed successfully. To view your listing <a href=\"%s\">click here</a>."
1916
  msgstr ""
1917
 
1918
- #: templates/job-submitted.php:25
1919
  msgid "%s submitted successfully. Your listing will be visible once approved."
1920
  msgstr ""
1921
 
1922
- #: wp-job-manager-functions.php:435
1923
  msgid "Reset"
1924
  msgstr ""
1925
 
1926
- #: wp-job-manager-functions.php:439
1927
  msgid "RSS"
1928
  msgstr ""
1929
 
1930
- #: wp-job-manager-functions.php:539
1931
  msgid "Invalid email address."
1932
  msgstr ""
1933
 
1934
- #: wp-job-manager-functions.php:547
1935
  msgid "Your email address isn&#8217;t correct."
1936
  msgstr ""
1937
 
1938
- #: wp-job-manager-functions.php:551
1939
  msgid "This email is already registered, please choose another one."
1940
  msgstr ""
1941
 
1942
- #: wp-job-manager-functions.php:849
1943
  msgid "Full Time"
1944
  msgstr ""
1945
 
1946
- #: wp-job-manager-functions.php:850
1947
  msgid "Part Time"
1948
  msgstr ""
1949
 
1950
- #: wp-job-manager-functions.php:851
1951
  msgid "Contractor"
1952
  msgstr ""
1953
 
1954
- #: wp-job-manager-functions.php:852
1955
  msgid "Temporary"
1956
  msgstr ""
1957
 
1958
- #: wp-job-manager-functions.php:853
1959
  msgid "Intern"
1960
  msgstr ""
1961
 
1962
- #: wp-job-manager-functions.php:854
1963
  msgid "Volunteer"
1964
  msgstr ""
1965
 
1966
- #: wp-job-manager-functions.php:855
1967
  msgid "Per Diem"
1968
  msgstr ""
1969
 
1970
- #: wp-job-manager-functions.php:856
1971
  msgid "Other"
1972
  msgstr ""
1973
 
1974
- #: wp-job-manager-functions.php:923
1975
  msgid "Passwords must be at least 8 characters long."
1976
  msgstr ""
1977
 
1978
- #: wp-job-manager-functions.php:1042
1979
  msgid "Choose a category&hellip;"
1980
  msgstr ""
1981
 
1982
- #: wp-job-manager-functions.php:1259
 
1983
  msgid "Uploaded files need to be one of the following file types: %s"
1984
  msgstr ""
1985
 
1986
- #: wp-job-manager-template.php:146
1987
  msgid "Inactive"
1988
  msgstr ""
1989
 
1990
- #: wp-job-manager-template.php:238
1991
- msgid "Application via \"%s\" listing on %s"
 
 
1992
  msgstr ""
1993
 
1994
- #: wp-job-manager-template.php:677
1995
  msgid "Username"
1996
  msgstr ""
1997
 
1998
- #: wp-job-manager-template.php:685
1999
  msgid "Password"
2000
  msgstr ""
2001
 
2002
- #: wp-job-manager-template.php:695
2003
  msgid "Verify Password"
2004
  msgstr ""
2005
 
2006
- #: wp-job-manager-template.php:702
2007
  msgid "Your email"
2008
  msgstr ""
2009
 
2010
- #: wp-job-manager-template.php:729
2011
  msgid "Posted on "
2012
  msgstr ""
2013
 
2014
- #: wp-job-manager-template.php:731 wp-job-manager-template.php:751
 
 
2015
  msgid "Posted %s ago"
2016
  msgstr ""
2017
 
2018
- #: wp-job-manager-template.php:774
2019
  msgid "Anywhere"
2020
  msgstr ""
2021
 
2022
- #: wp-job-manager.php:301
 
 
 
 
 
 
 
 
 
2023
  msgid "Load previous listings"
2024
  msgstr ""
2025
 
2026
- #: wp-job-manager.php:364
2027
  msgid "Invalid file type. Accepted types:"
2028
  msgstr ""
2029
 
2030
- #: wp-job-manager.php:375
2031
  msgid "Are you sure you want to delete this listing?"
2032
  msgstr ""
2033
 
2034
- #. Plugin Name of the plugin/theme
2035
- msgid "WP Job Manager"
2036
- msgstr ""
2037
-
2038
  #. Author URI of the plugin/theme
2039
  msgid "https://wpjobmanager.com/"
2040
  msgstr ""
@@ -2049,80 +2207,80 @@ msgstr ""
2049
  msgid "Automattic"
2050
  msgstr ""
2051
 
2052
- #: includes/admin/class-wp-job-manager-admin.php:131
2053
- #: includes/forms/class-wp-job-manager-form-submit-job.php:401
2054
  #. translators: jQuery date format, see
2055
  #. http:api.jqueryui.com/datepicker/#utility-formatDate
2056
  msgctxt "Date format for jQuery datepicker."
2057
  msgid "yy-mm-dd"
2058
  msgstr ""
2059
 
2060
- #: includes/admin/class-wp-job-manager-permalink-settings.php:81
2061
- #: includes/class-wp-job-manager-post-types.php:641
2062
  msgctxt "Job permalink - resave permalinks after changing this"
2063
  msgid "job"
2064
  msgstr ""
2065
 
2066
- #: includes/admin/class-wp-job-manager-permalink-settings.php:90
2067
- #: includes/class-wp-job-manager-post-types.php:642
2068
  msgctxt "Job category slug - resave permalinks after changing this"
2069
  msgid "job-category"
2070
  msgstr ""
2071
 
2072
- #: includes/admin/class-wp-job-manager-permalink-settings.php:99
2073
- #: includes/class-wp-job-manager-post-types.php:643
2074
  msgctxt "Job type slug - resave permalinks after changing this"
2075
  msgid "job-type"
2076
  msgstr ""
2077
 
2078
- #: includes/admin/class-wp-job-manager-setup.php:252
2079
  msgctxt "Default page title (wizard)"
2080
  msgid "Post a Job"
2081
  msgstr ""
2082
 
2083
- #: includes/admin/class-wp-job-manager-setup.php:260
2084
  msgctxt "Default page title (wizard)"
2085
  msgid "Job Dashboard"
2086
  msgstr ""
2087
 
2088
- #: includes/admin/class-wp-job-manager-setup.php:268
2089
  msgctxt "Default page title (wizard)"
2090
  msgid "Jobs"
2091
  msgstr ""
2092
 
2093
- #: includes/class-wp-job-manager-post-types.php:200
2094
  msgctxt "Post type archive slug - resave permalinks after changing this"
2095
  msgid "jobs"
2096
  msgstr ""
2097
 
2098
- #: includes/class-wp-job-manager-post-types.php:260
2099
- #: wp-job-manager-functions.php:316
2100
  msgctxt "post status"
2101
  msgid "Expired"
2102
  msgstr ""
2103
 
2104
- #: includes/class-wp-job-manager-post-types.php:269
2105
- #: wp-job-manager-functions.php:317
2106
  msgctxt "post status"
2107
  msgid "Preview"
2108
  msgstr ""
2109
 
2110
- #: wp-job-manager-functions.php:315
2111
  msgctxt "post status"
2112
  msgid "Draft"
2113
  msgstr ""
2114
 
2115
- #: wp-job-manager-functions.php:318
2116
  msgctxt "post status"
2117
  msgid "Pending approval"
2118
  msgstr ""
2119
 
2120
- #: wp-job-manager-functions.php:319
2121
  msgctxt "post status"
2122
  msgid "Pending payment"
2123
  msgstr ""
2124
 
2125
- #: wp-job-manager-functions.php:320
2126
  msgctxt "post status"
2127
  msgid "Active"
2128
  msgstr ""
2
  # This file is distributed under the GPL2+.
3
  msgid ""
4
  msgstr ""
5
+ "Project-Id-Version: WP Job Manager 1.31.1\n"
6
  "Report-Msgid-Bugs-To: https://github.com/Automattic/WP-Job-Manager/issues\n"
7
+ "POT-Creation-Date: 2018-07-11 16:27:40+00:00\n"
8
  "MIME-Version: 1.0\n"
9
  "Content-Type: text/plain; charset=utf-8\n"
10
  "Content-Transfer-Encoding: 8bit\n"
11
  "PO-Revision-Date: 2018-MO-DA HO:MI+ZONE\n"
12
  "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
13
  "Language-Team: LANGUAGE <EMAIL@ADDRESS>\n"
14
+ "X-Generator: grunt-wp-i18n1.0.2\n"
15
 
16
+ #: includes/3rd-party/wpml.php:84
17
  msgid "Page Not Set"
18
  msgstr ""
19
 
20
+ #: includes/3rd-party/wpml.php:98
21
+ #. translators: Placeholder (%s) is the URL to edit the primary language in
22
+ #. WPML.
23
  msgid "<a href=\"%s\">Switch to primary language</a> to edit this setting."
24
  msgstr ""
25
 
26
+ #: includes/abstracts/abstract-wp-job-manager-form.php:319
27
+ #: includes/abstracts/abstract-wp-job-manager-form.php:334
28
+ #. translators: Placeholder is for the label of the reCAPTCHA field.
29
+ #. translators: %s is the name of the form validation that failed.
30
  msgid "\"%s\" check failed. Please try again."
31
  msgstr ""
32
 
33
+ #: includes/admin/class-wp-job-manager-addons.php:124
34
+ #: includes/admin/class-wp-job-manager-admin.php:155
35
  #: includes/admin/views/html-admin-page-addons.php:2
36
  msgid "WP Job Manager Add-ons"
37
  msgstr ""
38
 
39
+ #: includes/admin/class-wp-job-manager-addons.php:131
40
  #: includes/helper/views/html-licences.php:6
41
  msgid "Licenses"
42
  msgstr ""
43
 
44
+ #: includes/admin/class-wp-job-manager-admin.php:89
45
+ #. translators: %s is the URL for the page where users can go to update
46
+ #. WordPress.
47
  msgid ""
48
  "<strong>WP Job Manager</strong> requires a more recent version of "
49
  "WordPress. <a href=\"%s\">Please update WordPresse</a> to avoid issues."
50
  msgstr ""
51
 
52
+ #: includes/admin/class-wp-job-manager-admin.php:101
53
+ #. translators: Placeholder (%s) is the URL where users can go to update
54
+ #. WordPress.
55
  msgid "<a href=\"%s\" style=\"color: red\">WordPress Update Required</a>"
56
  msgstr ""
57
 
58
+ #: includes/admin/class-wp-job-manager-admin.php:152
59
  msgid "Settings"
60
  msgstr ""
61
 
62
+ #: includes/admin/class-wp-job-manager-admin.php:155
63
  msgid "Add-ons"
64
  msgstr ""
65
 
66
+ #: includes/admin/class-wp-job-manager-cpt.php:77
67
+ #. translators: Placeholder (%s) is the plural name of the job listings post
68
+ #. type.
69
  msgid "Approve %s"
70
  msgstr ""
71
 
72
+ #: includes/admin/class-wp-job-manager-cpt.php:79
73
+ #. translators: Placeholder (%s) is the plural name of the job listings post
74
+ #. type.
75
  msgid "%s approved"
76
  msgstr ""
77
 
78
+ #: includes/admin/class-wp-job-manager-cpt.php:84
79
+ #. translators: Placeholder (%s) is the plural name of the job listings post
80
+ #. type.
81
  msgid "Expire %s"
82
  msgstr ""
83
 
84
+ #: includes/admin/class-wp-job-manager-cpt.php:86
85
+ #. translators: Placeholder (%s) is the plural name of the job listings post
86
+ #. type.
87
  msgid "%s expired"
88
  msgstr ""
89
 
90
+ #: includes/admin/class-wp-job-manager-cpt.php:91
91
+ #. translators: Placeholder (%s) is the plural name of the job listings post
92
+ #. type.
93
  msgid "Mark %s Filled"
94
  msgstr ""
95
 
96
+ #: includes/admin/class-wp-job-manager-cpt.php:93
97
+ #. translators: Placeholder (%s) is the plural name of the job listings post
98
+ #. type.
99
  msgid "%s marked as filled"
100
  msgstr ""
101
 
102
+ #: includes/admin/class-wp-job-manager-cpt.php:98
103
+ #. translators: Placeholder (%s) is the plural name of the job listings post
104
+ #. type.
105
  msgid "Mark %s Not Filled"
106
  msgstr ""
107
 
108
+ #: includes/admin/class-wp-job-manager-cpt.php:100
109
+ #. translators: Placeholder (%s) is the plural name of the job listings post
110
+ #. type.
111
  msgid "%s marked as not filled"
112
  msgstr ""
113
 
114
+ #: includes/admin/class-wp-job-manager-cpt.php:310
115
  msgid "Select category"
116
  msgstr ""
117
 
118
+ #: includes/admin/class-wp-job-manager-cpt.php:335
119
  msgid "Select Filled"
120
  msgstr ""
121
 
122
+ #: includes/admin/class-wp-job-manager-cpt.php:339
123
  msgid "Filled"
124
  msgstr ""
125
 
126
+ #: includes/admin/class-wp-job-manager-cpt.php:343
127
  msgid "Not Filled"
128
  msgstr ""
129
 
130
+ #: includes/admin/class-wp-job-manager-cpt.php:354
131
  msgid "Select Featured"
132
  msgstr ""
133
 
134
+ #: includes/admin/class-wp-job-manager-cpt.php:358
135
  msgid "Featured"
136
  msgstr ""
137
 
138
+ #: includes/admin/class-wp-job-manager-cpt.php:362
139
  msgid "Not Featured"
140
  msgstr ""
141
 
142
+ #: includes/admin/class-wp-job-manager-cpt.php:407
143
+ #: includes/admin/class-wp-job-manager-cpt.php:464
144
  msgid "Position"
145
  msgstr ""
146
 
147
+ #: includes/admin/class-wp-job-manager-cpt.php:424
148
+ #. translators: %1$s is the singular name of the job listing post type; %2$s is
149
+ #. the URL to view the listing.
150
+ msgid "%1$s updated. <a href=\"%2$s\">View</a>"
151
  msgstr ""
152
 
153
+ #: includes/admin/class-wp-job-manager-cpt.php:425
154
  msgid "Custom field updated."
155
  msgstr ""
156
 
157
+ #: includes/admin/class-wp-job-manager-cpt.php:426
158
  msgid "Custom field deleted."
159
  msgstr ""
160
 
161
+ #: includes/admin/class-wp-job-manager-cpt.php:428
162
+ #. translators: %s is the singular name of the job listing post type.
163
  msgid "%s updated."
164
  msgstr ""
165
 
166
+ #: includes/admin/class-wp-job-manager-cpt.php:430
167
+ #. translators: %1$s is the singular name of the job listing post type; %2$s is
168
+ #. the revision number.
169
+ msgid "%1$s restored to revision from %2$s"
170
  msgstr ""
171
 
172
+ #: includes/admin/class-wp-job-manager-cpt.php:432
173
+ #. translators: %1$s is the singular name of the job listing post type; %2$s is
174
+ #. the URL to view the listing.
175
+ msgid "%1$s published. <a href=\"%2$s\">View</a>"
176
  msgstr ""
177
 
178
+ #: includes/admin/class-wp-job-manager-cpt.php:434
179
+ #. translators: %1$s is the singular name of the job listing post type; %2$s is
180
+ #. the URL to view the listing.
181
  msgid "%s saved."
182
  msgstr ""
183
 
184
+ #: includes/admin/class-wp-job-manager-cpt.php:436
185
+ #. translators: %1$s is the singular name of the job listing post type; %2$s is
186
+ #. the URL to preview the listing.
187
+ msgid "%1$s submitted. <a target=\"_blank\" href=\"%2$s\">Preview</a>"
188
  msgstr ""
189
 
190
+ #: includes/admin/class-wp-job-manager-cpt.php:439
191
+ #. translators: %1$s is the singular name of the post type; %2$s is the date
192
+ #. the post will be published; %3$s is the URL to preview the listing.
193
  msgid ""
194
+ "%1$s scheduled for: <strong>%2$s</strong>. <a target=\"_blank\" "
195
+ "href=\"%3$s\">Preview</a>"
196
  msgstr ""
197
 
198
+ #: includes/admin/class-wp-job-manager-cpt.php:445
199
+ #. translators: %1$s is the singular name of the job listing post type; %2$s is
200
+ #. the URL to view the listing.
201
+ msgid "%1$s draft updated. <a target=\"_blank\" href=\"%2$s\">Preview</a>"
202
  msgstr ""
203
 
204
+ #: includes/admin/class-wp-job-manager-cpt.php:465
205
  msgid "Type"
206
  msgstr ""
207
 
208
+ #: includes/admin/class-wp-job-manager-cpt.php:466
209
+ #: includes/admin/class-wp-job-manager-writepanels.php:57
210
+ #: includes/class-wp-job-manager-email-notifications.php:234
211
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:183
212
+ #: includes/widgets/class-wp-job-manager-widget-recent-jobs.php:40
213
  #: templates/job-filters.php:35 templates/job-filters.php:36
214
  msgid "Location"
215
  msgstr ""
216
 
217
+ #: includes/admin/class-wp-job-manager-cpt.php:467
218
  msgid "Status"
219
  msgstr ""
220
 
221
+ #: includes/admin/class-wp-job-manager-cpt.php:468
222
  msgid "Posted"
223
  msgstr ""
224
 
225
+ #: includes/admin/class-wp-job-manager-cpt.php:469
226
  msgid "Expires"
227
  msgstr ""
228
 
229
+ #: includes/admin/class-wp-job-manager-cpt.php:470
230
+ #: includes/admin/class-wp-job-manager-settings.php:157
231
  msgid "Categories"
232
  msgstr ""
233
 
234
+ #: includes/admin/class-wp-job-manager-cpt.php:471
235
  msgid "Featured?"
236
  msgstr ""
237
 
238
+ #: includes/admin/class-wp-job-manager-cpt.php:472
239
+ #: includes/class-wp-job-manager-shortcodes.php:247
240
  msgid "Filled?"
241
  msgstr ""
242
 
243
+ #: includes/admin/class-wp-job-manager-cpt.php:473
244
  msgid "Actions"
245
  msgstr ""
246
 
247
+ #: includes/admin/class-wp-job-manager-cpt.php:538
248
+ #. translators: %d is the post ID for the job listing.
249
  msgid "ID: %d"
250
  msgstr ""
251
 
252
+ #: includes/admin/class-wp-job-manager-cpt.php:582
253
+ #. translators: %s placeholder is the username of the user.
254
  msgid "by a guest"
255
  msgstr ""
256
 
257
+ #: includes/admin/class-wp-job-manager-cpt.php:582
258
  msgid "by %s"
259
  msgstr ""
260
 
261
+ #: includes/admin/class-wp-job-manager-cpt.php:601
262
  msgid "Approve"
263
  msgstr ""
264
 
265
+ #: includes/admin/class-wp-job-manager-cpt.php:609
266
+ #: includes/admin/class-wp-job-manager-writepanels.php:282
267
+ #: includes/admin/class-wp-job-manager-writepanels.php:287
268
+ #: includes/admin/class-wp-job-manager-writepanels.php:292
269
  msgid "View"
270
  msgstr ""
271
 
272
+ #: includes/admin/class-wp-job-manager-cpt.php:616
273
+ #: includes/class-wp-job-manager-post-types.php:251
274
  #: templates/job-dashboard.php:52 templates/job-dashboard.php:70
275
  msgid "Edit"
276
  msgstr ""
277
 
278
+ #: includes/admin/class-wp-job-manager-cpt.php:623
279
  #: templates/job-dashboard.php:75
280
  msgid "Delete"
281
  msgstr ""
282
 
283
+ #: includes/admin/class-wp-job-manager-permalink-settings.php:60
284
  msgid "Job base"
285
  msgstr ""
286
 
287
+ #: includes/admin/class-wp-job-manager-permalink-settings.php:67
288
  msgid "Job category base"
289
  msgstr ""
290
 
291
+ #: includes/admin/class-wp-job-manager-permalink-settings.php:74
292
  msgid "Job type base"
293
  msgstr ""
294
 
295
+ #: includes/admin/class-wp-job-manager-settings.php:84
296
  msgid "General"
297
  msgstr ""
298
 
299
+ #: includes/admin/class-wp-job-manager-settings.php:89
300
  msgid "Date Format"
301
  msgstr ""
302
 
303
+ #: includes/admin/class-wp-job-manager-settings.php:90
304
  msgid ""
305
  "Choose how you want the published date for jobs to be displayed on the "
306
  "front-end."
307
  msgstr ""
308
 
309
+ #: includes/admin/class-wp-job-manager-settings.php:93
310
  msgid "Relative to the current date (e.g., 1 day, 1 week, 1 month ago)"
311
  msgstr ""
312
 
313
+ #: includes/admin/class-wp-job-manager-settings.php:94
314
  msgid "Default date format as defined in Settings"
315
  msgstr ""
316
 
317
+ #: includes/admin/class-wp-job-manager-settings.php:100
318
  msgid "Google Maps API Key"
319
  msgstr ""
320
 
321
+ #: includes/admin/class-wp-job-manager-settings.php:102
322
+ #. translators: Placeholder %s is URL to set up a Google Maps API key.
323
  msgid ""
324
  "Google requires an API key to retrieve location information for job "
325
  "listings. Acquire an API key from the <a href=\"%s\">Google Maps API "
326
  "developer site</a>."
327
  msgstr ""
328
 
329
+ #: includes/admin/class-wp-job-manager-settings.php:108
330
  msgid "Delete Data On Uninstall"
331
  msgstr ""
332
 
333
+ #: includes/admin/class-wp-job-manager-settings.php:109
334
  msgid ""
335
  "Delete WP Job Manager data when the plugin is deleted. Once removed, this "
336
  "data cannot be restored."
337
  msgstr ""
338
 
339
+ #: includes/admin/class-wp-job-manager-settings.php:117
340
+ #: includes/class-wp-job-manager-post-types.php:245
341
+ #: includes/class-wp-job-manager-post-types.php:342
342
  msgid "Job Listings"
343
  msgstr ""
344
 
345
+ #: includes/admin/class-wp-job-manager-settings.php:123
346
  msgid "Listings Per Page"
347
  msgstr ""
348
 
349
+ #: includes/admin/class-wp-job-manager-settings.php:124
350
  msgid "Number of job listings to display per page."
351
  msgstr ""
352
 
353
+ #: includes/admin/class-wp-job-manager-settings.php:130
354
  msgid "Filled Positions"
355
  msgstr ""
356
 
357
+ #: includes/admin/class-wp-job-manager-settings.php:131
358
  msgid "Hide filled positions"
359
  msgstr ""
360
 
361
+ #: includes/admin/class-wp-job-manager-settings.php:132
362
  msgid "Filled positions will not display in your archives."
363
  msgstr ""
364
 
365
+ #: includes/admin/class-wp-job-manager-settings.php:139
366
  msgid "Hide Expired Listings"
367
  msgstr ""
368
 
369
+ #: includes/admin/class-wp-job-manager-settings.php:140
370
  msgid "Hide expired listings in job archives/search"
371
  msgstr ""
372
 
373
+ #: includes/admin/class-wp-job-manager-settings.php:141
374
  msgid "Expired job listings will not be searchable."
375
  msgstr ""
376
 
377
+ #: includes/admin/class-wp-job-manager-settings.php:148
378
  msgid "Hide Expired Listings Content"
379
  msgstr ""
380
 
381
+ #: includes/admin/class-wp-job-manager-settings.php:149
382
  msgid "Hide content in expired single job listings"
383
  msgstr ""
384
 
385
+ #: includes/admin/class-wp-job-manager-settings.php:150
386
  msgid ""
387
  "Your site will display the titles of expired listings, but not the content "
388
  "of the listings. Otherwise, expired listings display their full content "
389
  "minus the application area."
390
  msgstr ""
391
 
392
+ #: includes/admin/class-wp-job-manager-settings.php:158
393
  msgid "Enable listing categories"
394
  msgstr ""
395
 
396
+ #: includes/admin/class-wp-job-manager-settings.php:159
397
  msgid ""
398
  "This lets users select from a list of categories when submitting a job. "
399
  "Note: an admin has to create categories before site users can select them."
400
  msgstr ""
401
 
402
+ #: includes/admin/class-wp-job-manager-settings.php:166
403
  msgid "Multi-select Categories"
404
  msgstr ""
405
 
406
+ #: includes/admin/class-wp-job-manager-settings.php:167
407
  msgid "Default to category multiselect"
408
  msgstr ""
409
 
410
+ #: includes/admin/class-wp-job-manager-settings.php:168
411
  msgid ""
412
  "The category selection box will default to allowing multiple selections on "
413
  "the [jobs] shortcode. Without this, users will only be able to select a "
414
  "single category when submitting jobs."
415
  msgstr ""
416
 
417
+ #: includes/admin/class-wp-job-manager-settings.php:175
418
  msgid "Category Filter Type"
419
  msgstr ""
420
 
421
+ #: includes/admin/class-wp-job-manager-settings.php:176
422
  msgid ""
423
  "Determines the logic used to display jobs when selecting multiple "
424
  "categories."
425
  msgstr ""
426
 
427
+ #: includes/admin/class-wp-job-manager-settings.php:179
428
  msgid "Jobs will be shown if within ANY selected category"
429
  msgstr ""
430
 
431
+ #: includes/admin/class-wp-job-manager-settings.php:180
432
  msgid "Jobs will be shown if within ALL selected categories"
433
  msgstr ""
434
 
435
+ #: includes/admin/class-wp-job-manager-settings.php:186
436
  msgid "Types"
437
  msgstr ""
438
 
439
+ #: includes/admin/class-wp-job-manager-settings.php:187
440
  msgid "Enable listing types"
441
  msgstr ""
442
 
443
+ #: includes/admin/class-wp-job-manager-settings.php:188
444
  msgid ""
445
  "This lets users select from a list of types when submitting a job. Note: an "
446
  "admin has to create types before site users can select them."
447
  msgstr ""
448
 
449
+ #: includes/admin/class-wp-job-manager-settings.php:195
450
  msgid "Multi-select Listing Types"
451
  msgstr ""
452
 
453
+ #: includes/admin/class-wp-job-manager-settings.php:196
454
  msgid "Allow multiple types for listings"
455
  msgstr ""
456
 
457
+ #: includes/admin/class-wp-job-manager-settings.php:197
458
  msgid ""
459
  "This allows users to select more than one type when submitting a job. The "
460
  "metabox on the post editor and the selection box on the front-end job "
461
  "submission form will both reflect this."
462
  msgstr ""
463
 
464
+ #: includes/admin/class-wp-job-manager-settings.php:204
465
  msgid "Job Submission"
466
  msgstr ""
467
 
468
+ #: includes/admin/class-wp-job-manager-settings.php:209
469
  msgid "Account Required"
470
  msgstr ""
471
 
472
+ #: includes/admin/class-wp-job-manager-settings.php:210
473
  msgid "Require an account to submit listings"
474
  msgstr ""
475
 
476
+ #: includes/admin/class-wp-job-manager-settings.php:211
477
  msgid "Limits job listing submissions to registered, logged-in users."
478
  msgstr ""
479
 
480
+ #: includes/admin/class-wp-job-manager-settings.php:218
481
  msgid "Account Creation"
482
  msgstr ""
483
 
484
+ #: includes/admin/class-wp-job-manager-settings.php:219
485
  msgid "Enable account creation during submission"
486
  msgstr ""
487
 
488
+ #: includes/admin/class-wp-job-manager-settings.php:220
489
  msgid ""
490
  "Includes account creation on the listing submission form, to allow "
491
  "non-registered users to create an account and submit a job listing "
492
  "simultaneously."
493
  msgstr ""
494
 
495
+ #: includes/admin/class-wp-job-manager-settings.php:227
496
  msgid "Account Username"
497
  msgstr ""
498
 
499
+ #: includes/admin/class-wp-job-manager-settings.php:228
500
  msgid "Generate usernames from email addresses"
501
  msgstr ""
502
 
503
+ #: includes/admin/class-wp-job-manager-settings.php:229
504
  msgid ""
505
  "Automatically generates usernames for new accounts from the registrant's "
506
  "email address. If this is not enabled, a \"username\" field will display "
507
  "instead."
508
  msgstr ""
509
 
510
+ #: includes/admin/class-wp-job-manager-settings.php:236
511
  msgid "Account Password"
512
  msgstr ""
513
 
514
+ #: includes/admin/class-wp-job-manager-settings.php:237
515
  msgid "Email new users a link to set a password"
516
  msgstr ""
517
 
518
+ #: includes/admin/class-wp-job-manager-settings.php:238
519
  msgid ""
520
  "Sends an email to the user with their username and a link to set their "
521
  "password. If this is not enabled, a \"password\" field will display "
522
  "instead, and their email address won't be verified."
523
  msgstr ""
524
 
525
+ #: includes/admin/class-wp-job-manager-settings.php:245
526
  msgid "Account Role"
527
  msgstr ""
528
 
529
+ #: includes/admin/class-wp-job-manager-settings.php:246
530
  msgid ""
531
  "Any new accounts created during submission will have this role. If you "
532
  "haven't enabled account creation during submission in the options above, "
533
  "your own method of assigning roles will apply."
534
  msgstr ""
535
 
536
+ #: includes/admin/class-wp-job-manager-settings.php:253
537
  msgid "Moderate New Listings"
538
  msgstr ""
539
 
540
+ #: includes/admin/class-wp-job-manager-settings.php:254
541
  msgid "Require admin approval of all new listing submissions"
542
  msgstr ""
543
 
544
+ #: includes/admin/class-wp-job-manager-settings.php:255
545
  msgid ""
546
  "Sets all new submissions to \"pending.\" They will not appear on your site "
547
  "until an admin approves them."
548
  msgstr ""
549
 
550
+ #: includes/admin/class-wp-job-manager-settings.php:262
551
  msgid "Allow Pending Edits"
552
  msgstr ""
553
 
554
+ #: includes/admin/class-wp-job-manager-settings.php:263
555
  msgid "Allow editing of pending listings"
556
  msgstr ""
557
 
558
+ #: includes/admin/class-wp-job-manager-settings.php:264
559
  msgid ""
560
  "Users can continue to edit pending listings until they are approved by an "
561
  "admin."
562
  msgstr ""
563
 
564
+ #: includes/admin/class-wp-job-manager-settings.php:271
565
  msgid "Allow Published Edits"
566
  msgstr ""
567
 
568
+ #: includes/admin/class-wp-job-manager-settings.php:272
569
  msgid "Allow editing of published listings"
570
  msgstr ""
571
 
572
+ #: includes/admin/class-wp-job-manager-settings.php:273
573
  msgid ""
574
  "Choose whether published job listings can be edited and if edits require "
575
  "admin approval. When moderation is required, the original job listings will "
576
  "be unpublished while edits await admin approval."
577
  msgstr ""
578
 
579
+ #: includes/admin/class-wp-job-manager-settings.php:276
580
  msgid "Users cannot edit"
581
  msgstr ""
582
 
583
+ #: includes/admin/class-wp-job-manager-settings.php:277
584
  msgid "Users can edit without admin approval"
585
  msgstr ""
586
 
587
+ #: includes/admin/class-wp-job-manager-settings.php:278
588
  msgid "Users can edit, but edits require admin approval"
589
  msgstr ""
590
 
591
+ #: includes/admin/class-wp-job-manager-settings.php:285
592
  msgid "Listing Duration"
593
  msgstr ""
594
 
595
+ #: includes/admin/class-wp-job-manager-settings.php:286
596
  msgid ""
597
  "Listings will display for the set number of days, then expire. Leave this "
598
  "field blank if you don't want listings to have an expiration date."
599
  msgstr ""
600
 
601
+ #: includes/admin/class-wp-job-manager-settings.php:292
602
  msgid "Application Method"
603
  msgstr ""
604
 
605
+ #: includes/admin/class-wp-job-manager-settings.php:293
606
  msgid ""
607
  "Choose the application method job listers will need to provide. Specify URL "
608
  "or email address only, or allow listers to choose which they prefer."
609
  msgstr ""
610
 
611
+ #: includes/admin/class-wp-job-manager-settings.php:296
612
  msgid "Email address or website URL"
613
  msgstr ""
614
 
615
+ #: includes/admin/class-wp-job-manager-settings.php:297
616
  msgid "Email addresses only"
617
  msgstr ""
618
 
619
+ #: includes/admin/class-wp-job-manager-settings.php:298
620
  msgid "Website URLs only"
621
  msgstr ""
622
 
623
+ #: includes/admin/class-wp-job-manager-settings.php:304
624
  msgid "reCAPTCHA"
625
  msgstr ""
626
 
627
+ #: includes/admin/class-wp-job-manager-settings.php:308
628
  msgid "Are you human?"
629
  msgstr ""
630
 
631
+ #: includes/admin/class-wp-job-manager-settings.php:310
632
  msgid "Field Label"
633
  msgstr ""
634
 
635
+ #: includes/admin/class-wp-job-manager-settings.php:311
636
  msgid "The label used for the reCAPTCHA field on forms."
637
  msgstr ""
638
 
639
+ #: includes/admin/class-wp-job-manager-settings.php:318
640
  msgid "Site Key"
641
  msgstr ""
642
 
643
+ #: includes/admin/class-wp-job-manager-settings.php:320
644
+ #. translators: Placeholder %s is URL to set up Google reCAPTCHA API key.
645
  msgid ""
646
  "You can retrieve your site key from <a href=\"%s\">Google's reCAPTCHA admin "
647
  "dashboard</a>."
648
  msgstr ""
649
 
650
+ #: includes/admin/class-wp-job-manager-settings.php:327
651
  msgid "Secret Key"
652
  msgstr ""
653
 
654
+ #: includes/admin/class-wp-job-manager-settings.php:329
655
+ #. translators: Placeholder %s is URL to set up Google reCAPTCHA API key.
656
  msgid ""
657
  "You can retrieve your secret key from <a href=\"%s\">Google's reCAPTCHA "
658
  "admin dashboard</a>."
659
  msgstr ""
660
 
661
+ #: includes/admin/class-wp-job-manager-settings.php:335
662
  msgid "Job Submission Form"
663
  msgstr ""
664
 
665
+ #: includes/admin/class-wp-job-manager-settings.php:336
666
  msgid "Display a reCAPTCHA field on job submission form."
667
  msgstr ""
668
 
669
+ #: includes/admin/class-wp-job-manager-settings.php:337
670
  msgid ""
671
  "This will help prevent bots from submitting job listings. You must have "
672
  "entered a valid site key and secret key above."
673
  msgstr ""
674
 
675
+ #: includes/admin/class-wp-job-manager-settings.php:344
676
  msgid "Pages"
677
  msgstr ""
678
 
679
+ #: includes/admin/class-wp-job-manager-settings.php:349
680
  msgid "Submit Job Form Page"
681
  msgstr ""
682
 
683
+ #: includes/admin/class-wp-job-manager-settings.php:350
684
  msgid ""
685
  "Select the page where you've used the [submit_job_form] shortcode. This "
686
  "lets the plugin know the location of the form."
687
  msgstr ""
688
 
689
+ #: includes/admin/class-wp-job-manager-settings.php:356
690
  msgid "Job Dashboard Page"
691
  msgstr ""
692
 
693
+ #: includes/admin/class-wp-job-manager-settings.php:357
694
  msgid ""
695
  "Select the page where you've used the [job_dashboard] shortcode. This lets "
696
  "the plugin know the location of the dashboard."
697
  msgstr ""
698
 
699
+ #: includes/admin/class-wp-job-manager-settings.php:363
700
  msgid "Job Listings Page"
701
  msgstr ""
702
 
703
+ #: includes/admin/class-wp-job-manager-settings.php:364
704
  msgid ""
705
  "Select the page where you've used the [jobs] shortcode. This lets the "
706
  "plugin know the location of the job listings page."
707
  msgstr ""
708
 
709
+ #: includes/admin/class-wp-job-manager-settings.php:411
710
  msgid "Settings successfully saved"
711
  msgstr ""
712
 
713
+ #: includes/admin/class-wp-job-manager-settings.php:436
714
  msgid "Save Changes"
715
  msgstr ""
716
 
717
+ #: includes/admin/class-wp-job-manager-settings.php:644
718
  msgid "--no page--"
719
  msgstr ""
720
 
721
+ #: includes/admin/class-wp-job-manager-settings.php:649
722
  msgid "Select a page&hellip;"
723
  msgstr ""
724
 
725
+ #: includes/admin/class-wp-job-manager-setup.php:52
726
  msgid "Setup"
727
  msgstr ""
728
 
729
+ #: includes/admin/class-wp-job-manager-setup.php:205
730
  msgid "WP Job Manager Setup"
731
  msgstr ""
732
 
733
+ #: includes/admin/class-wp-job-manager-setup.php:212
734
  msgid "1. Introduction"
735
  msgstr ""
736
 
737
+ #: includes/admin/class-wp-job-manager-setup.php:213
738
  msgid "2. Page Setup"
739
  msgstr ""
740
 
741
+ #: includes/admin/class-wp-job-manager-setup.php:214
742
  msgid "3. Done"
743
  msgstr ""
744
 
745
+ #: includes/admin/class-wp-job-manager-setup.php:219
746
  msgid "Welcome to the Setup Wizard!"
747
  msgstr ""
748
 
749
+ #: includes/admin/class-wp-job-manager-setup.php:221
750
  msgid ""
751
  "Thanks for installing <em>WP Job Manager</em>! Let's get your site ready to "
752
  "accept job listings."
753
  msgstr ""
754
 
755
+ #: includes/admin/class-wp-job-manager-setup.php:222
756
  msgid ""
757
  "This setup wizard will walk you through the process of creating pages for "
758
  "job submissions, management, and listings."
759
  msgstr ""
760
 
761
+ #: includes/admin/class-wp-job-manager-setup.php:226
762
+ #. translators: Placeholder %s is the path to WPJM documentation site.
763
  msgid ""
764
+ "If you'd prefer to skip this and set up your pages manually, our <a "
765
+ "href=\"%s\">documentation</a> will walk you through each step."
766
  msgstr ""
767
 
768
+ #: includes/admin/class-wp-job-manager-setup.php:236
769
  msgid "Start setup"
770
  msgstr ""
771
 
772
+ #: includes/admin/class-wp-job-manager-setup.php:237
773
  msgid "Skip setup. I will set up the plugin manually."
774
  msgstr ""
775
 
776
+ #: includes/admin/class-wp-job-manager-setup.php:244
777
  msgid "Page Setup"
778
  msgstr ""
779
 
780
+ #: includes/admin/class-wp-job-manager-setup.php:246
781
  msgid ""
782
  "With WP Job Manager, employers and applicants can post, manage, and browse "
783
  "job listings right on your website. Tell us which of these common pages "
784
  "you'd like your site to have and we'll create and configure them for you."
785
  msgstr ""
786
 
787
+ #: includes/admin/class-wp-job-manager-setup.php:251
788
+ #. translators: %1$s is URL to WordPress core shortcode documentation. %2$s is
789
+ #. URL to WPJM specific shortcode reference.
790
  msgid ""
791
+ "(These pages are created using <a href=\"%1$s\" title=\"What is a "
792
+ "shortcode?\" target=\"_blank\" class=\"help-page-link\">shortcodes</a>, \n"
793
+ "\t\t\t\t\t\t\t\twhich we take care of in this step. If you'd like to build "
794
+ "these pages yourself or want to add one of these options to an existing \n"
795
+ "\t\t\t\t\t\t\t\tpage on your site, you can skip this step and take a look "
796
+ "at <a href=\"%2$s\" target=\"_blank\" class=\"help-page-link\">shortcode "
797
+ "documentation</a> for detailed instructions.)"
798
  msgstr ""
799
 
800
+ #: includes/admin/class-wp-job-manager-setup.php:266
801
  msgid "Page Title"
802
  msgstr ""
803
 
804
+ #: includes/admin/class-wp-job-manager-setup.php:267
805
  msgid "Page Description"
806
  msgstr ""
807
 
808
+ #: includes/admin/class-wp-job-manager-setup.php:268
809
  msgid "Content Shortcode"
810
  msgstr ""
811
 
812
+ #: includes/admin/class-wp-job-manager-setup.php:276
813
  msgid ""
814
  "Creates a page that allows employers to post new jobs directly from a page "
815
  "on your website, instead of requiring them to log in to an admin area. If "
817
  "the admin dashboard only -- you can uncheck this setting."
818
  msgstr ""
819
 
820
+ #: includes/admin/class-wp-job-manager-setup.php:284
821
  msgid ""
822
  "Creates a page that allows employers to manage their job listings directly "
823
  "from a page on your website, instead of requiring them to log in to an "
825
  "only, you can uncheck this setting."
826
  msgstr ""
827
 
828
+ #: includes/admin/class-wp-job-manager-setup.php:291
829
  msgid "Creates a page where visitors can browse, search, and filter job listings."
830
  msgstr ""
831
 
832
+ #: includes/admin/class-wp-job-manager-setup.php:299
833
  msgid "Skip this step"
834
  msgstr ""
835
 
836
+ #: includes/admin/class-wp-job-manager-setup.php:309
837
  msgid "You're ready to start using WP Job Manager!"
838
  msgstr ""
839
 
840
+ #: includes/admin/class-wp-job-manager-setup.php:311
841
  msgid "Wondering what to do now? Here are some of the most common next steps:"
842
  msgstr ""
843
 
844
+ #: includes/admin/class-wp-job-manager-setup.php:314
845
  msgid "Tweak your settings"
846
  msgstr ""
847
 
848
+ #: includes/admin/class-wp-job-manager-setup.php:315
849
  msgid "Add a job using the admin dashboard"
850
  msgstr ""
851
 
852
+ #: includes/admin/class-wp-job-manager-setup.php:320
853
  msgid "View submitted job listings"
854
  msgstr ""
855
 
856
+ #: includes/admin/class-wp-job-manager-setup.php:322
857
  msgid "Add job listings to a page using the [jobs] shortcode"
858
  msgstr ""
859
 
860
+ #: includes/admin/class-wp-job-manager-setup.php:329
861
  msgid "Add a job via the front-end"
862
  msgstr ""
863
 
864
+ #: includes/admin/class-wp-job-manager-setup.php:331
865
  msgid "Learn to use the front-end job submission board"
866
  msgstr ""
867
 
868
+ #: includes/admin/class-wp-job-manager-setup.php:338
869
  msgid "View the job dashboard"
870
  msgstr ""
871
 
872
+ #: includes/admin/class-wp-job-manager-setup.php:340
873
  msgid "Learn to use the front-end job dashboard"
874
  msgstr ""
875
 
876
+ #: includes/admin/class-wp-job-manager-setup.php:349
877
+ #. translators: %1$s is the URL to WPJM support documentation; %2$s is the URL
878
+ #. to WPJM support forums.
879
  msgid ""
880
+ "If you need help, you can find more detail in our \n"
881
+ "\t\t\t\t\t\t\t<a href=\"%1$s\">support documentation</a> or post your "
882
+ "question on the\n"
883
+ "\t\t\t\t\t\t\t<a href=\"%2$s\">WP Job Manager support forums</a>. Happy "
884
+ "hiring!"
885
  msgstr ""
886
 
887
+ #: includes/admin/class-wp-job-manager-setup.php:360
888
  msgid "Support WP Job Manager's Ongoing Development"
889
  msgstr ""
890
 
891
+ #: includes/admin/class-wp-job-manager-setup.php:361
892
  msgid ""
893
  "There are lots of ways you can support open source software projects like "
894
  "this one: contributing code, fixing a bug, assisting with non-English "
896
  "spread the word. We appreciate your support!"
897
  msgstr ""
898
 
899
+ #: includes/admin/class-wp-job-manager-setup.php:363
900
  msgid "Leave a positive review"
901
  msgstr ""
902
 
903
+ #: includes/admin/class-wp-job-manager-setup.php:364
904
  msgid "Contribute a localization"
905
  msgstr ""
906
 
907
+ #: includes/admin/class-wp-job-manager-setup.php:365
908
  msgid "Contribute code or report a bug"
909
  msgstr ""
910
 
911
+ #: includes/admin/class-wp-job-manager-setup.php:366
912
  msgid "Help other users on the forums"
913
  msgstr ""
914
 
915
  #: includes/admin/class-wp-job-manager-taxonomy-meta.php:78
916
+ #: includes/admin/class-wp-job-manager-taxonomy-meta.php:101
917
+ #: includes/admin/class-wp-job-manager-taxonomy-meta.php:120
918
+ #: includes/rest-api/class-wp-job-manager-models-job-types-custom-fields.php:36
919
  msgid "Employment Type"
920
  msgstr ""
921
 
922
+ #: includes/admin/class-wp-job-manager-writepanels.php:58
923
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:187
924
  msgid "e.g. \"London\""
925
  msgstr ""
926
 
927
+ #: includes/admin/class-wp-job-manager-writepanels.php:59
928
  #: includes/rest-api/class-wp-job-manager-models-job-listings-custom-fields.php:28
929
  msgid "Leave this blank if the location is not important."
930
  msgstr ""
931
 
932
+ #: includes/admin/class-wp-job-manager-writepanels.php:63
933
  #: includes/rest-api/class-wp-job-manager-models-job-listings-custom-fields.php:32
934
  msgid "Application Email or URL"
935
  msgstr ""
936
 
937
+ #: includes/admin/class-wp-job-manager-writepanels.php:64
938
  msgid "URL or email which applicants use to apply"
939
  msgstr ""
940
 
941
+ #: includes/admin/class-wp-job-manager-writepanels.php:65
942
  msgid ""
943
  "This field is required for the \"application\" area to appear beneath the "
944
  "listing."
945
  msgstr ""
946
 
947
+ #: includes/admin/class-wp-job-manager-writepanels.php:70
948
+ #: includes/class-wp-job-manager-data-exporter.php:50
949
  #: includes/rest-api/class-wp-job-manager-models-job-listings-custom-fields.php:37
950
  msgid "Company Name"
951
  msgstr ""
952
 
953
+ #: includes/admin/class-wp-job-manager-writepanels.php:75
954
+ #: includes/class-wp-job-manager-data-exporter.php:51
955
  #: includes/rest-api/class-wp-job-manager-models-job-listings-custom-fields.php:41
956
  msgid "Company Website"
957
  msgstr ""
958
 
959
+ #: includes/admin/class-wp-job-manager-writepanels.php:80
960
+ #: includes/class-wp-job-manager-data-exporter.php:52
961
  #: includes/rest-api/class-wp-job-manager-models-job-listings-custom-fields.php:45
962
  msgid "Company Tagline"
963
  msgstr ""
964
 
965
+ #: includes/admin/class-wp-job-manager-writepanels.php:81
966
  msgid "Brief description about the company"
967
  msgstr ""
968
 
969
+ #: includes/admin/class-wp-job-manager-writepanels.php:85
970
+ #: includes/class-wp-job-manager-data-exporter.php:53
971
  #: includes/rest-api/class-wp-job-manager-models-job-listings-custom-fields.php:49
972
  msgid "Company Twitter"
973
  msgstr ""
974
 
975
+ #: includes/admin/class-wp-job-manager-writepanels.php:90
976
+ #: includes/class-wp-job-manager-data-exporter.php:54
977
  #: includes/rest-api/class-wp-job-manager-models-job-listings-custom-fields.php:53
978
  msgid "Company Video"
979
  msgstr ""
980
 
981
+ #: includes/admin/class-wp-job-manager-writepanels.php:91
982
  msgid "URL to the company video"
983
  msgstr ""
984
 
985
+ #: includes/admin/class-wp-job-manager-writepanels.php:96
986
  #: includes/rest-api/class-wp-job-manager-models-job-listings-custom-fields.php:57
987
  msgid "Position Filled"
988
  msgstr ""
989
 
990
+ #: includes/admin/class-wp-job-manager-writepanels.php:99
991
  msgid "Filled listings will no longer accept applications."
992
  msgstr ""
993
 
994
+ #: includes/admin/class-wp-job-manager-writepanels.php:104
995
  #: includes/rest-api/class-wp-job-manager-models-job-listings-custom-fields.php:64
996
  msgid "Featured Listing"
997
  msgstr ""
998
 
999
+ #: includes/admin/class-wp-job-manager-writepanels.php:106
1000
  msgid ""
1001
  "Featured listings will be sticky during searches, and can be styled "
1002
  "differently."
1003
  msgstr ""
1004
 
1005
+ #: includes/admin/class-wp-job-manager-writepanels.php:111
1006
  #: includes/rest-api/class-wp-job-manager-models-job-listings-custom-fields.php:68
1007
  msgid "Listing Expiry Date"
1008
  msgstr ""
1009
 
1010
+ #: includes/admin/class-wp-job-manager-writepanels.php:120
1011
+ #: includes/class-wp-job-manager-email-notifications.php:288
1012
  #: includes/rest-api/class-wp-job-manager-models-job-listings-custom-fields.php:75
1013
  msgid "Posted by"
1014
  msgstr ""
1015
 
1016
+ #: includes/admin/class-wp-job-manager-writepanels.php:163
1017
+ #. translators: Placeholder %s is the singular name for a job listing post
1018
+ #. type.
1019
  msgid "%s Data"
1020
  msgstr ""
1021
 
1022
+ #: includes/admin/class-wp-job-manager-writepanels.php:216
1023
  msgid "Most Used"
1024
  msgstr ""
1025
 
1026
+ #: includes/admin/class-wp-job-manager-writepanels.php:282
1027
+ #: includes/admin/class-wp-job-manager-writepanels.php:287
1028
+ #: includes/admin/class-wp-job-manager-writepanels.php:292
1029
  msgid "Use file"
1030
  msgstr ""
1031
 
1032
+ #: includes/admin/class-wp-job-manager-writepanels.php:282
1033
+ #: includes/admin/class-wp-job-manager-writepanels.php:287
1034
+ #: includes/admin/class-wp-job-manager-writepanels.php:292
1035
  msgid "Upload"
1036
  msgstr ""
1037
 
1038
+ #: includes/admin/class-wp-job-manager-writepanels.php:292
1039
  msgid "Add file"
1040
  msgstr ""
1041
 
1042
+ #: includes/admin/class-wp-job-manager-writepanels.php:556
1043
  msgid "Guest User"
1044
  msgstr ""
1045
 
1046
+ #: includes/admin/class-wp-job-manager-writepanels.php:559
1047
  msgid "Change"
1048
  msgstr ""
1049
 
1050
+ #: includes/admin/class-wp-job-manager-writepanels.php:563
1051
  msgid "Enter the ID of the user, or leave blank if submitted by a guest."
1052
  msgstr ""
1053
 
1054
+ #: includes/admin/class-wp-job-manager-writepanels.php:629
1055
+ #. translators: %1$s is placeholder for singular name of the job listing post
1056
+ #. type; %2$s is the intl formatted date the listing was last modified.
1057
+ msgid "%1$s was last modified by the user on %2$s."
1058
  msgstr ""
1059
 
1060
  #: includes/admin/views/html-admin-page-addons.php:13
1065
  msgid "No add-ons were found."
1066
  msgstr ""
1067
 
1068
+ #: includes/class-wp-job-manager-ajax.php:172
1069
+ #. translators: Placeholder %d is the number of found search results.
1070
  msgid "Search completed. Found %d matching record."
1071
  msgid_plural "Search completed. Found %d matching records."
1072
  msgstr[0] ""
1073
  msgstr[1] ""
1074
 
1075
+ #: includes/class-wp-job-manager-ajax.php:268
1076
  msgid "You must be logged in to upload files using this method."
1077
  msgstr ""
1078
 
1079
+ #. Plugin Name of the plugin/theme
1080
+ msgid "WP Job Manager"
1081
+ msgstr ""
1082
+
1083
+ #: includes/class-wp-job-manager-data-exporter.php:49
1084
+ #: includes/class-wp-job-manager-post-types.php:268
1085
+ msgid "Company Logo"
1086
+ msgstr ""
1087
+
1088
+ #: includes/class-wp-job-manager-data-exporter.php:79
1089
+ msgid "WP Job Manager User Data"
1090
+ msgstr ""
1091
+
1092
+ #: includes/class-wp-job-manager-email-notifications.php:223
1093
  msgid "Job title"
1094
  msgstr ""
1095
 
1096
+ #: includes/class-wp-job-manager-email-notifications.php:243
1097
+ #: includes/class-wp-job-manager-post-types.php:152
1098
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:191
1099
  msgid "Job type"
1100
  msgstr ""
1101
 
1102
+ #: includes/class-wp-job-manager-email-notifications.php:253
1103
+ #: includes/class-wp-job-manager-post-types.php:91
1104
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:200
1105
  msgid "Job category"
1106
  msgstr ""
1107
 
1108
+ #: includes/class-wp-job-manager-email-notifications.php:262
1109
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:225
1110
  msgid "Company name"
1111
  msgstr ""
1112
 
1113
+ #: includes/class-wp-job-manager-email-notifications.php:270
1114
  msgid "Company website"
1115
  msgstr ""
1116
 
1117
+ #: includes/class-wp-job-manager-email-notifications.php:279
1118
  msgid "Listing expires"
1119
  msgstr ""
1120
 
1121
+ #: includes/class-wp-job-manager-email-notifications.php:437
1122
  msgid "Email Notifications"
1123
  msgstr ""
1124
 
1125
+ #: includes/class-wp-job-manager-email-notifications.php:440
1126
  msgid "Select the email notifications to enable."
1127
  msgstr ""
1128
 
1129
+ #: includes/class-wp-job-manager-email-notifications.php:580
1130
  msgid "Format"
1131
  msgstr ""
1132
 
1133
+ #: includes/class-wp-job-manager-email-notifications.php:583
1134
  msgid "Send plain text email"
1135
  msgstr ""
1136
 
1137
+ #: includes/class-wp-job-manager-email-notifications.php:584
1138
  msgid "Send rich text email"
1139
  msgstr ""
1140
 
1141
+ #: includes/class-wp-job-manager-geocode.php:230
1142
  msgid "No results found"
1143
  msgstr ""
1144
 
1145
+ #: includes/class-wp-job-manager-geocode.php:233
1146
  msgid "Query limit reached"
1147
  msgstr ""
1148
 
1149
+ #: includes/class-wp-job-manager-geocode.php:237
1150
+ #: includes/class-wp-job-manager-geocode.php:240
 
1151
  msgid "Geocoding error"
1152
  msgstr ""
1153
 
1154
+ #: includes/class-wp-job-manager-install.php:67
1155
  msgid "Employer"
1156
  msgstr ""
1157
 
1158
+ #: includes/class-wp-job-manager-post-types.php:92
1159
  msgid "Job categories"
1160
  msgstr ""
1161
 
1162
+ #: includes/class-wp-job-manager-post-types.php:120
1163
+ #: includes/class-wp-job-manager-post-types.php:180
1164
+ #: includes/class-wp-job-manager-post-types.php:261
1165
+ #. translators: Placeholder %s is the plural label of the job listing category
1166
+ #. taxonomy type.
1167
+ #. translators: Placeholder %s is the plural label of the job listing job type
1168
+ #. taxonomy type.
1169
+ #. translators: Placeholder %s is the singular label of the job listing post
1170
+ #. type.
1171
  msgid "Search %s"
1172
  msgstr ""
1173
 
1174
+ #: includes/class-wp-job-manager-post-types.php:122
1175
+ #: includes/class-wp-job-manager-post-types.php:182
1176
+ #: includes/class-wp-job-manager-post-types.php:247
1177
+ #. translators: Placeholder %s is the plural label of the job listing category
1178
+ #. taxonomy type.
1179
+ #. translators: Placeholder %s is the plural label of the job listing job type
1180
+ #. taxonomy type.
1181
+ #. translators: Placeholder %s is the plural label of the job listing post
1182
+ #. type.
1183
  msgid "All %s"
1184
  msgstr ""
1185
 
1186
+ #: includes/class-wp-job-manager-post-types.php:124
1187
+ #: includes/class-wp-job-manager-post-types.php:184
1188
+ #: includes/class-wp-job-manager-post-types.php:267
1189
+ #. translators: Placeholder %s is the singular label of the job listing
1190
+ #. category taxonomy type.
1191
+ #. translators: Placeholder %s is the singular label of the job listing job
1192
+ #. type taxonomy type.
1193
+ #. translators: Placeholder %s is the singular label of the job listing post
1194
+ #. type.
1195
  msgid "Parent %s"
1196
  msgstr ""
1197
 
1198
+ #: includes/class-wp-job-manager-post-types.php:126
1199
+ #: includes/class-wp-job-manager-post-types.php:186
1200
+ #. translators: Placeholder %s is the singular label of the job listing
1201
+ #. category taxonomy type.
1202
+ #. translators: Placeholder %s is the singular label of the job listing job
1203
+ #. type taxonomy type.
1204
  msgid "Parent %s:"
1205
  msgstr ""
1206
 
1207
+ #: includes/class-wp-job-manager-post-types.php:128
1208
+ #: includes/class-wp-job-manager-post-types.php:188
1209
+ #: includes/class-wp-job-manager-post-types.php:253
1210
+ #. translators: Placeholder %s is the singular label of the job listing
1211
+ #. category taxonomy type.
1212
+ #. translators: Placeholder %s is the singular label of the job listing job
1213
+ #. type taxonomy type.
1214
+ #. translators: Placeholder %s is the singular label of the job listing post
1215
+ #. type.
1216
  msgid "Edit %s"
1217
  msgstr ""
1218
 
1219
+ #: includes/class-wp-job-manager-post-types.php:130
1220
+ #: includes/class-wp-job-manager-post-types.php:190
1221
+ #. translators: Placeholder %s is the singular label of the job listing
1222
+ #. category taxonomy type.
1223
+ #. translators: Placeholder %s is the singular label of the job listing job
1224
+ #. type taxonomy type.
1225
  msgid "Update %s"
1226
  msgstr ""
1227
 
1228
+ #: includes/class-wp-job-manager-post-types.php:132
1229
+ #: includes/class-wp-job-manager-post-types.php:192
1230
+ #. translators: Placeholder %s is the singular label of the job listing
1231
+ #. category taxonomy type.
1232
+ #. translators: Placeholder %s is the singular label of the job listing job
1233
+ #. type taxonomy type.
1234
  msgid "Add New %s"
1235
  msgstr ""
1236
 
1237
+ #: includes/class-wp-job-manager-post-types.php:134
1238
+ #: includes/class-wp-job-manager-post-types.php:194
1239
+ #. translators: Placeholder %s is the singular label of the job listing
1240
+ #. category taxonomy type.
1241
+ #. translators: Placeholder %s is the singular label of the job listing job
1242
+ #. type taxonomy type.
1243
  msgid "New %s Name"
1244
  msgstr ""
1245
 
1246
+ #: includes/class-wp-job-manager-post-types.php:153
1247
  msgid "Job types"
1248
  msgstr ""
1249
 
1250
+ #: includes/class-wp-job-manager-post-types.php:214
1251
  msgid "Job"
1252
  msgstr ""
1253
 
1254
+ #: includes/class-wp-job-manager-post-types.php:215
1255
  msgid "Jobs"
1256
  msgstr ""
1257
 
1258
+ #: includes/class-wp-job-manager-post-types.php:248
1259
  msgid "Add New"
1260
  msgstr ""
1261
 
1262
+ #: includes/class-wp-job-manager-post-types.php:250
1263
+ #. translators: Placeholder %s is the singular label of the job listing post
1264
+ #. type.
1265
  msgid "Add %s"
1266
  msgstr ""
1267
 
1268
+ #: includes/class-wp-job-manager-post-types.php:255
1269
+ #. translators: Placeholder %s is the singular label of the job listing post
1270
+ #. type.
1271
  msgid "New %s"
1272
  msgstr ""
1273
 
1274
+ #: includes/class-wp-job-manager-post-types.php:257
1275
+ #: includes/class-wp-job-manager-post-types.php:259
1276
+ #. translators: Placeholder %s is the singular label of the job listing post
1277
+ #. type.
1278
  msgid "View %s"
1279
  msgstr ""
1280
 
1281
+ #: includes/class-wp-job-manager-post-types.php:263
1282
+ #. translators: Placeholder %s is the singular label of the job listing post
1283
+ #. type.
1284
  msgid "No %s found"
1285
  msgstr ""
1286
 
1287
+ #: includes/class-wp-job-manager-post-types.php:265
1288
+ #. translators: Placeholder %s is the plural label of the job listing post
1289
+ #. type.
1290
  msgid "No %s found in trash"
1291
  msgstr ""
1292
 
1293
+ #: includes/class-wp-job-manager-post-types.php:269
 
 
 
 
1294
  msgid "Set company logo"
1295
  msgstr ""
1296
 
1297
+ #: includes/class-wp-job-manager-post-types.php:270
1298
  msgid "Remove company logo"
1299
  msgstr ""
1300
 
1301
+ #: includes/class-wp-job-manager-post-types.php:271
1302
  msgid "Use as company logo"
1303
  msgstr ""
1304
 
1305
+ #: includes/class-wp-job-manager-post-types.php:274
1306
+ #. translators: Placeholder %s is the plural label of the job listing post
1307
+ #. type.
1308
  msgid "This is where you can create and manage %s."
1309
  msgstr ""
1310
 
1311
+ #: includes/class-wp-job-manager-post-types.php:310
1312
+ #. translators: Placeholder %s is the number of expired posts of this type.
1313
  msgid "Expired <span class=\"count\">(%s)</span>"
1314
  msgid_plural "Expired <span class=\"count\">(%s)</span>"
1315
  msgstr[0] ""
1316
  msgstr[1] ""
1317
 
1318
+ #: includes/class-wp-job-manager-post-types.php:322
1319
+ #. translators: Placeholder %s is the number of posts in a preview state.
1320
  msgid "Preview <span class=\"count\">(%s)</span>"
1321
  msgid_plural "Preview <span class=\"count\">(%s)</span>"
1322
  msgstr[0] ""
1323
  msgstr[1] ""
1324
 
1325
+ #: includes/class-wp-job-manager-shortcodes.php:100
1326
  msgid "Invalid ID"
1327
  msgstr ""
1328
 
1329
+ #: includes/class-wp-job-manager-shortcodes.php:107
1330
  msgid "This position has already been filled"
1331
  msgstr ""
1332
 
1333
+ #: includes/class-wp-job-manager-shortcodes.php:115
1334
+ #. translators: Placeholder %s is the job listing title.
1335
  msgid "%s has been filled"
1336
  msgstr ""
1337
 
1338
+ #: includes/class-wp-job-manager-shortcodes.php:120
1339
  msgid "This position is not filled"
1340
  msgstr ""
1341
 
1342
+ #: includes/class-wp-job-manager-shortcodes.php:128
1343
+ #. translators: Placeholder %s is the job listing title.
1344
  msgid "%s has been marked as not filled"
1345
  msgstr ""
1346
 
1347
+ #: includes/class-wp-job-manager-shortcodes.php:136
1348
+ #. translators: Placeholder %s is the job listing title.
1349
  msgid "%s has been deleted"
1350
  msgstr ""
1351
 
1352
+ #: includes/class-wp-job-manager-shortcodes.php:141
1353
+ #: includes/class-wp-job-manager-shortcodes.php:154
1354
  msgid "Missing submission page."
1355
  msgstr ""
1356
 
1357
+ #: includes/class-wp-job-manager-shortcodes.php:246
1358
+ #: includes/widgets/class-wp-job-manager-widget-featured-jobs.php:30
1359
+ #: includes/widgets/class-wp-job-manager-widget-featured-jobs.php:46
1360
+ #: includes/widgets/class-wp-job-manager-widget-recent-jobs.php:30
1361
  msgid "Title"
1362
  msgstr ""
1363
 
1364
+ #: includes/class-wp-job-manager-shortcodes.php:248
1365
  msgid "Date Posted"
1366
  msgstr ""
1367
 
1368
+ #: includes/class-wp-job-manager-shortcodes.php:249
1369
  msgid "Listing Expires"
1370
  msgstr ""
1371
 
1372
+ #: includes/class-wp-job-manager-shortcodes.php:384
1373
+ #: includes/class-wp-job-manager-shortcodes.php:421
1374
  msgid "Load more listings"
1375
  msgstr ""
1376
 
1377
+ #: includes/class-wp-job-manager-usage-tracking.php:108
1378
+ #. translators: Placeholder %s is a URL to the document on wpjobmanager.com
1379
+ #. with info on usage tracking.
1380
  msgid ""
1381
  "We'd love if you helped us make WP Job Manager better by allowing us to "
1382
  "collect\n"
1383
+ "\t\t\t\t<a href=\"%s\" target=\"_blank\">usage tracking data</a>. No "
1384
+ "sensitive information is \n"
1385
+ "\t\t\t\tcollected, and you can opt out at any time."
1386
  msgstr ""
1387
 
1388
+ #: includes/class-wp-job-manager-usage-tracking.php:175
1389
  #. translators: the href tag contains the URL for the page telling users what
1390
  #. data WPJM tracks.
1391
  msgid ""
1394
  "\t\t\t\tNo sensitive information is collected."
1395
  msgstr ""
1396
 
1397
+ #: includes/class-wp-job-manager-usage-tracking.php:200
1398
+ #: lib/usage-tracking/class-usage-tracking-base.php:475
1399
  msgid "Enable Usage Tracking"
1400
  msgstr ""
1401
 
1417
  "frontend."
1418
  msgstr ""
1419
 
1420
+ #: includes/emails/class-wp-job-manager-email-admin-new-job.php:59
1421
+ #. translators: Placeholder %s is the job listing post title.
1422
  msgid "New Job Listing Submitted: %s"
1423
  msgstr ""
1424
 
1432
  "frontend."
1433
  msgstr ""
1434
 
1435
+ #: includes/emails/class-wp-job-manager-email-admin-updated-job.php:59
1436
+ #. translators: Placeholder %s is the job listing post title.
1437
  msgid "Job Listing Updated: %s"
1438
  msgstr ""
1439
 
1445
  msgid "Send notices to employers before a job listing expires."
1446
  msgstr ""
1447
 
1448
+ #: includes/emails/class-wp-job-manager-email-employer-expiring-job.php:75
1449
+ #. translators: Placeholder %s is the job listing post title.
1450
  msgid "Job Listing Expiring: %s"
1451
  msgstr ""
1452
 
1453
+ #: includes/emails/class-wp-job-manager-email-employer-expiring-job.php:128
1454
  msgid "Notice Period"
1455
  msgstr ""
1456
 
1457
+ #: includes/emails/class-wp-job-manager-email-employer-expiring-job.php:130
1458
  msgid "days"
1459
  msgstr ""
1460
 
1461
+ #: includes/forms/class-wp-job-manager-form-edit-job.php:97
1462
  msgid "Invalid listing"
1463
  msgstr ""
1464
 
1465
+ #: includes/forms/class-wp-job-manager-form-edit-job.php:129
1466
  msgid "Save changes"
1467
  msgstr ""
1468
 
1469
+ #: includes/forms/class-wp-job-manager-form-edit-job.php:132
1470
  msgid "Submit changes for approval"
1471
  msgstr ""
1472
 
1473
+ #: includes/forms/class-wp-job-manager-form-edit-job.php:183
1474
  msgid "Your changes have been saved."
1475
  msgstr ""
1476
 
1477
+ #: includes/forms/class-wp-job-manager-form-edit-job.php:189
1478
  msgid "View &rarr;"
1479
  msgstr ""
1480
 
1481
+ #: includes/forms/class-wp-job-manager-form-edit-job.php:191
1482
  msgid ""
1483
  "Your changes have been submitted and your listing will be visible again "
1484
  "once approved."
1485
  msgstr ""
1486
 
1487
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:69
1488
  msgid "Submit Details"
1489
  msgstr ""
1490
 
1491
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:75
1492
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:500
1493
  #: templates/job-preview.php:22
1494
  msgid "Preview"
1495
  msgstr ""
1496
 
1497
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:81
1498
  msgid "Done"
1499
  msgstr ""
1500
 
1501
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:150
1502
  msgid "Application email"
1503
  msgstr ""
1504
 
1505
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:151
1506
+ #: wp-job-manager-template.php:717
1507
  msgid "you@yourdomain.com"
1508
  msgstr ""
1509
 
1510
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:155
1511
  msgid "Application URL"
1512
  msgstr ""
1513
 
1514
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:156
1515
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:236
1516
  msgid "http://"
1517
  msgstr ""
1518
 
1519
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:160
1520
  msgid "Application email/URL"
1521
  msgstr ""
1522
 
1523
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:161
1524
  msgid "Enter an email address or website URL"
1525
  msgstr ""
1526
 
1527
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:176
1528
  msgid "Job Title"
1529
  msgstr ""
1530
 
1531
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:184
1532
  msgid "Leave this blank if the location is not important"
1533
  msgstr ""
1534
 
1535
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:194
1536
  msgid "Choose job type&hellip;"
1537
  msgstr ""
1538
 
1539
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:209
1540
  msgid "Description"
1541
  msgstr ""
1542
 
1543
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:228
1544
  msgid "Enter the name of the company"
1545
  msgstr ""
1546
 
1547
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:232
1548
  #: templates/content-single-job_listing-company.php:30
1549
  msgid "Website"
1550
  msgstr ""
1551
 
1552
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:240
1553
  msgid "Tagline"
1554
  msgstr ""
1555
 
1556
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:243
1557
  msgid "Briefly describe your company"
1558
  msgstr ""
1559
 
1560
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:248
1561
  msgid "Video"
1562
  msgstr ""
1563
 
1564
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:252
1565
  msgid "A link to a video about your company"
1566
  msgstr ""
1567
 
1568
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:256
1569
  msgid "Twitter username"
1570
  msgstr ""
1571
 
1572
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:259
1573
  msgid "@yourcompany"
1574
  msgstr ""
1575
 
1576
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:263
1577
  msgid "Logo"
1578
  msgstr ""
1579
 
1580
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:313
1581
+ #. translators: Placeholder %s is the label for the required field.
1582
  msgid "%s is a required field"
1583
  msgstr ""
1584
 
1585
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:324
1586
+ #. translators: Placeholder %s is the field label that is did not validate.
1587
  msgid "%s is invalid"
1588
  msgstr ""
1589
 
1590
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:341
1591
+ #: wp-job-manager-functions.php:1277
1592
+ #. translators: Placeholder %1$s is field label; %2$s is the file mime type;
1593
+ #. %3$s is the allowed mime-types.
1594
+ #. translators: %1$s is the file field label; %2$s is the file type; %3$s is
1595
+ #. the list of allowed file types.
1596
+ msgid "\"%1$s\" (filetype %2$s) needs to be one of the following file types: %3$s"
1597
  msgstr ""
1598
 
1599
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:356
1600
  msgid "Please enter a valid application email address"
1601
  msgstr ""
1602
 
1603
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:365
1604
  msgid "Please enter a valid application URL"
1605
  msgstr ""
1606
 
1607
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:375
1608
  msgid "Please enter a valid application email address or URL"
1609
  msgstr ""
1610
 
1611
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:535
1612
  msgid "Please enter a username."
1613
  msgstr ""
1614
 
1615
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:539
1616
  msgid "Please enter a password."
1617
  msgstr ""
1618
 
1619
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:543
1620
  msgid "Please enter your email address."
1621
  msgstr ""
1622
 
1623
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:549
1624
  msgid "Passwords must match."
1625
  msgstr ""
1626
 
1627
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:555
1628
+ #. translators: Placeholder %s is the password hint.
1629
  msgid "Invalid Password: %s"
1630
  msgstr ""
1631
 
1632
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:557
1633
  msgid "Password is not valid."
1634
  msgstr ""
1635
 
1636
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:580
1637
  msgid "You must be signed in to post a new listing."
1638
  msgstr ""
1639
 
1640
+ #: includes/helper/class-wp-job-manager-helper.php:265
1641
  msgid "Manage License (Requires Attention)"
1642
  msgstr ""
1643
 
1644
+ #: includes/helper/class-wp-job-manager-helper.php:268
1645
  msgid "Manage License"
1646
  msgstr ""
1647
 
1648
+ #: includes/helper/class-wp-job-manager-helper.php:271
1649
  #: includes/helper/views/html-licences.php:69
1650
  msgid "Activate License"
1651
  msgstr ""
1652
 
1653
+ #: includes/helper/class-wp-job-manager-helper.php:460
1654
  msgid ""
1655
  "Please enter a valid license key and email address in order to activate "
1656
  "this plugin's license."
1657
  msgstr ""
1658
 
1659
+ #: includes/helper/class-wp-job-manager-helper.php:490
1660
  msgid "Connection failed to the License Key API server - possible server issue."
1661
  msgstr ""
1662
 
1663
+ #: includes/helper/class-wp-job-manager-helper.php:498
1664
  msgid "Plugin license has been activated."
1665
  msgstr ""
1666
 
1667
+ #: includes/helper/class-wp-job-manager-helper.php:500
1668
  msgid "An unknown error occurred while attempting to activate the license"
1669
  msgstr ""
1670
 
1671
+ #: includes/helper/class-wp-job-manager-helper.php:512
1672
  msgid "license is not active."
1673
  msgstr ""
1674
 
1675
+ #: includes/helper/class-wp-job-manager-helper.php:528
1676
  msgid "Plugin license has been deactivated."
1677
  msgstr ""
1678
 
1699
  msgid "No plugins are activated that have licenses managed by WP Job Manager."
1700
  msgstr ""
1701
 
1702
+ #: includes/rest-api/class-wp-job-manager-controllers-status.php:54
1703
  msgid "Not Found"
1704
  msgstr ""
1705
 
1706
+ #: includes/rest-api/class-wp-job-manager-models-job-types-custom-fields.php:54
1707
  msgid "Invalid Employment Type"
1708
  msgstr ""
1709
 
1710
+ #: includes/rest-api/class-wp-job-manager-models-settings.php:74
1711
  msgid "Invalid page ID provided"
1712
  msgstr ""
1713
 
1714
  #: includes/widgets/class-wp-job-manager-widget-featured-jobs.php:21
1715
+ #: includes/widgets/class-wp-job-manager-widget-featured-jobs.php:29
1716
+ #. translators: Placeholder %s is the plural label for the job listing post
1717
+ #. type.
1718
+ msgid "Featured %s"
1719
  msgstr ""
1720
 
1721
  #: includes/widgets/class-wp-job-manager-widget-featured-jobs.php:23
1722
+ msgid "Display a list of featured listings on your site."
 
1723
  msgstr ""
1724
 
1725
+ #: includes/widgets/class-wp-job-manager-widget-featured-jobs.php:38
1726
+ #: includes/widgets/class-wp-job-manager-widget-recent-jobs.php:48
1727
  msgid "Number of listings to show"
1728
  msgstr ""
1729
 
1730
+ #: includes/widgets/class-wp-job-manager-widget-featured-jobs.php:43
1731
  msgid "Sort By"
1732
  msgstr ""
1733
 
1734
+ #: includes/widgets/class-wp-job-manager-widget-featured-jobs.php:45
1735
  msgid "Date"
1736
  msgstr ""
1737
 
1738
+ #: includes/widgets/class-wp-job-manager-widget-featured-jobs.php:47
1739
  msgid "Author"
1740
  msgstr ""
1741
 
1742
+ #: includes/widgets/class-wp-job-manager-widget-featured-jobs.php:48
1743
  msgid "Random"
1744
  msgstr ""
1745
 
1746
+ #: includes/widgets/class-wp-job-manager-widget-featured-jobs.php:54
1747
  msgid "Sort Direction"
1748
  msgstr ""
1749
 
1750
+ #: includes/widgets/class-wp-job-manager-widget-featured-jobs.php:56
1751
  msgid "Ascending"
1752
  msgstr ""
1753
 
1754
+ #: includes/widgets/class-wp-job-manager-widget-featured-jobs.php:57
1755
  msgid "Descending"
1756
  msgstr ""
1757
 
1758
  #: includes/widgets/class-wp-job-manager-widget-recent-jobs.php:21
1759
+ #: includes/widgets/class-wp-job-manager-widget-recent-jobs.php:29
1760
+ #. translators: Placeholder %s is the plural label for the job listing post
1761
+ #. type.
1762
+ msgid "Recent %s"
1763
+ msgstr ""
1764
+
1765
+ #: includes/widgets/class-wp-job-manager-widget-recent-jobs.php:23
1766
  msgid ""
1767
  "Display a list of recent listings on your site, optionally matching a "
1768
  "keyword and location."
1769
  msgstr ""
1770
 
1771
+ #: includes/widgets/class-wp-job-manager-widget-recent-jobs.php:35
1772
+ msgid "Keyword"
 
1773
  msgstr ""
1774
 
1775
+ #: includes/widgets/class-wp-job-manager-widget-recent-jobs.php:53
1776
+ msgid "Show Company Logo"
1777
  msgstr ""
1778
 
1779
+ #: lib/usage-tracking/class-usage-tracking-base.php:336
1780
  msgid "Every Two Weeks"
1781
  msgstr ""
1782
 
1783
+ #: lib/usage-tracking/class-usage-tracking-base.php:478
1784
  msgid "Disable Usage Tracking"
1785
  msgstr ""
1786
 
1787
+ #: lib/usage-tracking/class-usage-tracking-base.php:484
1788
  msgid "Usage data enabled. Thank you!"
1789
  msgstr ""
1790
 
1791
+ #: lib/usage-tracking/class-usage-tracking-base.php:487
1792
  msgid "Disabled usage tracking."
1793
  msgstr ""
1794
 
1795
+ #: lib/usage-tracking/class-usage-tracking-base.php:490
1796
  msgid "Something went wrong. Please try again later."
1797
  msgstr ""
1798
 
1873
  msgstr ""
1874
 
1875
  #: templates/emails/admin-expiring-job.php:30
1876
+ #: templates/emails/employer-expiring-job.php:32
1877
  msgid "The following job listing is expiring today from <a href=\"%s\">%s</a>."
1878
  msgstr ""
1879
 
1880
  #: templates/emails/admin-expiring-job.php:32
1881
+ #: templates/emails/employer-expiring-job.php:40
1882
  msgid "The following job listing is expiring soon from <a href=\"%s\">%s</a>."
1883
  msgstr ""
1884
 
1886
  msgid "Visit <a href=\"%s\">WordPress admin</a> to manage the listing."
1887
  msgstr ""
1888
 
1889
+ #: templates/emails/admin-new-job.php:26
1890
  msgid "A new job listing has been submitted to <a href=\"%s\">%s</a>."
1891
  msgstr ""
1892
 
1893
+ #: templates/emails/admin-new-job.php:33
1894
  #: templates/emails/plain/admin-new-job.php:26
1895
  msgid "It has been published and is now available to the public."
1896
  msgstr ""
1897
 
1898
+ #: templates/emails/admin-new-job.php:38
1899
  msgid ""
1900
  "It is awaiting approval by an administrator in <a href=\"%s\">WordPress "
1901
  "admin</a>."
1902
  msgstr ""
1903
 
1904
+ #: templates/emails/admin-updated-job.php:25
1905
  msgid "A job listing has been updated on <a href=\"%s\">%s</a>."
1906
  msgstr ""
1907
 
1908
+ #: templates/emails/admin-updated-job.php:28
1909
  #: templates/emails/plain/admin-updated-job.php:26
1910
  msgid "The changes have been published and are now available to the public."
1911
  msgstr ""
1912
 
1913
+ #: templates/emails/admin-updated-job.php:32
1914
  msgid ""
1915
  "The job listing is not publicly available until the changes are approved by "
1916
  "an administrator in the site's <a href=\"%s\">WordPress admin</a>."
1917
  msgstr ""
1918
 
1919
+ #: templates/emails/employer-expiring-job.php:48
1920
  msgid "Visit the <a href=\"%s\">job listing dashboard</a> to manage the listing."
1921
  msgstr ""
1922
 
1923
+ #: templates/emails/plain/admin-expiring-job.php:30
1924
  #: templates/emails/plain/employer-expiring-job.php:29
1925
  msgid "The following job listing is expiring today from %s (%s)."
1926
  msgstr ""
1927
 
1928
+ #: templates/emails/plain/admin-expiring-job.php:36
1929
  #: templates/emails/plain/employer-expiring-job.php:31
1930
  msgid "The following job listing is expiring soon from %s (%s)."
1931
  msgstr ""
1932
 
1933
+ #: templates/emails/plain/admin-expiring-job.php:43
1934
  msgid "Visit WordPress admin (%s) to manage the listing."
1935
  msgstr ""
1936
 
1961
  msgstr ""
1962
 
1963
  #: templates/form-fields/multiselect-field.php:20
1964
+ #: wp-job-manager-functions.php:1060
1965
  msgid "No results match"
1966
  msgstr ""
1967
 
1968
  #: templates/form-fields/multiselect-field.php:20
1969
+ #: wp-job-manager-functions.php:1061
1970
  msgid "Select Some Options"
1971
  msgstr ""
1972
 
2059
  msgid "Company Details"
2060
  msgstr ""
2061
 
2062
+ #: templates/job-submitted.php:24
2063
  msgid "%s listed successfully. To view your listing <a href=\"%s\">click here</a>."
2064
  msgstr ""
2065
 
2066
+ #: templates/job-submitted.php:33
2067
  msgid "%s submitted successfully. Your listing will be visible once approved."
2068
  msgstr ""
2069
 
2070
+ #: wp-job-manager-functions.php:445
2071
  msgid "Reset"
2072
  msgstr ""
2073
 
2074
+ #: wp-job-manager-functions.php:449
2075
  msgid "RSS"
2076
  msgstr ""
2077
 
2078
+ #: wp-job-manager-functions.php:554
2079
  msgid "Invalid email address."
2080
  msgstr ""
2081
 
2082
+ #: wp-job-manager-functions.php:562
2083
  msgid "Your email address isn&#8217;t correct."
2084
  msgstr ""
2085
 
2086
+ #: wp-job-manager-functions.php:566
2087
  msgid "This email is already registered, please choose another one."
2088
  msgstr ""
2089
 
2090
+ #: wp-job-manager-functions.php:866
2091
  msgid "Full Time"
2092
  msgstr ""
2093
 
2094
+ #: wp-job-manager-functions.php:867
2095
  msgid "Part Time"
2096
  msgstr ""
2097
 
2098
+ #: wp-job-manager-functions.php:868
2099
  msgid "Contractor"
2100
  msgstr ""
2101
 
2102
+ #: wp-job-manager-functions.php:869
2103
  msgid "Temporary"
2104
  msgstr ""
2105
 
2106
+ #: wp-job-manager-functions.php:870
2107
  msgid "Intern"
2108
  msgstr ""
2109
 
2110
+ #: wp-job-manager-functions.php:871
2111
  msgid "Volunteer"
2112
  msgstr ""
2113
 
2114
+ #: wp-job-manager-functions.php:872
2115
  msgid "Per Diem"
2116
  msgstr ""
2117
 
2118
+ #: wp-job-manager-functions.php:873
2119
  msgid "Other"
2120
  msgstr ""
2121
 
2122
+ #: wp-job-manager-functions.php:940
2123
  msgid "Passwords must be at least 8 characters long."
2124
  msgstr ""
2125
 
2126
+ #: wp-job-manager-functions.php:1059
2127
  msgid "Choose a category&hellip;"
2128
  msgstr ""
2129
 
2130
+ #: wp-job-manager-functions.php:1280
2131
+ #. translators: %s is the list of allowed file types.
2132
  msgid "Uploaded files need to be one of the following file types: %s"
2133
  msgstr ""
2134
 
2135
+ #: wp-job-manager-template.php:153
2136
  msgid "Inactive"
2137
  msgstr ""
2138
 
2139
+ #: wp-job-manager-template.php:247
2140
+ #. translators: %1$s is the job listing title; %2$s is the URL for the current
2141
+ #. WordPress instance.
2142
+ msgid "Application via \"%1$s\" listing on %2$s"
2143
  msgstr ""
2144
 
2145
+ #: wp-job-manager-template.php:691
2146
  msgid "Username"
2147
  msgstr ""
2148
 
2149
+ #: wp-job-manager-template.php:699
2150
  msgid "Password"
2151
  msgstr ""
2152
 
2153
+ #: wp-job-manager-template.php:709
2154
  msgid "Verify Password"
2155
  msgstr ""
2156
 
2157
+ #: wp-job-manager-template.php:716
2158
  msgid "Your email"
2159
  msgstr ""
2160
 
2161
+ #: wp-job-manager-template.php:743
2162
  msgid "Posted on "
2163
  msgstr ""
2164
 
2165
+ #: wp-job-manager-template.php:746 wp-job-manager-template.php:767
2166
+ #. translators: Placeholder %s is the relative, human readable time since the
2167
+ #. job listing was posted.
2168
  msgid "Posted %s ago"
2169
  msgstr ""
2170
 
2171
+ #: wp-job-manager-template.php:796
2172
  msgid "Anywhere"
2173
  msgstr ""
2174
 
2175
+ #: wp-job-manager.php:168
2176
+ #. translators: Placeholders %1$s and %2$s are the names of the two cookies
2177
+ #. used in WP Job Manager.
2178
+ msgid ""
2179
+ "This site adds the following cookies to help users resume job submissions "
2180
+ "that they \n"
2181
+ "\t\t\t\thave started but have not completed: %1$s and %2$s"
2182
+ msgstr ""
2183
+
2184
+ #: wp-job-manager.php:332
2185
  msgid "Load previous listings"
2186
  msgstr ""
2187
 
2188
+ #: wp-job-manager.php:407
2189
  msgid "Invalid file type. Accepted types:"
2190
  msgstr ""
2191
 
2192
+ #: wp-job-manager.php:422
2193
  msgid "Are you sure you want to delete this listing?"
2194
  msgstr ""
2195
 
 
 
 
 
2196
  #. Author URI of the plugin/theme
2197
  msgid "https://wpjobmanager.com/"
2198
  msgstr ""
2207
  msgid "Automattic"
2208
  msgstr ""
2209
 
2210
+ #: includes/admin/class-wp-job-manager-admin.php:139
2211
+ #: includes/forms/class-wp-job-manager-form-submit-job.php:413
2212
  #. translators: jQuery date format, see
2213
  #. http:api.jqueryui.com/datepicker/#utility-formatDate
2214
  msgctxt "Date format for jQuery datepicker."
2215
  msgid "yy-mm-dd"
2216
  msgstr ""
2217
 
2218
+ #: includes/admin/class-wp-job-manager-permalink-settings.php:86
2219
+ #: includes/class-wp-job-manager-post-types.php:701
2220
  msgctxt "Job permalink - resave permalinks after changing this"
2221
  msgid "job"
2222
  msgstr ""
2223
 
2224
+ #: includes/admin/class-wp-job-manager-permalink-settings.php:95
2225
+ #: includes/class-wp-job-manager-post-types.php:702
2226
  msgctxt "Job category slug - resave permalinks after changing this"
2227
  msgid "job-category"
2228
  msgstr ""
2229
 
2230
+ #: includes/admin/class-wp-job-manager-permalink-settings.php:104
2231
+ #: includes/class-wp-job-manager-post-types.php:703
2232
  msgctxt "Job type slug - resave permalinks after changing this"
2233
  msgid "job-type"
2234
  msgstr ""
2235
 
2236
+ #: includes/admin/class-wp-job-manager-setup.php:274
2237
  msgctxt "Default page title (wizard)"
2238
  msgid "Post a Job"
2239
  msgstr ""
2240
 
2241
+ #: includes/admin/class-wp-job-manager-setup.php:282
2242
  msgctxt "Default page title (wizard)"
2243
  msgid "Job Dashboard"
2244
  msgstr ""
2245
 
2246
+ #: includes/admin/class-wp-job-manager-setup.php:290
2247
  msgctxt "Default page title (wizard)"
2248
  msgid "Jobs"
2249
  msgstr ""
2250
 
2251
+ #: includes/class-wp-job-manager-post-types.php:225
2252
  msgctxt "Post type archive slug - resave permalinks after changing this"
2253
  msgid "jobs"
2254
  msgstr ""
2255
 
2256
+ #: includes/class-wp-job-manager-post-types.php:303
2257
+ #: wp-job-manager-functions.php:320
2258
  msgctxt "post status"
2259
  msgid "Expired"
2260
  msgstr ""
2261
 
2262
+ #: includes/class-wp-job-manager-post-types.php:316
2263
+ #: wp-job-manager-functions.php:321
2264
  msgctxt "post status"
2265
  msgid "Preview"
2266
  msgstr ""
2267
 
2268
+ #: wp-job-manager-functions.php:319
2269
  msgctxt "post status"
2270
  msgid "Draft"
2271
  msgstr ""
2272
 
2273
+ #: wp-job-manager-functions.php:322
2274
  msgctxt "post status"
2275
  msgid "Pending approval"
2276
  msgstr ""
2277
 
2278
+ #: wp-job-manager-functions.php:323
2279
  msgctxt "post status"
2280
  msgid "Pending payment"
2281
  msgstr ""
2282
 
2283
+ #: wp-job-manager-functions.php:324
2284
  msgctxt "post status"
2285
  msgid "Active"
2286
  msgstr ""
lib/usage-tracking/class-usage-tracking-base.php CHANGED
@@ -78,7 +78,7 @@ abstract class WP_Job_Manager_Usage_Tracking_Base {
78
  /**
79
  * Get prefix for actions and strings. Should be unique to this plugin.
80
  *
81
- * @return string The prefix string
82
  **/
83
  abstract protected function get_prefix();
84
 
@@ -86,7 +86,7 @@ abstract class WP_Job_Manager_Usage_Tracking_Base {
86
  * Get the text domain used by this plugin. This class will add some
87
  * strings to be translated.
88
  *
89
- * @return string The text domain string
90
  **/
91
  abstract protected function get_text_domain();
92
 
@@ -108,7 +108,7 @@ abstract class WP_Job_Manager_Usage_Tracking_Base {
108
  /**
109
  * Determine whether current user can manage the tracking options.
110
  *
111
- * @return bool true if the current user is allowed to manage the tracking
112
  * options, false otherwise.
113
  **/
114
  abstract protected function current_user_can_manage_tracking();
@@ -167,6 +167,7 @@ abstract class WP_Job_Manager_Usage_Tracking_Base {
167
  * subclass.
168
  *
169
  * @param string $subclass the name of the subclass.
 
170
  */
171
  protected static function get_instance_for_subclass( $subclass ) {
172
  if ( ! isset( self::$instances[ $subclass ] ) ) {
@@ -219,7 +220,7 @@ abstract class WP_Job_Manager_Usage_Tracking_Base {
219
  $properties['admin_email'] = get_option( 'admin_email' );
220
  $properties['_ut'] = $this->get_event_prefix() . ':site_url';
221
  // Use site URL as the userid to enable usage tracking at the site level.
222
- // Note that we would likely want to use site URL + user ID for userid if we were
223
  // to ever add event tracking at the user level.
224
  $properties['_ui'] = site_url();
225
  $properties['_ul'] = $user->user_login;
@@ -234,7 +235,8 @@ abstract class WP_Job_Manager_Usage_Tracking_Base {
234
 
235
  $pixel .= '?' . implode( '&', $p ) . '&_=_'; // EOF marker.
236
  $response = wp_remote_get(
237
- $pixel, array(
 
238
  'blocking' => true,
239
  'timeout' => 1,
240
  'redirection' => 2,
@@ -280,7 +282,7 @@ abstract class WP_Job_Manager_Usage_Tracking_Base {
280
  /**
281
  * Check if tracking is enabled.
282
  *
283
- * @return bool true if tracking is enabled, false otherwise
284
  **/
285
  public function is_tracking_enabled() {
286
  // Defer to the plugin-specific function.
@@ -325,6 +327,7 @@ abstract class WP_Job_Manager_Usage_Tracking_Base {
325
  * externally.
326
  *
327
  * @param array $schedules the existing cron schedules.
 
328
  **/
329
  public function add_usage_tracking_two_week_schedule( $schedules ) {
330
  $day_in_seconds = 86400;
@@ -547,7 +550,7 @@ abstract class WP_Job_Manager_Usage_Tracking_Base {
547
  jQuery( '#' + prefix + '-usage-tracking-notice' ).hide();
548
  }
549
 
550
- // Handle button clicks
551
  jQuery( '#' + prefix + '-usage-tracking-notice button' ).click( function( event ) {
552
  event.preventDefault();
553
 
78
  /**
79
  * Get prefix for actions and strings. Should be unique to this plugin.
80
  *
81
+ * @return string The prefix string.
82
  **/
83
  abstract protected function get_prefix();
84
 
86
  * Get the text domain used by this plugin. This class will add some
87
  * strings to be translated.
88
  *
89
+ * @return string The text domain string.
90
  **/
91
  abstract protected function get_text_domain();
92
 
108
  /**
109
  * Determine whether current user can manage the tracking options.
110
  *
111
+ * @return bool true if the current user is allowed to manage the tracking.
112
  * options, false otherwise.
113
  **/
114
  abstract protected function current_user_can_manage_tracking();
167
  * subclass.
168
  *
169
  * @param string $subclass the name of the subclass.
170
+ * @return object Instance of $subclass.
171
  */
172
  protected static function get_instance_for_subclass( $subclass ) {
173
  if ( ! isset( self::$instances[ $subclass ] ) ) {
220
  $properties['admin_email'] = get_option( 'admin_email' );
221
  $properties['_ut'] = $this->get_event_prefix() . ':site_url';
222
  // Use site URL as the userid to enable usage tracking at the site level.
223
+ // Note that we would likely want to use site URL + user ID for userid if we were.
224
  // to ever add event tracking at the user level.
225
  $properties['_ui'] = site_url();
226
  $properties['_ul'] = $user->user_login;
235
 
236
  $pixel .= '?' . implode( '&', $p ) . '&_=_'; // EOF marker.
237
  $response = wp_remote_get(
238
+ $pixel,
239
+ array(
240
  'blocking' => true,
241
  'timeout' => 1,
242
  'redirection' => 2,
282
  /**
283
  * Check if tracking is enabled.
284
  *
285
+ * @return bool true if tracking is enabled, false otherwise.
286
  **/
287
  public function is_tracking_enabled() {
288
  // Defer to the plugin-specific function.
327
  * externally.
328
  *
329
  * @param array $schedules the existing cron schedules.
330
+ * @return array of $schedules.
331
  **/
332
  public function add_usage_tracking_two_week_schedule( $schedules ) {
333
  $day_in_seconds = 86400;
550
  jQuery( '#' + prefix + '-usage-tracking-notice' ).hide();
551
  }
552
 
553
+ // Handle button clicks.
554
  jQuery( '#' + prefix + '-usage-tracking-notice button' ).click( function( event ) {
555
  event.preventDefault();
556
 
lib/usage-tracking/tests/test-class-usage-tracking.php CHANGED
@@ -38,20 +38,20 @@ class WP_Job_Manager_Usage_Tracking_Test extends WP_UnitTestCase {
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
  }
@@ -99,7 +99,7 @@ class WP_Job_Manager_Usage_Tracking_Test extends WP_UnitTestCase {
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
 
@@ -167,7 +167,7 @@ class WP_Job_Manager_Usage_Tracking_Test extends WP_UnitTestCase {
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' );
@@ -199,11 +199,10 @@ class WP_Job_Manager_Usage_Tracking_Test extends WP_UnitTestCase {
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 );
@@ -218,7 +217,7 @@ class WP_Job_Manager_Usage_Tracking_Test extends WP_UnitTestCase {
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(
@@ -248,10 +247,10 @@ class WP_Job_Manager_Usage_Tracking_Test extends WP_UnitTestCase {
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
 
@@ -265,7 +264,7 @@ class WP_Job_Manager_Usage_Tracking_Test extends WP_UnitTestCase {
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
 
@@ -407,16 +406,16 @@ class WP_Job_Manager_Usage_Tracking_Test extends WP_UnitTestCase {
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
  }
@@ -425,10 +424,10 @@ class WP_Job_Manager_Usage_Tracking_Test extends WP_UnitTestCase {
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
 
@@ -436,7 +435,7 @@ class WP_Job_Manager_Usage_Tracking_Test extends WP_UnitTestCase {
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 ) {
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
  }
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
 
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' );
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 simulate a WP_Error.
 
206
  $this->track_http_request['request_params'] = null;
207
  $this->track_http_request['request_url'] = null;
208
  add_filter( 'pre_http_request', array( $this, 'trackHttpRequest' ), 10, 3 );
217
  $query = array();
218
  parse_str( $parsed_url['query'], $query );
219
 
220
+ // Older versions (for PHP 5.2) of PHPUnit do not have this method.
221
  if ( method_exists( $this, 'assertArraySubset' ) ) {
222
  $this->assertArraySubset(
223
  array(
247
  );
248
  $timestamp = '1234';
249
 
250
+ // Disable tracking.
251
  $this->usage_tracking->set_tracking_enabled( false );
252
 
253
+ // Count network requests.
254
  $this->event_counts['http_request'] = 0;
255
  add_filter( 'pre_http_request', array( $this, 'countHttpRequest' ) );
256
 
264
  * @covers {Prefix}_Usage_Tracking::maybe_send_usage_data
265
  */
266
  public function testSendUsageData() {
267
+ // Count the number of network requests.
268
  $this->event_counts['http_request'] = 0;
269
  add_filter( 'pre_http_request', array( $this, 'countHttpRequest' ) );
270
 
406
  * Helper method for ajax request.
407
  */
408
  private function setupAjaxRequest() {
409
+ // Simulate an ajax request.
410
  add_filter( 'wp_doing_ajax', '__return_true' );
411
 
412
+ // Set up nonce.
413
  $_REQUEST['nonce'] = wp_create_nonce( 'tracking-opt-in' );
414
 
415
+ // Ensure current user can enable tracking.
416
  $this->allowCurrentUserToEnableTracking();
417
 
418
+ // When wp_die is called, save the args and throw an exception to stop.
419
  // execution.
420
  add_filter( 'wp_die_ajax_handler', array( $this, 'ajaxDieHandler' ) );
421
  }
424
  * Helper method to set up tracking opt-in dialog.
425
  */
426
  private function setupOptInDialog() {
427
+ // Ensure current user can enable tracking.
428
  $this->allowCurrentUserToEnableTracking();
429
 
430
+ // Ensure setting is not set.
431
  $this->usage_tracking->set_tracking_enabled( false );
432
  }
433
 
435
  * Update the capaility for the current user to be able to enable or
436
  * disable tracking.
437
  *
438
+ * @param bool $allow true if the current user should be allowed to update.
439
  * the tracking setting, false otherwise. Default: true
440
  **/
441
  private function allowCurrentUserToEnableTracking( $allow = true ) {
readme.txt CHANGED
@@ -3,7 +3,7 @@ Contributors: mikejolley, automattic, adamkheckler, alexsanford1, annezazu, cena
3
  Tags: job manager, job listing, job board, job management, job lists, job list, job, jobs, company, hiring, employment, employer, employees, candidate, freelance, internship, job listings, positions, board, application, hiring, listing, manager, recruiting, recruitment, talent
4
  Requires at least: 4.7.0
5
  Tested up to: 4.9
6
- Stable tag: 1.31.0
7
  License: GPLv3
8
  License URI: http://www.gnu.org/licenses/gpl-3.0.html
9
 
@@ -130,6 +130,17 @@ If you wish to be notified of new postings on your site you can use a plugin suc
130
  = What language files are available? =
131
  You can view (and contribute) translations via the [translate.wordpress.org](https://translate.wordpress.org/projects/wp-plugins/wp-job-manager).
132
 
 
 
 
 
 
 
 
 
 
 
 
133
  == Screenshots ==
134
 
135
  1. The submit job form.
@@ -141,6 +152,17 @@ You can view (and contribute) translations via the [translate.wordpress.org](htt
141
 
142
  == Changelog ==
143
 
 
 
 
 
 
 
 
 
 
 
 
144
  = 1.31.0 =
145
  * Change: Minimum WordPress version is now 4.7.0.
146
  * Enhancement: Add email notifications with initial support for new jobs, updated jobs, and expiring listings.
3
  Tags: job manager, job listing, job board, job management, job lists, job list, job, jobs, company, hiring, employment, employer, employees, candidate, freelance, internship, job listings, positions, board, application, hiring, listing, manager, recruiting, recruitment, talent
4
  Requires at least: 4.7.0
5
  Tested up to: 4.9
6
+ Stable tag: 1.31.1
7
  License: GPLv3
8
  License URI: http://www.gnu.org/licenses/gpl-3.0.html
9
 
130
  = What language files are available? =
131
  You can view (and contribute) translations via the [translate.wordpress.org](https://translate.wordpress.org/projects/wp-plugins/wp-job-manager).
132
 
133
+ == Unit Testing ==
134
+
135
+ The plugin contains all the files needed for running tests.
136
+ Developers who would like to run the existing tests or add their tests to the test suite and execute them will have to follow these steps:
137
+ 1. `cd` into the plugin directory.
138
+ 2. Run the install script(you will need to have `wget` installed) - `bash bin/install-wp-tests.sh <db-name> <db-user> <db-pass> <db-host> <wp-version>`.
139
+ 3. Run the plugin tests - `phpunit`
140
+
141
+ The install script installs a copy of WordPress in the `/tmp` directory along with the WordPress unit testing tools.
142
+ It then creates a database based on the parameters passed to it.
143
+
144
  == Screenshots ==
145
 
146
  1. The submit job form.
152
 
153
  == Changelog ==
154
 
155
+ = 1.31.1 =
156
+ * Enhancement: Add option to show company logo in Recent Jobs widget. (@RajeebTheGreat)
157
+ * Enhancement: Suggest additional cookie information on Privacy Policy page.
158
+ * Enhancement: Add WPJM related meta data to user data extract.
159
+ * Fix: Tightened the security of the plugin with additional string escaping.
160
+ * Fix: Issue with map link in admin backend. (@RajeebTheGreat)
161
+ * Fix: No longer auto-expire job listings in Draft status.
162
+ * Fix: Issue with undefined index error in WP admin. (@albionselimaj)
163
+ * Fix: Issue with duplicate usernames preventing submission of job listings. (@timothyjensen)
164
+ * Dev: Widespread code formatting cleanup throughout the plugin.
165
+
166
  = 1.31.0 =
167
  * Change: Minimum WordPress version is now 4.7.0.
168
  * Enhancement: Add email notifications with initial support for new jobs, updated jobs, and expiring listings.
templates/account-signin.php CHANGED
@@ -8,24 +8,24 @@
8
  * @author Automattic
9
  * @package WP Job Manager
10
  * @category Template
11
- * @version 1.31.0
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
15
- exit; // Exit if accessed directly
16
  }
17
  ?>
18
  <?php if ( is_user_logged_in() ) : ?>
19
 
20
  <fieldset class="fieldset-logged_in">
21
- <label><?php _e( 'Your account', 'wp-job-manager' ); ?></label>
22
  <div class="field account-sign-in">
23
  <?php
24
  $user = wp_get_current_user();
25
- printf( __( 'You are currently signed in as <strong>%s</strong>.', 'wp-job-manager' ), $user->user_login );
26
  ?>
27
 
28
- <a class="button" href="<?php echo apply_filters( 'submit_job_form_logout_url', wp_logout_url( get_permalink() ) ); ?>"><?php _e( 'Sign out', 'wp-job-manager' ); ?></a>
29
  </div>
30
  </fieldset>
31
 
@@ -36,20 +36,20 @@ if ( ! defined( 'ABSPATH' ) ) {
36
  $use_standard_password_email = wpjm_use_standard_password_setup_email();
37
  ?>
38
  <fieldset class="fieldset-login_required">
39
- <label><?php _e( 'Have an account?', 'wp-job-manager' ); ?></label>
40
  <div class="field account-sign-in">
41
- <a class="button" href="<?php echo apply_filters( 'submit_job_form_login_url', wp_login_url( get_permalink() ) ); ?>"><?php _e( 'Sign in', 'wp-job-manager' ); ?></a>
42
 
43
  <?php if ( $registration_enabled ) : ?>
44
 
45
- <?php printf( __( 'If you don\'t have an account you can %screate one below by entering your email address/username.', 'wp-job-manager' ), $account_required ? '' : __( 'optionally', 'wp-job-manager' ) . ' ' ); ?>
46
  <?php if ( $use_standard_password_email ) : ?>
47
- <?php printf( __( 'Your account details will be confirmed via email.', 'wp-job-manager' ) ); ?>
48
  <?php endif; ?>
49
 
50
  <?php elseif ( $account_required ) : ?>
51
 
52
- <?php echo apply_filters( 'submit_job_form_login_required_message', __('You must sign in to create a new listing.', 'wp-job-manager' ) ); ?>
53
 
54
  <?php endif; ?>
55
  </div>
@@ -60,7 +60,7 @@ if ( ! defined( 'ABSPATH' ) ) {
60
  ?>
61
  <fieldset class="fieldset-<?php echo esc_attr( $key ); ?>">
62
  <label
63
- for="<?php echo esc_attr( $key ); ?>"><?php echo $field[ 'label' ] . apply_filters( 'submit_job_form_required_label', $field[ 'required' ] ? '' : ' <small>' . __( '(optional)', 'wp-job-manager' ) . '</small>', $field ); ?></label>
64
  <div class="field <?php echo $field[ 'required' ] ? 'required-field' : ''; ?>">
65
  <?php get_job_manager_template( 'form-fields/' . $field[ 'type' ] . '-field.php', array( 'key' => $key, 'field' => $field ) ); ?>
66
  </div>
8
  * @author Automattic
9
  * @package WP Job Manager
10
  * @category Template
11
+ * @version 1.31.1
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
15
+ exit; // Exit if accessed directly.
16
  }
17
  ?>
18
  <?php if ( is_user_logged_in() ) : ?>
19
 
20
  <fieldset class="fieldset-logged_in">
21
+ <label><?php esc_html_e( 'Your account', 'wp-job-manager' ); ?></label>
22
  <div class="field account-sign-in">
23
  <?php
24
  $user = wp_get_current_user();
25
+ printf( wp_kses_post( __( 'You are currently signed in as <strong>%s</strong>.', 'wp-job-manager' ) ), esc_html( $user->user_login ) );
26
  ?>
27
 
28
+ <a class="button" href="<?php echo esc_url( apply_filters( 'submit_job_form_logout_url', wp_logout_url( get_permalink() ) ) ); ?>"><?php esc_html_e( 'Sign out', 'wp-job-manager' ); ?></a>
29
  </div>
30
  </fieldset>
31
 
36
  $use_standard_password_email = wpjm_use_standard_password_setup_email();
37
  ?>
38
  <fieldset class="fieldset-login_required">
39
+ <label><?php esc_html_e( 'Have an account?', 'wp-job-manager' ); ?></label>
40
  <div class="field account-sign-in">
41
+ <a class="button" href="<?php echo esc_url( apply_filters( 'submit_job_form_login_url', wp_login_url( get_permalink() ) ) ); ?>"><?php esc_html_e( 'Sign in', 'wp-job-manager' ); ?></a>
42
 
43
  <?php if ( $registration_enabled ) : ?>
44
 
45
+ <?php printf( esc_html__( 'If you don\'t have an account you can %screate one below by entering your email address/username.', 'wp-job-manager' ), $account_required ? '' : esc_html__( 'optionally', 'wp-job-manager' ) . ' ' ); ?>
46
  <?php if ( $use_standard_password_email ) : ?>
47
+ <?php printf( esc_html__( 'Your account details will be confirmed via email.', 'wp-job-manager' ) ); ?>
48
  <?php endif; ?>
49
 
50
  <?php elseif ( $account_required ) : ?>
51
 
52
+ <?php echo wp_kses_post( apply_filters( 'submit_job_form_login_required_message', __( 'You must sign in to create a new listing.', 'wp-job-manager' ) ) ); ?>
53
 
54
  <?php endif; ?>
55
  </div>
60
  ?>
61
  <fieldset class="fieldset-<?php echo esc_attr( $key ); ?>">
62
  <label
63
+ for="<?php echo esc_attr( $key ); ?>"><?php echo esc_html( $field[ 'label' ] ) . wp_kses_post( apply_filters( 'submit_job_form_required_label', $field[ 'required' ] ? '' : ' <small>' . __( '(optional)', 'wp-job-manager' ) . '</small>', $field ) ); ?></label>
64
  <div class="field <?php echo $field[ 'required' ] ? 'required-field' : ''; ?>">
65
  <?php get_job_manager_template( 'form-fields/' . $field[ 'type' ] . '-field.php', array( 'key' => $key, 'field' => $field ) ); ?>
66
  </div>
templates/content-job_listing.php CHANGED
@@ -13,7 +13,7 @@
13
  */
14
 
15
  if ( ! defined( 'ABSPATH' ) ) {
16
- exit; // Exit if accessed directly
17
  }
18
 
19
  global $post;
13
  */
14
 
15
  if ( ! defined( 'ABSPATH' ) ) {
16
+ exit; // Exit if accessed directly.
17
  }
18
 
19
  global $post;
templates/content-no-jobs-found.php CHANGED
@@ -9,15 +9,15 @@
9
  * @package WP Job Manager
10
  * @category Template
11
  * @since 1.0.0
12
- * @version 1.20.0
13
  */
14
 
15
  if ( ! defined( 'ABSPATH' ) ) {
16
- exit; // Exit if accessed directly
17
  }
18
  ?>
19
  <?php if ( defined( 'DOING_AJAX' ) ) : ?>
20
- <li class="no_job_listings_found"><?php _e( 'There are no listings matching your search.', 'wp-job-manager' ); ?></li>
21
  <?php else : ?>
22
- <p class="no_job_listings_found"><?php _e( 'There are currently no vacancies.', 'wp-job-manager' ); ?></p>
23
- <?php endif; ?>
9
  * @package WP Job Manager
10
  * @category Template
11
  * @since 1.0.0
12
+ * @version 1.31.1
13
  */
14
 
15
  if ( ! defined( 'ABSPATH' ) ) {
16
+ exit; // Exit if accessed directly.
17
  }
18
  ?>
19
  <?php if ( defined( 'DOING_AJAX' ) ) : ?>
20
+ <li class="no_job_listings_found"><?php esc_html_e( 'There are no listings matching your search.', 'wp-job-manager' ); ?></li>
21
  <?php else : ?>
22
+ <p class="no_job_listings_found"><?php esc_html_e( 'There are currently no vacancies.', 'wp-job-manager' ); ?></p>
23
+ <?php endif; ?>
templates/content-single-job_listing-company.php CHANGED
@@ -11,11 +11,11 @@
11
  * @package WP Job Manager
12
  * @category Template
13
  * @since 1.14.0
14
- * @version 1.28.0
15
  */
16
 
17
  if ( ! defined( 'ABSPATH' ) ) {
18
- exit; // Exit if accessed directly
19
  }
20
 
21
  if ( ! get_the_company_name() ) {
@@ -27,11 +27,11 @@ if ( ! get_the_company_name() ) {
27
 
28
  <p class="name">
29
  <?php if ( $website = get_the_company_website() ) : ?>
30
- <a class="website" href="<?php echo esc_url( $website ); ?>" target="_blank" rel="nofollow"><?php _e( 'Website', 'wp-job-manager' ); ?></a>
31
  <?php endif; ?>
32
  <?php the_company_twitter(); ?>
33
  <?php the_company_name( '<strong>', '</strong>' ); ?>
34
  </p>
35
  <?php the_company_tagline( '<p class="tagline">', '</p>' ); ?>
36
  <?php the_company_video(); ?>
37
- </div>
11
  * @package WP Job Manager
12
  * @category Template
13
  * @since 1.14.0
14
+ * @version 1.31.1
15
  */
16
 
17
  if ( ! defined( 'ABSPATH' ) ) {
18
+ exit; // Exit if accessed directly.
19
  }
20
 
21
  if ( ! get_the_company_name() ) {
27
 
28
  <p class="name">
29
  <?php if ( $website = get_the_company_website() ) : ?>
30
+ <a class="website" href="<?php echo esc_url( $website ); ?>" target="_blank" rel="nofollow"><?php esc_html_e( 'Website', 'wp-job-manager' ); ?></a>
31
  <?php endif; ?>
32
  <?php the_company_twitter(); ?>
33
  <?php the_company_name( '<strong>', '</strong>' ); ?>
34
  </p>
35
  <?php the_company_tagline( '<p class="tagline">', '</p>' ); ?>
36
  <?php the_company_video(); ?>
37
+ </div>
templates/content-single-job_listing-meta.php CHANGED
@@ -15,7 +15,7 @@
15
  */
16
 
17
  if ( ! defined( 'ABSPATH' ) ) {
18
- exit; // Exit if accessed directly
19
  }
20
 
21
  global $post;
15
  */
16
 
17
  if ( ! defined( 'ABSPATH' ) ) {
18
+ exit; // Exit if accessed directly.
19
  }
20
 
21
  global $post;
templates/content-single-job_listing.php CHANGED
@@ -13,7 +13,7 @@
13
  */
14
 
15
  if ( ! defined( 'ABSPATH' ) ) {
16
- exit; // Exit if accessed directly
17
  }
18
 
19
  global $post;
13
  */
14
 
15
  if ( ! defined( 'ABSPATH' ) ) {
16
+ exit; // Exit if accessed directly.
17
  }
18
 
19
  global $post;
templates/content-summary-job_listing.php CHANGED
@@ -8,11 +8,11 @@
8
  * @author Automattic
9
  * @package WP Job Manager
10
  * @category Template
11
- * @version 1.31.0
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
15
- exit; // Exit if accessed directly
16
  }
17
 
18
  global $job_manager;
@@ -29,7 +29,7 @@ global $job_manager;
29
  <?php } ?>
30
 
31
  <?php if ( $logo = get_the_company_logo() ) : ?>
32
- <img src="<?php echo esc_attr( $logo ); ?>" alt="<?php the_company_name(); ?>" title="<?php the_company_name(); ?> - <?php the_company_tagline(); ?>" />
33
  <?php endif; ?>
34
 
35
  <div class="job_summary_content">
8
  * @author Automattic
9
  * @package WP Job Manager
10
  * @category Template
11
+ * @version 1.31.1
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
15
+ exit; // Exit if accessed directly.
16
  }
17
 
18
  global $job_manager;
29
  <?php } ?>
30
 
31
  <?php if ( $logo = get_the_company_logo() ) : ?>
32
+ <img src="<?php echo esc_url( $logo ); ?>" alt="<?php the_company_name(); ?>" title="<?php the_company_name(); ?> - <?php the_company_tagline(); ?>" />
33
  <?php endif; ?>
34
 
35
  <div class="job_summary_content">
templates/content-widget-job_listing.php CHANGED
@@ -8,27 +8,34 @@
8
  * @author Automattic
9
  * @package WP Job Manager
10
  * @category Template
11
- * @version 1.27.0
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
15
- exit; // Exit if accessed directly
16
  }
17
  ?>
18
  <li <?php job_listing_class(); ?>>
19
  <a href="<?php the_job_permalink(); ?>">
20
- <div class="position">
21
- <h3><?php wpjm_the_job_title(); ?></h3>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22
  </div>
23
- <ul class="meta">
24
- <li class="location"><?php the_job_location( false ); ?></li>
25
- <li class="company"><?php the_company_name(); ?></li>
26
- <?php if ( get_option( 'job_manager_enable_types' ) ) { ?>
27
- <?php $types = wpjm_get_the_job_types(); ?>
28
- <?php if ( ! empty( $types ) ) : foreach ( $types as $type ) : ?>
29
- <li class="job-type <?php echo esc_attr( sanitize_title( $type->slug ) ); ?>"><?php echo esc_html( $type->name ); ?></li>
30
- <?php endforeach; endif; ?>
31
- <?php } ?>
32
- </ul>
33
  </a>
34
  </li>
8
  * @author Automattic
9
  * @package WP Job Manager
10
  * @category Template
11
+ * @version 1.31.1
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
15
+ exit; // Exit if accessed directly.
16
  }
17
  ?>
18
  <li <?php job_listing_class(); ?>>
19
  <a href="<?php the_job_permalink(); ?>">
20
+ <?php if ( isset( $show_logo ) && $show_logo ) { ?>
21
+ <div class="image">
22
+ <?php the_company_logo(); ?>
23
+ </div>
24
+ <?php } ?>
25
+ <div class="content">
26
+ <div class="position">
27
+ <h3><?php wpjm_the_job_title(); ?></h3>
28
+ </div>
29
+ <ul class="meta">
30
+ <li class="location"><?php the_job_location( false ); ?></li>
31
+ <li class="company"><?php the_company_name(); ?></li>
32
+ <?php if ( get_option( 'job_manager_enable_types' ) ) { ?>
33
+ <?php $types = wpjm_get_the_job_types(); ?>
34
+ <?php if ( ! empty( $types ) ) : foreach ( $types as $type ) : ?>
35
+ <li class="job-type <?php echo esc_attr( sanitize_title( $type->slug ) ); ?>"><?php echo esc_html( $type->name ); ?></li>
36
+ <?php endforeach; endif; ?>
37
+ <?php } ?>
38
+ </ul>
39
  </div>
 
 
 
 
 
 
 
 
 
 
40
  </a>
41
  </li>
templates/content-widget-no-jobs-found.php CHANGED
@@ -13,7 +13,7 @@
13
  */
14
 
15
  if ( ! defined( 'ABSPATH' ) ) {
16
- exit; // Exit if accessed directly
17
  }
18
 
19
  /** Intentionally empty - override to modify the content **/
13
  */
14
 
15
  if ( ! defined( 'ABSPATH' ) ) {
16
+ exit; // Exit if accessed directly.
17
  }
18
 
19
  /** Intentionally empty - override to modify the content **/
templates/emails/admin-expiring-job.php CHANGED
@@ -8,11 +8,11 @@
8
  * @author Automattic
9
  * @package WP Job Manager
10
  * @category Template
11
- * @version 1.31.0
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
15
- exit; // Exit if accessed directly
16
  }
17
 
18
  /**
@@ -27,12 +27,12 @@ $expiring_today = $args['expiring_today'];
27
 
28
  echo '<p>';
29
  if ( $expiring_today ) {
30
- printf( __( 'The following job listing is expiring today from <a href="%s">%s</a>.', 'wp-job-manager' ), home_url(), get_bloginfo( 'name' ) );
31
  } else {
32
- printf( __( 'The following job listing is expiring soon from <a href="%s">%s</a>.', 'wp-job-manager' ), home_url(), get_bloginfo( 'name' ) );
33
  }
34
  $edit_post_link = admin_url( sprintf( 'post.php?post=%d&amp;action=edit', $job->ID ) );
35
- printf( ' ' . __( 'Visit <a href="%s">WordPress admin</a> to manage the listing.', 'wp-job-manager' ), esc_url( $edit_post_link ) );
36
  echo '</p>';
37
 
38
  /**
8
  * @author Automattic
9
  * @package WP Job Manager
10
  * @category Template
11
+ * @version 1.31.1
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
15
+ exit; // Exit if accessed directly.
16
  }
17
 
18
  /**
27
 
28
  echo '<p>';
29
  if ( $expiring_today ) {
30
+ printf( esc_html__( 'The following job listing is expiring today from <a href="%s">%s</a>.', 'wp-job-manager' ), esc_url( home_url() ), esc_html( get_bloginfo( 'name' ) ) );
31
  } else {
32
+ printf( esc_html__( 'The following job listing is expiring soon from <a href="%s">%s</a>.', 'wp-job-manager' ), esc_url( home_url() ), esc_html( get_bloginfo( 'name' ) ) );
33
  }
34
  $edit_post_link = admin_url( sprintf( 'post.php?post=%d&amp;action=edit', $job->ID ) );
35
+ printf( ' ' . esc_html__( 'Visit <a href="%s">WordPress admin</a> to manage the listing.', 'wp-job-manager' ), esc_url( $edit_post_link ) );
36
  echo '</p>';
37
 
38
  /**
templates/emails/admin-new-job.php CHANGED
@@ -8,11 +8,11 @@
8
  * @author Automattic
9
  * @package WP Job Manager
10
  * @category Template
11
- * @version 1.31.0
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
15
- exit; // Exit if accessed directly
16
  }
17
 
18
  /**
@@ -21,13 +21,24 @@ if ( ! defined( 'ABSPATH' ) ) {
21
  $job = $args['job'];
22
  ?>
23
  <p><?php
24
- printf( __( 'A new job listing has been submitted to <a href="%s">%s</a>.', 'wp-job-manager' ), home_url(), get_bloginfo( 'name' ) );
 
 
 
 
 
 
25
  switch ( $job->post_status ) {
26
  case 'publish':
27
- printf( ' ' . __( 'It has been published and is now available to the public.', 'wp-job-manager' ) );
28
  break;
29
  case 'pending':
30
- printf( ' ' . __( 'It is awaiting approval by an administrator in <a href="%s">WordPress admin</a>.', 'wp-job-manager' ), esc_url( admin_url( 'edit.php?post_type=job_listing' ) ) );
 
 
 
 
 
31
  break;
32
  }
33
  ?></p>
8
  * @author Automattic
9
  * @package WP Job Manager
10
  * @category Template
11
+ * @version 1.31.1
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
15
+ exit; // Exit if accessed directly.
16
  }
17
 
18
  /**
21
  $job = $args['job'];
22
  ?>
23
  <p><?php
24
+ echo wp_kses_post(
25
+ sprintf(
26
+ __( 'A new job listing has been submitted to <a href="%s">%s</a>.', 'wp-job-manager' ),
27
+ home_url(),
28
+ get_bloginfo( 'name' )
29
+ )
30
+ );
31
  switch ( $job->post_status ) {
32
  case 'publish':
33
+ printf( ' ' . esc_html__( 'It has been published and is now available to the public.', 'wp-job-manager' ) );
34
  break;
35
  case 'pending':
36
+ echo wp_kses_post(
37
+ sprintf(
38
+ ' ' . __( 'It is awaiting approval by an administrator in <a href="%s">WordPress admin</a>.','wp-job-manager' ),
39
+ esc_url( admin_url( 'edit.php?post_type=job_listing' ) )
40
+ )
41
+ );
42
  break;
43
  }
44
  ?></p>
templates/emails/admin-updated-job.php CHANGED
@@ -8,11 +8,11 @@
8
  * @author Automattic
9
  * @package WP Job Manager
10
  * @category Template
11
- * @version 1.31.0
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
15
- exit; // Exit if accessed directly
16
  }
17
 
18
  /**
@@ -21,13 +21,17 @@ if ( ! defined( 'ABSPATH' ) ) {
21
  $job = $args['job'];
22
  ?>
23
  <p><?php
24
- printf( __( 'A job listing has been updated on <a href="%s">%s</a>.', 'wp-job-manager' ), home_url(), get_bloginfo( 'name' ) );
 
25
  switch ( $job->post_status ) {
26
  case 'publish':
27
- printf( ' ' . __( 'The changes have been published and are now available to the public.', 'wp-job-manager' ) );
28
  break;
29
  case 'pending':
30
- printf( ' ' . __( 'The job listing is not publicly available until the changes are approved by an administrator in the site\'s <a href="%s">WordPress admin</a>.', 'wp-job-manager' ), esc_url( admin_url( 'edit.php?post_type=job_listing' ) ) );
 
 
 
31
  break;
32
  }
33
  ?></p>
8
  * @author Automattic
9
  * @package WP Job Manager
10
  * @category Template
11
+ * @version 1.31.1
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
15
+ exit; // Exit if accessed directly.
16
  }
17
 
18
  /**
21
  $job = $args['job'];
22
  ?>
23
  <p><?php
24
+ echo wp_kses_post(
25
+ sprintf( __( 'A job listing has been updated on <a href="%s">%s</a>.', 'wp-job-manager' ), home_url(), esc_html( get_bloginfo( 'name' ) ) ) );
26
  switch ( $job->post_status ) {
27
  case 'publish':
28
+ printf( ' ' . esc_html__( 'The changes have been published and are now available to the public.', 'wp-job-manager' ) );
29
  break;
30
  case 'pending':
31
+ echo wp_kses_post( sprintf(
32
+ ' ' . __( 'The job listing is not publicly available until the changes are approved by an administrator in the site\'s <a href="%s">WordPress admin</a>.', 'wp-job-manager' ),
33
+ esc_url( admin_url( 'edit.php?post_type=job_listing' ) )
34
+ ) );
35
  break;
36
  }
37
  ?></p>
templates/emails/email-footer.php CHANGED
@@ -12,7 +12,7 @@
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
15
- exit; // Exit if accessed directly
16
  }
17
  ?>
18
  </div>
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
15
+ exit; // Exit if accessed directly.
16
  }
17
  ?>
18
  </div>
templates/emails/email-header.php CHANGED
@@ -8,18 +8,18 @@
8
  * @author Automattic
9
  * @package WP Job Manager
10
  * @category Template
11
- * @version 1.31.0
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
15
- exit; // Exit if accessed directly
16
  }
17
  ?>
18
  <!DOCTYPE html>
19
  <html <?php language_attributes(); ?>>
20
  <head>
21
  <meta http-equiv="Content-Type" content="text/html; charset=<?php bloginfo( 'charset' ); ?>" />
22
- <title><?php echo get_bloginfo( 'name', 'display' ); ?></title>
23
  </head>
24
  <body <?php echo is_rtl() ? 'rightmargin' : 'leftmargin'; ?>="0" marginwidth="0" topmargin="0" marginheight="0" offset="0">
25
  <div id="wrapper" dir="<?php echo is_rtl() ? 'rtl' : 'ltr'?>">
8
  * @author Automattic
9
  * @package WP Job Manager
10
  * @category Template
11
+ * @version 1.31.1
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
15
+ exit; // Exit if accessed directly.
16
  }
17
  ?>
18
  <!DOCTYPE html>
19
  <html <?php language_attributes(); ?>>
20
  <head>
21
  <meta http-equiv="Content-Type" content="text/html; charset=<?php bloginfo( 'charset' ); ?>" />
22
+ <title><?php echo esc_html( get_bloginfo( 'name' ) ); ?></title>
23
  </head>
24
  <body <?php echo is_rtl() ? 'rightmargin' : 'leftmargin'; ?>="0" marginwidth="0" topmargin="0" marginheight="0" offset="0">
25
  <div id="wrapper" dir="<?php echo is_rtl() ? 'rtl' : 'ltr'?>">
templates/emails/email-job-details.php CHANGED
@@ -8,11 +8,11 @@
8
  * @author Automattic
9
  * @package WP Job Manager
10
  * @category Template
11
- * @version 1.31.0
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
15
- exit; // Exit if accessed directly
16
  }
17
 
18
  $text_align = is_rtl() ? 'right' : 'left';
@@ -22,10 +22,10 @@ if ( ! empty( $fields ) ) : ?>
22
  <table border="0" cellpadding="10" cellspacing="0" width="100%" class="job-manager-email-job-details details">
23
  <?php foreach ( $fields as $field ) : ?>
24
  <tr>
25
- <td class="detail-label" style="text-align:<?php echo $text_align; ?>;">
26
  <?php echo wp_kses_post( $field['label'] ); ?>
27
  </td>
28
- <td class="detail-value" style="text-align:<?php echo $text_align; ?>;">
29
  <?php
30
  if ( ! empty( $field['url'] ) ) {
31
  echo sprintf( '<a href="%s">%s</a>', esc_url( $field['url'] ), wp_kses_post( $field['value'] ) );
8
  * @author Automattic
9
  * @package WP Job Manager
10
  * @category Template
11
+ * @version 1.31.1
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
15
+ exit; // Exit if accessed directly.
16
  }
17
 
18
  $text_align = is_rtl() ? 'right' : 'left';
22
  <table border="0" cellpadding="10" cellspacing="0" width="100%" class="job-manager-email-job-details details">
23
  <?php foreach ( $fields as $field ) : ?>
24
  <tr>
25
+ <td class="detail-label" style="text-align:<?php echo esc_attr( $text_align ); ?>;">
26
  <?php echo wp_kses_post( $field['label'] ); ?>
27
  </td>
28
+ <td class="detail-value" style="text-align:<?php echo esc_attr( $text_align ); ?>;">
29
  <?php
30
  if ( ! empty( $field['url'] ) ) {
31
  echo sprintf( '<a href="%s">%s</a>', esc_url( $field['url'] ), wp_kses_post( $field['value'] ) );
templates/emails/email-styles.php CHANGED
@@ -12,7 +12,7 @@
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
15
- exit; // Exit if accessed directly
16
  }
17
 
18
  $style_vars = array();
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
15
+ exit; // Exit if accessed directly.
16
  }
17
 
18
  $style_vars = array();
templates/emails/employer-expiring-job.php CHANGED
@@ -8,11 +8,11 @@
8
  * @author Automattic
9
  * @package WP Job Manager
10
  * @category Template
11
- * @version 1.31.0
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
15
- exit; // Exit if accessed directly
16
  }
17
 
18
  /**
@@ -27,11 +27,28 @@ $expiring_today = $args['expiring_today'];
27
 
28
  echo '<p>';
29
  if ( $expiring_today ) {
30
- printf( __( 'The following job listing is expiring today from <a href="%s">%s</a>.', 'wp-job-manager' ), home_url(), get_bloginfo( 'name' ) );
 
 
 
 
 
 
31
  } else {
32
- printf( __( 'The following job listing is expiring soon from <a href="%s">%s</a>.', 'wp-job-manager' ), home_url(), get_bloginfo( 'name' ) );
 
 
 
 
 
 
33
  }
34
- printf( ' ' . __( 'Visit the <a href="%s">job listing dashboard</a> to manage the listing.', 'wp-job-manager' ), esc_url( job_manager_get_permalink( 'job_dashboard' ) ) );
 
 
 
 
 
35
  echo '</p>';
36
 
37
  /**
8
  * @author Automattic
9
  * @package WP Job Manager
10
  * @category Template
11
+ * @version 1.31.1
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
15
+ exit; // Exit if accessed directly.
16
  }
17
 
18
  /**
27
 
28
  echo '<p>';
29
  if ( $expiring_today ) {
30
+ echo wp_kses_post(
31
+ sprintf(
32
+ __( 'The following job listing is expiring today from <a href="%s">%s</a>.', 'wp-job-manager' ),
33
+ home_url(),
34
+ get_bloginfo( 'name' )
35
+ )
36
+ );
37
  } else {
38
+ echo wp_kses_post(
39
+ sprintf(
40
+ __( 'The following job listing is expiring soon from <a href="%s">%s</a>.', 'wp-job-manager' ),
41
+ home_url(),
42
+ get_bloginfo( 'name' )
43
+ )
44
+ );
45
  }
46
+ echo wp_kses_post(
47
+ sprintf(
48
+ ' ' . __( 'Visit the <a href="%s">job listing dashboard</a> to manage the listing.', 'wp-job-manager' ),
49
+ esc_url( job_manager_get_permalink( 'job_dashboard' ) )
50
+ )
51
+ );
52
  echo '</p>';
53
 
54
  /**
templates/emails/plain/admin-expiring-job.php CHANGED
@@ -8,11 +8,11 @@
8
  * @author Automattic
9
  * @package WP Job Manager
10
  * @category Template
11
- * @version 1.31.0
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
15
- exit; // Exit if accessed directly
16
  }
17
 
18
  /**
@@ -26,12 +26,23 @@ $job = $args['job'];
26
  $expiring_today = $args['expiring_today'];
27
 
28
  if ( $expiring_today ) {
29
- printf( __( 'The following job listing is expiring today from %s (%s).', 'wp-job-manager' ), get_bloginfo( 'name' ), home_url() );
 
 
 
 
30
  } else {
31
- printf( __( 'The following job listing is expiring soon from %s (%s).', 'wp-job-manager' ), get_bloginfo( 'name' ), home_url() );
 
 
 
 
32
  }
33
  $edit_post_link = admin_url( sprintf( 'post.php?post=%d&amp;action=edit', $job->ID ) );
34
- printf( ' ' . __( 'Visit WordPress admin (%s) to manage the listing.', 'wp-job-manager' ), esc_url( $edit_post_link ) );
 
 
 
35
 
36
  /**
37
  * Show details about the job listing.
8
  * @author Automattic
9
  * @package WP Job Manager
10
  * @category Template
11
+ * @version 1.31.1
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
15
+ exit; // Exit if accessed directly.
16
  }
17
 
18
  /**
26
  $expiring_today = $args['expiring_today'];
27
 
28
  if ( $expiring_today ) {
29
+ printf(
30
+ esc_html__( 'The following job listing is expiring today from %s (%s).', 'wp-job-manager' ),
31
+ esc_html( get_bloginfo( 'name' ) ),
32
+ esc_url( home_url() )
33
+ );
34
  } else {
35
+ printf(
36
+ esc_html__( 'The following job listing is expiring soon from %s (%s).', 'wp-job-manager' ),
37
+ esc_html( get_bloginfo( 'name' ) ),
38
+ esc_url( home_url() )
39
+ );
40
  }
41
  $edit_post_link = admin_url( sprintf( 'post.php?post=%d&amp;action=edit', $job->ID ) );
42
+ printf(
43
+ ' ' . esc_html__( 'Visit WordPress admin (%s) to manage the listing.', 'wp-job-manager' ),
44
+ esc_url( $edit_post_link )
45
+ );
46
 
47
  /**
48
  * Show details about the job listing.
templates/emails/plain/admin-new-job.php CHANGED
@@ -8,11 +8,11 @@
8
  * @author Automattic
9
  * @package WP Job Manager
10
  * @category Template
11
- * @version 1.31.0
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
15
- exit; // Exit if accessed directly
16
  }
17
 
18
  /**
@@ -20,13 +20,13 @@ if ( ! defined( 'ABSPATH' ) ) {
20
  */
21
  $job = $args['job'];
22
 
23
- printf( __( 'A new job listing has been submitted to %s (%s).', 'wp-job-manager' ), get_bloginfo( 'name' ), home_url() );
24
  switch ( $job->post_status ) {
25
  case 'publish':
26
- printf( ' ' . __( 'It has been published and is now available to the public.', 'wp-job-manager' ) );
27
  break;
28
  case 'pending':
29
- printf( ' ' . __( 'It is awaiting approval by an administrator in WordPress admin (%s).', 'wp-job-manager' ), esc_url( admin_url( 'edit.php?post_type=job_listing' ) ) );
30
  break;
31
  }
32
 
8
  * @author Automattic
9
  * @package WP Job Manager
10
  * @category Template
11
+ * @version 1.31.1
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
15
+ exit; // Exit if accessed directly.
16
  }
17
 
18
  /**
20
  */
21
  $job = $args['job'];
22
 
23
+ printf( esc_html__( 'A new job listing has been submitted to %s (%s).', 'wp-job-manager' ), esc_html( get_bloginfo( 'name' ) ), esc_url( home_url() ) );
24
  switch ( $job->post_status ) {
25
  case 'publish':
26
+ printf( ' ' . esc_html__( 'It has been published and is now available to the public.', 'wp-job-manager' ) );
27
  break;
28
  case 'pending':
29
+ printf( ' ' . esc_html__( 'It is awaiting approval by an administrator in WordPress admin (%s).', 'wp-job-manager' ), esc_url( admin_url( 'edit.php?post_type=job_listing' ) ) );
30
  break;
31
  }
32
 
templates/emails/plain/admin-updated-job.php CHANGED
@@ -8,11 +8,11 @@
8
  * @author Automattic
9
  * @package WP Job Manager
10
  * @category Template
11
- * @version 1.31.0
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
15
- exit; // Exit if accessed directly
16
  }
17
 
18
  /**
@@ -20,13 +20,13 @@ if ( ! defined( 'ABSPATH' ) ) {
20
  */
21
  $job = $args['job'];
22
 
23
- printf( __( 'A job listing has been updated on %s (%s).', 'wp-job-manager' ), get_bloginfo( 'name' ), home_url() );
24
  switch ( $job->post_status ) {
25
  case 'publish':
26
- printf( ' ' . __( 'The changes have been published and are now available to the public.', 'wp-job-manager' ) );
27
  break;
28
  case 'pending':
29
- printf( ' ' . __( 'The job listing is not publicly available until the changes are approved by an administrator in the site\'s WordPress admin (%s).', 'wp-job-manager' ), esc_url( admin_url( 'edit.php?post_type=job_listing' ) ) );
30
  break;
31
  }
32
 
8
  * @author Automattic
9
  * @package WP Job Manager
10
  * @category Template
11
+ * @version 1.31.1
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
15
+ exit; // Exit if accessed directly.
16
  }
17
 
18
  /**
20
  */
21
  $job = $args['job'];
22
 
23
+ printf( esc_html__( 'A job listing has been updated on %s (%s).', 'wp-job-manager' ), esc_html( get_bloginfo( 'name' ) ), esc_url( home_url() ) );
24
  switch ( $job->post_status ) {
25
  case 'publish':
26
+ printf( ' ' . esc_html__( 'The changes have been published and are now available to the public.', 'wp-job-manager' ) );
27
  break;
28
  case 'pending':
29
+ printf( ' ' . esc_html__( 'The job listing is not publicly available until the changes are approved by an administrator in the site\'s WordPress admin (%s).', 'wp-job-manager' ), esc_url( admin_url( 'edit.php?post_type=job_listing' ) ) );
30
  break;
31
  }
32
 
templates/emails/plain/email-footer.php CHANGED
@@ -12,6 +12,5 @@
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
15
- exit; // Exit if accessed directly
16
  }
17
- ?>
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
15
+ exit; // Exit if accessed directly.
16
  }
 
templates/emails/plain/email-header.php CHANGED
@@ -12,6 +12,5 @@
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
15
- exit; // Exit if accessed directly
16
  }
17
- ?>
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
15
+ exit; // Exit if accessed directly.
16
  }
 
templates/emails/plain/email-job-details.php CHANGED
@@ -8,18 +8,18 @@
8
  * @author Automattic
9
  * @package WP Job Manager
10
  * @category Template
11
- * @version 1.31.0
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
15
- exit; // Exit if accessed directly
16
  }
17
 
18
  echo "\n\n";
19
 
20
  if ( ! empty( $fields ) ) {
21
  foreach ( $fields as $field ) {
22
- echo strip_tags( $field[ 'label' ] ) .': '. strip_tags( $field[ 'value' ] );
23
  if ( ! empty( $field['url'] ) ) {
24
  echo ' (' . esc_url( $field['url'] ) . ')';
25
  }
8
  * @author Automattic
9
  * @package WP Job Manager
10
  * @category Template
11
+ * @version 1.31.1
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
15
+ exit; // Exit if accessed directly.
16
  }
17
 
18
  echo "\n\n";
19
 
20
  if ( ! empty( $fields ) ) {
21
  foreach ( $fields as $field ) {
22
+ echo esc_html( wp_strip_all_tags( $field[ 'label' ] ) .': '. wp_strip_all_tags( $field[ 'value' ] ) );
23
  if ( ! empty( $field['url'] ) ) {
24
  echo ' (' . esc_url( $field['url'] ) . ')';
25
  }
templates/emails/plain/employer-expiring-job.php CHANGED
@@ -8,11 +8,11 @@
8
  * @author Automattic
9
  * @package WP Job Manager
10
  * @category Template
11
- * @version 1.31.0
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
15
- exit; // Exit if accessed directly
16
  }
17
 
18
  /**
@@ -26,11 +26,11 @@ $job = $args['job'];
26
  $expiring_today = $args['expiring_today'];
27
 
28
  if ( $expiring_today ) {
29
- printf( __( 'The following job listing is expiring today from %s (%s).', 'wp-job-manager' ), get_bloginfo( 'name' ), home_url() );
30
  } else {
31
- printf( __( 'The following job listing is expiring soon from %s (%s).', 'wp-job-manager' ), get_bloginfo( 'name' ), home_url() );
32
  }
33
- printf( ' ' . __( 'Visit the job listing dashboard (%s) to manage the listing.', 'wp-job-manager' ), esc_url( job_manager_get_permalink( 'job_dashboard' ) ) );
34
 
35
  /**
36
  * Show details about the job listing.
8
  * @author Automattic
9
  * @package WP Job Manager
10
  * @category Template
11
+ * @version 1.31.1
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
15
+ exit; // Exit if accessed directly.
16
  }
17
 
18
  /**
26
  $expiring_today = $args['expiring_today'];
27
 
28
  if ( $expiring_today ) {
29
+ printf( esc_html__( 'The following job listing is expiring today from %s (%s).', 'wp-job-manager' ), esc_html( get_bloginfo( 'name' ) ), esc_url( home_url() ) );
30
  } else {
31
+ printf( esc_html__( 'The following job listing is expiring soon from %s (%s).', 'wp-job-manager' ), esc_html( get_bloginfo( 'name' ) ), esc_url( home_url() ) );
32
  }
33
+ printf( ' ' . esc_html__( 'Visit the job listing dashboard (%s) to manage the listing.', 'wp-job-manager' ), esc_url( job_manager_get_permalink( 'job_dashboard' ) ) );
34
 
35
  /**
36
  * Show details about the job listing.
templates/form-fields/checkbox-field.php CHANGED
@@ -8,12 +8,12 @@
8
  * @author Automattic
9
  * @package WP Job Manager
10
  * @category Template
11
- * @version 1.21.0
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
15
- exit; // Exit if accessed directly
16
  }
17
  ?>
18
  <input type="checkbox" class="input-checkbox" name="<?php echo esc_attr( isset( $field['name'] ) ? $field['name'] : $key ); ?>" id="<?php echo esc_attr( $key ); ?>" <?php checked( ! empty( $field['value'] ), true ); ?> value="1" <?php if ( ! empty( $field['required'] ) ) echo 'required'; ?> />
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.31.1
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
15
+ exit; // Exit if accessed directly.
16
  }
17
  ?>
18
  <input type="checkbox" class="input-checkbox" name="<?php echo esc_attr( isset( $field['name'] ) ? $field['name'] : $key ); ?>" id="<?php echo esc_attr( $key ); ?>" <?php checked( ! empty( $field['value'] ), true ); ?> value="1" <?php if ( ! empty( $field['required'] ) ) echo 'required'; ?> />
19
+ <?php if ( ! empty( $field['description'] ) ) : ?><small class="description"><?php echo wp_kses_post( $field['description'] ); ?></small><?php endif; ?>
templates/form-fields/date-field.php CHANGED
@@ -8,11 +8,11 @@
8
  * @author Automattic
9
  * @package WP Job Manager
10
  * @category Template
11
- * @version 1.30.2
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
15
- exit; // Exit if accessed directly
16
  }
17
 
18
  wp_enqueue_script( 'wp-job-manager-datepicker' );
@@ -20,4 +20,4 @@ wp_enqueue_style( 'jquery-ui' );
20
 
21
  ?>
22
  <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'; ?> />
23
- <?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.31.1
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
15
+ exit; // Exit if accessed directly.
16
  }
17
 
18
  wp_enqueue_script( 'wp-job-manager-datepicker' );
20
 
21
  ?>
22
  <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'; ?> />
23
+ <?php if ( ! empty( $field['description'] ) ) : ?><small class="description"><?php echo wp_kses_post( $field['description'] ); ?></small><?php endif; ?>
templates/form-fields/file-field.php CHANGED
@@ -8,11 +8,11 @@
8
  * @author Automattic
9
  * @package WP Job Manager
10
  * @category Template
11
- * @version 1.27.0
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
15
- exit; // Exit if accessed directly
16
  }
17
 
18
  $classes = array( 'input-text' );
@@ -40,8 +40,8 @@ if ( ! empty( $field['ajax'] ) && job_manager_user_can_upload_file_via_ajax() )
40
  <input type="file" class="<?php echo esc_attr( implode( ' ', $classes ) ); ?>" data-file_types="<?php echo esc_attr( implode( '|', $allowed_mime_types ) ); ?>" <?php if ( ! empty( $field['multiple'] ) ) echo 'multiple'; ?> name="<?php echo esc_attr( isset( $field['name'] ) ? $field['name'] : $key ); ?><?php if ( ! empty( $field['multiple'] ) ) echo '[]'; ?>" id="<?php echo esc_attr( $key ); ?>" placeholder="<?php echo empty( $field['placeholder'] ) ? '' : esc_attr( $field['placeholder'] ); ?>" />
41
  <small class="description">
42
  <?php if ( ! empty( $field['description'] ) ) : ?>
43
- <?php echo $field['description']; ?>
44
  <?php else : ?>
45
- <?php printf( __( 'Maximum file size: %s.', 'wp-job-manager' ), size_format( wp_max_upload_size() ) ); ?>
46
  <?php endif; ?>
47
  </small>
8
  * @author Automattic
9
  * @package WP Job Manager
10
  * @category Template
11
+ * @version 1.31.1
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
15
+ exit; // Exit if accessed directly.
16
  }
17
 
18
  $classes = array( 'input-text' );
40
  <input type="file" class="<?php echo esc_attr( implode( ' ', $classes ) ); ?>" data-file_types="<?php echo esc_attr( implode( '|', $allowed_mime_types ) ); ?>" <?php if ( ! empty( $field['multiple'] ) ) echo 'multiple'; ?> name="<?php echo esc_attr( isset( $field['name'] ) ? $field['name'] : $key ); ?><?php if ( ! empty( $field['multiple'] ) ) echo '[]'; ?>" id="<?php echo esc_attr( $key ); ?>" placeholder="<?php echo empty( $field['placeholder'] ) ? '' : esc_attr( $field['placeholder'] ); ?>" />
41
  <small class="description">
42
  <?php if ( ! empty( $field['description'] ) ) : ?>
43
+ <?php echo wp_kses_post( $field['description'] ); ?>
44
  <?php else : ?>
45
+ <?php printf( esc_html__( 'Maximum file size: %s.', 'wp-job-manager' ), size_format( wp_max_upload_size() ) ); ?>
46
  <?php endif; ?>
47
  </small>
templates/form-fields/multiselect-field.php CHANGED
@@ -8,18 +8,18 @@
8
  * @author Automattic
9
  * @package WP Job Manager
10
  * @category Template
11
- * @version 1.23.7
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
15
- exit; // Exit if accessed directly
16
  }
17
 
18
  wp_enqueue_script( 'wp-job-manager-multiselect' );
19
  ?>
20
- <select multiple="multiple" name="<?php echo esc_attr( isset( $field['name'] ) ? $field['name'] : $key ); ?>[]" id="<?php echo esc_attr( $key ); ?>" class="job-manager-multiselect" <?php if ( ! empty( $field['required'] ) ) echo 'required'; ?> data-no_results_text="<?php _e( 'No results match', 'wp-job-manager' ); ?>" data-multiple_text="<?php _e( 'Select Some Options', 'wp-job-manager' ); ?>">
21
  <?php foreach ( $field['options'] as $key => $value ) : ?>
22
  <option value="<?php echo esc_attr( $key ); ?>" <?php if ( ! empty( $field['value'] ) && is_array( $field['value'] ) ) selected( in_array( $key, $field['value'] ), true ); ?>><?php echo esc_html( $value ); ?></option>
23
  <?php endforeach; ?>
24
  </select>
25
- <?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.31.1
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
15
+ exit; // Exit if accessed directly.
16
  }
17
 
18
  wp_enqueue_script( 'wp-job-manager-multiselect' );
19
  ?>
20
+ <select multiple="multiple" name="<?php echo esc_attr( isset( $field['name'] ) ? $field['name'] : $key ); ?>[]" id="<?php echo esc_attr( $key ); ?>" class="job-manager-multiselect" <?php if ( ! empty( $field['required'] ) ) echo 'required'; ?> data-no_results_text="<?php esc_attr_e( 'No results match', 'wp-job-manager' ); ?>" data-multiple_text="<?php esc_attr_e( 'Select Some Options', 'wp-job-manager' ); ?>">
21
  <?php foreach ( $field['options'] as $key => $value ) : ?>
22
  <option value="<?php echo esc_attr( $key ); ?>" <?php if ( ! empty( $field['value'] ) && is_array( $field['value'] ) ) selected( in_array( $key, $field['value'] ), true ); ?>><?php echo esc_html( $value ); ?></option>
23
  <?php endforeach; ?>
24
  </select>
25
+ <?php if ( ! empty( $field['description'] ) ) : ?><small class="description"><?php echo wp_kses_post( $field['description'] ); ?></small><?php endif; ?>
templates/form-fields/password-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
- <input type="password" class="input-text"<?php if ( isset( $field['autocomplete'] ) && false === $field['autocomplete'] ) { echo ' autocomplete="off"'; } ?> 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'] ); ?>" value="<?php echo isset( $field['value'] ) ? esc_attr( $field['value'] ) : ''; ?>" maxlength="<?php echo ! empty( $field['maxlength'] ) ? $field['maxlength'] : ''; ?>" <?php if ( ! empty( $field['required'] ) ) echo 'required'; ?> />
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.31.1
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
15
+ exit; // Exit if accessed directly.
16
  }
17
  ?>
18
+ <input type="password" class="input-text"<?php if ( isset( $field['autocomplete'] ) && false === $field['autocomplete'] ) { echo ' autocomplete="off"'; } ?> 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'] ); ?>" value="<?php echo isset( $field['value'] ) ? esc_attr( $field['value'] ) : ''; ?>" maxlength="<?php echo esc_attr( ! empty( $field['maxlength'] ) ? $field['maxlength'] : '' ); ?>" <?php if ( ! empty( $field['required'] ) ) echo 'required'; ?> />
19
+ <?php if ( ! empty( $field['description'] ) ) : ?><small class="description"><?php echo wp_kses_post( $field['description'] ); ?></small><?php endif; ?>
templates/form-fields/radio-field.php CHANGED
@@ -22,11 +22,11 @@
22
  * @author Automattic
23
  * @package WP Job Manager
24
  * @category Template
25
- * @version 1.23.0
26
  */
27
 
28
  if ( ! defined( 'ABSPATH' ) ) {
29
- exit; // Exit if accessed directly
30
  }
31
 
32
  $field['default'] = empty( $field['default'] ) ? current( array_keys( $field['options'] ) ) : $field['default'];
@@ -37,4 +37,4 @@ foreach ( $field['options'] as $option_key => $value ) : ?>
37
  <label><input type="radio" name="<?php echo esc_attr( isset( $field['name'] ) ? $field['name'] : $key ); ?>" value="<?php echo esc_attr( $option_key ); ?>" <?php checked( $default, $option_key ); ?> /> <?php echo esc_html( $value ); ?></label><br/>
38
 
39
  <?php endforeach; ?>
40
- <?php if ( ! empty( $field['description'] ) ) : ?><small class="description"><?php echo $field['description']; ?></small><?php endif; ?>
22
  * @author Automattic
23
  * @package WP Job Manager
24
  * @category Template
25
+ * @version 1.31.1
26
  */
27
 
28
  if ( ! defined( 'ABSPATH' ) ) {
29
+ exit; // Exit if accessed directly.
30
  }
31
 
32
  $field['default'] = empty( $field['default'] ) ? current( array_keys( $field['options'] ) ) : $field['default'];
37
  <label><input type="radio" name="<?php echo esc_attr( isset( $field['name'] ) ? $field['name'] : $key ); ?>" value="<?php echo esc_attr( $option_key ); ?>" <?php checked( $default, $option_key ); ?> /> <?php echo esc_html( $value ); ?></label><br/>
38
 
39
  <?php endforeach; ?>
40
+ <?php if ( ! empty( $field['description'] ) ) : ?><small class="description"><?php echo wp_kses_post( $field['description'] ); ?></small><?php endif; ?>
templates/form-fields/recaptcha-field.php CHANGED
@@ -8,17 +8,17 @@
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>
8
  * @author Automattic
9
  * @package WP Job Manager
10
  * @category Template
11
+ * @version 1.31.1
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 esc_html( $field['label'] ); ?></label>
20
  <div class="field <?php echo $field['required'] ? 'required-field' : ''; ?>">
21
+ <div class="g-recaptcha" data-sitekey="<?php echo esc_attr( $field['site_key'] ); ?>"></div>
22
+ <?php if ( ! empty( $field['description'] ) ) : ?><small class="description"><?php echo wp_kses_post( $field['description'] ); ?></small><?php endif; ?>
23
  </div>
24
  </fieldset>
templates/form-fields/select-field.php CHANGED
@@ -8,11 +8,11 @@
8
  * @author Automattic
9
  * @package WP Job Manager
10
  * @category Template
11
- * @version 1.19.0
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
15
- exit; // Exit if accessed directly
16
  }
17
  ?>
18
  <select name="<?php echo esc_attr( isset( $field['name'] ) ? $field['name'] : $key ); ?>" id="<?php echo esc_attr( $key ); ?>" <?php if ( ! empty( $field['required'] ) ) echo 'required'; ?>>
@@ -20,4 +20,4 @@ if ( ! defined( 'ABSPATH' ) ) {
20
  <option value="<?php echo esc_attr( $key ); ?>" <?php if ( isset( $field['value'] ) || isset( $field['default'] ) ) selected( isset( $field['value'] ) ? $field['value'] : $field['default'], $key ); ?>><?php echo esc_html( $value ); ?></option>
21
  <?php endforeach; ?>
22
  </select>
23
- <?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.31.1
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
15
+ exit; // Exit if accessed directly.
16
  }
17
  ?>
18
  <select name="<?php echo esc_attr( isset( $field['name'] ) ? $field['name'] : $key ); ?>" id="<?php echo esc_attr( $key ); ?>" <?php if ( ! empty( $field['required'] ) ) echo 'required'; ?>>
20
  <option value="<?php echo esc_attr( $key ); ?>" <?php if ( isset( $field['value'] ) || isset( $field['default'] ) ) selected( isset( $field['value'] ) ? $field['value'] : $field['default'], $key ); ?>><?php echo esc_html( $value ); ?></option>
21
  <?php endforeach; ?>
22
  </select>
23
+ <?php if ( ! empty( $field['description'] ) ) : ?><small class="description"><?php echo wp_kses_post( $field['description'] ); ?></small><?php endif; ?>
templates/form-fields/term-checklist-field.php CHANGED
@@ -8,14 +8,14 @@
8
  * @author Automattic
9
  * @package WP Job Manager
10
  * @category Template
11
- * @version 1.22.0
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
15
- exit; // Exit if accessed directly
16
  }
17
  ?>
18
- <ul class="job-manager-term-checklist job-manager-term-checklist-<?php echo $key ?>">
19
  <?php
20
  require_once( ABSPATH . '/wp-admin/includes/template.php' );
21
 
@@ -31,11 +31,11 @@ if ( ! defined( 'ABSPATH' ) ) {
31
  'checked_ontop' => false
32
  );
33
 
34
- // $field['post_id'] needs to be passed via the args so we can get the existing terms
35
  ob_start();
36
  wp_terms_checklist( 0, $args );
37
  $checklist = ob_get_clean();
38
  echo str_replace( "disabled='disabled'", '', $checklist );
39
  ?>
40
  </ul>
41
- <?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.31.1
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
15
+ exit; // Exit if accessed directly.
16
  }
17
  ?>
18
+ <ul class="job-manager-term-checklist job-manager-term-checklist-<?php echo esc_attr( $key ); ?>">
19
  <?php
20
  require_once( ABSPATH . '/wp-admin/includes/template.php' );
21
 
31
  'checked_ontop' => false
32
  );
33
 
34
+ // $field['post_id'] needs to be passed via the args so we can get the existing terms.
35
  ob_start();
36
  wp_terms_checklist( 0, $args );
37
  $checklist = ob_get_clean();
38
  echo str_replace( "disabled='disabled'", '', $checklist );
39
  ?>
40
  </ul>
41
+ <?php if ( ! empty( $field['description'] ) ) : ?><small class="description"><?php echo wp_kses_post( $field['description'] ); ?></small><?php endif; ?>
templates/form-fields/term-multiselect-field.php CHANGED
@@ -8,14 +8,14 @@
8
  * @author Automattic
9
  * @package WP Job Manager
10
  * @category Template
11
- * @version 1.22.2
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
15
- exit; // Exit if accessed directly
16
  }
17
 
18
- // Get selected value
19
  if ( isset( $field['value'] ) ) {
20
  $selected = $field['value'];
21
  } elseif ( ! empty( $field['default'] ) && is_int( $field['default'] ) ) {
@@ -41,4 +41,4 @@ if ( isset( $field['placeholder'] ) && ! empty( $field['placeholder'] ) ) $args[
41
 
42
  job_manager_dropdown_categories( apply_filters( 'job_manager_term_multiselect_field_args', $args ) );
43
 
44
- 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.31.1
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
15
+ exit; // Exit if accessed directly.
16
  }
17
 
18
+ // Get selected value.
19
  if ( isset( $field['value'] ) ) {
20
  $selected = $field['value'];
21
  } elseif ( ! empty( $field['default'] ) && is_int( $field['default'] ) ) {
41
 
42
  job_manager_dropdown_categories( apply_filters( 'job_manager_term_multiselect_field_args', $args ) );
43
 
44
+ if ( ! empty( $field['description'] ) ) : ?><small class="description"><?php echo wp_kses_post( $field['description'] ); ?></small><?php endif; ?>
templates/form-fields/term-select-field.php CHANGED
@@ -8,14 +8,14 @@
8
  * @author Automattic
9
  * @package WP Job Manager
10
  * @category Template
11
- * @version 1.27.0
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
15
- exit; // Exit if accessed directly
16
  }
17
 
18
- // Get selected value
19
  if ( isset( $field['value'] ) ) {
20
  $selected = $field['value'];
21
  } elseif ( is_int( $field['default'] ) ) {
@@ -26,7 +26,7 @@ if ( isset( $field['value'] ) ) {
26
  $selected = '';
27
  }
28
 
29
- // Select only supports 1 value
30
  if ( is_array( $selected ) ) {
31
  $selected = current( $selected );
32
  }
@@ -41,4 +41,4 @@ wp_dropdown_categories( apply_filters( 'job_manager_term_select_field_wp_dropdow
41
  'selected' => $selected,
42
  'hide_empty' => false
43
  ), $key, $field ) );
44
- 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.31.1
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
15
+ exit; // Exit if accessed directly.
16
  }
17
 
18
+ // Get selected value.
19
  if ( isset( $field['value'] ) ) {
20
  $selected = $field['value'];
21
  } elseif ( is_int( $field['default'] ) ) {
26
  $selected = '';
27
  }
28
 
29
+ // Select only supports 1 value.
30
  if ( is_array( $selected ) ) {
31
  $selected = current( $selected );
32
  }
41
  'selected' => $selected,
42
  'hide_empty' => false
43
  ), $key, $field ) );
44
+ if ( ! empty( $field['description'] ) ) : ?><small class="description"><?php echo wp_kses_post( $field['description'] ); ?></small><?php endif; ?>
templates/form-fields/text-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
- <input type="text" class="input-text" 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'] ) : ''; ?>" maxlength="<?php echo ! empty( $field['maxlength'] ) ? $field['maxlength'] : ''; ?>" <?php if ( ! empty( $field['required'] ) ) echo 'required'; ?> />
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.31.1
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
15
+ exit; // Exit if accessed directly.
16
  }
17
  ?>
18
+ <input type="text" class="input-text" 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'] ) : ''; ?>" maxlength="<?php echo esc_attr( ! empty( $field['maxlength'] ) ? $field['maxlength'] : '' ); ?>" <?php if ( ! empty( $field['required'] ) ) echo 'required'; ?> />
19
+ <?php if ( ! empty( $field['description'] ) ) : ?><small class="description"><?php echo wp_kses_post( $field['description'] ); ?></small><?php endif; ?>
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.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; ?>
8
  * @author Automattic
9
  * @package WP Job Manager
10
  * @category Template
11
+ * @version 1.31.1
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 esc_attr( ! 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 wp_kses_post( $field['description'] ); ?></small><?php endif; ?>
templates/form-fields/uploaded-file-html.php CHANGED
@@ -12,7 +12,7 @@
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
15
- exit; // Exit if accessed directly
16
  }
17
  ?>
18
  <div class="job-manager-uploaded-file">
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
15
+ exit; // Exit if accessed directly.
16
  }
17
  ?>
18
  <div class="job-manager-uploaded-file">
templates/form-fields/wp-editor-field.php CHANGED
@@ -8,11 +8,11 @@
8
  * @author Automattic
9
  * @package WP Job Manager
10
  * @category Template
11
- * @version 1.23.9
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
15
- exit; // Exit if accessed directly
16
  }
17
 
18
  $editor = apply_filters( 'submit_job_form_wp_editor_args', array(
@@ -35,4 +35,4 @@ $editor = apply_filters( 'submit_job_form_wp_editor_args', array(
35
  ),
36
  ) );
37
  wp_editor( isset( $field['value'] ) ? wp_kses_post( $field['value'] ) : '', $key, $editor );
38
- 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.31.1
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
15
+ exit; // Exit if accessed directly.
16
  }
17
 
18
  $editor = apply_filters( 'submit_job_form_wp_editor_args', array(
35
  ),
36
  ) );
37
  wp_editor( isset( $field['value'] ) ? wp_kses_post( $field['value'] ) : '', $key, $editor );
38
+ if ( ! empty( $field['description'] ) ) : ?><small class="description"><?php echo wp_kses_post( $field['description'] ); ?></small><?php endif; ?>
templates/job-application-email.php CHANGED
@@ -8,11 +8,11 @@
8
  * @author Automattic
9
  * @package WP Job Manager
10
  * @category Template
11
- * @version 1.9.0
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
15
- exit; // Exit if accessed directly
16
  }
17
  ?>
18
- <p><?php printf( __( 'To apply for this job <strong>email your details to</strong> <a class="job_application_email" href="mailto:%1$s%2$s">%1$s</a>', 'wp-job-manager' ), $apply->email, '?subject=' . rawurlencode( $apply->subject ) ); ?></p>
8
  * @author Automattic
9
  * @package WP Job Manager
10
  * @category Template
11
+ * @version 1.31.1
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
15
+ exit; // Exit if accessed directly.
16
  }
17
  ?>
18
+ <p><?php printf( wp_kses_post( __( 'To apply for this job <strong>email your details to</strong> <a class="job_application_email" href="mailto:%1$s%2$s">%1$s</a>', 'wp-job-manager' ) ), esc_html( $apply->email ), '?subject=' . rawurlencode( $apply->subject ) ); ?></p>
templates/job-application-url.php CHANGED
@@ -12,7 +12,7 @@
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
15
- exit; // Exit if accessed directly
16
  }
17
  ?>
18
  <p><?php esc_html_e( 'To apply for this job please visit', 'wp-job-manager' ); ?> <a href="<?php echo esc_url( $apply->url ); ?>" target="_blank" rel="nofollow"><?php echo esc_html( wp_parse_url( $apply->url, PHP_URL_HOST ) ); ?></a>.</p>
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
15
+ exit; // Exit if accessed directly.
16
  }
17
  ?>
18
  <p><?php esc_html_e( 'To apply for this job please visit', 'wp-job-manager' ); ?> <a href="<?php echo esc_url( $apply->url ); ?>" target="_blank" rel="nofollow"><?php echo esc_html( wp_parse_url( $apply->url, PHP_URL_HOST ) ); ?></a>.</p>
templates/job-application.php CHANGED
@@ -8,11 +8,11 @@
8
  * @author Automattic
9
  * @package WP Job Manager
10
  * @category Template
11
- * @version 1.16.1
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
15
- exit; // Exit if accessed directly
16
  }
17
  ?>
18
  <?php if ( $apply = get_the_job_application_method() ) :
@@ -20,9 +20,9 @@ if ( ! defined( 'ABSPATH' ) ) {
20
  ?>
21
  <div class="job_application application">
22
  <?php do_action( 'job_application_start', $apply ); ?>
23
-
24
- <input type="button" class="application_button button" value="<?php _e( 'Apply for job', 'wp-job-manager' ); ?>" />
25
-
26
  <div class="application_details">
27
  <?php
28
  /**
8
  * @author Automattic
9
  * @package WP Job Manager
10
  * @category Template
11
+ * @version 1.31.1
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
15
+ exit; // Exit if accessed directly.
16
  }
17
  ?>
18
  <?php if ( $apply = get_the_job_application_method() ) :
20
  ?>
21
  <div class="job_application application">
22
  <?php do_action( 'job_application_start', $apply ); ?>
23
+
24
+ <input type="button" class="application_button button" value="<?php esc_attr_e( 'Apply for job', 'wp-job-manager' ); ?>" />
25
+
26
  <div class="application_details">
27
  <?php
28
  /**
templates/job-dashboard-login.php CHANGED
@@ -8,15 +8,15 @@
8
  * @author Automattic
9
  * @package WP Job Manager
10
  * @category Template
11
- * @version 1.19.0
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
15
- exit; // Exit if accessed directly
16
  }
17
  ?>
18
  <div id="job-manager-job-dashboard">
19
 
20
- <p class="account-sign-in"><?php _e( 'You need to be signed in to manage your listings.', 'wp-job-manager' ); ?> <a class="button" href="<?php echo apply_filters( 'job_manager_job_dashboard_login_url', wp_login_url( get_permalink() ) ); ?>"><?php _e( 'Sign in', 'wp-job-manager' ); ?></a></p>
21
 
22
- </div>
8
  * @author Automattic
9
  * @package WP Job Manager
10
  * @category Template
11
+ * @version 1.31.1
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
15
+ exit; // Exit if accessed directly.
16
  }
17
  ?>
18
  <div id="job-manager-job-dashboard">
19
 
20
+ <p class="account-sign-in"><?php esc_html_e( 'You need to be signed in to manage your listings.', 'wp-job-manager' ); ?> <a class="button" href="<?php echo esc_url( apply_filters( 'job_manager_job_dashboard_login_url', wp_login_url( get_permalink() ) ) ); ?>"><?php esc_html_e( 'Sign in', 'wp-job-manager' ); ?></a></p>
21
 
22
+ </div>
templates/job-dashboard.php CHANGED
@@ -8,15 +8,15 @@
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
  <div id="job-manager-job-dashboard">
19
- <p><?php _e( 'Your listings are shown in the table below.', 'wp-job-manager' ); ?></p>
20
  <table class="job-manager-jobs">
21
  <thead>
22
  <tr>
@@ -28,7 +28,7 @@ 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 ) : ?>
@@ -37,7 +37,7 @@ if ( ! defined( 'ABSPATH' ) ) {
37
  <td class="<?php echo esc_attr( $key ); ?>">
38
  <?php if ('job_title' === $key ) : ?>
39
  <?php if ( $job->post_status == 'publish' ) : ?>
40
- <a href="<?php echo get_permalink( $job->ID ); ?>"><?php wpjm_the_job_title( $job ); ?></a>
41
  <?php else : ?>
42
  <?php wpjm_the_job_title( $job ); ?> <small>(<?php the_job_status( $job ); ?>)</small>
43
  <?php endif; ?>
@@ -85,9 +85,9 @@ if ( ! defined( 'ABSPATH' ) ) {
85
  ?>
86
  </ul>
87
  <?php elseif ('date' === $key ) : ?>
88
- <?php echo date_i18n( get_option( 'date_format' ), strtotime( $job->post_date ) ); ?>
89
  <?php elseif ('expires' === $key ) : ?>
90
- <?php echo $job->_job_expires ? date_i18n( get_option( 'date_format' ), strtotime( $job->_job_expires ) ) : '&ndash;'; ?>
91
  <?php elseif ('filled' === $key ) : ?>
92
  <?php echo is_position_filled( $job ) ? '&#10004;' : '&ndash;'; ?>
93
  <?php else : ?>
8
  * @author Automattic
9
  * @package WP Job Manager
10
  * @category Template
11
+ * @version 1.31.1
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
15
+ exit; // Exit if accessed directly.
16
  }
17
  ?>
18
  <div id="job-manager-job-dashboard">
19
+ <p><?php esc_html_e( 'Your listings are shown in the table below.', 'wp-job-manager' ); ?></p>
20
  <table class="job-manager-jobs">
21
  <thead>
22
  <tr>
28
  <tbody>
29
  <?php if ( ! $jobs ) : ?>
30
  <tr>
31
+ <td colspan="<?php echo intval( count( $job_dashboard_columns ) ); ?>"><?php esc_html_e( 'You do not have any active listings.', 'wp-job-manager' ); ?></td>
32
  </tr>
33
  <?php else : ?>
34
  <?php foreach ( $jobs as $job ) : ?>
37
  <td class="<?php echo esc_attr( $key ); ?>">
38
  <?php if ('job_title' === $key ) : ?>
39
  <?php if ( $job->post_status == 'publish' ) : ?>
40
+ <a href="<?php echo esc_url( get_permalink( $job->ID ) ); ?>"><?php wpjm_the_job_title( $job ); ?></a>
41
  <?php else : ?>
42
  <?php wpjm_the_job_title( $job ); ?> <small>(<?php the_job_status( $job ); ?>)</small>
43
  <?php endif; ?>
85
  ?>
86
  </ul>
87
  <?php elseif ('date' === $key ) : ?>
88
+ <?php echo esc_html( date_i18n( get_option( 'date_format' ), strtotime( $job->post_date ) ) ); ?>
89
  <?php elseif ('expires' === $key ) : ?>
90
+ <?php echo esc_html( $job->_job_expires ? date_i18n( get_option( 'date_format' ), strtotime( $job->_job_expires ) ) : '&ndash;' ); ?>
91
  <?php elseif ('filled' === $key ) : ?>
92
  <?php echo is_position_filled( $job ) ? '&#10004;' : '&ndash;'; ?>
93
  <?php else : ?>
templates/job-filter-job-types.php CHANGED
@@ -8,22 +8,22 @@
8
  * @author Automattic
9
  * @package WP Job Manager
10
  * @category Template
11
- * @version 1.20.0
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
15
- exit; // Exit if accessed directly
16
  }
17
  ?>
18
  <?php if ( ! is_tax( 'job_listing_type' ) && empty( $job_types ) ) : ?>
19
  <ul class="job_types">
20
  <?php foreach ( get_job_listing_types() as $type ) : ?>
21
- <li><label for="job_type_<?php echo $type->slug; ?>" class="<?php echo sanitize_title( $type->name ); ?>"><input type="checkbox" name="filter_job_type[]" value="<?php echo $type->slug; ?>" <?php checked( in_array( $type->slug, $selected_job_types ), true ); ?> id="job_type_<?php echo $type->slug; ?>" /> <?php echo $type->name; ?></label></li>
22
  <?php endforeach; ?>
23
  </ul>
24
  <input type="hidden" name="filter_job_type[]" value="" />
25
  <?php elseif ( $job_types ) : ?>
26
  <?php foreach ( $job_types as $job_type ) : ?>
27
- <input type="hidden" name="filter_job_type[]" value="<?php echo sanitize_title( $job_type ); ?>" />
28
  <?php endforeach; ?>
29
- <?php endif; ?>
8
  * @author Automattic
9
  * @package WP Job Manager
10
  * @category Template
11
+ * @version 1.31.1
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
15
+ exit; // Exit if accessed directly.
16
  }
17
  ?>
18
  <?php if ( ! is_tax( 'job_listing_type' ) && empty( $job_types ) ) : ?>
19
  <ul class="job_types">
20
  <?php foreach ( get_job_listing_types() as $type ) : ?>
21
+ <li><label for="job_type_<?php echo esc_attr( $type->slug ); ?>" class="<?php echo esc_attr( sanitize_title( $type->name ) ); ?>"><input type="checkbox" name="filter_job_type[]" value="<?php echo esc_attr( $type->slug ); ?>" <?php checked( in_array( $type->slug, $selected_job_types ), true ); ?> id="job_type_<?php echo esc_attr( $type->slug ); ?>" /> <?php echo esc_html( $type->name ); ?></label></li>
22
  <?php endforeach; ?>
23
  </ul>
24
  <input type="hidden" name="filter_job_type[]" value="" />
25
  <?php elseif ( $job_types ) : ?>
26
  <?php foreach ( $job_types as $job_type ) : ?>
27
+ <input type="hidden" name="filter_job_type[]" value="<?php echo esc_attr( sanitize_title( $job_type ) ); ?>" />
28
  <?php endforeach; ?>
29
+ <?php endif; ?>
templates/job-filters.php CHANGED
@@ -8,11 +8,11 @@
8
  * @author Automattic
9
  * @package WP Job Manager
10
  * @category Template
11
- * @version 1.31.0
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
15
- exit; // Exit if accessed directly
16
  }
17
 
18
  wp_enqueue_script( 'wp-job-manager-ajax-filters' );
@@ -27,22 +27,22 @@ do_action( 'job_manager_job_filters_before', $atts );
27
  <?php do_action( 'job_manager_job_filters_search_jobs_start', $atts ); ?>
28
 
29
  <div class="search_keywords">
30
- <label for="search_keywords"><?php _e( 'Keywords', 'wp-job-manager' ); ?></label>
31
  <input type="text" name="search_keywords" id="search_keywords" placeholder="<?php esc_attr_e( 'Keywords', 'wp-job-manager' ); ?>" value="<?php echo esc_attr( $keywords ); ?>" />
32
  </div>
33
 
34
  <div class="search_location">
35
- <label for="search_location"><?php _e( 'Location', 'wp-job-manager' ); ?></label>
36
  <input type="text" name="search_location" id="search_location" placeholder="<?php esc_attr_e( 'Location', 'wp-job-manager' ); ?>" value="<?php echo esc_attr( $location ); ?>" />
37
  </div>
38
 
39
  <?php if ( $categories ) : ?>
40
  <?php foreach ( $categories as $category ) : ?>
41
- <input type="hidden" name="search_categories[]" value="<?php echo sanitize_title( $category ); ?>" />
42
  <?php endforeach; ?>
43
  <?php elseif ( $show_categories && ! is_tax( 'job_listing_category' ) && get_terms( array( 'taxonomy' => 'job_listing_category' ) ) ) : ?>
44
  <div class="search_categories">
45
- <label for="search_categories"><?php _e( 'Category', 'wp-job-manager' ); ?></label>
46
  <?php if ( $show_category_multiselect ) : ?>
47
  <?php job_manager_dropdown_categories( array( 'taxonomy' => 'job_listing_category', 'hierarchical' => 1, 'name' => 'search_categories', 'orderby' => 'name', 'selected' => $selected_category, 'hide_empty' => true ) ); ?>
48
  <?php else : ?>
@@ -59,4 +59,4 @@ do_action( 'job_manager_job_filters_before', $atts );
59
 
60
  <?php do_action( 'job_manager_job_filters_after', $atts ); ?>
61
 
62
- <noscript><?php _e( 'Your browser does not support JavaScript, or it is disabled. JavaScript must be enabled in order to view listings.', 'wp-job-manager' ); ?></noscript>
8
  * @author Automattic
9
  * @package WP Job Manager
10
  * @category Template
11
+ * @version 1.31.1
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
15
+ exit; // Exit if accessed directly.
16
  }
17
 
18
  wp_enqueue_script( 'wp-job-manager-ajax-filters' );
27
  <?php do_action( 'job_manager_job_filters_search_jobs_start', $atts ); ?>
28
 
29
  <div class="search_keywords">
30
+ <label for="search_keywords"><?php esc_html_e( 'Keywords', 'wp-job-manager' ); ?></label>
31
  <input type="text" name="search_keywords" id="search_keywords" placeholder="<?php esc_attr_e( 'Keywords', 'wp-job-manager' ); ?>" value="<?php echo esc_attr( $keywords ); ?>" />
32
  </div>
33
 
34
  <div class="search_location">
35
+ <label for="search_location"><?php esc_html_e( 'Location', 'wp-job-manager' ); ?></label>
36
  <input type="text" name="search_location" id="search_location" placeholder="<?php esc_attr_e( 'Location', 'wp-job-manager' ); ?>" value="<?php echo esc_attr( $location ); ?>" />
37
  </div>
38
 
39
  <?php if ( $categories ) : ?>
40
  <?php foreach ( $categories as $category ) : ?>
41
+ <input type="hidden" name="search_categories[]" value="<?php echo esc_attr( sanitize_title( $category ) ); ?>" />
42
  <?php endforeach; ?>
43
  <?php elseif ( $show_categories && ! is_tax( 'job_listing_category' ) && get_terms( array( 'taxonomy' => 'job_listing_category' ) ) ) : ?>
44
  <div class="search_categories">
45
+ <label for="search_categories"><?php esc_html_e( 'Category', 'wp-job-manager' ); ?></label>
46
  <?php if ( $show_category_multiselect ) : ?>
47
  <?php job_manager_dropdown_categories( array( 'taxonomy' => 'job_listing_category', 'hierarchical' => 1, 'name' => 'search_categories', 'orderby' => 'name', 'selected' => $selected_category, 'hide_empty' => true ) ); ?>
48
  <?php else : ?>
59
 
60
  <?php do_action( 'job_manager_job_filters_after', $atts ); ?>
61
 
62
+ <noscript><?php esc_html_e( 'Your browser does not support JavaScript, or it is disabled. JavaScript must be enabled in order to view listings.', 'wp-job-manager' ); ?></noscript>
templates/job-listings-end.php CHANGED
@@ -12,7 +12,7 @@
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
15
- exit; // Exit if accessed directly
16
  }
17
  ?>
18
  </ul>
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
15
+ exit; // Exit if accessed directly.
16
  }
17
  ?>
18
  </ul>
templates/job-listings-start.php CHANGED
@@ -12,7 +12,7 @@
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
15
- exit; // Exit if accessed directly
16
  }
17
  ?>
18
  <ul class="job_listings">
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
15
+ exit; // Exit if accessed directly.
16
  }
17
  ?>
18
  <ul class="job_listings">
templates/job-pagination.php CHANGED
@@ -8,18 +8,18 @@
8
  * @author Automattic
9
  * @package WP Job Manager
10
  * @category Template
11
- * @version 1.21.4
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
15
- exit; // Exit if accessed directly
16
  }
17
 
18
  if ( $max_num_pages <= 1 ) {
19
  return;
20
  }
21
 
22
- // Calculate pages to output
23
  $end_size = 3;
24
  $mid_size = 3;
25
  $start_pages = range( 1, $end_size );
@@ -31,7 +31,7 @@ $prev_page = 0;
31
  <nav class="job-manager-pagination">
32
  <ul>
33
  <?php if ( $current_page && $current_page > 1 ) : ?>
34
- <li><a href="#" data-page="<?php echo $current_page - 1; ?>">&larr;</a></li>
35
  <?php endif; ?>
36
 
37
  <?php
@@ -40,16 +40,16 @@ $prev_page = 0;
40
  echo '<li><span class="gap">...</span></li>';
41
  }
42
  if ( $current_page == $page ) {
43
- echo '<li><span class="current" data-page="' . $page . '">' . $page . '</span></li>';
44
  } else {
45
- echo '<li><a href="#" data-page="' . $page . '">' . $page . '</a></li>';
46
  }
47
  $prev_page = $page;
48
  }
49
  ?>
50
 
51
  <?php if ( $current_page && $current_page < $max_num_pages ) : ?>
52
- <li><a href="#" data-page="<?php echo $current_page + 1; ?>">&rarr;</a></li>
53
  <?php endif; ?>
54
  </ul>
55
- </nav>
8
  * @author Automattic
9
  * @package WP Job Manager
10
  * @category Template
11
+ * @version 1.31.1
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
15
+ exit; // Exit if accessed directly.
16
  }
17
 
18
  if ( $max_num_pages <= 1 ) {
19
  return;
20
  }
21
 
22
+ // Calculate pages to output.
23
  $end_size = 3;
24
  $mid_size = 3;
25
  $start_pages = range( 1, $end_size );
31
  <nav class="job-manager-pagination">
32
  <ul>
33
  <?php if ( $current_page && $current_page > 1 ) : ?>
34
+ <li><a href="#" data-page="<?php echo esc_attr( $current_page - 1 ); ?>">&larr;</a></li>
35
  <?php endif; ?>
36
 
37
  <?php
40
  echo '<li><span class="gap">...</span></li>';
41
  }
42
  if ( $current_page == $page ) {
43
+ echo '<li><span class="current" data-page="' . esc_attr( $page ) . '">' . esc_html( $page ) . '</span></li>';
44
  } else {
45
+ echo '<li><a href="#" data-page="' . esc_attr( $page ) . '">' . esc_html( $page ) . '</a></li>';
46
  }
47
  $prev_page = $page;
48
  }
49
  ?>
50
 
51
  <?php if ( $current_page && $current_page < $max_num_pages ) : ?>
52
+ <li><a href="#" data-page="<?php echo esc_attr( $current_page + 1 ); ?>">&rarr;</a></li>
53
  <?php endif; ?>
54
  </ul>
55
+ </nav>
templates/job-preview.php CHANGED
@@ -8,18 +8,18 @@
8
  * @author Automattic
9
  * @package WP Job Manager
10
  * @category Template
11
- * @version 1.27.0
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
15
- exit; // Exit if accessed directly
16
  }
17
  ?>
18
  <form method="post" id="job_preview" action="<?php echo esc_url( $form->get_action() ); ?>">
19
  <div class="job_listing_preview_title">
20
- <input type="submit" name="continue" id="job_preview_submit_button" class="button job-manager-button-submit-listing" value="<?php echo apply_filters( 'submit_job_step_preview_submit_text', __( 'Submit Listing', 'wp-job-manager' ) ); ?>" />
21
- <input type="submit" name="edit_job" class="button job-manager-button-edit-listing" value="<?php _e( 'Edit listing', 'wp-job-manager' ); ?>" />
22
- <h2><?php _e( 'Preview', 'wp-job-manager' ); ?></h2>
23
  </div>
24
  <div class="job_listing_preview single_job_listing">
25
  <h1><?php wpjm_the_job_title(); ?></h1>
@@ -28,6 +28,6 @@ if ( ! defined( 'ABSPATH' ) ) {
28
 
29
  <input type="hidden" name="job_id" value="<?php echo esc_attr( $form->get_job_id() ); ?>" />
30
  <input type="hidden" name="step" value="<?php echo esc_attr( $form->get_step() ); ?>" />
31
- <input type="hidden" name="job_manager_form" value="<?php echo $form->get_form_name(); ?>" />
32
  </div>
33
  </form>
8
  * @author Automattic
9
  * @package WP Job Manager
10
  * @category Template
11
+ * @version 1.31.1
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
15
+ exit; // Exit if accessed directly.
16
  }
17
  ?>
18
  <form method="post" id="job_preview" action="<?php echo esc_url( $form->get_action() ); ?>">
19
  <div class="job_listing_preview_title">
20
+ <input type="submit" name="continue" id="job_preview_submit_button" class="button job-manager-button-submit-listing" value="<?php echo esc_attr( apply_filters( 'submit_job_step_preview_submit_text', __( 'Submit Listing', 'wp-job-manager' ) ) ); ?>" />
21
+ <input type="submit" name="edit_job" class="button job-manager-button-edit-listing" value="<?php esc_attr_e( 'Edit listing', 'wp-job-manager' ); ?>" />
22
+ <h2><?php esc_html_e( 'Preview', 'wp-job-manager' ); ?></h2>
23
  </div>
24
  <div class="job_listing_preview single_job_listing">
25
  <h1><?php wpjm_the_job_title(); ?></h1>
28
 
29
  <input type="hidden" name="job_id" value="<?php echo esc_attr( $form->get_job_id() ); ?>" />
30
  <input type="hidden" name="step" value="<?php echo esc_attr( $form->get_step() ); ?>" />
31
+ <input type="hidden" name="job_manager_form" value="<?php echo esc_attr( $form->get_form_name() ); ?>" />
32
  </div>
33
  </form>
templates/job-submit.php CHANGED
@@ -8,11 +8,11 @@
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
  global $job_manager;
@@ -21,7 +21,7 @@ global $job_manager;
21
 
22
  <?php
23
  if ( isset( $resume_edit ) && $resume_edit ) {
24
- printf( '<p><strong>' . __( "You are editing an existing job. %s", 'wp-job-manager' ) . '</strong></p>', '<a href="?new=1&key=' . $resume_edit . '">' . __( 'Create A New Job', 'wp-job-manager' ) . '</a>' );
25
  }
26
  ?>
27
 
@@ -40,7 +40,7 @@ global $job_manager;
40
 
41
  <?php foreach ( $job_fields as $key => $field ) : ?>
42
  <fieldset class="fieldset-<?php echo esc_attr( $key ); ?>">
43
- <label for="<?php echo esc_attr( $key ); ?>"><?php echo $field['label'] . apply_filters( 'submit_job_form_required_label', $field['required'] ? '' : ' <small>' . __( '(optional)', 'wp-job-manager' ) . '</small>', $field ); ?></label>
44
  <div class="field <?php echo $field['required'] ? 'required-field' : ''; ?>">
45
  <?php get_job_manager_template( 'form-fields/' . $field['type'] . '-field.php', array( 'key' => $key, 'field' => $field ) ); ?>
46
  </div>
@@ -51,13 +51,13 @@ global $job_manager;
51
 
52
  <!-- Company Information Fields -->
53
  <?php if ( $company_fields ) : ?>
54
- <h2><?php _e( 'Company Details', 'wp-job-manager' ); ?></h2>
55
 
56
  <?php do_action( 'submit_job_form_company_fields_start' ); ?>
57
 
58
  <?php foreach ( $company_fields as $key => $field ) : ?>
59
  <fieldset class="fieldset-<?php echo esc_attr( $key ); ?>">
60
- <label for="<?php echo esc_attr( $key ); ?>"><?php echo $field['label'] . apply_filters( 'submit_job_form_required_label', $field['required'] ? '' : ' <small>' . __( '(optional)', 'wp-job-manager' ) . '</small>', $field ); ?></label>
61
  <div class="field <?php echo $field['required'] ? 'required-field' : ''; ?>">
62
  <?php get_job_manager_template( 'form-fields/' . $field['type'] . '-field.php', array( 'key' => $key, 'field' => $field ) ); ?>
63
  </div>
@@ -70,11 +70,11 @@ global $job_manager;
70
  <?php do_action( 'submit_job_form_end' ); ?>
71
 
72
  <p>
73
- <input type="hidden" name="job_manager_form" value="<?php echo $form; ?>" />
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 : ?>
8
  * @author Automattic
9
  * @package WP Job Manager
10
  * @category Template
11
+ * @version 1.31.1
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
15
+ exit; // Exit if accessed directly.
16
  }
17
 
18
  global $job_manager;
21
 
22
  <?php
23
  if ( isset( $resume_edit ) && $resume_edit ) {
24
+ printf( '<p><strong>' . esc_html__( "You are editing an existing job. %s", 'wp-job-manager' ) . '</strong></p>', '<a href="?new=1&key=' . esc_attr( $resume_edit ) . '">' . esc_html__( 'Create A New Job', 'wp-job-manager' ) . '</a>' );
25
  }
26
  ?>
27
 
40
 
41
  <?php foreach ( $job_fields as $key => $field ) : ?>
42
  <fieldset class="fieldset-<?php echo esc_attr( $key ); ?>">
43
+ <label for="<?php echo esc_attr( $key ); ?>"><?php echo wp_kses_post( $field['label'] ) . wp_kses_post( apply_filters( 'submit_job_form_required_label', $field['required'] ? '' : ' <small>' . __( '(optional)', 'wp-job-manager' ) . '</small>', $field ) ); ?></label>
44
  <div class="field <?php echo $field['required'] ? 'required-field' : ''; ?>">
45
  <?php get_job_manager_template( 'form-fields/' . $field['type'] . '-field.php', array( 'key' => $key, 'field' => $field ) ); ?>
46
  </div>
51
 
52
  <!-- Company Information Fields -->
53
  <?php if ( $company_fields ) : ?>
54
+ <h2><?php esc_html_e( 'Company Details', 'wp-job-manager' ); ?></h2>
55
 
56
  <?php do_action( 'submit_job_form_company_fields_start' ); ?>
57
 
58
  <?php foreach ( $company_fields as $key => $field ) : ?>
59
  <fieldset class="fieldset-<?php echo esc_attr( $key ); ?>">
60
+ <label for="<?php echo esc_attr( $key ); ?>"><?php echo esc_html( $field['label'] ) . wp_kses_post( apply_filters( 'submit_job_form_required_label', $field['required'] ? '' : ' <small>' . __( '(optional)', 'wp-job-manager' ) . '</small>', $field ) ); ?></label>
61
  <div class="field <?php echo $field['required'] ? 'required-field' : ''; ?>">
62
  <?php get_job_manager_template( 'form-fields/' . $field['type'] . '-field.php', array( 'key' => $key, 'field' => $field ) ); ?>
63
  </div>
70
  <?php do_action( 'submit_job_form_end' ); ?>
71
 
72
  <p>
73
+ <input type="hidden" name="job_manager_form" value="<?php echo esc_attr( $form ); ?>" />
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 esc_url( includes_url( 'images/spinner.gif' ) ); ?>);"></span>
78
  </p>
79
 
80
  <?php else : ?>
templates/job-submitted.php CHANGED
@@ -8,25 +8,37 @@
8
  * @author Automattic
9
  * @package WP Job Manager
10
  * @category Template
11
- * @version 1.20.0
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
15
- exit; // Exit if accessed directly
16
  }
17
 
18
  global $wp_post_types;
19
 
20
  switch ( $job->post_status ) :
21
  case 'publish' :
22
- printf( __( '%s listed successfully. To view your listing <a href="%s">click here</a>.', 'wp-job-manager' ), $wp_post_types['job_listing']->labels->singular_name, get_permalink( $job->ID ) );
 
 
 
 
 
 
23
  break;
24
  case 'pending' :
25
- printf( __( '%s submitted successfully. Your listing will be visible once approved.', 'wp-job-manager' ), $wp_post_types['job_listing']->labels->singular_name, get_permalink( $job->ID ) );
 
 
 
 
 
 
26
  break;
27
  default :
28
  do_action( 'job_manager_job_submitted_content_' . str_replace( '-', '_', sanitize_title( $job->post_status ) ), $job );
29
  break;
30
  endswitch;
31
 
32
- do_action( 'job_manager_job_submitted_content_after', sanitize_title( $job->post_status ), $job );
8
  * @author Automattic
9
  * @package WP Job Manager
10
  * @category Template
11
+ * @version 1.31.1
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
15
+ exit; // Exit if accessed directly.
16
  }
17
 
18
  global $wp_post_types;
19
 
20
  switch ( $job->post_status ) :
21
  case 'publish' :
22
+ echo wp_kses_post(
23
+ sprintf(
24
+ __( '%s listed successfully. To view your listing <a href="%s">click here</a>.', 'wp-job-manager' ),
25
+ esc_html( $wp_post_types['job_listing']->labels->singular_name ),
26
+ get_permalink( $job->ID )
27
+ )
28
+ );
29
  break;
30
  case 'pending' :
31
+ echo wp_kses_post(
32
+ sprintf(
33
+ esc_html__( '%s submitted successfully. Your listing will be visible once approved.', 'wp-job-manager' ),
34
+ esc_html( $wp_post_types['job_listing']->labels->singular_name ),
35
+ get_permalink( $job->ID )
36
+ )
37
+ );
38
  break;
39
  default :
40
  do_action( 'job_manager_job_submitted_content_' . str_replace( '-', '_', sanitize_title( $job->post_status ) ), $job );
41
  break;
42
  endswitch;
43
 
44
+ do_action( 'job_manager_job_submitted_content_after', sanitize_title( $job->post_status ), $job );
templates/pagination.php CHANGED
@@ -12,7 +12,7 @@
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
15
- exit; // Exit if accessed directly
16
  }
17
 
18
  if ( $max_num_pages <= 1 ) {
12
  */
13
 
14
  if ( ! defined( 'ABSPATH' ) ) {
15
+ exit; // Exit if accessed directly.
16
  }
17
 
18
  if ( $max_num_pages <= 1 ) {
uninstall.php CHANGED
@@ -32,5 +32,5 @@ if ( ! is_multisite() ) {
32
  switch_to_blog( $original_blog_id );
33
  }
34
 
35
- include dirname( __FILE__ ) . '/includes/class-wp-job-manager-usage-tracking.php';
36
  WP_Job_Manager_Usage_Tracking::get_instance()->clear_options();
32
  switch_to_blog( $original_blog_id );
33
  }
34
 
35
+ require dirname( __FILE__ ) . '/includes/class-wp-job-manager-usage-tracking.php';
36
  WP_Job_Manager_Usage_Tracking::get_instance()->clear_options();
wp-job-manager-deprecated.php CHANGED
@@ -1,86 +1,90 @@
1
  <?php
2
  /**
3
  * Deprecated functions. Do not use these.
 
 
4
  */
5
 
6
  if ( ! function_exists( 'order_featured_job_listing' ) ) :
7
- /**
8
- * Was used for sorting.
9
- *
10
- * @deprecated 1.22.4
11
- * @param array $args
12
- * @return array
13
- */
14
- function order_featured_job_listing( $args ) {
15
- global $wpdb;
16
- $args['orderby'] = "$wpdb->posts.menu_order ASC, $wpdb->posts.post_date DESC";
17
- return $args;
18
- }
 
19
  endif;
20
 
21
 
22
 
23
  if ( ! function_exists( 'the_job_type' ) ) :
24
- /**
25
- * Displays the job type for the listing.
26
- *
27
- * @since 1.0.0
28
- * @deprecated 1.27.0 Use `wpjm_the_job_types()` instead.
29
- *
30
- * @param int|WP_Post $post
31
- * @return string
32
- */
33
- function the_job_type( $post = null ) {
34
- _deprecated_function( __FUNCTION__, '1.27.0', 'wpjm_the_job_types' );
35
 
36
- if ( ! get_option( 'job_manager_enable_types' ) ) {
37
- return '';
38
- }
39
- if ( $job_type = get_the_job_type( $post ) ) {
40
- echo $job_type->name;
 
 
41
  }
42
- }
43
  endif;
44
 
45
  if ( ! function_exists( 'get_the_job_type' ) ) :
46
- /**
47
- * Gets the job type for the listing.
48
- *
49
- * @since 1.0.0
50
- * @deprecated 1.27.0 Use `wpjm_get_the_job_types()` instead.
51
- *
52
- * @param int|WP_Post $post (default: null)
53
- * @return string|bool|null
54
- */
55
- function get_the_job_type( $post = null ) {
56
- _deprecated_function( __FUNCTION__, '1.27.0', 'wpjm_get_the_job_types' );
57
 
58
- $post = get_post( $post );
59
- if ( $post->post_type !== 'job_listing' ) {
60
- return;
61
- }
62
 
63
- $types = wp_get_post_terms( $post->ID, 'job_listing_type' );
64
 
65
- if ( $types ) {
66
- $type = current( $types );
67
- } else {
68
- $type = false;
69
- }
70
 
71
- return apply_filters( 'the_job_type', $type, $post );
72
- }
73
  endif;
74
 
75
  if ( ! function_exists( 'wpjm_get_permalink_structure' ) ) :
76
- /**
77
- * Retrieves permalink settings. Moved to `WP_Job_Manager_Post_Types` class in 1.28.0.
78
- *
79
- * @since 1.27.0
80
- * @deprecated 1.28.0
81
- * @return array
82
- */
83
- function wpjm_get_permalink_structure() {
84
- return WP_Job_Manager_Post_Types::get_permalink_structure();
85
- }
86
  endif;
1
  <?php
2
  /**
3
  * Deprecated functions. Do not use these.
4
+ *
5
+ * @package wp-job-manager
6
  */
7
 
8
  if ( ! function_exists( 'order_featured_job_listing' ) ) :
9
+ /**
10
+ * Was used for sorting.
11
+ *
12
+ * @deprecated 1.22.4
13
+ *
14
+ * @param array $args
15
+ * @return array
16
+ */
17
+ function order_featured_job_listing( $args ) {
18
+ global $wpdb;
19
+ $args['orderby'] = "$wpdb->posts.menu_order ASC, $wpdb->posts.post_date DESC";
20
+ return $args;
21
+ }
22
  endif;
23
 
24
 
25
 
26
  if ( ! function_exists( 'the_job_type' ) ) :
27
+ /**
28
+ * Displays the job type for the listing.
29
+ *
30
+ * @since 1.0.0
31
+ * @deprecated 1.27.0 Use `wpjm_the_job_types()` instead.
32
+ *
33
+ * @param int|WP_Post $post
34
+ * @return string
35
+ */
36
+ function the_job_type( $post = null ) {
37
+ _deprecated_function( __FUNCTION__, '1.27.0', 'wpjm_the_job_types' );
38
 
39
+ if ( ! get_option( 'job_manager_enable_types' ) ) {
40
+ return '';
41
+ }
42
+ $job_type = get_the_job_type( $post );
43
+ if ( $job_type ) {
44
+ echo esc_html( $job_type->name );
45
+ }
46
  }
 
47
  endif;
48
 
49
  if ( ! function_exists( 'get_the_job_type' ) ) :
50
+ /**
51
+ * Gets the job type for the listing.
52
+ *
53
+ * @since 1.0.0
54
+ * @deprecated 1.27.0 Use `wpjm_get_the_job_types()` instead.
55
+ *
56
+ * @param int|WP_Post $post (default: null).
57
+ * @return string|bool|null
58
+ */
59
+ function get_the_job_type( $post = null ) {
60
+ _deprecated_function( __FUNCTION__, '1.27.0', 'wpjm_get_the_job_types' );
61
 
62
+ $post = get_post( $post );
63
+ if ( 'job_listing' !== $post->post_type ) {
64
+ return;
65
+ }
66
 
67
+ $types = wp_get_post_terms( $post->ID, 'job_listing_type' );
68
 
69
+ if ( $types ) {
70
+ $type = current( $types );
71
+ } else {
72
+ $type = false;
73
+ }
74
 
75
+ return apply_filters( 'the_job_type', $type, $post );
76
+ }
77
  endif;
78
 
79
  if ( ! function_exists( 'wpjm_get_permalink_structure' ) ) :
80
+ /**
81
+ * Retrieves permalink settings. Moved to `WP_Job_Manager_Post_Types` class in 1.28.0.
82
+ *
83
+ * @since 1.27.0
84
+ * @deprecated 1.28.0
85
+ * @return array
86
+ */
87
+ function wpjm_get_permalink_structure() {
88
+ return WP_Job_Manager_Post_Types::get_permalink_structure();
89
+ }
90
  endif;
wp-job-manager-functions.php CHANGED
@@ -1,212 +1,214 @@
1
  <?php
2
  if ( ! function_exists( 'get_job_listings' ) ) :
3
- /**
4
- * Queries job listings with certain criteria and returns them.
5
- *
6
- * @since 1.0.5
7
- * @param string|array|object $args Arguments used to retrieve job listings.
8
- * @return WP_Query
9
- */
10
- function get_job_listings( $args = array() ) {
11
- global $wpdb, $job_manager_keyword;
12
-
13
- $args = wp_parse_args( $args, array(
14
- 'search_location' => '',
15
- 'search_keywords' => '',
16
- 'search_categories' => array(),
17
- 'job_types' => array(),
18
- 'post_status' => array(),
19
- 'offset' => 0,
20
- 'posts_per_page' => 20,
21
- 'orderby' => 'date',
22
- 'order' => 'DESC',
23
- 'featured' => null,
24
- 'filled' => null,
25
- 'fields' => 'all'
26
- ) );
27
-
28
  /**
29
- * Perform actions that need to be done prior to the start of the job listings query.
30
  *
31
- * @since 1.26.0
32
- *
33
- * @param array $args Arguments used to retrieve job listings.
34
  */
35
- do_action( 'get_job_listings_init', $args );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
36
 
37
- if ( ! empty( $args['post_status'] ) ) {
38
- $post_status = $args['post_status'];
39
- } elseif ( false == get_option( 'job_manager_hide_expired', get_option( 'job_manager_hide_expired_content', 1 ) ) ) {
40
- $post_status = array( 'publish', 'expired' );
41
- } else {
42
- $post_status = 'publish';
43
- }
 
44
 
45
- $query_args = array(
46
- 'post_type' => 'job_listing',
47
- 'post_status' => $post_status,
48
- 'ignore_sticky_posts' => 1,
49
- 'offset' => absint( $args['offset'] ),
50
- 'posts_per_page' => intval( $args['posts_per_page'] ),
51
- 'orderby' => $args['orderby'],
52
- 'order' => $args['order'],
53
- 'tax_query' => array(),
54
- 'meta_query' => array(),
55
- 'update_post_term_cache' => false,
56
- 'update_post_meta_cache' => false,
57
- 'cache_results' => false,
58
- 'fields' => $args['fields']
59
- );
60
 
61
- if ( $args['posts_per_page'] < 0 ) {
62
- $query_args['no_found_rows'] = true;
63
- }
 
 
 
 
 
 
 
 
 
 
 
 
64
 
65
- if ( ! empty( $args['search_location'] ) ) {
66
- $location_meta_keys = array( 'geolocation_formatted_address', '_job_location', 'geolocation_state_long' );
67
- $location_search = array( 'relation' => 'OR' );
68
- foreach ( $location_meta_keys as $meta_key ) {
69
- $location_search[] = array(
70
- 'key' => $meta_key,
71
- 'value' => $args['search_location'],
72
- 'compare' => 'like'
73
- );
74
  }
75
- $query_args['meta_query'][] = $location_search;
76
- }
77
 
78
- if ( ! is_null( $args['featured'] ) ) {
79
- $query_args['meta_query'][] = array(
80
- 'key' => '_featured',
81
- 'value' => '1',
82
- 'compare' => $args['featured'] ? '=' : '!='
83
- );
84
- }
 
 
 
 
 
85
 
86
- if ( ! is_null( $args['filled'] ) || 1 === absint( get_option( 'job_manager_hide_filled_positions' ) ) ) {
87
- $query_args['meta_query'][] = array(
88
- 'key' => '_filled',
89
- 'value' => '1',
90
- 'compare' => $args['filled'] ? '=' : '!='
91
- );
92
- }
93
 
94
- if ( ! empty( $args['job_types'] ) ) {
95
- $query_args['tax_query'][] = array(
96
- 'taxonomy' => 'job_listing_type',
97
- 'field' => 'slug',
98
- 'terms' => $args['job_types']
99
- );
100
- }
101
 
102
- if ( ! empty( $args['search_categories'] ) ) {
103
- $field = is_numeric( $args['search_categories'][0] ) ? 'term_id' : 'slug';
104
- $operator = 'all' === get_option( 'job_manager_category_filter_type', 'all' ) && sizeof( $args['search_categories'] ) > 1 ? 'AND' : 'IN';
105
- $query_args['tax_query'][] = array(
106
- 'taxonomy' => 'job_listing_category',
107
- 'field' => $field,
108
- 'terms' => array_values( $args['search_categories'] ),
109
- 'include_children' => $operator !== 'AND' ,
110
- 'operator' => $operator
111
- );
112
- }
113
 
114
- if ( 'featured' === $args['orderby'] ) {
115
- $query_args['orderby'] = array(
116
- 'menu_order' => 'ASC',
117
- 'date' => 'DESC',
118
- 'ID' => 'DESC',
119
- );
120
- }
 
 
 
 
121
 
122
- if ( 'rand_featured' === $args['orderby'] ) {
123
- $query_args['orderby'] = array(
124
- 'menu_order' => 'ASC',
125
- 'rand' => 'ASC'
126
- );
127
- }
 
128
 
129
- $job_manager_keyword = sanitize_text_field( $args['search_keywords'] );
 
 
 
 
 
130
 
131
- if ( ! empty( $job_manager_keyword ) && strlen( $job_manager_keyword ) >= apply_filters( 'job_manager_get_listings_keyword_length_threshold', 2 ) ) {
132
- $query_args['s'] = $job_manager_keyword;
133
- add_filter( 'posts_search', 'get_job_listings_keyword_search' );
134
- }
135
 
136
- $query_args = apply_filters( 'job_manager_get_listings', $query_args, $args );
 
 
 
137
 
138
- if ( empty( $query_args['meta_query'] ) ) {
139
- unset( $query_args['meta_query'] );
140
- }
141
 
142
- if ( empty( $query_args['tax_query'] ) ) {
143
- unset( $query_args['tax_query'] );
144
- }
145
 
146
- /** This filter is documented in wp-job-manager.php */
147
- $query_args['lang'] = apply_filters( 'wpjm_lang', null );
 
148
 
149
- // Filter args
150
- $query_args = apply_filters( 'get_job_listings_query_args', $query_args, $args );
151
 
 
 
152
 
153
- do_action( 'before_get_job_listings', $query_args, $args );
154
 
155
- // Cache results
156
- if ( apply_filters( 'get_job_listings_cache_results', true ) ) {
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 );
164
- if ( $cached_query_posts
165
  && is_object( $cached_query_posts )
166
  && isset( $cached_query_posts->max_num_pages )
167
  && isset( $cached_query_posts->found_posts )
168
  && isset( $cached_query_posts->posts )
169
  && is_array( $cached_query_posts->posts )
170
- ) {
171
- $posts = array_map( 'get_post', $cached_query_posts->posts );
172
- $result = new WP_Query();
173
- $result->parse_query( $query_args );
174
- $result->posts = $posts;
175
- $result->found_posts = intval( $cached_query_posts->found_posts );
176
- $result->max_num_pages = intval( $cached_query_posts->max_num_pages );
177
- $result->post_count = count( $posts );
 
178
  }
179
- }
180
 
181
- if ( false === $result ) {
182
- $result = new WP_Query( $query_args );
183
- $cached_query_results = false;
184
 
185
- $cacheable_result = array();
186
- $cacheable_result['posts'] = array_values( $result->posts );
187
- $cacheable_result['found_posts'] = $result->found_posts;
188
- $cacheable_result['max_num_pages'] = $result->max_num_pages;
189
- set_transient( $query_args_hash, json_encode( $cacheable_result ), DAY_IN_SECONDS );
190
- }
191
 
192
- if ( $cached_query_results ) {
193
- // random order is cached so shuffle them
194
- if ( 'rand_featured' === $args['orderby'] ) {
195
- usort( $result->posts, '_wpjm_shuffle_featured_post_results_helper' );
196
- } elseif ( 'rand' === $args['orderby'] ) {
197
- shuffle( $result->posts );
 
198
  }
 
 
199
  }
200
- } else {
201
- $result = new WP_Query( $query_args );
202
- }
203
 
204
- do_action( 'after_get_job_listings', $query_args, $args );
205
 
206
- remove_filter( 'posts_search', 'get_job_listings_keyword_search' );
207
 
208
- return $result;
209
- }
210
  endif;
211
 
212
  if ( ! function_exists( '_wpjm_shuffle_featured_post_results_helper' ) ) :
@@ -220,11 +222,11 @@ if ( ! function_exists( '_wpjm_shuffle_featured_post_results_helper' ) ) :
220
  */
221
  function _wpjm_shuffle_featured_post_results_helper( $a, $b ) {
222
  if ( -1 === $a->menu_order || -1 === $b->menu_order ) {
223
- // Left is featured
224
  if ( 0 === $b->menu_order ) {
225
  return -1;
226
  }
227
- // Right is featured
228
  if ( 0 === $a->menu_order ) {
229
  return 1;
230
  }
@@ -246,7 +248,7 @@ if ( ! function_exists( 'get_job_listings_keyword_search' ) ) :
246
  function get_job_listings_keyword_search( $search ) {
247
  global $wpdb, $job_manager_keyword;
248
 
249
- // Searchable Meta Keys: set to empty to search all meta keys
250
  $searchable_meta_keys = array(
251
  '_job_location',
252
  '_company_name',
@@ -259,22 +261,22 @@ if ( ! function_exists( 'get_job_listings_keyword_search' ) ) :
259
 
260
  $searchable_meta_keys = apply_filters( 'job_listing_searchable_meta_keys', $searchable_meta_keys );
261
 
262
- // Set Search DB Conditions
263
- $conditions = array();
264
 
265
- // Search Post Meta
266
- if( apply_filters( 'job_listing_search_post_meta', true ) ) {
267
 
268
- // Only selected meta keys
269
- if( $searchable_meta_keys ) {
270
  $conditions[] = "{$wpdb->posts}.ID IN ( SELECT post_id FROM {$wpdb->postmeta} WHERE meta_key IN ( '" . implode( "','", array_map( 'esc_sql', $searchable_meta_keys ) ) . "' ) AND meta_value LIKE '%" . esc_sql( $job_manager_keyword ) . "%' )";
271
  } else {
272
- // No meta keys defined, search all post meta value
273
  $conditions[] = "{$wpdb->posts}.ID IN ( SELECT post_id FROM {$wpdb->postmeta} WHERE meta_value LIKE '%" . esc_sql( $job_manager_keyword ) . "%' )";
274
  }
275
  }
276
 
277
- // Search taxonomy
278
  $conditions[] = "{$wpdb->posts}.ID IN ( SELECT object_id FROM {$wpdb->term_relationships} AS tr LEFT JOIN {$wpdb->term_taxonomy} AS tt ON tr.term_taxonomy_id = tt.term_taxonomy_id LEFT JOIN {$wpdb->terms} AS t ON tt.term_id = t.term_id WHERE t.name LIKE '%" . esc_sql( $job_manager_keyword ) . "%' )";
279
 
280
  /**
@@ -304,179 +306,193 @@ if ( ! function_exists( 'get_job_listings_keyword_search' ) ) :
304
  endif;
305
 
306
  if ( ! function_exists( 'get_job_listing_post_statuses' ) ) :
307
- /**
308
- * Gets post statuses used for jobs.
309
- *
310
- * @since 1.12.0
311
- * @return array
312
- */
313
- function get_job_listing_post_statuses() {
314
- return apply_filters( 'job_listing_post_statuses', array(
315
- 'draft' => _x( 'Draft', 'post status', 'wp-job-manager' ),
316
- 'expired' => _x( 'Expired', 'post status', 'wp-job-manager' ),
317
- 'preview' => _x( 'Preview', 'post status', 'wp-job-manager' ),
318
- 'pending' => _x( 'Pending approval', 'post status', 'wp-job-manager' ),
319
- 'pending_payment' => _x( 'Pending payment', 'post status', 'wp-job-manager' ),
320
- 'publish' => _x( 'Active', 'post status', 'wp-job-manager' ),
321
- ) );
322
- }
 
 
 
323
  endif;
324
 
325
  if ( ! function_exists( 'get_featured_job_ids' ) ) :
326
- /**
327
- * Gets the ids of featured jobs.
328
- *
329
- * @since 1.0.4
330
- * @return array
331
- */
332
- function get_featured_job_ids() {
333
- return get_posts( array(
334
- 'posts_per_page' => -1,
335
- 'post_type' => 'job_listing',
336
- 'post_status' => 'publish',
337
- 'meta_key' => '_featured',
338
- 'meta_value' => '1',
339
- 'fields' => 'ids'
340
- ) );
341
- }
 
 
 
342
  endif;
343
 
344
  if ( ! function_exists( 'get_job_listing_types' ) ) :
345
- /**
346
- * Gets job listing types.
347
- *
348
- * @since 1.0.0
349
- * @param string|array $fields
350
- * @return WP_Term[]
351
- */
352
- function get_job_listing_types( $fields = 'all' ) {
353
- if ( ! get_option( 'job_manager_enable_types' ) ) {
354
- return array();
355
- } else {
356
- $args = array(
357
- 'fields' => $fields,
358
- 'hide_empty' => false,
359
- 'order' => 'ASC',
360
- 'orderby' => 'name'
361
- );
362
 
363
- $args = apply_filters( 'get_job_listing_types_args', $args );
364
 
365
- // Prevent users from filtering the taxonomy
366
- $args['taxonomy'] = 'job_listing_type';
367
 
368
- return get_terms( $args );
 
369
  }
370
- }
371
  endif;
372
 
373
  if ( ! function_exists( 'get_job_listing_categories' ) ) :
374
- /**
375
- * Gets job categories.
376
- *
377
- * @since 1.0.0
378
- * @return array
379
- */
380
- function get_job_listing_categories() {
381
- if ( ! get_option( 'job_manager_enable_categories' ) ) {
382
- return array();
383
- }
384
-
385
- $args = array(
386
- 'orderby' => 'name',
387
- 'order' => 'ASC',
388
- 'hide_empty' => false,
389
- );
390
-
391
  /**
392
- * Change the category query arguments.
393
  *
394
- * @since 1.31.0
395
- *
396
- * @param array $args
397
  */
398
- $args = apply_filters( 'get_job_listing_category_args', $args );
 
 
 
 
 
 
 
 
 
399
 
400
- // Prevent users from filtering the taxonomy
401
- $args['taxonomy'] = 'job_listing_category';
 
 
 
 
 
 
402
 
403
- return get_terms( $args );
404
- }
 
 
 
405
  endif;
406
 
407
  if ( ! function_exists( 'job_manager_get_filtered_links' ) ) :
408
- /**
409
- * Shows links after filtering jobs
410
- *
411
- * @since 1.0.6
412
- * @param array $args
413
- * @return string
414
- */
415
- function job_manager_get_filtered_links( $args = array() ) {
416
- $job_categories = array();
417
- $types = get_job_listing_types();
418
-
419
- // Convert to slugs
420
- if ( $args['search_categories'] ) {
421
- foreach ( $args['search_categories'] as $category ) {
422
- if ( is_numeric( $category ) ) {
423
- $category_object = get_term_by( 'id', $category, 'job_listing_category' );
424
- if ( ! is_wp_error( $category_object ) ) {
425
- $job_categories[] = $category_object->slug;
 
 
 
426
  }
427
- } else {
428
- $job_categories[] = $category;
429
  }
430
  }
431
- }
432
 
433
- $links = apply_filters( 'job_manager_job_filters_showing_jobs_links', array(
434
- 'reset' => array(
435
- 'name' => __( 'Reset', 'wp-job-manager' ),
436
- 'url' => '#'
437
- ),
438
- 'rss_link' => array(
439
- 'name' => __( 'RSS', 'wp-job-manager' ),
440
- 'url' => get_job_listing_rss_link( apply_filters( 'job_manager_get_listings_custom_filter_rss_args', array(
441
- 'job_types' => isset( $args['filter_job_types'] ) ? implode( ',', $args['filter_job_types'] ) : '',
442
- 'search_location' => $args['search_location'],
443
- 'job_categories' => implode( ',', $job_categories ),
444
- 'search_keywords' => $args['search_keywords'],
445
- ) ) )
446
- )
447
- ), $args );
448
-
449
- if ( count( (array) $args['filter_job_types'] ) === count( $types )
450
- && empty( $args['search_keywords'] )
451
- && empty( $args['search_location'] )
452
- && empty( $args['search_categories'] )
453
- && ! apply_filters( 'job_manager_get_listings_custom_filter', false )
454
- ) {
455
- unset( $links['reset'] );
456
- }
457
 
458
- $return = '';
 
 
 
 
 
 
 
459
 
460
- foreach ( $links as $key => $link ) {
461
- $return .= '<a href="' . esc_url( $link['url'] ) . '" class="' . esc_attr( $key ) . '">' . $link['name'] . '</a>';
462
- }
463
 
464
- return $return;
465
- }
 
 
 
 
466
  endif;
467
 
468
  if ( ! function_exists( 'get_job_listing_rss_link' ) ) :
469
- /**
470
- * Get the Job Listing RSS link
471
- *
472
- * @since 1.0.0
473
- * @param array $args
474
- * @return string
475
- */
476
- function get_job_listing_rss_link( $args = array() ) {
477
- $rss_link = add_query_arg( urlencode_deep( array_merge( array( 'feed' => 'job_feed' ), $args ) ), home_url() );
478
- return $rss_link;
479
- }
480
  endif;
481
 
482
  if ( ! function_exists( 'wp_job_manager_notify_new_user' ) ) :
@@ -491,7 +507,7 @@ if ( ! function_exists( 'wp_job_manager_notify_new_user' ) ) :
491
  global $wp_version;
492
 
493
  if ( version_compare( $wp_version, '4.3.1', '<' ) ) {
494
- wp_new_user_notification( $user_id, $password );
495
  } else {
496
  $notify = 'admin';
497
  if ( empty( $password ) ) {
@@ -502,117 +518,116 @@ if ( ! function_exists( 'wp_job_manager_notify_new_user' ) ) :
502
  }
503
  endif;
504
 
505
- if ( ! function_exists( 'job_manager_create_account' ) ) :
506
- /**
507
- * Handles account creation.
508
- *
509
- * @since 1.0.0
510
- * @param string|array|object $args containing username, email, role
511
- * @param string $deprecated role string
512
- * @return WP_Error|bool was an account created?
513
- */
514
- function wp_job_manager_create_account( $args, $deprecated = '' ) {
515
- global $current_user;
516
-
517
- // Soft Deprecated in 1.20.0
518
- if ( ! is_array( $args ) ) {
519
- $username = '';
520
- $password = false;
521
- $email = $args;
522
- $role = $deprecated;
523
- } else {
524
- $defaults = array(
525
- 'username' => '',
526
- 'email' => '',
527
- 'password' => false,
528
- 'role' => get_option( 'default_role' )
529
- );
530
 
531
- $args = wp_parse_args( $args, $defaults );
532
- extract( $args );
533
- }
534
 
535
- $username = sanitize_user( $username );
536
- $email = apply_filters( 'user_registration_email', sanitize_email( $email ) );
537
 
538
- if ( empty( $email ) ) {
539
- return new WP_Error( 'validation-error', __( 'Invalid email address.', 'wp-job-manager' ) );
540
- }
541
 
542
- if ( empty( $username ) ) {
543
- $username = sanitize_user( current( explode( '@', $email ) ) );
544
- }
545
 
546
- if ( ! is_email( $email ) ) {
547
- return new WP_Error( 'validation-error', __( 'Your email address isn&#8217;t correct.', 'wp-job-manager' ) );
548
- }
549
 
550
- if ( email_exists( $email ) ) {
551
- return new WP_Error( 'validation-error', __( 'This email is already registered, please choose another one.', 'wp-job-manager' ) );
552
- }
553
 
554
- // Ensure username is unique
555
- $append = 1;
556
- $o_username = $username;
557
 
558
- while ( username_exists( $username ) ) {
559
- $username = $o_username . $append;
560
- $append ++;
561
- }
562
 
563
- // Final error checking
564
- $reg_errors = new WP_Error();
565
- $reg_errors = apply_filters( 'job_manager_registration_errors', $reg_errors, $username, $email );
566
 
567
- do_action( 'job_manager_register_post', $username, $email, $reg_errors );
568
 
569
- if ( $reg_errors->get_error_code() ) {
570
- return $reg_errors;
571
- }
572
 
573
- // Create account
574
- $new_user = array(
575
- 'user_login' => $username,
576
- 'user_pass' => $password,
577
- 'user_email' => $email,
578
- 'role' => $role,
579
- );
580
 
581
- // User is forced to set up account with email sent to them. This password will remain a secret.
582
- if ( empty( $new_user['user_pass'] ) ) {
583
- $new_user['user_pass'] = wp_generate_password();
584
- }
585
 
586
- $user_id = wp_insert_user( apply_filters( 'job_manager_create_account_data', $new_user ) );
587
 
588
- if ( is_wp_error( $user_id ) ) {
589
- return $user_id;
590
- }
591
 
592
- /**
593
- * Send notification to new users.
594
- *
595
- * @since 1.28.0
596
- *
597
- * @param int $user_id
598
- * @param string|bool $password
599
- * @param array $new_user {
600
- * Information about the new user.
601
- *
602
- * @type string $user_login Username for the user.
603
- * @type string $user_pass Password for the user (may be blank).
604
- * @type string $user_email Email for the new user account.
605
- * @type string $role New user's role.
606
- * }
607
- */
608
- do_action( 'wpjm_notify_new_user', $user_id, $password, $new_user );
609
 
610
- // Login
611
- wp_set_auth_cookie( $user_id, true, is_ssl() );
612
- $current_user = get_user_by( 'id', $user_id );
613
 
614
- return true;
615
- }
616
  endif;
617
 
618
  /**
@@ -669,7 +684,7 @@ function job_manager_user_can_edit_job( $job_id ) {
669
  if ( ! is_user_logged_in() || ! $job_id ) {
670
  $can_edit = false;
671
  } else {
672
- $job = get_post( $job_id );
673
 
674
  if ( ! $job || ( absint( $job->post_author ) !== get_current_user_id() && ! current_user_can( 'edit_post', $job_id ) ) ) {
675
  $can_edit = false;
@@ -694,7 +709,7 @@ function is_wpjm() {
694
  *
695
  * @param bool $is_wpjm
696
  */
697
- return apply_filters( 'is_wpjm', ( is_wpjm_page() || has_wpjm_shortcode() || is_wpjm_job_listing() || is_wpjm_taxonomy() ) ? true : false );
698
  }
699
 
700
  /**
@@ -708,11 +723,13 @@ function is_wpjm_page() {
708
  $is_wpjm_page = is_post_type_archive( 'job_listing' );
709
 
710
  if ( ! $is_wpjm_page ) {
711
- $wpjm_page_ids = array_filter( array(
712
- get_option( 'job_manager_submit_job_form_page_id', false ),
713
- get_option( 'job_manager_job_dashboard_page_id', false ),
714
- get_option( 'job_manager_jobs_page_id', false ),
715
- ) );
 
 
716
 
717
  /**
718
  * Filters a list of all page IDs related to WPJM.
@@ -723,7 +740,7 @@ function is_wpjm_page() {
723
  */
724
  $wpjm_page_ids = array_unique( apply_filters( 'job_manager_page_ids', $wpjm_page_ids ) );
725
 
726
- $is_wpjm_page = is_page( $wpjm_page_ids );
727
  }
728
 
729
  /**
@@ -823,7 +840,7 @@ function wpjm_use_standard_password_setup_email() {
823
 
824
  // If username is being automatically generated, force them to send password setup email.
825
  if ( ! job_manager_generate_username_from_email() ) {
826
- $use_standard_password_setup_email = get_option( 'job_manager_use_standard_password_setup_email' ) == 1 ? true : false;
827
  }
828
 
829
  /**
@@ -845,15 +862,15 @@ function wpjm_use_standard_password_setup_email() {
845
  * @return array
846
  */
847
  function wpjm_job_listing_employment_type_options() {
848
- $employment_types = array();
849
- $employment_types['FULL_TIME'] = __( 'Full Time', 'wp-job-manager' );
850
- $employment_types['PART_TIME'] = __( 'Part Time', 'wp-job-manager' );
851
  $employment_types['CONTRACTOR'] = __( 'Contractor', 'wp-job-manager' );
852
- $employment_types['TEMPORARY'] = __( 'Temporary', 'wp-job-manager' );
853
- $employment_types['INTERN'] = __( 'Intern', 'wp-job-manager' );
854
- $employment_types['VOLUNTEER'] = __( 'Volunteer', 'wp-job-manager' );
855
- $employment_types['PER_DIEM'] = __( 'Per Diem', 'wp-job-manager' );
856
- $employment_types['OTHER'] = __( 'Other', 'wp-job-manager' );
857
 
858
  /**
859
  * Filter the list of employment types.
@@ -881,7 +898,7 @@ function wpjm_job_listing_employment_type_enabled() {
881
  *
882
  * @param bool True if employment type meta field is enabled on job type terms.
883
  */
884
- return apply_filters( 'wpjm_job_listing_employment_type_enabled', get_option( 'job_manager_enable_types' ) ? true : false );
885
  }
886
 
887
  /**
@@ -894,7 +911,7 @@ function wpjm_job_listing_employment_type_enabled() {
894
  */
895
  function wpjm_validate_new_password( $password ) {
896
  // Password must be at least 8 characters long. Trimming here because `wp_hash_password()` will later on.
897
- $is_valid_password = strlen( trim ( $password ) ) >= 8;
898
 
899
  /**
900
  * Allows overriding default WPJM password validation rules.
@@ -920,7 +937,7 @@ function wpjm_get_password_rules_hint() {
920
  *
921
  * @param string $password_rules Password rules description.
922
  */
923
- return apply_filters( 'wpjm_password_rules_hint', __( 'Passwords must be at least 8 characters long.', 'wp-job-manager') );
924
  }
925
 
926
  /**
@@ -930,7 +947,7 @@ function wpjm_get_password_rules_hint() {
930
  * @return bool
931
  */
932
  function job_manager_multi_job_type() {
933
- return apply_filters( 'job_manager_multi_job_type', get_option( 'job_manager_multi_job_type' ) == 1 ? true : false );
934
  }
935
 
936
  /**
@@ -940,7 +957,7 @@ function job_manager_multi_job_type() {
940
  * @return bool
941
  */
942
  function job_manager_enable_registration() {
943
- return apply_filters( 'job_manager_enable_registration', get_option( 'job_manager_enable_registration' ) == 1 ? true : false );
944
  }
945
 
946
  /**
@@ -950,7 +967,7 @@ function job_manager_enable_registration() {
950
  * @return bool
951
  */
952
  function job_manager_generate_username_from_email() {
953
- return apply_filters( 'job_manager_generate_username_from_email', get_option( 'job_manager_generate_username_from_email' ) == 1 ? true : false );
954
  }
955
 
956
  /**
@@ -960,7 +977,7 @@ function job_manager_generate_username_from_email() {
960
  * @return bool
961
  */
962
  function job_manager_user_requires_account() {
963
- return apply_filters( 'job_manager_user_requires_account', get_option( 'job_manager_user_requires_account' ) == 1 ? true : false );
964
  }
965
 
966
  /**
@@ -970,7 +987,7 @@ function job_manager_user_requires_account() {
970
  * @return bool
971
  */
972
  function job_manager_user_can_edit_pending_submissions() {
973
- return apply_filters( 'job_manager_user_can_edit_pending_submissions', get_option( 'job_manager_user_can_edit_pending_submissions' ) == 1 ? true : false );
974
  }
975
 
976
  /**
@@ -987,7 +1004,7 @@ function wpjm_user_can_edit_published_submissions() {
987
  *
988
  * @param bool $can_edit_published_submissions
989
  */
990
- return apply_filters( 'job_manager_user_can_edit_published_submissions', in_array( get_option( 'job_manager_user_edit_published_submissions' ), array( 'yes', 'yes_moderated' ) ) );
991
  }
992
 
993
  /**
@@ -1041,7 +1058,7 @@ function job_manager_dropdown_categories( $args = '' ) {
1041
  'show_option_all' => false,
1042
  'placeholder' => __( 'Choose a category&hellip;', 'wp-job-manager' ),
1043
  'no_results_text' => __( 'No results match', 'wp-job-manager' ),
1044
- 'multiple_text' => __( 'Select Some Options', 'wp-job-manager' )
1045
  );
1046
 
1047
  $r = wp_parse_args( $args, $defaults );
@@ -1053,42 +1070,40 @@ function job_manager_dropdown_categories( $args = '' ) {
1053
  /** This filter is documented in wp-job-manager.php */
1054
  $r['lang'] = apply_filters( 'wpjm_lang', null );
1055
 
1056
- extract( $r );
1057
-
1058
- // Store in a transient to help sites with many cats
1059
- $categories_hash = 'jm_cats_' . md5( json_encode( $r ) . WP_Job_Manager_Cache_Helper::get_transient_version( 'jm_get_' . $r['taxonomy'] ) );
1060
  $categories = get_transient( $categories_hash );
1061
 
1062
  if ( empty( $categories ) ) {
1063
- $categories = get_terms( array(
1064
- 'taxonomy' => $r['taxonomy'],
1065
- 'orderby' => $r['orderby'],
1066
- 'order' => $r['order'],
1067
- 'hide_empty' => $r['hide_empty'],
1068
- 'parent' => $r['parent'],
1069
- 'child_of' => $r['child_of'],
1070
- 'exclude' => $r['exclude'],
1071
- 'hierarchical' => $r['hierarchical'],
1072
- ) );
 
 
1073
  set_transient( $categories_hash, $categories, DAY_IN_SECONDS * 7 );
1074
  }
1075
 
1076
- $name = esc_attr( $name );
1077
- $class = esc_attr( $class );
1078
- $id = $id ? esc_attr( $id ) : $name;
1079
 
1080
- $output = "<select name='" . esc_attr( $name ) . "[]' id='" . esc_attr( $id ) . "' class='" . esc_attr( $class ) . "' " . ( $multiple ? "multiple='multiple'" : '' ) . " data-placeholder='" . esc_attr( $placeholder ) . "' data-no_results_text='" . esc_attr( $no_results_text ) . "' data-multiple_text='" . esc_attr( $multiple_text ) . "'>\n";
1081
 
1082
- if ( $show_option_all ) {
1083
- $output .= '<option value="">' . esc_html( $show_option_all ) . '</option>';
1084
  }
1085
 
1086
  if ( ! empty( $categories ) ) {
1087
- include_once( JOB_MANAGER_PLUGIN_DIR . '/includes/class-wp-job-manager-category-walker.php' );
1088
 
1089
- $walker = new WP_Job_Manager_Category_Walker;
1090
 
1091
- if ( $hierarchical ) {
1092
  $depth = $r['depth']; // Walk the full depth.
1093
  } else {
1094
  $depth = -1; // Flat.
@@ -1099,8 +1114,8 @@ function job_manager_dropdown_categories( $args = '' ) {
1099
 
1100
  $output .= "</select>\n";
1101
 
1102
- if ( $echo ) {
1103
- echo $output;
1104
  }
1105
 
1106
  return $output;
@@ -1110,7 +1125,7 @@ function job_manager_dropdown_categories( $args = '' ) {
1110
  * Gets the page ID of a page if set.
1111
  *
1112
  * @since 1.23.12
1113
- * @param string $page e.g. job_dashboard, submit_job_form, jobs
1114
  * @return int
1115
  */
1116
  function job_manager_get_page_id( $page ) {
@@ -1133,11 +1148,12 @@ function job_manager_get_page_id( $page ) {
1133
  * Gets the permalink of a page if set.
1134
  *
1135
  * @since 1.16.0
1136
- * @param string $page e.g. job_dashboard, submit_job_form, jobs
1137
  * @return string|bool
1138
  */
1139
  function job_manager_get_permalink( $page ) {
1140
- if ( $page_id = job_manager_get_page_id( $page ) ) {
 
1141
  return get_permalink( $page_id );
1142
  } else {
1143
  return false;
@@ -1184,20 +1200,20 @@ function job_manager_prepare_uploaded_files( $file_data ) {
1184
  $files_to_upload = array();
1185
 
1186
  if ( is_array( $file_data['name'] ) ) {
1187
- foreach( $file_data['name'] as $file_data_key => $file_data_value ) {
1188
  if ( $file_data['name'][ $file_data_key ] ) {
1189
- $type = wp_check_filetype( $file_data['name'][ $file_data_key ] ); // Map mime type to one WordPress recognises
1190
  $files_to_upload[] = array(
1191
  'name' => $file_data['name'][ $file_data_key ],
1192
  'type' => $type['type'],
1193
  'tmp_name' => $file_data['tmp_name'][ $file_data_key ],
1194
  'error' => $file_data['error'][ $file_data_key ],
1195
- 'size' => $file_data['size'][ $file_data_key ]
1196
  );
1197
  }
1198
  }
1199
  } else {
1200
- $type = wp_check_filetype( $file_data['name'] ); // Map mime type to one WordPress recognises
1201
  $file_data['type'] = $type['type'];
1202
  $files_to_upload[] = $file_data;
1203
  }
@@ -1210,20 +1226,23 @@ function job_manager_prepare_uploaded_files( $file_data ) {
1210
  *
1211
  * @since 1.21.0
1212
  * @param array|WP_Error $file Array of $_FILE data to upload.
1213
- * @param string|array|object $args Optional arguments
1214
- * @return stdClass|WP_Error Object containing file information, or error
1215
  */
1216
  function job_manager_upload_file( $file, $args = array() ) {
1217
  global $job_manager_upload, $job_manager_uploading_file;
1218
 
1219
- include_once( ABSPATH . 'wp-admin/includes/file.php' );
1220
- include_once( ABSPATH . 'wp-admin/includes/media.php' );
1221
 
1222
- $args = wp_parse_args( $args, array(
1223
- 'file_key' => '',
1224
- 'file_label' => '',
1225
- 'allowed_mime_types' => '',
1226
- ) );
 
 
 
1227
 
1228
  $job_manager_upload = true;
1229
  $job_manager_uploading_file = $args['file_key'];
@@ -1243,8 +1262,8 @@ function job_manager_upload_file( $file, $args = array() ) {
1243
  * @since 1.25.2
1244
  *
1245
  * @param array $file Array of $_FILE data to upload.
1246
- * @param array $args Optional file arguments
1247
- * @param array $allowed_mime_types Array of allowed mime types from field config or defaults
1248
  */
1249
  $file = apply_filters( 'job_manager_upload_file_pre_upload', $file, $args, $allowed_mime_types );
1250
 
@@ -1252,10 +1271,12 @@ function job_manager_upload_file( $file, $args = array() ) {
1252
  return $file;
1253
  }
1254
 
1255
- if ( ! in_array( $file['type'], $allowed_mime_types ) ) {
1256
  if ( $args['file_label'] ) {
1257
- return new WP_Error( 'upload', sprintf( __( '"%s" (filetype %s) needs to be one of the following file types: %s', 'wp-job-manager' ), $args['file_label'], $file['type'], implode( ', ', array_keys( $allowed_mime_types ) ) ) );
 
1258
  } else {
 
1259
  return new WP_Error( 'upload', sprintf( __( 'Uploaded files need to be one of the following file types: %s', 'wp-job-manager' ), implode( ', ', array_keys( $allowed_mime_types ) ) ) );
1260
  }
1261
  } else {
@@ -1285,7 +1306,7 @@ function job_manager_upload_file( $file, $args = array() ) {
1285
  * @param string $field Field used.
1286
  * @return array Array of allowed mime types
1287
  */
1288
- function job_manager_get_allowed_mime_types( $field = '' ){
1289
  if ( 'company_logo' === $field ) {
1290
  $allowed_mime_types = array(
1291
  'jpg|jpeg|jpe' => 'image/jpeg',
@@ -1330,7 +1351,7 @@ function calculate_job_expiry( $job_id ) {
1330
  // Get duration from the product if set...
1331
  $duration = get_post_meta( $job_id, '_job_duration', true );
1332
 
1333
- // ...otherwise use the global option
1334
  if ( ! $duration ) {
1335
  $duration = absint( get_option( 'job_manager_submission_duration' ) );
1336
  }
@@ -1350,30 +1371,37 @@ function calculate_job_expiry( $job_id ) {
1350
  * @return int 0 on fail or the post ID.
1351
  */
1352
  function job_manager_duplicate_listing( $post_id ) {
1353
- if ( empty( $post_id ) || ! ( $post = get_post( $post_id ) ) ) {
 
 
1354
  return 0;
1355
  }
1356
 
1357
- global $wpdb;
 
 
 
1358
 
1359
  /**
1360
  * Duplicate the post.
1361
  */
1362
- $new_post_id = wp_insert_post( array(
1363
- 'comment_status' => $post->comment_status,
1364
- 'ping_status' => $post->ping_status,
1365
- 'post_author' => $post->post_author,
1366
- 'post_content' => $post->post_content,
1367
- 'post_excerpt' => $post->post_excerpt,
1368
- 'post_name' => $post->post_name,
1369
- 'post_parent' => $post->post_parent,
1370
- 'post_password' => $post->post_password,
1371
- 'post_status' => 'preview',
1372
- 'post_title' => $post->post_title,
1373
- 'post_type' => $post->post_type,
1374
- 'to_ping' => $post->to_ping,
1375
- 'menu_order' => $post->menu_order
1376
- ) );
 
 
1377
 
1378
  /**
1379
  * Copy taxonomies.
@@ -1392,8 +1420,12 @@ function job_manager_duplicate_listing( $post_id ) {
1392
 
1393
  if ( ! empty( $post_meta ) ) {
1394
  $post_meta = wp_list_pluck( $post_meta, 'meta_value', 'meta_key' );
 
 
 
 
1395
  foreach ( $post_meta as $meta_key => $meta_value ) {
1396
- if ( in_array( $meta_key, apply_filters( 'job_manager_duplicate_listing_ignore_keys', array( '_filled', '_featured', '_job_expires', '_job_duration', '_package_id', '_user_package_id' ) ) ) ) {
1397
  continue;
1398
  }
1399
  update_post_meta( $new_post_id, $meta_key, maybe_unserialize( $meta_value ) );
1
  <?php
2
  if ( ! function_exists( 'get_job_listings' ) ) :
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3
  /**
4
+ * Queries job listings with certain criteria and returns them.
5
  *
6
+ * @since 1.0.5
7
+ * @param string|array|object $args Arguments used to retrieve job listings.
8
+ * @return WP_Query
9
  */
10
+ function get_job_listings( $args = array() ) {
11
+ global $job_manager_keyword;
12
+
13
+ $args = wp_parse_args(
14
+ $args,
15
+ array(
16
+ 'search_location' => '',
17
+ 'search_keywords' => '',
18
+ 'search_categories' => array(),
19
+ 'job_types' => array(),
20
+ 'post_status' => array(),
21
+ 'offset' => 0,
22
+ 'posts_per_page' => 20,
23
+ 'orderby' => 'date',
24
+ 'order' => 'DESC',
25
+ 'featured' => null,
26
+ 'filled' => null,
27
+ 'fields' => 'all',
28
+ )
29
+ );
30
 
31
+ /**
32
+ * Perform actions that need to be done prior to the start of the job listings query.
33
+ *
34
+ * @since 1.26.0
35
+ *
36
+ * @param array $args Arguments used to retrieve job listings.
37
+ */
38
+ do_action( 'get_job_listings_init', $args );
39
 
40
+ if ( ! empty( $args['post_status'] ) ) {
41
+ $post_status = $args['post_status'];
42
+ } elseif ( 0 === intval( get_option( 'job_manager_hide_expired', get_option( 'job_manager_hide_expired_content', 1 ) ) ) ) {
43
+ $post_status = array( 'publish', 'expired' );
44
+ } else {
45
+ $post_status = 'publish';
46
+ }
 
 
 
 
 
 
 
 
47
 
48
+ $query_args = array(
49
+ 'post_type' => 'job_listing',
50
+ 'post_status' => $post_status,
51
+ 'ignore_sticky_posts' => 1,
52
+ 'offset' => absint( $args['offset'] ),
53
+ 'posts_per_page' => intval( $args['posts_per_page'] ),
54
+ 'orderby' => $args['orderby'],
55
+ 'order' => $args['order'],
56
+ 'tax_query' => array(),
57
+ 'meta_query' => array(),
58
+ 'update_post_term_cache' => false,
59
+ 'update_post_meta_cache' => false,
60
+ 'cache_results' => false,
61
+ 'fields' => $args['fields'],
62
+ );
63
 
64
+ if ( $args['posts_per_page'] < 0 ) {
65
+ $query_args['no_found_rows'] = true;
 
 
 
 
 
 
 
66
  }
 
 
67
 
68
+ if ( ! empty( $args['search_location'] ) ) {
69
+ $location_meta_keys = array( 'geolocation_formatted_address', '_job_location', 'geolocation_state_long' );
70
+ $location_search = array( 'relation' => 'OR' );
71
+ foreach ( $location_meta_keys as $meta_key ) {
72
+ $location_search[] = array(
73
+ 'key' => $meta_key,
74
+ 'value' => $args['search_location'],
75
+ 'compare' => 'like',
76
+ );
77
+ }
78
+ $query_args['meta_query'][] = $location_search;
79
+ }
80
 
81
+ if ( ! is_null( $args['featured'] ) ) {
82
+ $query_args['meta_query'][] = array(
83
+ 'key' => '_featured',
84
+ 'value' => '1',
85
+ 'compare' => $args['featured'] ? '=' : '!=',
86
+ );
87
+ }
88
 
89
+ if ( ! is_null( $args['filled'] ) || 1 === absint( get_option( 'job_manager_hide_filled_positions' ) ) ) {
90
+ $query_args['meta_query'][] = array(
91
+ 'key' => '_filled',
92
+ 'value' => '1',
93
+ 'compare' => $args['filled'] ? '=' : '!=',
94
+ );
95
+ }
96
 
97
+ if ( ! empty( $args['job_types'] ) ) {
98
+ $query_args['tax_query'][] = array(
99
+ 'taxonomy' => 'job_listing_type',
100
+ 'field' => 'slug',
101
+ 'terms' => $args['job_types'],
102
+ );
103
+ }
 
 
 
 
104
 
105
+ if ( ! empty( $args['search_categories'] ) ) {
106
+ $field = is_numeric( $args['search_categories'][0] ) ? 'term_id' : 'slug';
107
+ $operator = 'all' === get_option( 'job_manager_category_filter_type', 'all' ) && count( $args['search_categories'] ) > 1 ? 'AND' : 'IN';
108
+ $query_args['tax_query'][] = array(
109
+ 'taxonomy' => 'job_listing_category',
110
+ 'field' => $field,
111
+ 'terms' => array_values( $args['search_categories'] ),
112
+ 'include_children' => 'AND' !== $operator,
113
+ 'operator' => $operator,
114
+ );
115
+ }
116
 
117
+ if ( 'featured' === $args['orderby'] ) {
118
+ $query_args['orderby'] = array(
119
+ 'menu_order' => 'ASC',
120
+ 'date' => 'DESC',
121
+ 'ID' => 'DESC',
122
+ );
123
+ }
124
 
125
+ if ( 'rand_featured' === $args['orderby'] ) {
126
+ $query_args['orderby'] = array(
127
+ 'menu_order' => 'ASC',
128
+ 'rand' => 'ASC',
129
+ );
130
+ }
131
 
132
+ $job_manager_keyword = sanitize_text_field( $args['search_keywords'] );
 
 
 
133
 
134
+ if ( ! empty( $job_manager_keyword ) && strlen( $job_manager_keyword ) >= apply_filters( 'job_manager_get_listings_keyword_length_threshold', 2 ) ) {
135
+ $query_args['s'] = $job_manager_keyword;
136
+ add_filter( 'posts_search', 'get_job_listings_keyword_search' );
137
+ }
138
 
139
+ $query_args = apply_filters( 'job_manager_get_listings', $query_args, $args );
 
 
140
 
141
+ if ( empty( $query_args['meta_query'] ) ) {
142
+ unset( $query_args['meta_query'] );
143
+ }
144
 
145
+ if ( empty( $query_args['tax_query'] ) ) {
146
+ unset( $query_args['tax_query'] );
147
+ }
148
 
149
+ /** This filter is documented in wp-job-manager.php */
150
+ $query_args['lang'] = apply_filters( 'wpjm_lang', null );
151
 
152
+ // Filter args.
153
+ $query_args = apply_filters( 'get_job_listings_query_args', $query_args, $args );
154
 
155
+ do_action( 'before_get_job_listings', $query_args, $args );
156
 
157
+ // Cache results.
158
+ if ( apply_filters( 'get_job_listings_cache_results', true ) ) {
159
+ $to_hash = wp_json_encode( $query_args );
160
+ $query_args_hash = 'jm_' . md5( $to_hash . JOB_MANAGER_VERSION ) . WP_Job_Manager_Cache_Helper::get_transient_version( 'get_job_listings' );
161
+ $result = false;
162
+ $cached_query_results = true;
163
+ $cached_query_posts = get_transient( $query_args_hash );
164
+ if ( is_string( $cached_query_posts ) ) {
165
+ $cached_query_posts = json_decode( $cached_query_posts, false );
166
+ if ( $cached_query_posts
167
  && is_object( $cached_query_posts )
168
  && isset( $cached_query_posts->max_num_pages )
169
  && isset( $cached_query_posts->found_posts )
170
  && isset( $cached_query_posts->posts )
171
  && is_array( $cached_query_posts->posts )
172
+ ) {
173
+ $posts = array_map( 'get_post', $cached_query_posts->posts );
174
+ $result = new WP_Query();
175
+ $result->parse_query( $query_args );
176
+ $result->posts = $posts;
177
+ $result->found_posts = intval( $cached_query_posts->found_posts );
178
+ $result->max_num_pages = intval( $cached_query_posts->max_num_pages );
179
+ $result->post_count = count( $posts );
180
+ }
181
  }
 
182
 
183
+ if ( false === $result ) {
184
+ $result = new WP_Query( $query_args );
185
+ $cached_query_results = false;
186
 
187
+ $cacheable_result = array();
188
+ $cacheable_result['posts'] = array_values( $result->posts );
189
+ $cacheable_result['found_posts'] = $result->found_posts;
190
+ $cacheable_result['max_num_pages'] = $result->max_num_pages;
191
+ set_transient( $query_args_hash, wp_json_encode( $cacheable_result ), DAY_IN_SECONDS );
192
+ }
193
 
194
+ if ( $cached_query_results ) {
195
+ // random order is cached so shuffle them.
196
+ if ( 'rand_featured' === $args['orderby'] ) {
197
+ usort( $result->posts, '_wpjm_shuffle_featured_post_results_helper' );
198
+ } elseif ( 'rand' === $args['orderby'] ) {
199
+ shuffle( $result->posts );
200
+ }
201
  }
202
+ } else {
203
+ $result = new WP_Query( $query_args );
204
  }
 
 
 
205
 
206
+ do_action( 'after_get_job_listings', $query_args, $args );
207
 
208
+ remove_filter( 'posts_search', 'get_job_listings_keyword_search' );
209
 
210
+ return $result;
211
+ }
212
  endif;
213
 
214
  if ( ! function_exists( '_wpjm_shuffle_featured_post_results_helper' ) ) :
222
  */
223
  function _wpjm_shuffle_featured_post_results_helper( $a, $b ) {
224
  if ( -1 === $a->menu_order || -1 === $b->menu_order ) {
225
+ // Left is featured.
226
  if ( 0 === $b->menu_order ) {
227
  return -1;
228
  }
229
+ // Right is featured.
230
  if ( 0 === $a->menu_order ) {
231
  return 1;
232
  }
248
  function get_job_listings_keyword_search( $search ) {
249
  global $wpdb, $job_manager_keyword;
250
 
251
+ // Searchable Meta Keys: set to empty to search all meta keys.
252
  $searchable_meta_keys = array(
253
  '_job_location',
254
  '_company_name',
261
 
262
  $searchable_meta_keys = apply_filters( 'job_listing_searchable_meta_keys', $searchable_meta_keys );
263
 
264
+ // Set Search DB Conditions.
265
+ $conditions = array();
266
 
267
+ // Search Post Meta.
268
+ if ( apply_filters( 'job_listing_search_post_meta', true ) ) {
269
 
270
+ // Only selected meta keys.
271
+ if ( $searchable_meta_keys ) {
272
  $conditions[] = "{$wpdb->posts}.ID IN ( SELECT post_id FROM {$wpdb->postmeta} WHERE meta_key IN ( '" . implode( "','", array_map( 'esc_sql', $searchable_meta_keys ) ) . "' ) AND meta_value LIKE '%" . esc_sql( $job_manager_keyword ) . "%' )";
273
  } else {
274
+ // No meta keys defined, search all post meta value.
275
  $conditions[] = "{$wpdb->posts}.ID IN ( SELECT post_id FROM {$wpdb->postmeta} WHERE meta_value LIKE '%" . esc_sql( $job_manager_keyword ) . "%' )";
276
  }
277
  }
278
 
279
+ // Search taxonomy.
280
  $conditions[] = "{$wpdb->posts}.ID IN ( SELECT object_id FROM {$wpdb->term_relationships} AS tr LEFT JOIN {$wpdb->term_taxonomy} AS tt ON tr.term_taxonomy_id = tt.term_taxonomy_id LEFT JOIN {$wpdb->terms} AS t ON tt.term_id = t.term_id WHERE t.name LIKE '%" . esc_sql( $job_manager_keyword ) . "%' )";
281
 
282
  /**
306
  endif;
307
 
308
  if ( ! function_exists( 'get_job_listing_post_statuses' ) ) :
309
+ /**
310
+ * Gets post statuses used for jobs.
311
+ *
312
+ * @since 1.12.0
313
+ * @return array
314
+ */
315
+ function get_job_listing_post_statuses() {
316
+ return apply_filters(
317
+ 'job_listing_post_statuses',
318
+ array(
319
+ 'draft' => _x( 'Draft', 'post status', 'wp-job-manager' ),
320
+ 'expired' => _x( 'Expired', 'post status', 'wp-job-manager' ),
321
+ 'preview' => _x( 'Preview', 'post status', 'wp-job-manager' ),
322
+ 'pending' => _x( 'Pending approval', 'post status', 'wp-job-manager' ),
323
+ 'pending_payment' => _x( 'Pending payment', 'post status', 'wp-job-manager' ),
324
+ 'publish' => _x( 'Active', 'post status', 'wp-job-manager' ),
325
+ )
326
+ );
327
+ }
328
  endif;
329
 
330
  if ( ! function_exists( 'get_featured_job_ids' ) ) :
331
+ /**
332
+ * Gets the ids of featured jobs.
333
+ *
334
+ * @since 1.0.4
335
+ * @return array
336
+ */
337
+ function get_featured_job_ids() {
338
+ return get_posts(
339
+ array(
340
+ 'posts_per_page' => -1,
341
+ 'suppress_filters' => false,
342
+ 'post_type' => 'job_listing',
343
+ 'post_status' => 'publish',
344
+ 'meta_key' => '_featured',
345
+ 'meta_value' => '1',
346
+ 'fields' => 'ids',
347
+ )
348
+ );
349
+ }
350
  endif;
351
 
352
  if ( ! function_exists( 'get_job_listing_types' ) ) :
353
+ /**
354
+ * Gets job listing types.
355
+ *
356
+ * @since 1.0.0
357
+ * @param string|array $fields
358
+ * @return WP_Term[]
359
+ */
360
+ function get_job_listing_types( $fields = 'all' ) {
361
+ if ( ! get_option( 'job_manager_enable_types' ) ) {
362
+ return array();
363
+ } else {
364
+ $args = array(
365
+ 'fields' => $fields,
366
+ 'hide_empty' => false,
367
+ 'order' => 'ASC',
368
+ 'orderby' => 'name',
369
+ );
370
 
371
+ $args = apply_filters( 'get_job_listing_types_args', $args );
372
 
373
+ // Prevent users from filtering the taxonomy.
374
+ $args['taxonomy'] = 'job_listing_type';
375
 
376
+ return get_terms( $args );
377
+ }
378
  }
 
379
  endif;
380
 
381
  if ( ! function_exists( 'get_job_listing_categories' ) ) :
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
382
  /**
383
+ * Gets job categories.
384
  *
385
+ * @since 1.0.0
386
+ * @return array
 
387
  */
388
+ function get_job_listing_categories() {
389
+ if ( ! get_option( 'job_manager_enable_categories' ) ) {
390
+ return array();
391
+ }
392
+
393
+ $args = array(
394
+ 'orderby' => 'name',
395
+ 'order' => 'ASC',
396
+ 'hide_empty' => false,
397
+ );
398
 
399
+ /**
400
+ * Change the category query arguments.
401
+ *
402
+ * @since 1.31.0
403
+ *
404
+ * @param array $args
405
+ */
406
+ $args = apply_filters( 'get_job_listing_category_args', $args );
407
 
408
+ // Prevent users from filtering the taxonomy.
409
+ $args['taxonomy'] = 'job_listing_category';
410
+
411
+ return get_terms( $args );
412
+ }
413
  endif;
414
 
415
  if ( ! function_exists( 'job_manager_get_filtered_links' ) ) :
416
+ /**
417
+ * Shows links after filtering jobs
418
+ *
419
+ * @since 1.0.6
420
+ * @param array $args
421
+ * @return string
422
+ */
423
+ function job_manager_get_filtered_links( $args = array() ) {
424
+ $job_categories = array();
425
+ $types = get_job_listing_types();
426
+
427
+ // Convert to slugs.
428
+ if ( $args['search_categories'] ) {
429
+ foreach ( $args['search_categories'] as $category ) {
430
+ if ( is_numeric( $category ) ) {
431
+ $category_object = get_term_by( 'id', $category, 'job_listing_category' );
432
+ if ( ! is_wp_error( $category_object ) ) {
433
+ $job_categories[] = $category_object->slug;
434
+ }
435
+ } else {
436
+ $job_categories[] = $category;
437
  }
 
 
438
  }
439
  }
 
440
 
441
+ $links = apply_filters(
442
+ 'job_manager_job_filters_showing_jobs_links',
443
+ array(
444
+ 'reset' => array(
445
+ 'name' => __( 'Reset', 'wp-job-manager' ),
446
+ 'url' => '#',
447
+ ),
448
+ 'rss_link' => array(
449
+ 'name' => __( 'RSS', 'wp-job-manager' ),
450
+ 'url' => get_job_listing_rss_link(
451
+ apply_filters(
452
+ 'job_manager_get_listings_custom_filter_rss_args',
453
+ array(
454
+ 'job_types' => isset( $args['filter_job_types'] ) ? implode( ',', $args['filter_job_types'] ) : '',
455
+ 'search_location' => $args['search_location'],
456
+ 'job_categories' => implode( ',', $job_categories ),
457
+ 'search_keywords' => $args['search_keywords'],
458
+ )
459
+ )
460
+ ),
461
+ ),
462
+ ), $args
463
+ );
 
464
 
465
+ if ( count( (array) $args['filter_job_types'] ) === count( $types )
466
+ && empty( $args['search_keywords'] )
467
+ && empty( $args['search_location'] )
468
+ && empty( $args['search_categories'] )
469
+ && ! apply_filters( 'job_manager_get_listings_custom_filter', false )
470
+ ) {
471
+ unset( $links['reset'] );
472
+ }
473
 
474
+ $return = '';
 
 
475
 
476
+ foreach ( $links as $key => $link ) {
477
+ $return .= '<a href="' . esc_url( $link['url'] ) . '" class="' . esc_attr( $key ) . '">' . wp_kses_post( $link['name'] ) . '</a>';
478
+ }
479
+
480
+ return $return;
481
+ }
482
  endif;
483
 
484
  if ( ! function_exists( 'get_job_listing_rss_link' ) ) :
485
+ /**
486
+ * Get the Job Listing RSS link
487
+ *
488
+ * @since 1.0.0
489
+ * @param array $args
490
+ * @return string
491
+ */
492
+ function get_job_listing_rss_link( $args = array() ) {
493
+ $rss_link = add_query_arg( urlencode_deep( array_merge( array( 'feed' => 'job_feed' ), $args ) ), home_url() );
494
+ return $rss_link;
495
+ }
496
  endif;
497
 
498
  if ( ! function_exists( 'wp_job_manager_notify_new_user' ) ) :
507
  global $wp_version;
508
 
509
  if ( version_compare( $wp_version, '4.3.1', '<' ) ) {
510
+ wp_new_user_notification( $user_id, $password ); // phpcs:ignore WordPress.WP.DeprecatedParameters.Wp_new_user_notificationParam2Found
511
  } else {
512
  $notify = 'admin';
513
  if ( empty( $password ) ) {
518
  }
519
  endif;
520
 
521
+ if ( ! function_exists( 'wp_job_manager_create_account' ) ) :
522
+ /**
523
+ * Handles account creation.
524
+ *
525
+ * @since 1.0.0
526
+ * @param string|array|object $args containing username, email, role.
527
+ * @param string $deprecated role string.
528
+ * @return WP_Error|bool True if account was created.
529
+ */
530
+ function wp_job_manager_create_account( $args, $deprecated = '' ) {
531
+ // Soft Deprecated in 1.20.0.
532
+ if ( ! is_array( $args ) ) {
533
+ $args = array(
534
+ 'username' => '',
535
+ 'password' => false,
536
+ 'email' => $args,
537
+ 'role' => $deprecated,
538
+ );
539
+ } else {
540
+ $defaults = array(
541
+ 'username' => '',
542
+ 'email' => '',
543
+ 'password' => false,
544
+ 'role' => get_option( 'default_role' ),
545
+ );
546
 
547
+ $args = wp_parse_args( $args, $defaults );
548
+ }
 
549
 
550
+ $username = sanitize_user( $args['username'], true );
551
+ $email = apply_filters( 'user_registration_email', sanitize_email( $args['email'] ) );
552
 
553
+ if ( empty( $email ) ) {
554
+ return new WP_Error( 'validation-error', __( 'Invalid email address.', 'wp-job-manager' ) );
555
+ }
556
 
557
+ if ( empty( $username ) ) {
558
+ $username = sanitize_user( current( explode( '@', $email ) ), true );
559
+ }
560
 
561
+ if ( ! is_email( $email ) ) {
562
+ return new WP_Error( 'validation-error', __( 'Your email address isn&#8217;t correct.', 'wp-job-manager' ) );
563
+ }
564
 
565
+ if ( email_exists( $email ) ) {
566
+ return new WP_Error( 'validation-error', __( 'This email is already registered, please choose another one.', 'wp-job-manager' ) );
567
+ }
568
 
569
+ // Ensure username is unique.
570
+ $append = 1;
571
+ $o_username = $username;
572
 
573
+ while ( username_exists( $username ) ) {
574
+ $username = $o_username . $append;
575
+ $append ++;
576
+ }
577
 
578
+ // Final error checking.
579
+ $reg_errors = new WP_Error();
580
+ $reg_errors = apply_filters( 'job_manager_registration_errors', $reg_errors, $username, $email );
581
 
582
+ do_action( 'job_manager_register_post', $username, $email, $reg_errors );
583
 
584
+ if ( $reg_errors->get_error_code() ) {
585
+ return $reg_errors;
586
+ }
587
 
588
+ // Create account.
589
+ $new_user = array(
590
+ 'user_login' => $username,
591
+ 'user_pass' => $args['password'],
592
+ 'user_email' => $email,
593
+ 'role' => $args['role'],
594
+ );
595
 
596
+ // User is forced to set up account with email sent to them. This password will remain a secret.
597
+ if ( empty( $new_user['user_pass'] ) ) {
598
+ $new_user['user_pass'] = wp_generate_password();
599
+ }
600
 
601
+ $user_id = wp_insert_user( apply_filters( 'job_manager_create_account_data', $new_user ) );
602
 
603
+ if ( is_wp_error( $user_id ) ) {
604
+ return $user_id;
605
+ }
606
 
607
+ /**
608
+ * Send notification to new users.
609
+ *
610
+ * @since 1.28.0
611
+ *
612
+ * @param int $user_id
613
+ * @param string|bool $password
614
+ * @param array $new_user {
615
+ * Information about the new user.
616
+ *
617
+ * @type string $user_login Username for the user.
618
+ * @type string $user_pass Password for the user (may be blank).
619
+ * @type string $user_email Email for the new user account.
620
+ * @type string $role New user's role.
621
+ * }
622
+ */
623
+ do_action( 'wpjm_notify_new_user', $user_id, $args['password'], $new_user );
624
 
625
+ // Login.
626
+ wp_set_auth_cookie( $user_id, true, is_ssl() );
627
+ wp_set_current_user( $user_id );
628
 
629
+ return true;
630
+ }
631
  endif;
632
 
633
  /**
684
  if ( ! is_user_logged_in() || ! $job_id ) {
685
  $can_edit = false;
686
  } else {
687
+ $job = get_post( $job_id );
688
 
689
  if ( ! $job || ( absint( $job->post_author ) !== get_current_user_id() && ! current_user_can( 'edit_post', $job_id ) ) ) {
690
  $can_edit = false;
709
  *
710
  * @param bool $is_wpjm
711
  */
712
+ return apply_filters( 'is_wpjm', ( is_wpjm_page() || has_wpjm_shortcode() || is_wpjm_job_listing() || is_wpjm_taxonomy() ) );
713
  }
714
 
715
  /**
723
  $is_wpjm_page = is_post_type_archive( 'job_listing' );
724
 
725
  if ( ! $is_wpjm_page ) {
726
+ $wpjm_page_ids = array_filter(
727
+ array(
728
+ get_option( 'job_manager_submit_job_form_page_id', false ),
729
+ get_option( 'job_manager_job_dashboard_page_id', false ),
730
+ get_option( 'job_manager_jobs_page_id', false ),
731
+ )
732
+ );
733
 
734
  /**
735
  * Filters a list of all page IDs related to WPJM.
740
  */
741
  $wpjm_page_ids = array_unique( apply_filters( 'job_manager_page_ids', $wpjm_page_ids ) );
742
 
743
+ $is_wpjm_page = is_page( $wpjm_page_ids );
744
  }
745
 
746
  /**
840
 
841
  // If username is being automatically generated, force them to send password setup email.
842
  if ( ! job_manager_generate_username_from_email() ) {
843
+ $use_standard_password_setup_email = 1 === intval( get_option( 'job_manager_use_standard_password_setup_email' ) );
844
  }
845
 
846
  /**
862
  * @return array
863
  */
864
  function wpjm_job_listing_employment_type_options() {
865
+ $employment_types = array();
866
+ $employment_types['FULL_TIME'] = __( 'Full Time', 'wp-job-manager' );
867
+ $employment_types['PART_TIME'] = __( 'Part Time', 'wp-job-manager' );
868
  $employment_types['CONTRACTOR'] = __( 'Contractor', 'wp-job-manager' );
869
+ $employment_types['TEMPORARY'] = __( 'Temporary', 'wp-job-manager' );
870
+ $employment_types['INTERN'] = __( 'Intern', 'wp-job-manager' );
871
+ $employment_types['VOLUNTEER'] = __( 'Volunteer', 'wp-job-manager' );
872
+ $employment_types['PER_DIEM'] = __( 'Per Diem', 'wp-job-manager' );
873
+ $employment_types['OTHER'] = __( 'Other', 'wp-job-manager' );
874
 
875
  /**
876
  * Filter the list of employment types.
898
  *
899
  * @param bool True if employment type meta field is enabled on job type terms.
900
  */
901
+ return apply_filters( 'wpjm_job_listing_employment_type_enabled', (bool) get_option( 'job_manager_enable_types' ) );
902
  }
903
 
904
  /**
911
  */
912
  function wpjm_validate_new_password( $password ) {
913
  // Password must be at least 8 characters long. Trimming here because `wp_hash_password()` will later on.
914
+ $is_valid_password = strlen( trim( $password ) ) >= 8;
915
 
916
  /**
917
  * Allows overriding default WPJM password validation rules.
937
  *
938
  * @param string $password_rules Password rules description.
939
  */
940
+ return apply_filters( 'wpjm_password_rules_hint', __( 'Passwords must be at least 8 characters long.', 'wp-job-manager' ) );
941
  }
942
 
943
  /**
947
  * @return bool
948
  */
949
  function job_manager_multi_job_type() {
950
+ return apply_filters( 'job_manager_multi_job_type', 1 === intval( get_option( 'job_manager_multi_job_type' ) ) );
951
  }
952
 
953
  /**
957
  * @return bool
958
  */
959
  function job_manager_enable_registration() {
960
+ return apply_filters( 'job_manager_enable_registration', 1 === intval( get_option( 'job_manager_enable_registration' ) ) );
961
  }
962
 
963
  /**
967
  * @return bool
968
  */
969
  function job_manager_generate_username_from_email() {
970
+ return apply_filters( 'job_manager_generate_username_from_email', 1 === intval( get_option( 'job_manager_generate_username_from_email' ) ) );
971
  }
972
 
973
  /**
977
  * @return bool
978
  */
979
  function job_manager_user_requires_account() {
980
+ return apply_filters( 'job_manager_user_requires_account', 1 === intval( get_option( 'job_manager_user_requires_account' ) ) );
981
  }
982
 
983
  /**
987
  * @return bool
988
  */
989
  function job_manager_user_can_edit_pending_submissions() {
990
+ return apply_filters( 'job_manager_user_can_edit_pending_submissions', 1 === intval( get_option( 'job_manager_user_can_edit_pending_submissions' ) ) );
991
  }
992
 
993
  /**
1004
  *
1005
  * @param bool $can_edit_published_submissions
1006
  */
1007
+ return apply_filters( 'job_manager_user_can_edit_published_submissions', in_array( get_option( 'job_manager_user_edit_published_submissions' ), array( 'yes', 'yes_moderated' ), true ) );
1008
  }
1009
 
1010
  /**
1058
  'show_option_all' => false,
1059
  'placeholder' => __( 'Choose a category&hellip;', 'wp-job-manager' ),
1060
  'no_results_text' => __( 'No results match', 'wp-job-manager' ),
1061
+ 'multiple_text' => __( 'Select Some Options', 'wp-job-manager' ),
1062
  );
1063
 
1064
  $r = wp_parse_args( $args, $defaults );
1070
  /** This filter is documented in wp-job-manager.php */
1071
  $r['lang'] = apply_filters( 'wpjm_lang', null );
1072
 
1073
+ // Store in a transient to help sites with many cats.
1074
+ $categories_hash = 'jm_cats_' . md5( wp_json_encode( $r ) . WP_Job_Manager_Cache_Helper::get_transient_version( 'jm_get_' . $r['taxonomy'] ) );
 
 
1075
  $categories = get_transient( $categories_hash );
1076
 
1077
  if ( empty( $categories ) ) {
1078
+ $categories = get_terms(
1079
+ array(
1080
+ 'taxonomy' => $r['taxonomy'],
1081
+ 'orderby' => $r['orderby'],
1082
+ 'order' => $r['order'],
1083
+ 'hide_empty' => $r['hide_empty'],
1084
+ 'parent' => $r['parent'],
1085
+ 'child_of' => $r['child_of'],
1086
+ 'exclude' => $r['exclude'],
1087
+ 'hierarchical' => $r['hierarchical'],
1088
+ )
1089
+ );
1090
  set_transient( $categories_hash, $categories, DAY_IN_SECONDS * 7 );
1091
  }
1092
 
1093
+ $id = $r['id'] ? $r['id'] : $r['name'];
 
 
1094
 
1095
+ $output = "<select name='" . esc_attr( $r['name'] ) . "[]' id='" . esc_attr( $id ) . "' class='" . esc_attr( $r['class'] ) . "' " . ( $r['multiple'] ? "multiple='multiple'" : '' ) . " data-placeholder='" . esc_attr( $r['placeholder'] ) . "' data-no_results_text='" . esc_attr( $r['no_results_text'] ) . "' data-multiple_text='" . esc_attr( $r['multiple_text'] ) . "'>\n";
1096
 
1097
+ if ( $r['show_option_all'] ) {
1098
+ $output .= '<option value="">' . esc_html( $r['show_option_all'] ) . '</option>';
1099
  }
1100
 
1101
  if ( ! empty( $categories ) ) {
1102
+ include_once JOB_MANAGER_PLUGIN_DIR . '/includes/class-wp-job-manager-category-walker.php';
1103
 
1104
+ $walker = new WP_Job_Manager_Category_Walker();
1105
 
1106
+ if ( $r['hierarchical'] ) {
1107
  $depth = $r['depth']; // Walk the full depth.
1108
  } else {
1109
  $depth = -1; // Flat.
1114
 
1115
  $output .= "</select>\n";
1116
 
1117
+ if ( $r['echo'] ) {
1118
+ echo $output; // WPCS: XSS ok.
1119
  }
1120
 
1121
  return $output;
1125
  * Gets the page ID of a page if set.
1126
  *
1127
  * @since 1.23.12
1128
+ * @param string $page e.g. job_dashboard, submit_job_form, jobs.
1129
  * @return int
1130
  */
1131
  function job_manager_get_page_id( $page ) {
1148
  * Gets the permalink of a page if set.
1149
  *
1150
  * @since 1.16.0
1151
+ * @param string $page e.g. job_dashboard, submit_job_form, jobs.
1152
  * @return string|bool
1153
  */
1154
  function job_manager_get_permalink( $page ) {
1155
+ $page_id = job_manager_get_page_id( $page );
1156
+ if ( $page_id ) {
1157
  return get_permalink( $page_id );
1158
  } else {
1159
  return false;
1200
  $files_to_upload = array();
1201
 
1202
  if ( is_array( $file_data['name'] ) ) {
1203
+ foreach ( $file_data['name'] as $file_data_key => $file_data_value ) {
1204
  if ( $file_data['name'][ $file_data_key ] ) {
1205
+ $type = wp_check_filetype( $file_data['name'][ $file_data_key ] ); // Map mime type to one WordPress recognises.
1206
  $files_to_upload[] = array(
1207
  'name' => $file_data['name'][ $file_data_key ],
1208
  'type' => $type['type'],
1209
  'tmp_name' => $file_data['tmp_name'][ $file_data_key ],
1210
  'error' => $file_data['error'][ $file_data_key ],
1211
+ 'size' => $file_data['size'][ $file_data_key ],
1212
  );
1213
  }
1214
  }
1215
  } else {
1216
+ $type = wp_check_filetype( $file_data['name'] ); // Map mime type to one WordPress recognises.
1217
  $file_data['type'] = $type['type'];
1218
  $files_to_upload[] = $file_data;
1219
  }
1226
  *
1227
  * @since 1.21.0
1228
  * @param array|WP_Error $file Array of $_FILE data to upload.
1229
+ * @param string|array|object $args Optional arguments.
1230
+ * @return stdClass|WP_Error Object containing file information, or error.
1231
  */
1232
  function job_manager_upload_file( $file, $args = array() ) {
1233
  global $job_manager_upload, $job_manager_uploading_file;
1234
 
1235
+ include_once ABSPATH . 'wp-admin/includes/file.php';
1236
+ include_once ABSPATH . 'wp-admin/includes/media.php';
1237
 
1238
+ $args = wp_parse_args(
1239
+ $args,
1240
+ array(
1241
+ 'file_key' => '',
1242
+ 'file_label' => '',
1243
+ 'allowed_mime_types' => '',
1244
+ )
1245
+ );
1246
 
1247
  $job_manager_upload = true;
1248
  $job_manager_uploading_file = $args['file_key'];
1262
  * @since 1.25.2
1263
  *
1264
  * @param array $file Array of $_FILE data to upload.
1265
+ * @param array $args Optional file arguments.
1266
+ * @param array $allowed_mime_types Array of allowed mime types from field config or defaults.
1267
  */
1268
  $file = apply_filters( 'job_manager_upload_file_pre_upload', $file, $args, $allowed_mime_types );
1269
 
1271
  return $file;
1272
  }
1273
 
1274
+ if ( ! in_array( $file['type'], $allowed_mime_types, true ) ) {
1275
  if ( $args['file_label'] ) {
1276
+ // translators: %1$s is the file field label; %2$s is the file type; %3$s is the list of allowed file types.
1277
+ return new WP_Error( 'upload', sprintf( __( '"%1$s" (filetype %2$s) needs to be one of the following file types: %3$s', 'wp-job-manager' ), $args['file_label'], $file['type'], implode( ', ', array_keys( $allowed_mime_types ) ) ) );
1278
  } else {
1279
+ // translators: %s is the list of allowed file types.
1280
  return new WP_Error( 'upload', sprintf( __( 'Uploaded files need to be one of the following file types: %s', 'wp-job-manager' ), implode( ', ', array_keys( $allowed_mime_types ) ) ) );
1281
  }
1282
  } else {
1306
  * @param string $field Field used.
1307
  * @return array Array of allowed mime types
1308
  */
1309
+ function job_manager_get_allowed_mime_types( $field = '' ) {
1310
  if ( 'company_logo' === $field ) {
1311
  $allowed_mime_types = array(
1312
  'jpg|jpeg|jpe' => 'image/jpeg',
1351
  // Get duration from the product if set...
1352
  $duration = get_post_meta( $job_id, '_job_duration', true );
1353
 
1354
+ // ...otherwise use the global option.
1355
  if ( ! $duration ) {
1356
  $duration = absint( get_option( 'job_manager_submission_duration' ) );
1357
  }
1371
  * @return int 0 on fail or the post ID.
1372
  */
1373
  function job_manager_duplicate_listing( $post_id ) {
1374
+ global $wpdb;
1375
+
1376
+ if ( empty( $post_id ) ) {
1377
  return 0;
1378
  }
1379
 
1380
+ $post = get_post( $post_id );
1381
+ if ( ! $post ) {
1382
+ return 0;
1383
+ }
1384
 
1385
  /**
1386
  * Duplicate the post.
1387
  */
1388
+ $new_post_id = wp_insert_post(
1389
+ array(
1390
+ 'comment_status' => $post->comment_status,
1391
+ 'ping_status' => $post->ping_status,
1392
+ 'post_author' => $post->post_author,
1393
+ 'post_content' => $post->post_content,
1394
+ 'post_excerpt' => $post->post_excerpt,
1395
+ 'post_name' => $post->post_name,
1396
+ 'post_parent' => $post->post_parent,
1397
+ 'post_password' => $post->post_password,
1398
+ 'post_status' => 'preview',
1399
+ 'post_title' => $post->post_title,
1400
+ 'post_type' => $post->post_type,
1401
+ 'to_ping' => $post->to_ping,
1402
+ 'menu_order' => $post->menu_order,
1403
+ )
1404
+ );
1405
 
1406
  /**
1407
  * Copy taxonomies.
1420
 
1421
  if ( ! empty( $post_meta ) ) {
1422
  $post_meta = wp_list_pluck( $post_meta, 'meta_value', 'meta_key' );
1423
+
1424
+ $default_duplicate_ignore_keys = array( '_filled', '_featured', '_job_expires', '_job_duration', '_package_id', '_user_package_id' );
1425
+ $duplicate_ignore_keys = apply_filters( 'job_manager_duplicate_listing_ignore_keys', $default_duplicate_ignore_keys, true );
1426
+
1427
  foreach ( $post_meta as $meta_key => $meta_value ) {
1428
+ if ( in_array( $meta_key, $duplicate_ignore_keys, true ) ) {
1429
  continue;
1430
  }
1431
  update_post_meta( $new_post_id, $meta_key, maybe_unserialize( $meta_value ) );
wp-job-manager-template.php CHANGED
@@ -4,9 +4,9 @@
4
  *
5
  * Template functions specifically created for job listings
6
  *
7
- * @author Mike Jolley
8
- * @category Core
9
- * @package Job Manager/Template
10
  * @version 1.25.3
11
  */
12
 
@@ -15,15 +15,16 @@
15
  *
16
  * @since 1.0.0
17
  * @param mixed $template_name
18
- * @param array $args (default: array())
19
- * @param string $template_path (default: '')
20
- * @param string $default_path (default: '')
21
  */
22
  function get_job_manager_template( $template_name, $args = array(), $template_path = 'job_manager', $default_path = '' ) {
23
  if ( $args && is_array( $args ) ) {
24
- extract( $args );
 
25
  }
26
- include( locate_job_manager_template( $template_name, $template_path, $default_path ) );
27
  }
28
 
29
  /**
@@ -31,34 +32,34 @@ function get_job_manager_template( $template_name, $args = array(), $template_pa
31
  *
32
  * This is the load order:
33
  *
34
- * yourtheme / $template_path / $template_name
35
- * yourtheme / $template_name
36
- * $default_path / $template_name
37
  *
38
  * @since 1.0.0
39
  * @param string $template_name
40
- * @param string $template_path (default: 'job_manager')
41
- * @param string|bool $default_path (default: '') False to not load a default
42
  * @return string
43
  */
44
  function locate_job_manager_template( $template_name, $template_path = 'job_manager', $default_path = '' ) {
45
- // Look within passed path within the theme - this is priority
46
  $template = locate_template(
47
  array(
48
  trailingslashit( $template_path ) . $template_name,
49
- $template_name
50
  )
51
  );
52
 
53
- // Get default template
54
- if ( ! $template && $default_path !== false ) {
55
  $default_path = $default_path ? $default_path : JOB_MANAGER_PLUGIN_DIR . '/templates/';
56
  if ( file_exists( trailingslashit( $default_path ) . $template_name ) ) {
57
  $template = trailingslashit( $default_path ) . $template_name;
58
  }
59
  }
60
 
61
- // Return what we found
62
  return apply_filters( 'job_manager_locate_template', $template, $template_name, $template_path );
63
  }
64
 
@@ -67,9 +68,9 @@ function locate_job_manager_template( $template_name, $template_path = 'job_mana
67
  *
68
  * @since 1.0.0
69
  * @param string $slug
70
- * @param string $name (default: '')
71
- * @param string $template_path (default: 'job_manager')
72
- * @param string|bool $default_path (default: '') False to not load a default
73
  */
74
  function get_job_manager_template_part( $slug, $name = '', $template_path = 'job_manager', $default_path = '' ) {
75
  $template = '';
@@ -78,7 +79,7 @@ function get_job_manager_template_part( $slug, $name = '', $template_path = 'job
78
  $template = locate_job_manager_template( "{$slug}-{$name}.php", $template_path, $default_path );
79
  }
80
 
81
- // If template file doesn't exist, look in yourtheme/slug.php and yourtheme/job_manager/slug.php
82
  if ( ! $template ) {
83
  $template = locate_job_manager_template( "{$slug}.php", $template_path, $default_path );
84
  }
@@ -114,7 +115,13 @@ add_filter( 'body_class', 'job_manager_body_class' );
114
  */
115
  function get_job_listing_pagination( $max_num_pages, $current_page = 1 ) {
116
  ob_start();
117
- get_job_manager_template( 'job-pagination.php', array( 'max_num_pages' => $max_num_pages, 'current_page' => absint( $current_page ) ) );
 
 
 
 
 
 
118
  return ob_get_clean();
119
  }
120
 
@@ -125,7 +132,7 @@ function get_job_listing_pagination( $max_num_pages, $current_page = 1 ) {
125
  * @param int|WP_Post $post
126
  */
127
  function the_job_status( $post = null ) {
128
- echo get_the_job_status( $post );
129
  }
130
 
131
  /**
@@ -143,7 +150,7 @@ function get_the_job_status( $post = null ) {
143
  if ( isset( $statuses[ $status ] ) ) {
144
  $status = $statuses[ $status ];
145
  } else {
146
- $status = __( 'Inactive', 'wp-job-manager' );
147
  }
148
 
149
  return apply_filters( 'the_job_status', $status, $post );
@@ -158,7 +165,7 @@ function get_the_job_status( $post = null ) {
158
  */
159
  function is_position_filled( $post = null ) {
160
  $post = get_post( $post );
161
- return $post->_filled ? true : false;
162
  }
163
 
164
  /**
@@ -170,7 +177,7 @@ function is_position_filled( $post = null ) {
170
  */
171
  function is_position_featured( $post = null ) {
172
  $post = get_post( $post );
173
- return $post->_featured ? true : false;
174
  }
175
 
176
  /**
@@ -182,25 +189,25 @@ function is_position_featured( $post = null ) {
182
  */
183
  function candidates_can_apply( $post = null ) {
184
  $post = get_post( $post );
185
- return apply_filters( 'job_manager_candidates_can_apply', ( ! is_position_filled() && ! in_array( $post->post_status, array( 'preview', 'expired' ) ) ), $post );
186
  }
187
 
188
  /**
189
  * Displays the permalink for the job listing post.
190
  *
191
  * @since 1.0.0
192
- * @param int|WP_Post $post (default: null)
193
  * @return void
194
  */
195
  function the_job_permalink( $post = null ) {
196
- echo get_the_job_permalink( $post );
197
  }
198
 
199
  /**
200
  * Gets the permalink for a job listing.
201
  *
202
  * @since 1.0.0
203
- * @param int|WP_Post $post (default: null)
204
  * @return string
205
  */
206
  function get_the_job_permalink( $post = null ) {
@@ -214,7 +221,7 @@ function get_the_job_permalink( $post = null ) {
214
  * Gets the application method for the job listing.
215
  *
216
  * @since 1.0.0
217
- * @param int|WP_Post $post (default: null)
218
  * @return stdClass|bool|null
219
  */
220
  function get_the_job_application_method( $post = null ) {
@@ -235,10 +242,13 @@ function get_the_job_application_method( $post = null ) {
235
  $method->type = 'email';
236
  $method->raw_email = $apply;
237
  $method->email = antispambot( $apply );
238
- $method->subject = apply_filters( 'job_manager_application_email_subject', sprintf( __( 'Application via "%s" listing on %s', 'wp-job-manager' ), $post->post_title, home_url() ), $post );
 
 
239
  } else {
240
- if ( strpos( $apply, 'http' ) !== 0 )
241
  $apply = 'http://' . $apply;
 
242
  $method->type = 'url';
243
  $method->url = $apply;
244
  }
@@ -254,12 +264,12 @@ function get_the_job_application_method( $post = null ) {
254
  * @param WP_Post|int|null $post
255
  * @return bool|array
256
  */
257
- function wpjm_get_job_employment_types( $post = null) {
258
  if ( ! wpjm_job_listing_employment_type_enabled() ) {
259
  return false;
260
  }
261
  $employment_types = array();
262
- $job_types = wpjm_get_the_job_types( $post );
263
 
264
  if ( ! empty( $job_types ) ) {
265
  foreach ( $job_types as $job_type ) {
@@ -355,44 +365,48 @@ function wpjm_get_job_listing_structured_data( $post = null ) {
355
  return false;
356
  }
357
 
358
- $data = array();
359
- $data['@context'] = 'http://schema.org/';
360
- $data['@type'] = 'JobPosting';
361
  $data['datePosted'] = get_post_time( 'c', false, $post );
362
 
363
  $job_expires = get_post_meta( $post->ID, '_job_expires', true );
364
  if ( ! empty( $job_expires ) ) {
365
- $data[ 'validThrough' ] = date( 'c', strtotime( $job_expires ) );
366
  }
367
 
368
- $data['title'] = strip_tags( wpjm_get_the_job_title( $post ) );
369
  $data['description'] = wpjm_get_the_job_description( $post );
370
 
371
- $employmentTypes = wpjm_get_job_employment_types();
372
- if ( ! empty( $employmentTypes ) ) {
373
- $data['employmentType'] = $employmentTypes;
374
  }
375
 
376
- $data['hiringOrganization'] = array();
377
  $data['hiringOrganization']['@type'] = 'Organization';
378
- $data['hiringOrganization']['name'] = get_the_company_name( $post );
379
- if ( $company_website = get_the_company_website( $post ) ) {
 
 
380
  $data['hiringOrganization']['sameAs'] = $company_website;
381
- $data['hiringOrganization']['url'] = $company_website;
382
  }
383
- if ( $company_logo = get_the_company_logo( $post, 'full' ) ) {
 
 
384
  $data['hiringOrganization']['logo'] = $company_logo;
385
  }
386
 
387
- $data['identifier'] = array();
388
  $data['identifier']['@type'] = 'PropertyValue';
389
- $data['identifier']['name'] = get_the_company_name( $post );
390
  $data['identifier']['value'] = get_the_guid( $post );
391
 
392
  $location = get_the_job_location( $post );
393
  if ( ! empty( $location ) ) {
394
- $data['jobLocation'] = array();
395
- $data['jobLocation']['@type'] = 'Place';
396
  $data['jobLocation']['address'] = wpjm_get_job_listing_location_structured_data( $post );
397
  if ( empty( $data['jobLocation']['address'] ) ) {
398
  $data['jobLocation']['address'] = $location;
@@ -425,14 +439,14 @@ function wpjm_get_job_listing_location_structured_data( $post ) {
425
  return false;
426
  }
427
 
428
- $mapping = array();
429
- $mapping['streetAddress'] = array( 'street_number', 'street' );
430
  $mapping['addressLocality'] = 'city';
431
- $mapping['addressRegion'] = 'state_short';
432
- $mapping['postalCode'] = 'postcode';
433
- $mapping['addressCountry'] = 'country_short';
434
 
435
- $address = array();
436
  $address['@type'] = 'PostalAddress';
437
  foreach ( $mapping as $schema_key => $geolocation_key ) {
438
  if ( is_array( $geolocation_key ) ) {
@@ -452,7 +466,7 @@ function wpjm_get_job_listing_location_structured_data( $post ) {
452
  }
453
  }
454
 
455
- // No address parts were found
456
  if ( 1 === count( $address ) ) {
457
  $address = false;
458
  }
@@ -473,11 +487,11 @@ function wpjm_get_job_listing_location_structured_data( $post ) {
473
  *
474
  * @since 1.27.0
475
  * @param int|WP_Post $post
476
- * @return string
477
  */
478
  function wpjm_the_job_title( $post = null ) {
479
- if ( $job_title = wpjm_get_the_job_title( $post ) ) {
480
- echo $job_title;
 
481
  }
482
  }
483
 
@@ -485,16 +499,16 @@ function wpjm_the_job_title( $post = null ) {
485
  * Gets the job title for the listing.
486
  *
487
  * @since 1.27.0
488
- * @param int|WP_Post $post (default: null)
489
  * @return string|bool|null
490
  */
491
  function wpjm_get_the_job_title( $post = null ) {
492
  $post = get_post( $post );
493
  if ( ! $post || 'job_listing' !== $post->post_type ) {
494
- return;
495
  }
496
 
497
- $title = esc_html( get_the_title( $post ) );
498
 
499
  /**
500
  * Filter for the job title.
@@ -511,11 +525,11 @@ function wpjm_get_the_job_title( $post = null ) {
511
  *
512
  * @since 1.28.0
513
  * @param int|WP_Post $post
514
- * @return string
515
  */
516
  function wpjm_the_job_description( $post = null ) {
517
- if ( $job_description = wpjm_get_the_job_description( $post ) ) {
518
- echo $job_description;
 
519
  }
520
  }
521
 
@@ -523,13 +537,13 @@ function wpjm_the_job_description( $post = null ) {
523
  * Gets the job description for the listing.
524
  *
525
  * @since 1.28.0
526
- * @param int|WP_Post $post (default: null)
527
  * @return string|bool|null
528
  */
529
  function wpjm_get_the_job_description( $post = null ) {
530
  $post = get_post( $post );
531
  if ( ! $post || 'job_listing' !== $post->post_type ) {
532
- return;
533
  }
534
 
535
  $description = apply_filters( 'the_job_description', get_the_content( $post ) );
@@ -662,19 +676,19 @@ function wpjm_get_the_job_categories( $post = null ) {
662
  *
663
  * @since 1.27.0
664
  *
665
- * @return array $registration_fields
666
  */
667
  function wpjm_get_registration_fields() {
668
  $generate_username_from_email = job_manager_generate_username_from_email();
669
  $use_standard_password_setup_email = wpjm_use_standard_password_setup_email();
670
- $account_required = job_manager_user_requires_account();
671
 
672
  $registration_fields = array();
673
  if ( job_manager_enable_registration() ) {
674
  if ( ! $generate_username_from_email ) {
675
  $registration_fields['create_account_username'] = array(
676
  'type' => 'text',
677
- 'label' => __( 'Username', 'wp-job-manager' ),
678
  'required' => $account_required,
679
  'value' => isset( $_POST['create_account_username'] ) ? $_POST['create_account_username'] : '',
680
  );
@@ -682,24 +696,24 @@ function wpjm_get_registration_fields() {
682
  if ( ! $use_standard_password_setup_email ) {
683
  $registration_fields['create_account_password'] = array(
684
  'type' => 'password',
685
- 'label' => __( 'Password', 'wp-job-manager' ),
686
  'autocomplete' => false,
687
  'required' => $account_required,
688
  );
689
- $password_hint = wpjm_get_password_rules_hint();
690
  if ( $password_hint ) {
691
  $registration_fields['create_account_password']['description'] = $password_hint;
692
  }
693
  $registration_fields['create_account_password_verify'] = array(
694
  'type' => 'password',
695
- 'label' => __( 'Verify Password', 'wp-job-manager' ),
696
  'autocomplete' => false,
697
  'required' => $account_required,
698
  );
699
  }
700
  $registration_fields['create_account_email'] = array(
701
  'type' => 'text',
702
- 'label' => __( 'Your email', 'wp-job-manager' ),
703
  'placeholder' => __( 'you@yourdomain.com', 'wp-job-manager' ),
704
  'required' => $account_required,
705
  'value' => isset( $_POST['create_account_email'] ) ? $_POST['create_account_email'] : '',
@@ -720,18 +734,19 @@ function wpjm_get_registration_fields() {
720
  * Displays the published date of the job listing.
721
  *
722
  * @since 1.25.3
723
- * @param int|WP_Post $post (default: null)
724
  */
725
  function the_job_publish_date( $post = null ) {
726
  $date_format = get_option( 'job_manager_date_format' );
727
 
728
- if ( $date_format === 'default' ) {
729
- $display_date = __( 'Posted on ', 'wp-job-manager' ) . date_i18n( get_option( 'date_format' ), get_post_time( 'U' ) );
730
  } else {
731
- $display_date = sprintf( __( 'Posted %s ago', 'wp-job-manager' ), human_time_diff( get_post_time( 'U' ), current_time( 'timestamp' ) ) );
 
732
  }
733
 
734
- echo '<time datetime="' . get_post_time( 'Y-m-d' ) . '">' . $display_date . '</time>';
735
  }
736
 
737
 
@@ -739,15 +754,16 @@ function the_job_publish_date( $post = null ) {
739
  * Gets the published date of the job listing.
740
  *
741
  * @since 1.25.3
742
- * @param int|WP_Post $post (default: null)
743
  * @return string|int|false
744
  */
745
  function get_the_job_publish_date( $post = null ) {
746
  $date_format = get_option( 'job_manager_date_format' );
747
 
748
- if ( $date_format === 'default' ) {
749
  return get_post_time( get_option( 'date_format' ) );
750
  } else {
 
751
  return sprintf( __( 'Posted %s ago', 'wp-job-manager' ), human_time_diff( get_post_time( 'U' ), current_time( 'timestamp' ) ) );
752
  }
753
  }
@@ -757,7 +773,7 @@ function get_the_job_publish_date( $post = null ) {
757
  * Displays the location for the job listing.
758
  *
759
  * @since 1.0.0
760
- * @param bool $map_link whether or not to link to Google Maps
761
  * @param int|WP_Post $post
762
  */
763
  function the_job_location( $map_link = true, $post = null ) {
@@ -765,8 +781,14 @@ function the_job_location( $map_link = true, $post = null ) {
765
 
766
  if ( $location ) {
767
  if ( $map_link ) {
768
- // If linking to google maps, we don't want anything but text here
769
- echo apply_filters( 'the_job_location_map_link', '<a class="google_map_link" href="' . esc_url( 'http://maps.google.com/maps?q=' . urlencode( strip_tags( $location ) ) . '&zoom=14&size=512x512&maptype=roadmap&sensor=false' ) . '" target="_blank">' . esc_html( strip_tags( $location ) ) . '</a>', $location, $post );
 
 
 
 
 
 
770
  } else {
771
  echo wp_kses_post( $location );
772
  }
@@ -779,13 +801,13 @@ function the_job_location( $map_link = true, $post = null ) {
779
  * Gets the location for the job listing.
780
  *
781
  * @since 1.0.0
782
- * @param int|WP_Post $post (default: null)
783
  * @return string|null
784
  */
785
  function get_the_job_location( $post = null ) {
786
  $post = get_post( $post );
787
  if ( ! $post || 'job_listing' !== $post->post_type ) {
788
- return;
789
  }
790
 
791
  return apply_filters( 'the_job_location', $post->_job_location, $post );
@@ -795,26 +817,26 @@ function get_the_job_location( $post = null ) {
795
  * Displays the company logo.
796
  *
797
  * @since 1.0.0
798
- * @param string $size (default: 'full')
799
- * @param mixed $default (default: null)
800
- * @param int|WP_Post $post (default: null)
801
  */
802
  function the_company_logo( $size = 'thumbnail', $default = null, $post = null ) {
803
  $logo = get_the_company_logo( $post, $size );
804
 
805
  if ( has_post_thumbnail( $post ) ) {
806
- echo '<img class="company_logo" src="' . esc_attr( $logo ) . '" alt="' . esc_attr( get_the_company_name( $post ) ) . '" />';
807
 
808
- // Before 1.24.0, logo URLs were stored in post meta.
809
  } elseif ( ! empty( $logo ) && ( strstr( $logo, 'http' ) || file_exists( $logo ) ) ) {
810
- if ( $size !== 'full' ) {
811
  $logo = job_manager_get_resized_image( $logo, $size );
812
  }
813
- echo '<img class="company_logo" src="' . esc_attr( $logo ) . '" alt="' . esc_attr( get_the_company_name( $post ) ) . '" />';
814
  } elseif ( $default ) {
815
- echo '<img class="company_logo" src="' . esc_attr( $default ) . '" alt="' . esc_attr( get_the_company_name( $post ) ) . '" />';
816
  } else {
817
- echo '<img class="company_logo" src="' . esc_attr( apply_filters( 'job_manager_default_company_logo', JOB_MANAGER_PLUGIN_URL . '/assets/images/company.png' ) ) . '" alt="' . esc_attr( get_the_company_name( $post ) ) . '" />';
818
  }
819
  }
820
 
@@ -822,9 +844,9 @@ function the_company_logo( $size = 'thumbnail', $default = null, $post = null )
822
  * Gets the company logo.
823
  *
824
  * @since 1.0.0
825
- * @param int|WP_Post $post (default: null)
826
  * @param string $size
827
- * @return string Image SRC
828
  */
829
  function get_the_company_logo( $post = null, $size = 'thumbnail' ) {
830
  $post = get_post( $post );
@@ -851,9 +873,12 @@ function get_the_company_logo( $post = null, $size = 'thumbnail' ) {
851
  function job_manager_get_resized_image( $logo, $size ) {
852
  global $_wp_additional_image_sizes;
853
 
854
- if ( $size !== 'full' && strstr( $logo, WP_CONTENT_URL ) && ( isset( $_wp_additional_image_sizes[ $size ] ) || in_array( $size, array( 'thumbnail', 'medium', 'large' ) ) ) ) {
 
 
 
855
 
856
- if ( in_array( $size, array( 'thumbnail', 'medium', 'large' ) ) ) {
857
  $img_width = get_option( $size . '_size_w' );
858
  $img_height = get_option( $size . '_size_h' );
859
  $img_crop = get_option( $size . '_size_crop' );
@@ -882,9 +907,9 @@ function job_manager_get_resized_image( $logo, $size ) {
882
 
883
  $resize = $image->resize( $img_width, $img_height, $img_crop );
884
 
885
- if ( ! is_wp_error( $resize ) ) {
886
 
887
- $save = $image->save( $resized_logo_path );
888
 
889
  if ( ! is_wp_error( $save ) ) {
890
  $logo = dirname( $logo ) . '/' . basename( $resized_logo_path );
@@ -912,11 +937,11 @@ function the_company_video( $post = null ) {
912
  $video = get_the_company_video( $post );
913
  $filetype = wp_check_filetype( $video );
914
 
915
- if( ! empty( $video ) ){
916
- // FV Wordpress Flowplayer Support for advanced video formats
917
  if ( shortcode_exists( 'flowplayer' ) ) {
918
- $video_embed = '[flowplayer src="' . esc_attr( $video ) . '"]';
919
- } elseif ( ! empty( $filetype[ 'ext' ] ) ) {
920
  $video_embed = wp_video_shortcode( array( 'src' => $video ) );
921
  } else {
922
  $video_embed = wp_oembed_get( $video );
@@ -926,7 +951,7 @@ function the_company_video( $post = null ) {
926
  $video_embed = apply_filters( 'the_company_video_embed', $video_embed, $post );
927
 
928
  if ( $video_embed ) {
929
- echo '<div class="company_video">' . $video_embed . '</div>';
930
  }
931
  }
932
 
@@ -934,13 +959,13 @@ function the_company_video( $post = null ) {
934
  * Gets the company video URL.
935
  *
936
  * @since 1.14.0
937
- * @param int|WP_Post $post (default: null)
938
  * @return string|null
939
  */
940
  function get_the_company_video( $post = null ) {
941
  $post = get_post( $post );
942
  if ( ! $post || 'job_listing' !== $post->post_type ) {
943
- return;
944
  }
945
  return apply_filters( 'the_company_video', $post->_company_video, $post );
946
  }
@@ -950,32 +975,34 @@ function get_the_company_video( $post = null ) {
950
  *
951
  * @since 1.0.0
952
  * @since 1.0.1 Add the `$post` argument.
953
- * @param string $before (default: '')
954
- * @param string $after (default: '')
955
- * @param bool $echo (default: true)
956
- * @param int|WP_Post|null $post (default: null)
957
- * @return string|void
958
  */
959
  function the_company_name( $before = '', $after = '', $echo = true, $post = null ) {
960
  $company_name = get_the_company_name( $post );
961
 
962
- if ( strlen( $company_name ) == 0 )
963
- return;
 
964
 
965
- $company_name = esc_attr( strip_tags( $company_name ) );
966
  $company_name = $before . $company_name . $after;
967
 
968
- if ( $echo )
969
- echo $company_name;
970
- else
971
  return $company_name;
 
972
  }
973
 
974
  /**
975
  * Gets the company name.
976
  *
977
  * @since 1.0.0
978
- * @param int $post (default: null)
979
  * @return string
980
  */
981
  function get_the_company_name( $post = null ) {
@@ -991,14 +1018,15 @@ function get_the_company_name( $post = null ) {
991
  * Gets the company website.
992
  *
993
  * @since 1.0.0
994
- * @param int $post (default: null)
995
  * @return null|string
996
  */
997
  function get_the_company_website( $post = null ) {
998
  $post = get_post( $post );
999
 
1000
- if ( ! $post || 'job_listing' !== $post->post_type )
1001
  return;
 
1002
 
1003
  $website = $post->_company_website;
1004
 
@@ -1013,39 +1041,42 @@ function get_the_company_website( $post = null ) {
1013
  * Displays or retrieves the current company tagline with optional content.
1014
  *
1015
  * @since 1.0.0
1016
- * @param string $before (default: '')
1017
- * @param string $after (default: '')
1018
- * @param bool $echo (default: true)
1019
- * @param int|WP_Post|null $post (default: null)
1020
  * @return string|void
1021
  */
1022
  function the_company_tagline( $before = '', $after = '', $echo = true, $post = null ) {
1023
  $company_tagline = get_the_company_tagline( $post );
1024
 
1025
- if ( strlen( $company_tagline ) == 0 )
1026
  return;
 
1027
 
1028
- $company_tagline = esc_attr( strip_tags( $company_tagline ) );
1029
  $company_tagline = $before . $company_tagline . $after;
1030
 
1031
- if ( $echo )
1032
- echo $company_tagline;
1033
- else
1034
  return $company_tagline;
 
1035
  }
1036
 
1037
  /**
1038
  * Gets the company tagline.
1039
  *
1040
  * @since 1.0.0
1041
- * @param int|WP_Post|null $post (default: null)
1042
  * @return string|null
1043
  */
1044
  function get_the_company_tagline( $post = null ) {
1045
  $post = get_post( $post );
1046
 
1047
- if ( ! $post || 'job_listing' !== $post->post_type )
1048
- return;
 
1049
 
1050
  return apply_filters( 'the_company_tagline', $post->_company_tagline, $post );
1051
  }
@@ -1054,46 +1085,50 @@ function get_the_company_tagline( $post = null ) {
1054
  * Displays or retrieves the current company Twitter link with optional content.
1055
  *
1056
  * @since 1.0.0
1057
- * @param string $before (default: '')
1058
- * @param string $after (default: '')
1059
- * @param bool $echo (default: true)
1060
- * @param int|WP_Post|null $post (default: null)
1061
- * @return string|void
1062
  */
1063
  function the_company_twitter( $before = '', $after = '', $echo = true, $post = null ) {
1064
  $company_twitter = get_the_company_twitter( $post );
1065
 
1066
- if ( strlen( $company_twitter ) == 0 )
1067
- return;
 
1068
 
1069
- $company_twitter = esc_attr( strip_tags( $company_twitter ) );
1070
- $company_twitter = $before . '<a href="http://twitter.com/' . $company_twitter . '" class="company_twitter" target="_blank">' . $company_twitter . '</a>' . $after;
1071
 
1072
- if ( $echo )
1073
- echo $company_twitter;
1074
- else
1075
  return $company_twitter;
 
1076
  }
1077
 
1078
  /**
1079
  * Gets the company Twitter link.
1080
  *
1081
  * @since 1.0.0
1082
- * @param int|WP_Post|null $post (default: null)
1083
  * @return string|null
1084
  */
1085
  function get_the_company_twitter( $post = null ) {
1086
  $post = get_post( $post );
1087
- if ( ! $post || 'job_listing' !== $post->post_type )
1088
- return;
 
1089
 
1090
  $company_twitter = $post->_company_twitter;
1091
 
1092
- if ( strlen( $company_twitter ) == 0 )
1093
- return;
 
1094
 
1095
- if ( strpos( $company_twitter, '@' ) === 0 )
1096
  $company_twitter = substr( $company_twitter, 1 );
 
1097
 
1098
  return apply_filters( 'the_company_twitter', $company_twitter, $post );
1099
  }
@@ -1102,12 +1137,12 @@ function get_the_company_twitter( $post = null ) {
1102
  * Outputs the job listing class.
1103
  *
1104
  * @since 1.0.0
1105
- * @param string $class (default: '')
1106
- * @param int|WP_Post $post_id (default: null)
1107
  */
1108
  function job_listing_class( $class = '', $post_id = null ) {
1109
- // Separates classes with a single space, collates classes for post DIV
1110
- echo 'class="' . join( ' ', get_job_listing_class( $class, $post_id ) ) . '"';
1111
  }
1112
 
1113
  /**
@@ -1115,13 +1150,13 @@ function job_listing_class( $class = '', $post_id = null ) {
1115
  *
1116
  * @since 1.0.0
1117
  * @param string $class
1118
- * @param int|WP_Post $post_id (default: null)
1119
  * @return array
1120
  */
1121
  function get_job_listing_class( $class = '', $post_id = null ) {
1122
  $post = get_post( $post_id );
1123
 
1124
- if ( empty( $post ) || 'job_listing' !== $post->post_type ) {
1125
  return array();
1126
  }
1127
 
@@ -1150,7 +1185,7 @@ function get_job_listing_class( $class = '', $post_id = null ) {
1150
  function wpjm_add_post_class( $classes, $class, $post_id ) {
1151
  $post = get_post( $post_id );
1152
 
1153
- if ( empty( $post ) || 'job_listing' !== $post->post_type ) {
1154
  return $classes;
1155
  }
1156
 
4
  *
5
  * Template functions specifically created for job listings
6
  *
7
+ * @author Mike Jolley
8
+ * @category Core
9
+ * @package Job Manager/Template
10
  * @version 1.25.3
11
  */
12
 
15
  *
16
  * @since 1.0.0
17
  * @param mixed $template_name
18
+ * @param array $args (default: array()).
19
+ * @param string $template_path (default: '').
20
+ * @param string $default_path (default: '').
21
  */
22
  function get_job_manager_template( $template_name, $args = array(), $template_path = 'job_manager', $default_path = '' ) {
23
  if ( $args && is_array( $args ) ) {
24
+ // Please, forgive us.
25
+ extract( $args ); // phpcs:ignore WordPress.Functions.DontExtract.extract_extract
26
  }
27
+ include locate_job_manager_template( $template_name, $template_path, $default_path );
28
  }
29
 
30
  /**
32
  *
33
  * This is the load order:
34
  *
35
+ * yourtheme / $template_path / $template_name
36
+ * yourtheme / $template_name
37
+ * $default_path / $template_name
38
  *
39
  * @since 1.0.0
40
  * @param string $template_name
41
+ * @param string $template_path (default: 'job_manager').
42
+ * @param string|bool $default_path (default: '') False to not load a default.
43
  * @return string
44
  */
45
  function locate_job_manager_template( $template_name, $template_path = 'job_manager', $default_path = '' ) {
46
+ // Look within passed path within the theme - this is priority.
47
  $template = locate_template(
48
  array(
49
  trailingslashit( $template_path ) . $template_name,
50
+ $template_name,
51
  )
52
  );
53
 
54
+ // Get default template.
55
+ if ( ! $template && false !== $default_path ) {
56
  $default_path = $default_path ? $default_path : JOB_MANAGER_PLUGIN_DIR . '/templates/';
57
  if ( file_exists( trailingslashit( $default_path ) . $template_name ) ) {
58
  $template = trailingslashit( $default_path ) . $template_name;
59
  }
60
  }
61
 
62
+ // Return what we found.
63
  return apply_filters( 'job_manager_locate_template', $template, $template_name, $template_path );
64
  }
65
 
68
  *
69
  * @since 1.0.0
70
  * @param string $slug
71
+ * @param string $name (default: '').
72
+ * @param string $template_path (default: 'job_manager').
73
+ * @param string|bool $default_path (default: '') False to not load a default.
74
  */
75
  function get_job_manager_template_part( $slug, $name = '', $template_path = 'job_manager', $default_path = '' ) {
76
  $template = '';
79
  $template = locate_job_manager_template( "{$slug}-{$name}.php", $template_path, $default_path );
80
  }
81
 
82
+ // If template file doesn't exist, look in yourtheme/slug.php and yourtheme/job_manager/slug.php.
83
  if ( ! $template ) {
84
  $template = locate_job_manager_template( "{$slug}.php", $template_path, $default_path );
85
  }
115
  */
116
  function get_job_listing_pagination( $max_num_pages, $current_page = 1 ) {
117
  ob_start();
118
+ get_job_manager_template(
119
+ 'job-pagination.php',
120
+ array(
121
+ 'max_num_pages' => $max_num_pages,
122
+ 'current_page' => absint( $current_page ),
123
+ )
124
+ );
125
  return ob_get_clean();
126
  }
127
 
132
  * @param int|WP_Post $post
133
  */
134
  function the_job_status( $post = null ) {
135
+ echo wp_kses_post( get_the_job_status( $post ) );
136
  }
137
 
138
  /**
150
  if ( isset( $statuses[ $status ] ) ) {
151
  $status = $statuses[ $status ];
152
  } else {
153
+ $status = esc_html__( 'Inactive', 'wp-job-manager' );
154
  }
155
 
156
  return apply_filters( 'the_job_status', $status, $post );
165
  */
166
  function is_position_filled( $post = null ) {
167
  $post = get_post( $post );
168
+ return (bool) $post->_filled;
169
  }
170
 
171
  /**
177
  */
178
  function is_position_featured( $post = null ) {
179
  $post = get_post( $post );
180
+ return (bool) $post->_featured;
181
  }
182
 
183
  /**
189
  */
190
  function candidates_can_apply( $post = null ) {
191
  $post = get_post( $post );
192
+ return apply_filters( 'job_manager_candidates_can_apply', ( ! is_position_filled() && ! in_array( $post->post_status, array( 'preview', 'expired' ), true ) ), $post );
193
  }
194
 
195
  /**
196
  * Displays the permalink for the job listing post.
197
  *
198
  * @since 1.0.0
199
+ * @param int|WP_Post $post (default: null).
200
  * @return void
201
  */
202
  function the_job_permalink( $post = null ) {
203
+ echo esc_url( get_the_job_permalink( $post ) );
204
  }
205
 
206
  /**
207
  * Gets the permalink for a job listing.
208
  *
209
  * @since 1.0.0
210
+ * @param int|WP_Post $post (default: null).
211
  * @return string
212
  */
213
  function get_the_job_permalink( $post = null ) {
221
  * Gets the application method for the job listing.
222
  *
223
  * @since 1.0.0
224
+ * @param int|WP_Post $post (default: null).
225
  * @return stdClass|bool|null
226
  */
227
  function get_the_job_application_method( $post = null ) {
242
  $method->type = 'email';
243
  $method->raw_email = $apply;
244
  $method->email = antispambot( $apply );
245
+
246
+ // translators: %1$s is the job listing title; %2$s is the URL for the current WordPress instance.
247
+ $method->subject = apply_filters( 'job_manager_application_email_subject', sprintf( esc_html__( 'Application via "%1$s" listing on %2$s', 'wp-job-manager' ), esc_html( $post->post_title ), esc_url( home_url() ) ), $post );
248
  } else {
249
+ if ( strpos( $apply, 'http' ) !== 0 ) {
250
  $apply = 'http://' . $apply;
251
+ }
252
  $method->type = 'url';
253
  $method->url = $apply;
254
  }
264
  * @param WP_Post|int|null $post
265
  * @return bool|array
266
  */
267
+ function wpjm_get_job_employment_types( $post = null ) {
268
  if ( ! wpjm_job_listing_employment_type_enabled() ) {
269
  return false;
270
  }
271
  $employment_types = array();
272
+ $job_types = wpjm_get_the_job_types( $post );
273
 
274
  if ( ! empty( $job_types ) ) {
275
  foreach ( $job_types as $job_type ) {
365
  return false;
366
  }
367
 
368
+ $data = array();
369
+ $data['@context'] = 'http://schema.org/';
370
+ $data['@type'] = 'JobPosting';
371
  $data['datePosted'] = get_post_time( 'c', false, $post );
372
 
373
  $job_expires = get_post_meta( $post->ID, '_job_expires', true );
374
  if ( ! empty( $job_expires ) ) {
375
+ $data['validThrough'] = date( 'c', strtotime( $job_expires ) );
376
  }
377
 
378
+ $data['title'] = wp_strip_all_tags( wpjm_get_the_job_title( $post ) );
379
  $data['description'] = wpjm_get_the_job_description( $post );
380
 
381
+ $employment_types = wpjm_get_job_employment_types();
382
+ if ( ! empty( $employment_types ) ) {
383
+ $data['employmentType'] = $employment_types;
384
  }
385
 
386
+ $data['hiringOrganization'] = array();
387
  $data['hiringOrganization']['@type'] = 'Organization';
388
+ $data['hiringOrganization']['name'] = get_the_company_name( $post );
389
+
390
+ $company_website = get_the_company_website( $post );
391
+ if ( $company_website ) {
392
  $data['hiringOrganization']['sameAs'] = $company_website;
393
+ $data['hiringOrganization']['url'] = $company_website;
394
  }
395
+
396
+ $company_logo = get_the_company_logo( $post, 'full' );
397
+ if ( $company_logo ) {
398
  $data['hiringOrganization']['logo'] = $company_logo;
399
  }
400
 
401
+ $data['identifier'] = array();
402
  $data['identifier']['@type'] = 'PropertyValue';
403
+ $data['identifier']['name'] = get_the_company_name( $post );
404
  $data['identifier']['value'] = get_the_guid( $post );
405
 
406
  $location = get_the_job_location( $post );
407
  if ( ! empty( $location ) ) {
408
+ $data['jobLocation'] = array();
409
+ $data['jobLocation']['@type'] = 'Place';
410
  $data['jobLocation']['address'] = wpjm_get_job_listing_location_structured_data( $post );
411
  if ( empty( $data['jobLocation']['address'] ) ) {
412
  $data['jobLocation']['address'] = $location;
439
  return false;
440
  }
441
 
442
+ $mapping = array();
443
+ $mapping['streetAddress'] = array( 'street_number', 'street' );
444
  $mapping['addressLocality'] = 'city';
445
+ $mapping['addressRegion'] = 'state_short';
446
+ $mapping['postalCode'] = 'postcode';
447
+ $mapping['addressCountry'] = 'country_short';
448
 
449
+ $address = array();
450
  $address['@type'] = 'PostalAddress';
451
  foreach ( $mapping as $schema_key => $geolocation_key ) {
452
  if ( is_array( $geolocation_key ) ) {
466
  }
467
  }
468
 
469
+ // No address parts were found.
470
  if ( 1 === count( $address ) ) {
471
  $address = false;
472
  }
487
  *
488
  * @since 1.27.0
489
  * @param int|WP_Post $post
 
490
  */
491
  function wpjm_the_job_title( $post = null ) {
492
+ $job_title = wpjm_get_the_job_title( $post );
493
+ if ( $job_title ) {
494
+ echo wp_kses_post( $job_title );
495
  }
496
  }
497
 
499
  * Gets the job title for the listing.
500
  *
501
  * @since 1.27.0
502
+ * @param int|WP_Post $post (default: null).
503
  * @return string|bool|null
504
  */
505
  function wpjm_get_the_job_title( $post = null ) {
506
  $post = get_post( $post );
507
  if ( ! $post || 'job_listing' !== $post->post_type ) {
508
+ return null;
509
  }
510
 
511
+ $title = wp_strip_all_tags( get_the_title( $post ) );
512
 
513
  /**
514
  * Filter for the job title.
525
  *
526
  * @since 1.28.0
527
  * @param int|WP_Post $post
 
528
  */
529
  function wpjm_the_job_description( $post = null ) {
530
+ $job_description = wpjm_get_the_job_description( $post );
531
+ if ( $job_description ) {
532
+ echo wp_kses_post( $job_description );
533
  }
534
  }
535
 
537
  * Gets the job description for the listing.
538
  *
539
  * @since 1.28.0
540
+ * @param int|WP_Post $post (default: null).
541
  * @return string|bool|null
542
  */
543
  function wpjm_get_the_job_description( $post = null ) {
544
  $post = get_post( $post );
545
  if ( ! $post || 'job_listing' !== $post->post_type ) {
546
+ return null;
547
  }
548
 
549
  $description = apply_filters( 'the_job_description', get_the_content( $post ) );
676
  *
677
  * @since 1.27.0
678
  *
679
+ * @return array $registration_fields.
680
  */
681
  function wpjm_get_registration_fields() {
682
  $generate_username_from_email = job_manager_generate_username_from_email();
683
  $use_standard_password_setup_email = wpjm_use_standard_password_setup_email();
684
+ $account_required = job_manager_user_requires_account();
685
 
686
  $registration_fields = array();
687
  if ( job_manager_enable_registration() ) {
688
  if ( ! $generate_username_from_email ) {
689
  $registration_fields['create_account_username'] = array(
690
  'type' => 'text',
691
+ 'label' => esc_html__( 'Username', 'wp-job-manager' ),
692
  'required' => $account_required,
693
  'value' => isset( $_POST['create_account_username'] ) ? $_POST['create_account_username'] : '',
694
  );
696
  if ( ! $use_standard_password_setup_email ) {
697
  $registration_fields['create_account_password'] = array(
698
  'type' => 'password',
699
+ 'label' => esc_html__( 'Password', 'wp-job-manager' ),
700
  'autocomplete' => false,
701
  'required' => $account_required,
702
  );
703
+ $password_hint = wpjm_get_password_rules_hint();
704
  if ( $password_hint ) {
705
  $registration_fields['create_account_password']['description'] = $password_hint;
706
  }
707
  $registration_fields['create_account_password_verify'] = array(
708
  'type' => 'password',
709
+ 'label' => esc_html__( 'Verify Password', 'wp-job-manager' ),
710
  'autocomplete' => false,
711
  'required' => $account_required,
712
  );
713
  }
714
  $registration_fields['create_account_email'] = array(
715
  'type' => 'text',
716
+ 'label' => esc_html__( 'Your email', 'wp-job-manager' ),
717
  'placeholder' => __( 'you@yourdomain.com', 'wp-job-manager' ),
718
  'required' => $account_required,
719
  'value' => isset( $_POST['create_account_email'] ) ? $_POST['create_account_email'] : '',
734
  * Displays the published date of the job listing.
735
  *
736
  * @since 1.25.3
737
+ * @param int|WP_Post $post (default: null).
738
  */
739
  function the_job_publish_date( $post = null ) {
740
  $date_format = get_option( 'job_manager_date_format' );
741
 
742
+ if ( 'default' === $date_format ) {
743
+ $display_date = esc_html__( 'Posted on ', 'wp-job-manager' ) . date_i18n( get_option( 'date_format' ), get_post_time( 'U' ) );
744
  } else {
745
+ // translators: Placeholder %s is the relative, human readable time since the job listing was posted.
746
+ $display_date = sprintf( esc_html__( 'Posted %s ago', 'wp-job-manager' ), human_time_diff( get_post_time( 'U' ), current_time( 'timestamp' ) ) );
747
  }
748
 
749
+ echo '<time datetime="' . esc_attr( get_post_time( 'Y-m-d' ) ) . '">' . wp_kses_post( $display_date ) . '</time>';
750
  }
751
 
752
 
754
  * Gets the published date of the job listing.
755
  *
756
  * @since 1.25.3
757
+ * @param int|WP_Post $post (default: null).
758
  * @return string|int|false
759
  */
760
  function get_the_job_publish_date( $post = null ) {
761
  $date_format = get_option( 'job_manager_date_format' );
762
 
763
+ if ( 'default' === $date_format ) {
764
  return get_post_time( get_option( 'date_format' ) );
765
  } else {
766
+ // translators: Placeholder %s is the relative, human readable time since the job listing was posted.
767
  return sprintf( __( 'Posted %s ago', 'wp-job-manager' ), human_time_diff( get_post_time( 'U' ), current_time( 'timestamp' ) ) );
768
  }
769
  }
773
  * Displays the location for the job listing.
774
  *
775
  * @since 1.0.0
776
+ * @param bool $map_link whether or not to link to Google Maps.
777
  * @param int|WP_Post $post
778
  */
779
  function the_job_location( $map_link = true, $post = null ) {
781
 
782
  if ( $location ) {
783
  if ( $map_link ) {
784
+ // If linking to google maps, we don't want anything but text here.
785
+ echo wp_kses_post(
786
+ apply_filters(
787
+ 'the_job_location_map_link',
788
+ '<a class="google_map_link" href="' . esc_url( 'http://maps.google.com/maps?q=' . rawurlencode( wp_strip_all_tags( $location ) ) . '&zoom=14&size=512x512&maptype=roadmap&sensor=false' ) . '" target="_blank">' . esc_html( wp_strip_all_tags( $location ) ) . '</a>',
789
+ $location, $post
790
+ )
791
+ );
792
  } else {
793
  echo wp_kses_post( $location );
794
  }
801
  * Gets the location for the job listing.
802
  *
803
  * @since 1.0.0
804
+ * @param int|WP_Post $post (default: null).
805
  * @return string|null
806
  */
807
  function get_the_job_location( $post = null ) {
808
  $post = get_post( $post );
809
  if ( ! $post || 'job_listing' !== $post->post_type ) {
810
+ return null;
811
  }
812
 
813
  return apply_filters( 'the_job_location', $post->_job_location, $post );
817
  * Displays the company logo.
818
  *
819
  * @since 1.0.0
820
+ * @param string $size (default: 'full').
821
+ * @param mixed $default (default: null).
822
+ * @param int|WP_Post $post (default: null).
823
  */
824
  function the_company_logo( $size = 'thumbnail', $default = null, $post = null ) {
825
  $logo = get_the_company_logo( $post, $size );
826
 
827
  if ( has_post_thumbnail( $post ) ) {
828
+ echo '<img class="company_logo" src="' . esc_url( $logo ) . '" alt="' . esc_attr( get_the_company_name( $post ) ) . '" />';
829
 
830
+ // Before 1.24.0, logo URLs were stored in post meta.
831
  } elseif ( ! empty( $logo ) && ( strstr( $logo, 'http' ) || file_exists( $logo ) ) ) {
832
+ if ( 'full' !== $size ) {
833
  $logo = job_manager_get_resized_image( $logo, $size );
834
  }
835
+ echo '<img class="company_logo" src="' . esc_url( $logo ) . '" alt="' . esc_attr( get_the_company_name( $post ) ) . '" />';
836
  } elseif ( $default ) {
837
+ echo '<img class="company_logo" src="' . esc_url( $default ) . '" alt="' . esc_attr( get_the_company_name( $post ) ) . '" />';
838
  } else {
839
+ echo '<img class="company_logo" src="' . esc_url( apply_filters( 'job_manager_default_company_logo', JOB_MANAGER_PLUGIN_URL . '/assets/images/company.png' ) ) . '" alt="' . esc_attr( get_the_company_name( $post ) ) . '" />';
840
  }
841
  }
842
 
844
  * Gets the company logo.
845
  *
846
  * @since 1.0.0
847
+ * @param int|WP_Post $post (default: null).
848
  * @param string $size
849
+ * @return string Image SRC.
850
  */
851
  function get_the_company_logo( $post = null, $size = 'thumbnail' ) {
852
  $post = get_post( $post );
873
  function job_manager_get_resized_image( $logo, $size ) {
874
  global $_wp_additional_image_sizes;
875
 
876
+ if ( 'full' !== $size
877
+ && strstr( $logo, WP_CONTENT_URL )
878
+ && ( isset( $_wp_additional_image_sizes[ $size ] ) || in_array( $size, array( 'thumbnail', 'medium', 'large' ), true ) )
879
+ ) {
880
 
881
+ if ( in_array( $size, array( 'thumbnail', 'medium', 'large' ), true ) ) {
882
  $img_width = get_option( $size . '_size_w' );
883
  $img_height = get_option( $size . '_size_h' );
884
  $img_crop = get_option( $size . '_size_crop' );
907
 
908
  $resize = $image->resize( $img_width, $img_height, $img_crop );
909
 
910
+ if ( ! is_wp_error( $resize ) ) {
911
 
912
+ $save = $image->save( $resized_logo_path );
913
 
914
  if ( ! is_wp_error( $save ) ) {
915
  $logo = dirname( $logo ) . '/' . basename( $resized_logo_path );
937
  $video = get_the_company_video( $post );
938
  $filetype = wp_check_filetype( $video );
939
 
940
+ if ( ! empty( $video ) ) {
941
+ // FV WordPress Flowplayer Support for advanced video formats.
942
  if ( shortcode_exists( 'flowplayer' ) ) {
943
+ $video_embed = '[flowplayer src="' . esc_url( $video ) . '"]';
944
+ } elseif ( ! empty( $filetype['ext'] ) ) {
945
  $video_embed = wp_video_shortcode( array( 'src' => $video ) );
946
  } else {
947
  $video_embed = wp_oembed_get( $video );
951
  $video_embed = apply_filters( 'the_company_video_embed', $video_embed, $post );
952
 
953
  if ( $video_embed ) {
954
+ echo '<div class="company_video">' . $video_embed . '</div>'; // WPCS: XSS ok.
955
  }
956
  }
957
 
959
  * Gets the company video URL.
960
  *
961
  * @since 1.14.0
962
+ * @param int|WP_Post $post (default: null).
963
  * @return string|null
964
  */
965
  function get_the_company_video( $post = null ) {
966
  $post = get_post( $post );
967
  if ( ! $post || 'job_listing' !== $post->post_type ) {
968
+ return null;
969
  }
970
  return apply_filters( 'the_company_video', $post->_company_video, $post );
971
  }
975
  *
976
  * @since 1.0.0
977
  * @since 1.0.1 Add the `$post` argument.
978
+ * @param string $before (default: '').
979
+ * @param string $after (default: '').
980
+ * @param bool $echo (default: true).
981
+ * @param int|WP_Post|null $post (default: null).
982
+ * @return string|null
983
  */
984
  function the_company_name( $before = '', $after = '', $echo = true, $post = null ) {
985
  $company_name = get_the_company_name( $post );
986
 
987
+ if ( 0 === strlen( $company_name ) ) {
988
+ return null;
989
+ }
990
 
991
+ $company_name = esc_attr( wp_strip_all_tags( $company_name ) );
992
  $company_name = $before . $company_name . $after;
993
 
994
+ if ( $echo ) {
995
+ echo wp_kses_post( $company_name );
996
+ } else {
997
  return $company_name;
998
+ }
999
  }
1000
 
1001
  /**
1002
  * Gets the company name.
1003
  *
1004
  * @since 1.0.0
1005
+ * @param int $post (default: null).
1006
  * @return string
1007
  */
1008
  function get_the_company_name( $post = null ) {
1018
  * Gets the company website.
1019
  *
1020
  * @since 1.0.0
1021
+ * @param int $post (default: null).
1022
  * @return null|string
1023
  */
1024
  function get_the_company_website( $post = null ) {
1025
  $post = get_post( $post );
1026
 
1027
+ if ( ! $post || 'job_listing' !== $post->post_type ) {
1028
  return;
1029
+ }
1030
 
1031
  $website = $post->_company_website;
1032
 
1041
  * Displays or retrieves the current company tagline with optional content.
1042
  *
1043
  * @since 1.0.0
1044
+ * @param string $before (default: '').
1045
+ * @param string $after (default: '').
1046
+ * @param bool $echo (default: true).
1047
+ * @param int|WP_Post|null $post (default: null).
1048
  * @return string|void
1049
  */
1050
  function the_company_tagline( $before = '', $after = '', $echo = true, $post = null ) {
1051
  $company_tagline = get_the_company_tagline( $post );
1052
 
1053
+ if ( 0 === strlen( $company_tagline ) ) {
1054
  return;
1055
+ }
1056
 
1057
+ $company_tagline = esc_attr( wp_strip_all_tags( $company_tagline ) );
1058
  $company_tagline = $before . $company_tagline . $after;
1059
 
1060
+ if ( $echo ) {
1061
+ echo wp_kses_post( $company_tagline );
1062
+ } else {
1063
  return $company_tagline;
1064
+ }
1065
  }
1066
 
1067
  /**
1068
  * Gets the company tagline.
1069
  *
1070
  * @since 1.0.0
1071
+ * @param int|WP_Post|null $post (default: null).
1072
  * @return string|null
1073
  */
1074
  function get_the_company_tagline( $post = null ) {
1075
  $post = get_post( $post );
1076
 
1077
+ if ( ! $post || 'job_listing' !== $post->post_type ) {
1078
+ return null;
1079
+ }
1080
 
1081
  return apply_filters( 'the_company_tagline', $post->_company_tagline, $post );
1082
  }
1085
  * Displays or retrieves the current company Twitter link with optional content.
1086
  *
1087
  * @since 1.0.0
1088
+ * @param string $before (default: '').
1089
+ * @param string $after (default: '').
1090
+ * @param bool $echo (default: true).
1091
+ * @param int|WP_Post|null $post (default: null).
1092
+ * @return string|null
1093
  */
1094
  function the_company_twitter( $before = '', $after = '', $echo = true, $post = null ) {
1095
  $company_twitter = get_the_company_twitter( $post );
1096
 
1097
+ if ( 0 === strlen( $company_twitter ) ) {
1098
+ return null;
1099
+ }
1100
 
1101
+ $company_twitter = $before . '<a href="' . esc_url( 'https://twitter.com/' . $company_twitter ) . '" class="company_twitter" target="_blank">' . esc_html( wp_strip_all_tags( $company_twitter ) ) . '</a>' . $after;
 
1102
 
1103
+ if ( $echo ) {
1104
+ echo wp_kses_post( $company_twitter );
1105
+ } else {
1106
  return $company_twitter;
1107
+ }
1108
  }
1109
 
1110
  /**
1111
  * Gets the company Twitter link.
1112
  *
1113
  * @since 1.0.0
1114
+ * @param int|WP_Post|null $post (default: null).
1115
  * @return string|null
1116
  */
1117
  function get_the_company_twitter( $post = null ) {
1118
  $post = get_post( $post );
1119
+ if ( ! $post || 'job_listing' !== $post->post_type ) {
1120
+ return null;
1121
+ }
1122
 
1123
  $company_twitter = $post->_company_twitter;
1124
 
1125
+ if ( 0 === strlen( $company_twitter ) ) {
1126
+ return null;
1127
+ }
1128
 
1129
+ if ( 0 === strpos( $company_twitter, '@' ) ) {
1130
  $company_twitter = substr( $company_twitter, 1 );
1131
+ }
1132
 
1133
  return apply_filters( 'the_company_twitter', $company_twitter, $post );
1134
  }
1137
  * Outputs the job listing class.
1138
  *
1139
  * @since 1.0.0
1140
+ * @param string $class (default: '').
1141
+ * @param int|WP_Post $post_id (default: null).
1142
  */
1143
  function job_listing_class( $class = '', $post_id = null ) {
1144
+ // Separates classes with a single space, collates classes for post DIV.
1145
+ echo 'class="' . esc_attr( join( ' ', get_job_listing_class( $class, $post_id ) ) ) . '"';
1146
  }
1147
 
1148
  /**
1150
  *
1151
  * @since 1.0.0
1152
  * @param string $class
1153
+ * @param int|WP_Post $post_id (default: null).
1154
  * @return array
1155
  */
1156
  function get_job_listing_class( $class = '', $post_id = null ) {
1157
  $post = get_post( $post_id );
1158
 
1159
+ if ( empty( $post ) || 'job_listing' !== $post->post_type ) {
1160
  return array();
1161
  }
1162
 
1185
  function wpjm_add_post_class( $classes, $class, $post_id ) {
1186
  $post = get_post( $post_id );
1187
 
1188
+ if ( empty( $post ) || 'job_listing' !== $post->post_type ) {
1189
  return $classes;
1190
  }
1191
 
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.31.0
7
  * Author: Automattic
8
  * Author URI: https://wpjobmanager.com/
9
  * Requires at least: 4.7.0
@@ -11,7 +11,10 @@
11
  * Text Domain: wp-job-manager
12
  * Domain Path: /languages/
13
  * License: GPL2+
 
 
14
  */
 
15
  if ( ! defined( 'ABSPATH' ) ) {
16
  exit;
17
  }
@@ -32,6 +35,8 @@ class WP_Job_Manager {
32
  private static $_instance = null;
33
 
34
  /**
 
 
35
  * @var WP_Job_Manager_REST_API
36
  */
37
  private $rest_api = null;
@@ -57,68 +62,73 @@ class WP_Job_Manager {
57
  * Constructor.
58
  */
59
  public function __construct() {
60
- // Define constants
61
- define( 'JOB_MANAGER_VERSION', '1.31.0' );
62
  define( 'JOB_MANAGER_MINIMUM_WP_VERSION', '4.7.0' );
63
  define( 'JOB_MANAGER_PLUGIN_DIR', untrailingslashit( plugin_dir_path( __FILE__ ) ) );
64
  define( 'JOB_MANAGER_PLUGIN_URL', untrailingslashit( plugins_url( basename( plugin_dir_path( __FILE__ ) ), basename( __FILE__ ) ) ) );
65
  define( 'JOB_MANAGER_PLUGIN_BASENAME', plugin_basename( __FILE__ ) );
66
 
67
- // Includes
68
- include_once( JOB_MANAGER_PLUGIN_DIR . '/includes/class-wp-job-manager-install.php' );
69
- include_once( JOB_MANAGER_PLUGIN_DIR . '/includes/class-wp-job-manager-post-types.php' );
70
- include_once( JOB_MANAGER_PLUGIN_DIR . '/includes/class-wp-job-manager-ajax.php' );
71
- include_once( JOB_MANAGER_PLUGIN_DIR . '/includes/class-wp-job-manager-shortcodes.php' );
72
- include_once( JOB_MANAGER_PLUGIN_DIR . '/includes/class-wp-job-manager-api.php' );
73
- include_once( JOB_MANAGER_PLUGIN_DIR . '/includes/class-wp-job-manager-forms.php' );
74
- include_once( JOB_MANAGER_PLUGIN_DIR . '/includes/class-wp-job-manager-geocode.php' );
75
- include_once( JOB_MANAGER_PLUGIN_DIR . '/includes/class-wp-job-manager-cache-helper.php' );
76
- include_once( JOB_MANAGER_PLUGIN_DIR . '/includes/helper/class-wp-job-manager-helper.php' );
77
- include_once( JOB_MANAGER_PLUGIN_DIR . '/includes/abstracts/abstract-wp-job-manager-email.php' );
78
- include_once( JOB_MANAGER_PLUGIN_DIR . '/includes/abstracts/abstract-wp-job-manager-email-template.php' );
79
- include_once( JOB_MANAGER_PLUGIN_DIR . '/includes/class-wp-job-manager-email-notifications.php' );
 
80
 
81
  add_action( 'rest_api_init', array( $this, 'rest_api' ) );
82
 
83
  if ( is_admin() ) {
84
- include_once( JOB_MANAGER_PLUGIN_DIR . '/includes/admin/class-wp-job-manager-admin.php' );
85
  }
86
 
87
- // Load 3rd party customizations
88
- include_once( JOB_MANAGER_PLUGIN_DIR . '/includes/3rd-party/3rd-party.php' );
89
 
90
- // Init classes
91
  $this->forms = WP_Job_Manager_Forms::instance();
92
  $this->post_types = WP_Job_Manager_Post_Types::instance();
93
 
94
- // Schedule cron jobs
95
  self::maybe_schedule_cron_jobs();
96
 
97
- // Activation - works with symlinks
98
  register_activation_hook( basename( dirname( __FILE__ ) ) . '/' . basename( __FILE__ ), array( $this, 'activate' ) );
99
 
100
- // Switch theme
101
  add_action( 'after_switch_theme', array( 'WP_Job_Manager_Ajax', 'add_endpoint' ), 10 );
102
  add_action( 'after_switch_theme', array( $this->post_types, 'register_post_types' ), 11 );
103
  add_action( 'after_switch_theme', 'flush_rewrite_rules', 15 );
104
 
105
- // Actions
106
  add_action( 'after_setup_theme', array( $this, 'load_plugin_textdomain' ) );
107
  add_action( 'after_setup_theme', array( $this, 'include_template_functions' ), 11 );
108
  add_action( 'widgets_init', array( $this, 'widgets_init' ) );
109
  add_action( 'wp_loaded', array( $this, 'register_shared_assets' ) );
110
  add_action( 'wp_enqueue_scripts', array( $this, 'frontend_scripts' ) );
111
  add_action( 'admin_init', array( $this, 'updater' ) );
 
112
  add_action( 'wp_logout', array( $this, 'cleanup_job_posting_cookies' ) );
113
  add_action( 'init', array( 'WP_Job_Manager_Email_Notifications', 'init' ) );
114
 
 
 
 
115
  add_action( 'init', array( $this, 'usage_tracking_init' ) );
116
  register_deactivation_hook( __FILE__, array( $this, 'usage_tracking_cleanup' ) );
117
 
118
- // Other cleanup
119
  register_deactivation_hook( __FILE__, array( $this, 'unschedule_cron_jobs' ) );
120
 
121
- // Defaults for WPJM core actions
122
  add_action( 'wpjm_notify_new_user', 'wp_job_manager_notify_new_user', 10, 2 );
123
  }
124
 
@@ -145,6 +155,28 @@ class WP_Job_Manager {
145
  }
146
  }
147
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
148
  /**
149
  * Loads textdomain for plugin.
150
  */
@@ -160,7 +192,7 @@ class WP_Job_Manager {
160
  */
161
  public function rest_api() {
162
  if ( null === $this->rest_api ) {
163
- include_once( JOB_MANAGER_PLUGIN_DIR . '/includes/rest-api/class-wp-job-manager-rest-api.php' );
164
  $this->rest_api = new WP_Job_Manager_REST_API( dirname( __FILE__ ) );
165
  }
166
  return $this->rest_api;
@@ -170,26 +202,26 @@ class WP_Job_Manager {
170
  * Loads plugin's core helper template functions.
171
  */
172
  public function include_template_functions() {
173
- include_once( JOB_MANAGER_PLUGIN_DIR . '/wp-job-manager-deprecated.php' );
174
- include_once( JOB_MANAGER_PLUGIN_DIR . '/wp-job-manager-functions.php' );
175
- include_once( JOB_MANAGER_PLUGIN_DIR . '/wp-job-manager-template.php' );
176
  }
177
 
178
  /**
179
  * Loads plugin's widgets.
180
  */
181
  public function widgets_init() {
182
- include_once( JOB_MANAGER_PLUGIN_DIR . '/includes/class-wp-job-manager-widget.php' );
183
- include_once( JOB_MANAGER_PLUGIN_DIR . '/includes/widgets/class-wp-job-manager-widget-recent-jobs.php' );
184
- include_once( JOB_MANAGER_PLUGIN_DIR . '/includes/widgets/class-wp-job-manager-widget-featured-jobs.php' );
185
  }
186
 
187
  /**
188
  * Initialize the Usage Tracking system.
189
  */
190
  public function usage_tracking_init() {
191
- include_once( JOB_MANAGER_PLUGIN_DIR . '/includes/class-wp-job-manager-usage-tracking.php' );
192
- include_once( JOB_MANAGER_PLUGIN_DIR . '/includes/class-wp-job-manager-usage-tracking-data.php' );
193
 
194
  WP_Job_Manager_Usage_Tracking::get_instance()->set_callback(
195
  array( 'WP_Job_Manager_Usage_Tracking_Data', 'get_usage_data' )
@@ -286,7 +318,6 @@ class WP_Job_Manager {
286
  * }
287
  * return $chosen_used_on_page;
288
  * } );
289
- *
290
  */
291
  if ( ! defined( 'JOB_MANAGER_TEST_NEW_ASSET_BEHAVIOR' ) || true !== JOB_MANAGER_TEST_NEW_ASSET_BEHAVIOR ) {
292
  add_filter( 'job_manager_chosen_enabled', '__return_true' );
@@ -295,7 +326,7 @@ class WP_Job_Manager {
295
 
296
  $ajax_url = WP_Job_Manager_Ajax::get_endpoint();
297
  $ajax_filter_deps = array( 'jquery', 'jquery-deserialize' );
298
- $ajax_data = array(
299
  'ajax_url' => $ajax_url,
300
  'is_rtl' => is_rtl() ? 1 : 0,
301
  'i18n_load_prev_listings' => __( 'Load previous listings', 'wp-job-manager' ),
@@ -310,7 +341,7 @@ class WP_Job_Manager {
310
  */
311
  $ajax_data['lang'] = apply_filters( 'wpjm_lang', null );
312
 
313
- $chosen_shortcodes = array( 'submit_job_form', 'job_dashboard', 'jobs' );
314
  $chosen_used_on_page = has_wpjm_shortcode( null, $chosen_shortcodes );
315
 
316
  /**
@@ -329,10 +360,13 @@ class WP_Job_Manager {
329
  wp_enqueue_style( 'chosen', JOB_MANAGER_PLUGIN_URL . '/assets/css/chosen.css', array(), '1.1.0' );
330
  $ajax_filter_deps[] = 'chosen';
331
 
332
- wp_localize_script( 'chosen', 'job_manager_chosen_multiselect_args',
333
- apply_filters( 'job_manager_chosen_multiselect_args', array(
334
- 'search_contains' => true,
335
- ) )
 
 
 
336
  );
337
  }
338
 
@@ -342,27 +376,37 @@ class WP_Job_Manager {
342
  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 );
343
 
344
  ob_start();
345
- get_job_manager_template( 'form-fields/uploaded-file-html.php', array(
346
- 'name' => '',
347
- 'value' => '',
348
- 'extension' => 'jpg',
349
- ) );
 
 
 
350
  $js_field_html_img = ob_get_clean();
351
 
352
  ob_start();
353
- get_job_manager_template( 'form-fields/uploaded-file-html.php', array(
354
- 'name' => '',
355
- 'value' => '',
356
- 'extension' => 'zip',
357
- ) );
 
 
 
358
  $js_field_html = ob_get_clean();
359
 
360
- wp_localize_script( 'wp-job-manager-ajax-file-upload', 'job_manager_ajax_file_upload', array(
361
- 'ajax_url' => $ajax_url,
362
- 'js_field_html_img' => esc_js( str_replace( "\n", '', $js_field_html_img ) ),
363
- 'js_field_html' => esc_js( str_replace( "\n", '', $js_field_html ) ),
364
- 'i18n_invalid_file_type' => __( 'Invalid file type. Accepted types:', 'wp-job-manager' ),
365
- ) );
 
 
 
 
366
  }
367
 
368
  wp_register_script( 'jquery-deserialize', JOB_MANAGER_PLUGIN_URL . '/assets/js/jquery-deserialize/jquery.deserialize.js', array( 'jquery' ), '1.2.1', true );
@@ -371,10 +415,13 @@ class WP_Job_Manager {
371
  wp_register_script( 'wp-job-manager-job-application', JOB_MANAGER_PLUGIN_URL . '/assets/js/job-application.min.js', array( 'jquery' ), JOB_MANAGER_VERSION, true );
372
  wp_register_script( 'wp-job-manager-job-submission', JOB_MANAGER_PLUGIN_URL . '/assets/js/job-submission.min.js', array( 'jquery' ), JOB_MANAGER_VERSION, true );
373
  wp_localize_script( 'wp-job-manager-ajax-filters', 'job_manager_ajax_filters', $ajax_data );
374
- wp_localize_script( 'wp-job-manager-job-dashboard', 'job_manager_job_dashboard', array(
375
- 'i18n_confirm_delete' => __( 'Are you sure you want to delete this listing?', 'wp-job-manager' ),
376
- ) );
377
-
 
 
 
378
 
379
  /**
380
  * Filter whether to enqueue WPJM core's frontend scripts. By default, they will only be enqueued on WPJM related
@@ -414,7 +461,7 @@ add_filter( 'post_types_to_delete_with_user', 'job_manager_add_post_types', 10 )
414
  * @since 1.26
415
  * @return WP_Job_Manager
416
  */
417
- function WPJM() {
418
  return WP_Job_Manager::instance();
419
  }
420
 
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.31.1
7
  * Author: Automattic
8
  * Author URI: https://wpjobmanager.com/
9
  * Requires at least: 4.7.0
11
  * Text Domain: wp-job-manager
12
  * Domain Path: /languages/
13
  * License: GPL2+
14
+ *
15
+ * @package wp-job-manager
16
  */
17
+
18
  if ( ! defined( 'ABSPATH' ) ) {
19
  exit;
20
  }
35
  private static $_instance = null;
36
 
37
  /**
38
+ * REST API instance.
39
+ *
40
  * @var WP_Job_Manager_REST_API
41
  */
42
  private $rest_api = null;
62
  * Constructor.
63
  */
64
  public function __construct() {
65
+ // Define constants.
66
+ define( 'JOB_MANAGER_VERSION', '1.31.1' );
67
  define( 'JOB_MANAGER_MINIMUM_WP_VERSION', '4.7.0' );
68
  define( 'JOB_MANAGER_PLUGIN_DIR', untrailingslashit( plugin_dir_path( __FILE__ ) ) );
69
  define( 'JOB_MANAGER_PLUGIN_URL', untrailingslashit( plugins_url( basename( plugin_dir_path( __FILE__ ) ), basename( __FILE__ ) ) ) );
70
  define( 'JOB_MANAGER_PLUGIN_BASENAME', plugin_basename( __FILE__ ) );
71
 
72
+ // Includes.
73
+ include_once JOB_MANAGER_PLUGIN_DIR . '/includes/class-wp-job-manager-install.php';
74
+ include_once JOB_MANAGER_PLUGIN_DIR . '/includes/class-wp-job-manager-post-types.php';
75
+ include_once JOB_MANAGER_PLUGIN_DIR . '/includes/class-wp-job-manager-ajax.php';
76
+ include_once JOB_MANAGER_PLUGIN_DIR . '/includes/class-wp-job-manager-shortcodes.php';
77
+ include_once JOB_MANAGER_PLUGIN_DIR . '/includes/class-wp-job-manager-api.php';
78
+ include_once JOB_MANAGER_PLUGIN_DIR . '/includes/class-wp-job-manager-forms.php';
79
+ include_once JOB_MANAGER_PLUGIN_DIR . '/includes/class-wp-job-manager-geocode.php';
80
+ include_once JOB_MANAGER_PLUGIN_DIR . '/includes/class-wp-job-manager-cache-helper.php';
81
+ include_once JOB_MANAGER_PLUGIN_DIR . '/includes/helper/class-wp-job-manager-helper.php';
82
+ include_once JOB_MANAGER_PLUGIN_DIR . '/includes/abstracts/abstract-wp-job-manager-email.php';
83
+ include_once JOB_MANAGER_PLUGIN_DIR . '/includes/abstracts/abstract-wp-job-manager-email-template.php';
84
+ include_once JOB_MANAGER_PLUGIN_DIR . '/includes/class-wp-job-manager-email-notifications.php';
85
+ include_once JOB_MANAGER_PLUGIN_DIR . '/includes/class-wp-job-manager-data-exporter.php';
86
 
87
  add_action( 'rest_api_init', array( $this, 'rest_api' ) );
88
 
89
  if ( is_admin() ) {
90
+ include_once JOB_MANAGER_PLUGIN_DIR . '/includes/admin/class-wp-job-manager-admin.php';
91
  }
92
 
93
+ // Load 3rd party customizations.
94
+ include_once JOB_MANAGER_PLUGIN_DIR . '/includes/3rd-party/3rd-party.php';
95
 
96
+ // Init classes.
97
  $this->forms = WP_Job_Manager_Forms::instance();
98
  $this->post_types = WP_Job_Manager_Post_Types::instance();
99
 
100
+ // Schedule cron jobs.
101
  self::maybe_schedule_cron_jobs();
102
 
103
+ // Activation - works with symlinks.
104
  register_activation_hook( basename( dirname( __FILE__ ) ) . '/' . basename( __FILE__ ), array( $this, 'activate' ) );
105
 
106
+ // Switch theme.
107
  add_action( 'after_switch_theme', array( 'WP_Job_Manager_Ajax', 'add_endpoint' ), 10 );
108
  add_action( 'after_switch_theme', array( $this->post_types, 'register_post_types' ), 11 );
109
  add_action( 'after_switch_theme', 'flush_rewrite_rules', 15 );
110
 
111
+ // Actions.
112
  add_action( 'after_setup_theme', array( $this, 'load_plugin_textdomain' ) );
113
  add_action( 'after_setup_theme', array( $this, 'include_template_functions' ), 11 );
114
  add_action( 'widgets_init', array( $this, 'widgets_init' ) );
115
  add_action( 'wp_loaded', array( $this, 'register_shared_assets' ) );
116
  add_action( 'wp_enqueue_scripts', array( $this, 'frontend_scripts' ) );
117
  add_action( 'admin_init', array( $this, 'updater' ) );
118
+ add_action( 'admin_init', array( $this, 'add_privacy_policy_content' ) );
119
  add_action( 'wp_logout', array( $this, 'cleanup_job_posting_cookies' ) );
120
  add_action( 'init', array( 'WP_Job_Manager_Email_Notifications', 'init' ) );
121
 
122
+ // Filters.
123
+ add_filter( 'wp_privacy_personal_data_exporters', array( 'WP_Job_Manager_Data_Exporter', 'register_wpjm_user_data_exporter' ) );
124
+
125
  add_action( 'init', array( $this, 'usage_tracking_init' ) );
126
  register_deactivation_hook( __FILE__, array( $this, 'usage_tracking_cleanup' ) );
127
 
128
+ // Other cleanup.
129
  register_deactivation_hook( __FILE__, array( $this, 'unschedule_cron_jobs' ) );
130
 
131
+ // Defaults for WPJM core actions.
132
  add_action( 'wpjm_notify_new_user', 'wp_job_manager_notify_new_user', 10, 2 );
133
  }
134
 
155
  }
156
  }
157
 
158
+ /**
159
+ * Adds Privacy Policy suggested content.
160
+ */
161
+ public function add_privacy_policy_content() {
162
+ if ( ! function_exists( 'wp_add_privacy_policy_content' ) ) {
163
+ return;
164
+ }
165
+
166
+ $content = sprintf(
167
+ // translators: Placeholders %1$s and %2$s are the names of the two cookies used in WP Job Manager.
168
+ __( 'This site adds the following cookies to help users resume job submissions that they
169
+ have started but have not completed: %1$s and %2$s', 'wp-job-manager'
170
+ ),
171
+ '<code>wp-job-manager-submitting-job-id</code>', '<code>wp-job-manager-submitting-job-key</code>'
172
+ );
173
+
174
+ wp_add_privacy_policy_content(
175
+ 'WP Job Manager',
176
+ wp_kses_post( wpautop( $content, false ) )
177
+ );
178
+ }
179
+
180
  /**
181
  * Loads textdomain for plugin.
182
  */
192
  */
193
  public function rest_api() {
194
  if ( null === $this->rest_api ) {
195
+ include_once JOB_MANAGER_PLUGIN_DIR . '/includes/rest-api/class-wp-job-manager-rest-api.php';
196
  $this->rest_api = new WP_Job_Manager_REST_API( dirname( __FILE__ ) );
197
  }
198
  return $this->rest_api;
202
  * Loads plugin's core helper template functions.
203
  */
204
  public function include_template_functions() {
205
+ include_once JOB_MANAGER_PLUGIN_DIR . '/wp-job-manager-deprecated.php';
206
+ include_once JOB_MANAGER_PLUGIN_DIR . '/wp-job-manager-functions.php';
207
+ include_once JOB_MANAGER_PLUGIN_DIR . '/wp-job-manager-template.php';
208
  }
209
 
210
  /**
211
  * Loads plugin's widgets.
212
  */
213
  public function widgets_init() {
214
+ include_once JOB_MANAGER_PLUGIN_DIR . '/includes/class-wp-job-manager-widget.php';
215
+ include_once JOB_MANAGER_PLUGIN_DIR . '/includes/widgets/class-wp-job-manager-widget-recent-jobs.php';
216
+ include_once JOB_MANAGER_PLUGIN_DIR . '/includes/widgets/class-wp-job-manager-widget-featured-jobs.php';
217
  }
218
 
219
  /**
220
  * Initialize the Usage Tracking system.
221
  */
222
  public function usage_tracking_init() {
223
+ include_once JOB_MANAGER_PLUGIN_DIR . '/includes/class-wp-job-manager-usage-tracking.php';
224
+ include_once JOB_MANAGER_PLUGIN_DIR . '/includes/class-wp-job-manager-usage-tracking-data.php';
225
 
226
  WP_Job_Manager_Usage_Tracking::get_instance()->set_callback(
227
  array( 'WP_Job_Manager_Usage_Tracking_Data', 'get_usage_data' )
318
  * }
319
  * return $chosen_used_on_page;
320
  * } );
 
321
  */
322
  if ( ! defined( 'JOB_MANAGER_TEST_NEW_ASSET_BEHAVIOR' ) || true !== JOB_MANAGER_TEST_NEW_ASSET_BEHAVIOR ) {
323
  add_filter( 'job_manager_chosen_enabled', '__return_true' );
326
 
327
  $ajax_url = WP_Job_Manager_Ajax::get_endpoint();
328
  $ajax_filter_deps = array( 'jquery', 'jquery-deserialize' );
329
+ $ajax_data = array(
330
  'ajax_url' => $ajax_url,
331
  'is_rtl' => is_rtl() ? 1 : 0,
332
  'i18n_load_prev_listings' => __( 'Load previous listings', 'wp-job-manager' ),
341
  */
342
  $ajax_data['lang'] = apply_filters( 'wpjm_lang', null );
343
 
344
+ $chosen_shortcodes = array( 'submit_job_form', 'job_dashboard', 'jobs' );
345
  $chosen_used_on_page = has_wpjm_shortcode( null, $chosen_shortcodes );
346
 
347
  /**
360
  wp_enqueue_style( 'chosen', JOB_MANAGER_PLUGIN_URL . '/assets/css/chosen.css', array(), '1.1.0' );
361
  $ajax_filter_deps[] = 'chosen';
362
 
363
+ wp_localize_script(
364
+ 'chosen', 'job_manager_chosen_multiselect_args',
365
+ apply_filters(
366
+ 'job_manager_chosen_multiselect_args', array(
367
+ 'search_contains' => true,
368
+ )
369
+ )
370
  );
371
  }
372
 
376
  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 );
377
 
378
  ob_start();
379
+ get_job_manager_template(
380
+ 'form-fields/uploaded-file-html.php',
381
+ array(
382
+ 'name' => '',
383
+ 'value' => '',
384
+ 'extension' => 'jpg',
385
+ )
386
+ );
387
  $js_field_html_img = ob_get_clean();
388
 
389
  ob_start();
390
+ get_job_manager_template(
391
+ 'form-fields/uploaded-file-html.php',
392
+ array(
393
+ 'name' => '',
394
+ 'value' => '',
395
+ 'extension' => 'zip',
396
+ )
397
+ );
398
  $js_field_html = ob_get_clean();
399
 
400
+ wp_localize_script(
401
+ 'wp-job-manager-ajax-file-upload',
402
+ 'job_manager_ajax_file_upload',
403
+ array(
404
+ 'ajax_url' => $ajax_url,
405
+ 'js_field_html_img' => esc_js( str_replace( "\n", '', $js_field_html_img ) ),
406
+ 'js_field_html' => esc_js( str_replace( "\n", '', $js_field_html ) ),
407
+ 'i18n_invalid_file_type' => __( 'Invalid file type. Accepted types:', 'wp-job-manager' ),
408
+ )
409
+ );
410
  }
411
 
412
  wp_register_script( 'jquery-deserialize', JOB_MANAGER_PLUGIN_URL . '/assets/js/jquery-deserialize/jquery.deserialize.js', array( 'jquery' ), '1.2.1', true );
415
  wp_register_script( 'wp-job-manager-job-application', JOB_MANAGER_PLUGIN_URL . '/assets/js/job-application.min.js', array( 'jquery' ), JOB_MANAGER_VERSION, true );
416
  wp_register_script( 'wp-job-manager-job-submission', JOB_MANAGER_PLUGIN_URL . '/assets/js/job-submission.min.js', array( 'jquery' ), JOB_MANAGER_VERSION, true );
417
  wp_localize_script( 'wp-job-manager-ajax-filters', 'job_manager_ajax_filters', $ajax_data );
418
+ wp_localize_script(
419
+ 'wp-job-manager-job-dashboard',
420
+ 'job_manager_job_dashboard',
421
+ array(
422
+ 'i18n_confirm_delete' => __( 'Are you sure you want to delete this listing?', 'wp-job-manager' ),
423
+ )
424
+ );
425
 
426
  /**
427
  * Filter whether to enqueue WPJM core's frontend scripts. By default, they will only be enqueued on WPJM related
461
  * @since 1.26
462
  * @return WP_Job_Manager
463
  */
464
+ function WPJM() { // phpcs:ignore WordPress.NamingConventions.ValidFunctionName
465
  return WP_Job_Manager::instance();
466
  }
467