Skip to content

feature: integrate WP job manager#1847

Open
sapayth wants to merge 1 commit into
weDevsOfficial:developfrom
sapayth:feature/integrate_wp_job_manager
Open

feature: integrate WP job manager#1847
sapayth wants to merge 1 commit into
weDevsOfficial:developfrom
sapayth:feature/integrate_wp_job_manager

Conversation

@sapayth
Copy link
Copy Markdown
Contributor

@sapayth sapayth commented Apr 17, 2026

closes #461
Related PR #1490

Summary

Adds a native WP Job Manager integration to WPUF. When WP Job Manager is active, a new "Post a Job" form template appears in the Post Form Template picker, letting site owners build a branded job submission form in the WPUF drag-and-drop builder instead of editing PHP to customize the WPJM shortcode.

Submissions create real WP Job Manager job listings with all expected meta (location, application email/URL, company info, etc.), respect WPJM's approval setting, and fire the same "new job submitted" notifications employers already expect.

Technical Notes

  • New template registered under the key post_form_template_wp_job_manager. If WPUF Pro ships a richer version, it replaces this one via the same key.
  • New filters for integrators:
    • wpuf_enable_wpjm_integration — kill-switch.
    • wpuf_wpjm_meta_mapping — customize WPUF-field → WPJM-meta mapping.
    • wpuf_wpjm_should_approve — override the approval decision per submission.
  • Job listing expiry is left entirely to WP Job Manager — WPUF does not write _job_expires.
  • Submissions flag _public_submission = 1 so WPJM's own handler fires job_manager_job_submitted (admin + employer emails) without risk of double-firing.
  • job_listing_category and job_listing_type added to the free taxonomy allowlist so WPUF taxonomy fields can target them without Pro.

Summary by CodeRabbit

  • New Features
    • Introduced WP Job Manager integration with a pre-built job listing form template.
    • Job submissions now map to meta fields including location, remote position, application URL, and company details.
    • Integrated approval workflow that respects WP Job Manager approval settings.
    • Added job category and job type taxonomies for form configuration.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 17, 2026

Walkthrough

This PR introduces a new WP Job Manager integration for WPUF, adding a form template, metadata mapping handler, and integration bootstrap class. The changes extend the integration loader and taxonomy system to conditionally support job listings when WP Job Manager is active.

Changes

Cohort / File(s) Summary
Integration Setup
includes/Integrations.php, includes/Free/Free_Loader.php, wpuf-functions.php
Extended integration registration mapping and loader to conditionally include WP Job Manager; added taxonomies (job_listing_category, job_listing_type) to the free taxonomy list.
WP Job Manager Integration
includes/Integrations/WP_Job_Manager/WPUF_WP_Job_Manager_Integration.php, includes/Integrations/WP_Job_Manager/Meta_Mapper.php, includes/Integrations/WP_Job_Manager/Template_Free.php
New integration classes: bootstrap class initializes integration with hook registration; Meta_Mapper handles job submission metadata persistence with sanitization and post status conditionals; Template_Free defines form template with 11 job-submission fields and settings.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested labels

needs: dev review

Poem

🐰 A job-listing garden grows today,
With WPJM in the WPUF way,
Meta fields dance, templates take their place,
Integration hooks embrace with grace! 🌱✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feature: integrate WP job manager' directly and clearly summarizes the main change—adding WP Job Manager integration to the WPUF plugin.
Docstring Coverage ✅ Passed Docstring coverage is 93.75% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (3)
includes/Integrations/WP_Job_Manager/WPUF_WP_Job_Manager_Integration.php (1)

35-73: Redundant class_exists( 'WP_Job_Manager' ) gate.

Integrations::__construct() (includes/Integrations.php:40) already instantiates this class only when class_exists( 'WP_Job_Manager' ) is true, so is_wpjm_active() / the early return at line 36–38 is dead code in the normal load path. Safe to keep as a defensive guard, but worth collapsing if you want to reduce duplication — otherwise at least add a comment noting it's only for direct instantiation paths (tests, WP-CLI, etc.).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@includes/Integrations/WP_Job_Manager/WPUF_WP_Job_Manager_Integration.php`
around lines 35 - 73, The init_handlers method contains a redundant runtime
check using is_wpjm_active()/class_exists('WP_Job_Manager') because
Integrations::__construct() already only instantiates
WPUF_WP_Job_Manager_Integration when WP_Job_Manager exists; collapse the
duplicate guard by removing the early return block in init_handlers (the if (!
$this->is_wpjm_active()) return;) or, if you prefer to keep it as defensive
code, add a clarifying comment above is_wpjm_active() and the guard referencing
Integrations::__construct() and explaining it's only for direct instantiation
paths (tests/CLI) so reviewers understand the intent; update code around
init_handlers and is_wpjm_active accordingly.
includes/Integrations/WP_Job_Manager/Meta_Mapper.php (1)

158-172: Silent drop when fields are submitted but empty.

isset( $_POST[ $field_name ] ) returns true for submitted-but-empty fields, so empty strings get written (overwriting prior values on edit — acceptable). However, the wpuf_wpjm_meta_mapping filter allows third-parties to add keys that may not map to any posted field name — those are correctly skipped. Just flagging: if you later change get_meta_mapping() to $field_name => $meta_key pairs where $field_name !== $meta_key, make sure the free template's field name matches $field_name, not $meta_key. Worth a one-line comment.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@includes/Integrations/WP_Job_Manager/Meta_Mapper.php` around lines 158 - 172,
Add a one-line clarifying comment in persist_meta above the foreach that
explains the shape of get_meta_mapping() (keys are form input names, values are
post meta keys), that isset($_POST[$field_name]) will be true for
submitted-but-empty fields (which will overwrite existing meta with empty
values), and that third-party filters (wpuf_wpjm_meta_mapping) must supply the
form field "name" as the array key ($field_name) not the meta key ($meta_key).
includes/Integrations/WP_Job_Manager/Template_Free.php (1)

22-22: Redundant enabled guard.

This template is only registered in Free_Loader::post_form_templates() when class_exists( 'WP_Job_Manager' ) is already true, so $this->enabled is effectively always true here. Either drop the check or leave it as a belt-and-braces guard — flagging for awareness, not blocking.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@includes/Integrations/WP_Job_Manager/Template_Free.php` at line 22, The
$this->enabled assignment in Template_Free is redundant because
Free_Loader::post_form_templates() only registers this template when
class_exists('WP_Job_Manager') is true; update Template_Free to set
$this->enabled = true unconditionally (or remove the assignment entirely) to
remove the needless class_exists check—modify the Template_Free class's
constructor/property initialization (the $this->enabled line) accordingly and
leave Free_Loader::post_form_templates() untouched.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@includes/Integrations/WP_Job_Manager/Meta_Mapper.php`:
- Around line 216-235: The sanitize_for_meta function currently calls
WP_Job_Manager_Post_Types::sanitize_meta_field_url,
::sanitize_meta_field_application, and ::sanitize_meta_field_based_on_input_type
directly which can cause fatal errors if those static methods are missing;
update sanitize_for_meta to wrap each WP_Job_Manager_Post_Types::method call in
is_callable checks (e.g., is_callable([WP_Job_Manager_Post_Types::class,
'sanitize_meta_field_url'])) and if the method is not callable fall back to safe
defaults: for URL/video use sanitize_text_field (or
wp_sanitize_redirect/esc_url_raw if available), for application use
sanitize_text_field or handle arrays with array_map('sanitize_text_field'), and
for the default case fall back to returning sanitized string/array via
sanitize_text_field/array_map — keep the existing _remote_position cast
unchanged and reference sanitize_for_meta and the three
WP_Job_Manager_Post_Types method names when making the changes.

---

Nitpick comments:
In `@includes/Integrations/WP_Job_Manager/Meta_Mapper.php`:
- Around line 158-172: Add a one-line clarifying comment in persist_meta above
the foreach that explains the shape of get_meta_mapping() (keys are form input
names, values are post meta keys), that isset($_POST[$field_name]) will be true
for submitted-but-empty fields (which will overwrite existing meta with empty
values), and that third-party filters (wpuf_wpjm_meta_mapping) must supply the
form field "name" as the array key ($field_name) not the meta key ($meta_key).

In `@includes/Integrations/WP_Job_Manager/Template_Free.php`:
- Line 22: The $this->enabled assignment in Template_Free is redundant because
Free_Loader::post_form_templates() only registers this template when
class_exists('WP_Job_Manager') is true; update Template_Free to set
$this->enabled = true unconditionally (or remove the assignment entirely) to
remove the needless class_exists check—modify the Template_Free class's
constructor/property initialization (the $this->enabled line) accordingly and
leave Free_Loader::post_form_templates() untouched.

In `@includes/Integrations/WP_Job_Manager/WPUF_WP_Job_Manager_Integration.php`:
- Around line 35-73: The init_handlers method contains a redundant runtime check
using is_wpjm_active()/class_exists('WP_Job_Manager') because
Integrations::__construct() already only instantiates
WPUF_WP_Job_Manager_Integration when WP_Job_Manager exists; collapse the
duplicate guard by removing the early return block in init_handlers (the if (!
$this->is_wpjm_active()) return;) or, if you prefer to keep it as defensive
code, add a clarifying comment above is_wpjm_active() and the guard referencing
Integrations::__construct() and explaining it's only for direct instantiation
paths (tests/CLI) so reviewers understand the intent; update code around
init_handlers and is_wpjm_active accordingly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c0a288e8-5532-4677-8a5f-fc91c5cc2379

📥 Commits

Reviewing files that changed from the base of the PR and between 9cf91fb and 08da246.

📒 Files selected for processing (6)
  • includes/Free/Free_Loader.php
  • includes/Integrations.php
  • includes/Integrations/WP_Job_Manager/Meta_Mapper.php
  • includes/Integrations/WP_Job_Manager/Template_Free.php
  • includes/Integrations/WP_Job_Manager/WPUF_WP_Job_Manager_Integration.php
  • wpuf-functions.php

Comment on lines +216 to +235
private function sanitize_for_meta( $value, $meta_key ) {
if ( ! class_exists( WP_Job_Manager_Post_Types::class ) ) {
return is_array( $value ) ? array_map( 'sanitize_text_field', $value ) : sanitize_text_field( $value );
}

switch ( $meta_key ) {
case '_company_website':
case '_company_video':
return WP_Job_Manager_Post_Types::sanitize_meta_field_url( $value );

case '_application':
return WP_Job_Manager_Post_Types::sanitize_meta_field_application( $value );

case '_remote_position':
return (int) (bool) $value;

default:
return WP_Job_Manager_Post_Types::sanitize_meta_field_based_on_input_type( $value, $meta_key );
}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

In the current WP Job Manager plugin source, what is the visibility (public/private/protected) of WP_Job_Manager_Post_Types::sanitize_meta_field_url, sanitize_meta_field_application, and sanitize_meta_field_based_on_input_type, and in which version did they become public?

💡 Result:

The methods WP_Job_Manager_Post_Types::sanitize_meta_field_url, ::sanitize_meta_field_application, and ::sanitize_meta_field_based_on_input_type do not appear to exist in the current WP Job Manager plugin source code (version 2.4.1 as of 2026-02-24, trunk branch last updated 2026-04-01). Extensive searches of the GitHub repository (https://github.com/Automattic/WP-Job-Manager), changelogs, and related files (including class-wp-job-manager-writepanels.php, class-wp-job-manager-cpt.php, wp-job-manager-functions.php) show references to WP_Job_Manager_Post_Types::get_job_listing_fields which returns field configurations used for sanitization callbacks, but no explicit methods matching these names or changes to their visibility (public/private/protected). The class WP_Job_Manager_Post_Types is referenced throughout the codebase for post types, taxonomies, capabilities, and expiration handling, but the specific sanitize methods are not found in available source snippets or changelogs. They may be private/internal callbacks not publicly documented, non-existent, or in an unindexed file. No version where they "became public" is mentioned in changelogs.

Citations:


🏁 Script executed:

# Check for WPJM version requirements
fd -e 'composer.json' -e 'composer.lock' -e 'readme.txt' -e 'readme.md' | head -20

Repository: weDevsOfficial/wp-user-frontend

Length of output: 57


🏁 Script executed:

# Search for any WPJM version requirements or constants
rg -i "wp.job.manager|wpjm|job.manager" --max-count=20 -t php -t json -t md -t txt

Repository: weDevsOfficial/wp-user-frontend

Length of output: 5967


🏁 Script executed:

# Check the target file modification date and context
git log --oneline -n 10 -- 'includes/Integrations/WP_Job_Manager/Meta_Mapper.php' 2>/dev/null || echo "Git history not available"

Repository: weDevsOfficial/wp-user-frontend

Length of output: 116


🏁 Script executed:

# Search for any references to the sanitizer methods anywhere in the codebase
rg "sanitize_meta_field_(url|application|based_on_input_type)" --max-count=20

Repository: weDevsOfficial/wp-user-frontend

Length of output: 523


🏁 Script executed:

cat -n 'includes/Integrations/WP_Job_Manager/Meta_Mapper.php' | head -100

Repository: weDevsOfficial/wp-user-frontend

Length of output: 3733


🏁 Script executed:

# Check the integration bootstrap file for version requirements
cat -n 'includes/Integrations/WP_Job_Manager/WPUF_WP_Job_Manager_Integration.php'

Repository: weDevsOfficial/wp-user-frontend

Length of output: 2274


🏁 Script executed:

# Search for any WPJM version constants or requirements in the codebase
rg -i "wp.*job.*manager.*version|WPJM.*version|wpjm.*minimum" -t php

Repository: weDevsOfficial/wp-user-frontend

Length of output: 57


Wrap direct WPJM method calls in is_callable() checks with appropriate fallbacks.

The methods WP_Job_Manager_Post_Types::sanitize_meta_field_url(), sanitize_meta_field_application(), and sanitize_meta_field_based_on_input_type() do not exist in the current WP Job Manager plugin source and will cause fatal errors when form submissions reach the sanitization step.

Implement the defensive fallback pattern to gracefully handle missing WPJM methods:

Suggested fix
     private function sanitize_for_meta( $value, $meta_key ) {
-        if ( ! class_exists( WP_Job_Manager_Post_Types::class ) ) {
+        if ( ! class_exists( WP_Job_Manager_Post_Types::class ) ) {
             return is_array( $value ) ? array_map( 'sanitize_text_field', $value ) : sanitize_text_field( $value );
         }

         switch ( $meta_key ) {
             case '_company_website':
             case '_company_video':
-                return WP_Job_Manager_Post_Types::sanitize_meta_field_url( $value );
+                return is_callable( [ WP_Job_Manager_Post_Types::class, 'sanitize_meta_field_url' ] )
+                    ? WP_Job_Manager_Post_Types::sanitize_meta_field_url( $value )
+                    : esc_url_raw( is_array( $value ) ? '' : $value );

             case '_application':
-                return WP_Job_Manager_Post_Types::sanitize_meta_field_application( $value );
+                return is_callable( [ WP_Job_Manager_Post_Types::class, 'sanitize_meta_field_application' ] )
+                    ? WP_Job_Manager_Post_Types::sanitize_meta_field_application( $value )
+                    : sanitize_text_field( is_array( $value ) ? '' : $value );

             case '_remote_position':
                 return (int) (bool) $value;

             default:
-                return WP_Job_Manager_Post_Types::sanitize_meta_field_based_on_input_type( $value, $meta_key );
+                return is_callable( [ WP_Job_Manager_Post_Types::class, 'sanitize_meta_field_based_on_input_type' ] )
+                    ? WP_Job_Manager_Post_Types::sanitize_meta_field_based_on_input_type( $value, $meta_key )
+                    : ( is_array( $value ) ? array_map( 'sanitize_text_field', $value ) : sanitize_text_field( $value ) );
         }
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@includes/Integrations/WP_Job_Manager/Meta_Mapper.php` around lines 216 - 235,
The sanitize_for_meta function currently calls
WP_Job_Manager_Post_Types::sanitize_meta_field_url,
::sanitize_meta_field_application, and ::sanitize_meta_field_based_on_input_type
directly which can cause fatal errors if those static methods are missing;
update sanitize_for_meta to wrap each WP_Job_Manager_Post_Types::method call in
is_callable checks (e.g., is_callable([WP_Job_Manager_Post_Types::class,
'sanitize_meta_field_url'])) and if the method is not callable fall back to safe
defaults: for URL/video use sanitize_text_field (or
wp_sanitize_redirect/esc_url_raw if available), for application use
sanitize_text_field or handle arrays with array_map('sanitize_text_field'), and
for the default case fall back to returning sanitized string/array via
sanitize_text_field/array_map — keep the existing _remote_position cast
unchanged and reference sanitize_for_meta and the three
WP_Job_Manager_Post_Types method names when making the changes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant