Nexus Pro provides Person, Product, and Place entity templates with essential schema fields out of the box. However, many projects require additional custom fields—industry-specific data, extra properties, or specialized metadata. Extending Nexus Pro through hooks and filters allows adding custom fields while maintaining plugin compatibility and update safety.

This developer guide shows you how to extend Nexus Pro’s entity templates, add custom meta fields, integrate with schema output, and create admin interfaces for your custom data.
Understanding Nexus Pro Architecture
Foundation for safe extensions.
Entity Template Structure
Three Custom Post Types:
1. Person (nexus_person):
- Name, job title, bio
- Social profiles
- Contact information
- Person schema markup
2. Product (nexus_product):
- Product name, description
- Price, availability
- Images, SKU
- Product schema markup
3. Place (nexus_place):
- Business name, type
- Address, coordinates
- Hours, contact
- LocalBusiness schema markup
Hook System
Nexus Pro provides hooks for:
- Adding meta fields to admin
- Saving custom meta data
- Filtering schema output
- Modifying entity queries
- Extending admin interfaces
Hook Naming Convention:
nexus_pro_{entity}_{action}
Examples:
nexus_pro_person_meta_fieldsnexus_pro_product_schemanexus_pro_place_save_meta
Adding Custom Fields to Person Entity
Extend Person template with additional fields.
Register Custom Meta Fields
Add Fields to Admin:
/**
* Add custom fields to Person entity edit screen.
*/
function add_custom_person_fields($post) {
// Get current values
$linkedin = get_post_meta($post->ID, 'linkedin_url', true);
$github = get_post_meta($post->ID, 'github_url', true);
$expertise = get_post_meta($post->ID, 'expertise_areas', true);
?>
<div class="nexus-pro-custom-fields">
<h3>Additional Professional Information</h3>
<p>
<label for="linkedin_url">LinkedIn Profile:</label><br>
<input type="url" id="linkedin_url" name="linkedin_url"
value="<?php echo esc_attr($linkedin); ?>"
class="widefat" placeholder="https://linkedin.com/in/username">
</p>
<p>
<label for="github_url">GitHub Profile:</label><br>
<input type="url" id="github_url" name="github_url"
value="<?php echo esc_attr($github); ?>"
class="widefat" placeholder="https://github.com/username">
</p>
<p>
<label for="expertise_areas">Expertise Areas (comma-separated):</label><br>
<input type="text" id="expertise_areas" name="expertise_areas"
value="<?php echo esc_attr($expertise); ?>"
class="widefat" placeholder="WordPress, PHP, JavaScript">
</p>
</div>
<?php
}
add_action('nexus_pro_person_meta_fields', 'add_custom_person_fields');
Save Custom Meta Data
Hook Into Save Process:
/**
* Save custom Person meta fields.
*/
function save_custom_person_meta($post_id) {
// Security checks
if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
return;
}
if (!current_user_can('edit_post', $post_id)) {
return;
}
// Verify post type
if (get_post_type($post_id) !== 'nexus_person') {
return;
}
// Save LinkedIn URL
if (isset($_POST['linkedin_url'])) {
update_post_meta(
$post_id,
'linkedin_url',
esc_url_raw($_POST['linkedin_url'])
);
}
// Save GitHub URL
if (isset($_POST['github_url'])) {
update_post_meta(
$post_id,
'github_url',
esc_url_raw($_POST['github_url'])
);
}
// Save expertise areas
if (isset($_POST['expertise_areas'])) {
$expertise = sanitize_text_field($_POST['expertise_areas']);
update_post_meta($post_id, 'expertise_areas', $expertise);
}
}
add_action('save_post_nexus_person', 'save_custom_person_meta');
Add to Person Schema
Extend Schema Output:
/**
* Add custom fields to Person schema.
*/
function extend_person_schema($schema, $post_id) {
// Add LinkedIn to sameAs
$linkedin = get_post_meta($post_id, 'linkedin_url', true);
if ($linkedin) {
if (!isset($schema['sameAs'])) {
$schema['sameAs'] = [];
}
$schema['sameAs'][] = $linkedin;
}
// Add GitHub to sameAs
$github = get_post_meta($post_id, 'github_url', true);
if ($github) {
if (!isset($schema['sameAs'])) {
$schema['sameAs'] = [];
}
$schema['sameAs'][] = $github;
}
// Add expertise as knowsAbout
$expertise = get_post_meta($post_id, 'expertise_areas', true);
if ($expertise) {
$areas = array_map('trim', explode(',', $expertise));
$schema['knowsAbout'] = $areas;
}
return $schema;
}
add_filter('nexus_pro_person_schema', 'extend_person_schema', 10, 2);
Adding Custom Fields to Product Entity
Extend Product template.
Product Meta Fields
Additional Product Data:
/**
* Add custom fields to Product entity.
*/
function add_custom_product_fields($post) {
$dimensions = get_post_meta($post->ID, 'product_dimensions', true);
$weight = get_post_meta($post->ID, 'product_weight', true);
$material = get_post_meta($post->ID, 'product_material', true);
$warranty = get_post_meta($post->ID, 'warranty_period', true);
?>
<div class="nexus-pro-product-specs">
<h3>Product Specifications</h3>
<p>
<label for="product_dimensions">Dimensions (L x W x H in cm):</label><br>
<input type="text" id="product_dimensions" name="product_dimensions"
value="<?php echo esc_attr($dimensions); ?>"
placeholder="30 x 20 x 15">
</p>
<p>
<label for="product_weight">Weight (kg):</label><br>
<input type="number" id="product_weight" name="product_weight"
value="<?php echo esc_attr($weight); ?>"
step="0.01" min="0">
</p>
<p>
<label for="product_material">Material:</label><br>
<input type="text" id="product_material" name="product_material"
value="<?php echo esc_attr($material); ?>"
placeholder="Stainless Steel">
</p>
<p>
<label for="warranty_period">Warranty Period (months):</label><br>
<input type="number" id="warranty_period" name="warranty_period"
value="<?php echo esc_attr($warranty); ?>"
min="0">
</p>
</div>
<?php
}
add_action('nexus_pro_product_meta_fields', 'add_custom_product_fields');
Save Product Meta
/**
* Save custom Product meta fields.
*/
function save_custom_product_meta($post_id) {
if (get_post_type($post_id) !== 'nexus_product') {
return;
}
$fields = [
'product_dimensions' => 'sanitize_text_field',
'product_weight' => 'floatval',
'product_material' => 'sanitize_text_field',
'warranty_period' => 'absint'
];
foreach ($fields as $field => $sanitize_callback) {
if (isset($_POST[$field])) {
$value = call_user_func($sanitize_callback, $_POST[$field]);
update_post_meta($post_id, $field, $value);
}
}
}
add_action('save_post_nexus_product', 'save_custom_product_meta');
Extend Product Schema
/**
* Add specifications to Product schema.
*/
function extend_product_schema($schema, $post_id) {
// Add dimensions
$dimensions = get_post_meta($post_id, 'product_dimensions', true);
if ($dimensions) {
$schema['depth'] = [
'@type' => 'QuantitativeValue',
'value' => $dimensions
];
}
// Add weight
$weight = get_post_meta($post_id, 'product_weight', true);
if ($weight) {
$schema['weight'] = [
'@type' => 'QuantitativeValue',
'value' => $weight,
'unitCode' => 'KGM' // Kilograms
];
}
// Add material
$material = get_post_meta($post_id, 'product_material', true);
if ($material) {
$schema['material'] = $material;
}
// Add warranty
$warranty = get_post_meta($post_id, 'warranty_period', true);
if ($warranty) {
$schema['warranty'] = [
'@type' => 'WarrantyPromise',
'durationOfWarranty' => [
'@type' => 'QuantitativeValue',
'value' => $warranty,
'unitCode' => 'MON' // Months
]
];
}
return $schema;
}
add_filter('nexus_pro_product_schema', 'extend_product_schema', 10, 2);
Adding Custom Fields to Place Entity
Extend LocalBusiness template.
Place Meta Fields
Business-Specific Data:
/**
* Add custom fields to Place entity.
*/
function add_custom_place_fields($post) {
$parking = get_post_meta($post->ID, 'parking_available', true);
$accessibility = get_post_meta($post->ID, 'wheelchair_accessible', true);
$payment_methods = get_post_meta($post->ID, 'payment_methods', true);
$languages = get_post_meta($post->ID, 'languages_spoken', true);
?>
<div class="nexus-pro-place-amenities">
<h3>Business Amenities</h3>
<p>
<label>
<input type="checkbox" name="parking_available" value="1"
<?php checked($parking, '1'); ?>>
Parking Available
</label>
</p>
<p>
<label>
<input type="checkbox" name="wheelchair_accessible" value="1"
<?php checked($accessibility, '1'); ?>>
Wheelchair Accessible
</label>
</p>
<p>
<label>Payment Methods Accepted:</label><br>
<select name="payment_methods[]" multiple size="5" class="widefat">
<?php
$methods = ['Cash', 'Credit Card', 'Debit Card', 'PayPal', 'Apple Pay', 'Google Pay'];
$selected = is_array($payment_methods) ? $payment_methods : [];
foreach ($methods as $method) {
$is_selected = in_array($method, $selected) ? 'selected' : '';
echo "<option value='" . esc_attr($method) . "' $is_selected>$method</option>";
}
?>
</select>
<small>Hold Ctrl/Cmd to select multiple</small>
</p>
<p>
<label>Languages Spoken:</label><br>
<input type="text" name="languages_spoken"
value="<?php echo esc_attr($languages); ?>"
class="widefat" placeholder="English, Spanish, French">
</p>
</div>
<?php
}
add_action('nexus_pro_place_meta_fields', 'add_custom_place_fields');
Save Place Meta
/**
* Save custom Place meta fields.
*/
function save_custom_place_meta($post_id) {
if (get_post_type($post_id) !== 'nexus_place') {
return;
}
// Save checkboxes
update_post_meta($post_id, 'parking_available',
isset($_POST['parking_available']) ? '1' : '0');
update_post_meta($post_id, 'wheelchair_accessible',
isset($_POST['wheelchair_accessible']) ? '1' : '0');
// Save payment methods array
if (isset($_POST['payment_methods'])) {
$methods = array_map('sanitize_text_field', $_POST['payment_methods']);
update_post_meta($post_id, 'payment_methods', $methods);
} else {
delete_post_meta($post_id, 'payment_methods');
}
// Save languages
if (isset($_POST['languages_spoken'])) {
update_post_meta($post_id, 'languages_spoken',
sanitize_text_field($_POST['languages_spoken']));
}
}
add_action('save_post_nexus_place', 'save_custom_place_meta');
Extend LocalBusiness Schema
/**
* Add amenities to LocalBusiness schema.
*/
function extend_place_schema($schema, $post_id) {
// Add parking
$parking = get_post_meta($post_id, 'parking_available', true);
if ($parking === '1') {
$schema['amenityFeature'][] = [
'@type' => 'LocationFeatureSpecification',
'name' => 'Parking',
'value' => true
];
}
// Add accessibility
$accessibility = get_post_meta($post_id, 'wheelchair_accessible', true);
if ($accessibility === '1') {
$schema['amenityFeature'][] = [
'@type' => 'LocationFeatureSpecification',
'name' => 'Wheelchair Accessible',
'value' => true
];
}
// Add payment methods
$payment_methods = get_post_meta($post_id, 'payment_methods', true);
if (is_array($payment_methods) && !empty($payment_methods)) {
$schema['paymentAccepted'] = implode(', ', $payment_methods);
}
// Add languages
$languages = get_post_meta($post_id, 'languages_spoken', true);
if ($languages) {
$lang_array = array_map('trim', explode(',', $languages));
$schema['availableLanguage'] = $lang_array;
}
return $schema;
}
add_filter('nexus_pro_place_schema', 'extend_place_schema', 10, 2);
Creating Custom Meta Boxes
Professional admin interfaces.
Meta Box with Tabs
Organized Field Groups:
/**
* Register tabbed meta box.
*/
function register_tabbed_meta_box() {
add_meta_box(
'nexus_pro_extended_meta',
'Extended Information',
'render_tabbed_meta_box',
['nexus_person', 'nexus_product', 'nexus_place'],
'normal',
'high'
);
}
add_action('add_meta_boxes', 'register_tabbed_meta_box');
/**
* Render tabbed interface.
*/
function render_tabbed_meta_box($post) {
wp_nonce_field('save_extended_meta', 'extended_meta_nonce');
?>
<div class="nexus-pro-tabs">
<ul class="tab-nav">
<li><a href="#tab-basic" class="active">Basic Info</a></li>
<li><a href="#tab-advanced">Advanced</a></li>
<li><a href="#tab-schema">Schema Data</a></li>
</ul>
<div id="tab-basic" class="tab-content active">
<?php render_basic_fields($post); ?>
</div>
<div id="tab-advanced" class="tab-content">
<?php render_advanced_fields($post); ?>
</div>
<div id="tab-schema" class="tab-content">
<?php render_schema_fields($post); ?>
</div>
</div>
<style>
.tab-nav { list-style: none; margin: 0; padding: 0; border-bottom: 1px solid #ccc; }
.tab-nav li { display: inline-block; margin: 0; }
.tab-nav a { display: block; padding: 10px 15px; text-decoration: none; border: 1px solid #ccc; border-bottom: none; background: #f1f1f1; }
.tab-nav a.active { background: #fff; }
.tab-content { display: none; padding: 20px; border: 1px solid #ccc; border-top: none; }
.tab-content.active { display: block; }
</style>
<script>
jQuery(document).ready(function($) {
$('.tab-nav a').click(function(e) {
e.preventDefault();
$('.tab-nav a, .tab-content').removeClass('active');
$(this).addClass('active');
$($(this).attr('href')).addClass('active');
});
});
</script>
<?php
}
Repeatable Fields
Dynamic Field Groups:
/**
* Render repeatable fields (e.g., certifications).
*/
function render_repeatable_certifications($post) {
$certifications = get_post_meta($post->ID, 'certifications', true);
if (!is_array($certifications)) {
$certifications = [];
}
?>
<div id="certifications-container">
<h4>Certifications</h4>
<div class="certifications-list">
<?php
if (empty($certifications)) {
$certifications = [['name' => '', 'issuer' => '', 'date' => '']];
}
foreach ($certifications as $index => $cert) {
?>
<div class="certification-item" data-index="<?php echo $index; ?>">
<input type="text" name="certifications[<?php echo $index; ?>][name]"
value="<?php echo esc_attr($cert['name'] ?? ''); ?>"
placeholder="Certification Name">
<input type="text" name="certifications[<?php echo $index; ?>][issuer]"
value="<?php echo esc_attr($cert['issuer'] ?? ''); ?>"
placeholder="Issuing Organization">
<input type="date" name="certifications[<?php echo $index; ?>][date]"
value="<?php echo esc_attr($cert['date'] ?? ''); ?>">
<button type="button" class="remove-certification">Remove</button>
</div>
<?php
}
?>
</div>
<button type="button" id="add-certification">Add Certification</button>
</div>
<script>
jQuery(document).ready(function($) {
var certIndex = <?php echo count($certifications); ?>;
$('#add-certification').click(function() {
var html = '<div class="certification-item" data-index="' + certIndex + '">' +
'<input type="text" name="certifications[' + certIndex + '][name]" placeholder="Certification Name">' +
'<input type="text" name="certifications[' + certIndex + '][issuer]" placeholder="Issuing Organization">' +
'<input type="date" name="certifications[' + certIndex + '][date]">' +
'<button type="button" class="remove-certification">Remove</button>' +
'</div>';
$('.certifications-list').append(html);
certIndex++;
});
$(document).on('click', '.remove-certification', function() {
$(this).closest('.certification-item').remove();
});
});
</script>
<?php
}
Best Practices
Professional extension guidelines.
Use Proper Hook Priorities
// Default priority (10)
add_filter('nexus_pro_person_schema', 'extend_person_schema', 10, 2);
// Run late to ensure all other modifications are done
add_filter('nexus_pro_person_schema', 'final_person_adjustments', 999, 2);
Validate and Sanitize
// Always validate and sanitize user input
function save_custom_meta($post_id) {
// URL validation
if (isset($_POST['website'])) {
$url = esc_url_raw($_POST['website']);
if (filter_var($url, FILTER_VALIDATE_URL)) {
update_post_meta($post_id, 'website', $url);
}
}
// Email validation
if (isset($_POST['email'])) {
$email = sanitize_email($_POST['email']);
if (is_email($email)) {
update_post_meta($post_id, 'email', $email);
}
}
// Number validation
if (isset($_POST['price'])) {
$price = floatval($_POST['price']);
if ($price >= 0) {
update_post_meta($post_id, 'price', $price);
}
}
}
Check for Empty Values
// Don't add empty fields to schema
function extend_schema_safely($schema, $post_id) {
$custom_field = get_post_meta($post_id, 'custom_field', true);
if (!empty($custom_field)) {
$schema['customProperty'] = $custom_field;
}
return $schema;
}
Use Nonces for Security
// Add nonce to form
wp_nonce_field('save_custom_meta', 'custom_meta_nonce');
// Verify nonce when saving
function save_custom_meta($post_id) {
if (!isset($_POST['custom_meta_nonce']) ||
!wp_verify_nonce($_POST['custom_meta_nonce'], 'save_custom_meta')) {
return;
}
// Proceed with saving
}
Document Your Extensions
/**
* Extend Nexus Pro Person entity with professional certifications.
*
* Adds repeatable certification fields to Person entity admin interface
* and includes them in Person schema output as credentials.
*
* @since 1.0.0
* @param WP_Post $post The post object.
*/
function add_certification_fields($post) {
// Implementation
}
Conclusion
Extending Nexus Pro through hooks and filters allows adding custom fields to entity templates while maintaining plugin compatibility. By understanding the hook system, implementing proper validation, and following WordPress development best practices, you can customize Nexus Pro for any project requirements.
Extension Checklist:
- ✓ Use Nexus Pro hooks (not core files)
- ✓ Add meta fields with action hooks
- ✓ Save data securely with nonces
- ✓ Validate and sanitize all input
- ✓ Extend schema with filter hooks
- ✓ Check for empty values
- ✓ Test schema with validators
- ✓ Document custom code
- ✓ Prefix function names
- ✓ Test with plugin updates
Available Hooks:
nexus_pro_{entity}_meta_fields– Add fields to adminnexus_pro_{entity}_schema– Filter schema outputsave_post_nexus_{entity}– Save custom metanexus_pro_{entity}_query– Modify entity queries
Start with simple single-field additions to understand the hook system, then progress to complex meta boxes, repeatable fields, and advanced schema integrations. Always test extensions after Nexus Pro updates to ensure compatibility.
Related Articles:

