Architecture & Compatibility
Q: What’s the purpose of the new compatibility layer?
A: The compatibility layer (v2.9.0) provides:
- Middleware between Reign theme and WP Job Manager plugins
- Custom hooks that won’t break when plugins update
- Centralized integration point for all three WP Job Manager plugins
- Future-proof architecture for adding new features
Q: How does the plugin maintain backward compatibility?
A: We ensure backward compatibility by:
- Never removing existing hooks/functions
- Adding new features through filters
- Using deprecation notices before removing features
- Maintaining original function signatures
- Testing with multiple WP/plugin versions
Q: What’s the hook execution order?
A: Hook priority order:
// Priority 5-9: Early modifications
// Priority 10: Default (most hooks)
// Priority 20-50: Late modifications
// Priority 99-999: Cleanup and final modifications
Hooks & Filters
Q: Should I use WP Job Manager hooks or Reign hooks?
A: Best practice:
- Use Reign hooks (
reign_wpjm_*) for Reign-specific customizations - Use WP Job Manager hooks for plugin-agnostic features
- Reign hooks provide additional data and won’t break with updates
Example:
// Preferred: Use Reign hook
add_filter( 'reign_wpjm_job_query_args', 'my_custom_query', 10, 2 );
// Alternative: Direct WP Job Manager hook
add_filter( 'get_job_listings_query_args', 'my_custom_query', 10, 2 );
Q: How do I add custom job fields?
A: Multiple approaches:
// Method 1: Via form fields filter
add_filter( 'submit_job_form_fields', function( $fields ) {
$fields['job']['custom_field'] = array(
'label' => 'Custom Field',
'type' => 'text',
'required' => false,
'priority' => 30
);
return $fields;
} );
// Method 2: Via Reign compatibility hook
add_filter( 'reign_wpjm_job_fields', function( $fields ) {
// Add custom field
return $fields;
} );
// Save the field
add_action( 'job_manager_update_job_data', function( $job_id, $values ) {
if ( isset( $values['job']['custom_field'] ) ) {
update_post_meta( $job_id, '_custom_field', sanitize_text_field( $values['job']['custom_field'] ) );
}
}, 10, 2 );
Q: How do I modify job queries?
A: Use the query filter:
add_filter( 'reign_wpjm_job_query_args', function( $query_args, $args ) {
// Only show jobs from last 30 days
$query_args['date_query'] = array(
array(
'after' => '30 days ago'
)
);
// Exclude filled positions
$query_args['meta_query'][] = array(
'key' => '_filled',
'value' => '1',
'compare' => '!='
);
return $query_args;
}, 10, 2 );
Templates
Q: How do I override templates?
A: Template hierarchy:
1. /yourtheme/job_manager/template-name.php (highest priority)
2. /yourtheme/template-name.php
3. /reign-wp-job-manager-addon/templates/job_manager/template-name.php
4. /wp-job-manager/templates/template-name.php (lowest priority)
Example override:
// Copy from:
// /plugins/reign-wp-job-manager-addon/templates/job_manager/content-single-job_listing.php
// To:
// /themes/your-theme/job_manager/content-single-job_listing.php
Q: How do I create a custom layout?
A: Create new layout template:
// 1. Create template file
// /yourtheme/job_manager/content-job_listing_custom.php
// 2. Register the layout
add_filter( 'reign_job_layouts', function( $layouts ) {
$layouts['custom'] = __( 'Custom Layout', 'text-domain' );
return $layouts;
} );
// 3. Load the template
add_filter( 'reign_job_layout_template', function( $template, $layout ) {
if ( 'custom' === $layout ) {
$template = 'content-job_listing_custom.php';
}
return $template;
}, 10, 2 );
Q: How do I add content to specific template positions?
A: Use template hooks:
// Add content before job meta
add_action( 'job_listing_meta_start', function() {
echo '<div class="featured-badge">Featured</div>';
} );
// Add content after single job
add_action( 'single_job_listing_end', function() {
get_template_part( 'parts/related', 'jobs' );
} );
// Add to resume sidebar
add_action( 'single_resume_sidebar', function() {
echo '<div class="contact-form">Contact Form Here</div>';
}, 25 ); // Priority 25 to position it correctly
Custom Post Types & Taxonomies
Q: How do I add custom taxonomies?
A: Register and integrate:
// 1. Register taxonomy
add_action( 'init', function() {
register_taxonomy( 'job_department', array( 'job_listing' ), array(
'labels' => array(
'name' => 'Departments',
'singular_name' => 'Department'
),
'public' => true,
'hierarchical' => true
) );
} );
// 2. Add to submission form
add_filter( 'submit_job_form_fields', function( $fields ) {
$fields['job']['job_department'] = array(
'label' => 'Department',
'type' => 'term-multiselect',
'taxonomy' => 'job_department',
'required' => false,
'priority' => 35
);
return $fields;
} );
Q: How do I modify post type arguments?
A: Use the registration filter:
add_filter( 'register_post_type_job_listing', function( $args ) {
// Add excerpt support
$args['supports'][] = 'excerpt';
// Change slug
$args['rewrite']['slug'] = 'careers';
return $args;
} );
Database & Performance
Q: How do I optimize job queries?
A: Performance tips:
// 1. Use transients for expensive queries
function get_featured_jobs( $limit = 5 ) {
$cache_key = 'featured_jobs_' . $limit;
$jobs = get_transient( $cache_key );
if ( false === $jobs ) {
$jobs = get_posts( array(
'post_type' => 'job_listing',
'meta_key' => '_featured',
'meta_value' => '1',
'posts_per_page' => $limit,
'fields' => 'ids' // Only get IDs for better performance
) );
set_transient( $cache_key, $jobs, HOUR_IN_SECONDS );
}
return $jobs;
}
// 2. Add database indexes
function add_custom_indexes() {
global $wpdb;
$wpdb->query( "ALTER TABLE {$wpdb->postmeta} ADD INDEX reign_job_featured (_featured)" );
}
// 3. Use specific queries
$job_count = $wpdb->get_var( "
SELECT COUNT(*)
FROM {$wpdb->posts}
WHERE post_type = 'job_listing'
AND post_status = 'publish'
" );
Q: How do I handle large datasets?
A: Pagination and lazy loading:
// AJAX pagination
add_action( 'wp_ajax_load_more_jobs', 'handle_load_more_jobs' );
add_action( 'wp_ajax_nopriv_load_more_jobs', 'handle_load_more_jobs' );
function handle_load_more_jobs() {
$page = intval( $_POST['page'] );
$per_page = 10;
$jobs = get_posts( array(
'post_type' => 'job_listing',
'posts_per_page' => $per_page,
'paged' => $page,
'post_status' => 'publish'
) );
ob_start();
foreach ( $jobs as $job ) {
reign_job_mate_get_template( 'content-job_listing.php', array( 'post' => $job ) );
}
$html = ob_get_clean();
wp_send_json_success( array( 'html' => $html ) );
}
AJAX & REST API
Q: How do I create custom AJAX endpoints?
A: Register AJAX handlers:
// Register AJAX action
add_action( 'wp_ajax_reign_custom_action', 'handle_custom_action' );
add_action( 'wp_ajax_nopriv_reign_custom_action', 'handle_custom_action' );
function handle_custom_action() {
// Verify nonce
if ( ! wp_verify_nonce( $_POST['nonce'], 'reign_ajax_nonce' ) ) {
wp_die( 'Security check failed' );
}
// Process request
$data = array(
'success' => true,
'message' => 'Action completed'
);
wp_send_json( $data );
}
// JavaScript
jQuery.ajax({
url: reign_ajax.ajax_url,
type: 'POST',
data: {
action: 'reign_custom_action',
nonce: reign_ajax.nonce
},
success: function( response ) {
console.log( response );
}
});
Q: How do I add REST API endpoints?
A: Register custom routes:
add_action( 'rest_api_init', function() {
register_rest_route( 'reign/v1', '/jobs/featured', array(
'methods' => 'GET',
'callback' => 'get_featured_jobs_api',
'permission_callback' => '__return_true'
) );
} );
function get_featured_jobs_api( WP_REST_Request $request ) {
$jobs = get_posts( array(
'post_type' => 'job_listing',
'meta_key' => '_featured',
'meta_value' => '1',
'posts_per_page' => 10
) );
return rest_ensure_response( $jobs );
}
Security
Q: How do I properly sanitize user input?
A: Use appropriate sanitization:
// Text fields
$text = sanitize_text_field( $_POST['text_field'] );
// Email
$email = sanitize_email( $_POST['email'] );
// URL
$url = esc_url_raw( $_POST['url'] );
// HTML content
$html = wp_kses_post( $_POST['description'] );
// Numbers
$number = intval( $_POST['number'] );
$float = floatval( $_POST['price'] );
// File uploads
if ( ! function_exists( 'wp_handle_upload' ) ) {
require_once( ABSPATH . 'wp-admin/includes/file.php' );
}
$uploaded_file = wp_handle_upload( $_FILES['file'], array( 'test_form' => false ) );
Q: How do I implement proper capability checks?
A: Check user permissions:
// Check capabilities
if ( ! current_user_can( 'edit_job_listings' ) ) {
wp_die( 'Insufficient permissions' );
}
// Custom capability
add_filter( 'user_has_cap', function( $allcaps, $caps, $args ) {
if ( isset( $caps[0] ) && 'manage_job_applications' === $caps[0] ) {
if ( user_can( $args[1], 'edit_others_job_listings' ) ) {
$allcaps['manage_job_applications'] = true;
}
}
return $allcaps;
}, 10, 3 );
Customization
Q: How do I add custom CSS/JS to specific pages?
A: Conditional enqueuing:
add_action( 'wp_enqueue_scripts', function() {
// Only on job pages
if ( is_singular( 'job_listing' ) ) {
wp_enqueue_style(
'reign-job-custom',
get_stylesheet_directory_uri() . '/assets/css/job-custom.css'
);
wp_enqueue_script(
'reign-job-custom',
get_stylesheet_directory_uri() . '/assets/js/job-custom.js',
array( 'jquery' ),
'1.0.0',
true
);
// Localize script
wp_localize_script( 'reign-job-custom', 'reign_job_vars', array(
'ajax_url' => admin_url( 'admin-ajax.php' ),
'job_id' => get_the_ID(),
'nonce' => wp_create_nonce( 'reign_job_nonce' )
) );
}
} );
Q: How do I create a child theme compatible with the addon?
A: Child theme structure:
// child-theme/functions.php
add_action( 'after_setup_theme', function() {
// Load parent and child styles
add_action( 'wp_enqueue_scripts', function() {
wp_enqueue_style( 'parent-style', get_template_directory_uri() . '/style.css' );
wp_enqueue_style( 'child-style', get_stylesheet_uri(), array( 'parent-style' ) );
} );
} );
// Override templates by placing them in:
// child-theme/job_manager/template-name.php
// child-theme/wp-job-manager-resumes/template-name.php
Debugging & Testing
Q: How do I debug hook execution?
A: Debug helpers:
// Log hook execution
add_action( 'all', function( $hook ) {
if ( strpos( $hook, 'reign' ) !== false || strpos( $hook, 'job' ) !== false ) {
error_log( "Hook fired: " . $hook );
}
} );
// Check if hook exists
if ( has_action( 'reign_wpjm_job_submitted' ) ) {
error_log( 'Hook has callbacks attached' );
}
// List all callbacks for a hook
global $wp_filter;
if ( isset( $wp_filter['reign_wpjm_job_submitted'] ) ) {
var_dump( $wp_filter['reign_wpjm_job_submitted'] );
}
Q: How do I test compatibility with different plugin versions?
A: Version checking:
// Check plugin versions
if ( defined( 'JOB_MANAGER_VERSION' ) ) {
if ( version_compare( JOB_MANAGER_VERSION, '2.0.0', '<' ) ) {
// Use legacy code
} else {
// Use modern code
}
}
// Feature detection
if ( function_exists( 'wpjm_get_the_job_types' ) ) {
// Function exists, safe to use
}
// Class detection
if ( class_exists( 'WP_Job_Manager_Applications' ) ) {
// Applications plugin is active
}
Migration & Updates
Q: How do I migrate from direct WP Job Manager integration?
A: Migration steps:
// Old way (direct)
add_action( 'job_listing_meta_start', 'my_function' );
// New way (compatibility layer)
add_action( 'reign_wpjm_job_listing_meta_start', 'my_function' );
// Migration helper
function migrate_to_reign_hooks() {
// Remove old hook
remove_action( 'job_listing_meta_start', 'old_function' );
// Add new hook
add_action( 'reign_wpjm_job_listing_meta_start', 'new_function' );
}
add_action( 'init', 'migrate_to_reign_hooks', 999 );
Q: How do I handle database updates?
A: Version-based updates:
function reign_job_manager_update_check() {
$current_version = get_option( 'reign_job_manager_version', '1.0.0' );
if ( version_compare( $current_version, '2.9.0', '<' ) ) {
// Run 2.9.0 updates
reign_job_manager_update_290();
update_option( 'reign_job_manager_version', '2.9.0' );
}
}
function reign_job_manager_update_290() {
// Update database schema
// Migrate settings
// Clear caches
}
Common Issues & Solutions
Q: Templates not overriding properly?
A: Troubleshooting steps:
- Check template path is correct
- Clear all caches
- Check template hierarchy
- Verify filter priority
- Use template debug mode
// Debug template loading
add_filter( 'reign_job_manager_locate_template', function( $template, $template_name ) {
error_log( "Loading template: {$template_name} from {$template}" );
return $template;
}, 10, 2 );
Q: Hooks not firing?
A: Check:
- Hook name is correct
- Priority conflicts
- Conditional loading
- Plugin load order
// Force early loading
add_action( 'plugins_loaded', function() {
// Your hooks here
}, 5 ); // Priority 5 = very early
Q: Performance issues with many jobs?
A: Optimization strategies:
- Use pagination
- Implement caching
- Optimize queries
- Use AJAX loading
- Add database indexes
Best Practices
Do’s
- Use Reign compatibility hooks when available
- Sanitize all user input
- Use nonces for forms
- Cache expensive operations
- Follow WordPress coding standards
- Test with multiple plugin versions
- Use child themes for customization
Don’ts
- Don’t modify plugin files directly
- Don’t use deprecated functions
- Don’t bypass security checks
- Don’t load resources globally
- Don’t hardcode paths
- Don’t ignore error messages
- Don’t skip validation
Resources
Tools
- Query Monitor plugin for debugging
- Theme Check plugin for validation
- Debug Bar for development
- Postman for API testing
Code Examples
// Complete example: Custom job widget
class Reign_Featured_Jobs_Widget extends WP_Widget {
public function __construct() {
parent::__construct(
'reign_featured_jobs',
'Featured Jobs',
array( 'description' => 'Display featured job listings' )
);
}
public function widget( $args, $instance ) {
$jobs = get_posts( array(
'post_type' => 'job_listing',
'meta_key' => '_featured',
'meta_value' => '1',
'posts_per_page' => 5
) );
echo $args['before_widget'];
echo $args['before_title'] . $instance['title'] . $args['after_title'];
echo '<ul>';
foreach ( $jobs as $job ) {
printf(
'<li><a href="%s">%s</a></li>',
get_permalink( $job ),
get_the_title( $job )
);
}
echo '</ul>';
echo $args['after_widget'];
}
}
add_action( 'widgets_init', function() {
register_widget( 'Reign_Featured_Jobs_Widget' );
} );
