frs-wp-users
Version: 2.2.0 Repository: derintolu/frs-wp-users
Advanced user profile management system with guest profiles, REST API, FluentCRM sync, Follow Up Boss integration, and intranet module.
Features
Implemented
| ID | Feature | Priority |
|---|---|---|
| FRS-USERS-001 | Profile Management | P0 |
| FRS-USERS-002 | FluentCRM Integration | P1 |
| FRS-USERS-003 | Profile Sync (Hub ↔ Marketing) | P1 |
| FRS-USERS-008 | Follow Up Boss Integration | P1 |
Planned
| ID | Feature | Priority |
|---|---|---|
| FRS-USERS-004 | WordPress Abilities API | P1 |
| FRS-USERS-005 | Intranet Directory | P1 |
| FRS-USERS-006 | Intranet Profile | P1 |
| FRS-USERS-007 | Network-Wide Bookmarks | P2 |
Installation
# Clone to plugins directory
git clone https://github.com/derintolu/frs-wp-users.git
# Activate
wp plugin activate frs-wp-usersProfile Roles
WordPress Roles (Capabilities)
| Role | Slug | URL Prefix |
|---|---|---|
| Loan Officer | loan_officer | /lo/ |
| Real Estate Agent | re_agent | /agent/ |
| Escrow Officer | escrow_officer | /escrow/ |
| Property Manager | property_manager | /pm/ |
| Dual License | dual_license | /lo/ |
| Staff | staff | /staff/ |
| Leadership | leadership | /leader/ |
| Assistant | assistant | /staff/ |
| Partner | partner | (none) |
Company Roles (Directory Categorization)
Stored as multi-value frs_company_role meta:
| Company Role | Maps to WP Role |
|---|---|
loan_originator | loan_officer |
broker_associate | re_agent |
sales_associate | re_agent |
escrow_officer | escrow_officer |
property_manager | property_manager |
partner | partner |
leadership | leadership |
staff | staff |
REST API
Base: /wp-json/frs-users/v1/
Endpoints
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| GET | /profiles | Public | List all profiles |
| POST | /profiles | Editor | Create profile |
| GET | /profiles/{id} | Public | Get single profile |
| PUT | /profiles/{id} | Editor | Update profile |
| DELETE | /profiles/{id} | Editor | Delete profile |
| GET | /profiles/slug/{slug} | Public | Get by profile slug |
| GET | /profiles/user/{id|me} | Public | Get by WordPress user ID |
| GET | /service-areas | Public | List all service areas |
| GET | /vcard/{id} | Public | Download vCard |
| POST | /meeting-request | Public | Submit meeting request |
| POST | /webhook/profile-updated | HMAC | Profile sync webhook |
Example Request
# Get loan originators in a specific region
curl -X GET \
'https://myhub21.com/wp-json/frs-users/v1/profiles?company_role=loan_originator®ion=los-angeles'Example Response
{
"data": [
{
"id": 45,
"display_name": "Sarah Johnson",
"first_name": "Sarah",
"last_name": "Johnson",
"email": "sarah@21stcenturylending.com",
"frs_company_role": ["loan_originator"],
"frs_job_title": "Senior Loan Officer",
"frs_nmls": "1234567",
"frs_phone_number": "(555) 123-4567",
"frs_mobile_number": "(555) 987-6543",
"frs_office": "Los Angeles",
"frs_city_state": "Los Angeles, CA",
"frs_region": "los-angeles",
"frs_service_areas": ["Los Angeles", "Orange County", "Ventura"],
"frs_biography": "15+ years helping families achieve homeownership...",
"frs_headshot_id": 1234,
"frs_profile_slug": "sarah-johnson",
"frs_linkedin_url": "https://linkedin.com/in/sarahjohnson",
"avatar_url": "https://myhub21.com/wp-content/uploads/avatars/sarah.jpg"
}
],
"total": 1,
"pages": 1
}Profile Meta Fields
All fields prefixed with frs_ and stored in wp_usermeta.
Core Fields
| Field | Meta Key | Type |
|---|---|---|
| Phone | frs_phone_number | string |
| Mobile | frs_mobile_number | string |
| Job Title | frs_job_title | string |
| Biography | frs_biography | text |
| Headshot | frs_headshot_id | attachment_id |
Licensing Fields
| Field | Meta Key | Type |
|---|---|---|
| NMLS | frs_nmls | string |
| NMLS Number | frs_nmls_number | string |
| License Number | frs_license_number | string |
| DRE License | frs_dre_license | string |
Location Fields
| Field | Meta Key | Type |
|---|---|---|
| Office | frs_office | string |
| City/State | frs_city_state | string |
| Region | frs_region | string |
| Service Areas | frs_service_areas | JSON array |
Social Fields
| Field | Meta Key |
|---|---|
frs_facebook_url | |
frs_instagram_url | |
frs_linkedin_url | |
frs_twitter_url | |
| YouTube | frs_youtube_url |
| TikTok | frs_tiktok_url |
Profile Fields
| Field | Meta Key | Type |
|---|---|---|
| Profile Slug | frs_profile_slug | string |
| Profile Headline | frs_profile_headline | string |
| Profile Theme | frs_profile_theme | string |
| Is Active | frs_is_active | boolean |
| QR Code Data | frs_qr_code_data | string |
JSON Array Fields
| Field | Meta Key |
|---|---|
| Specialties | frs_specialties |
| LO Specialties | frs_specialties_lo |
| Languages | frs_languages |
| Custom Links | frs_custom_links |
Sync Fields
| Field | Meta Key |
|---|---|
| Company Role | frs_company_role (multi-value) |
| Person Type | frs_select_person_type |
| Agent ID | frs_agent_id |
| FluentCRM Synced | frs_synced_to_fluentcrm_at |
Site Contexts
Set via FRS_SITE_CONTEXT constant in wp-config.php to control which roles are visible per site.
| Context | Company Roles | Can Edit |
|---|---|---|
development | All 8 roles | Yes |
hub | All 8 roles | Yes |
21stcenturylending | loan_originator, leadership | No |
c21masters | broker_associate, sales_associate, leadership | No |
Precedence: Constant → Filter (frs_site_context) → Option → Default (development)
// wp-config.php
define('FRS_SITE_CONTEXT', '21stcenturylending');FluentCRM Integration
Real-time sync between profiles and FluentCRM contacts on user create/update/role change.
Sync Triggers
- Profile create → Create FluentCRM contact
- Profile update → Update FluentCRM contact
- Role change → Update FluentCRM tags
- Profile delete → Remove tags (contact preserved)
Tag Mapping
| Company Role | FluentCRM Tag |
|---|---|
| loan_originator | Loan Originator |
| broker_associate | Broker Associate |
| sales_associate | Sales Associate |
| leadership | Leadership |
| staff | Staff |
Configuration
FluentCRM runs on main site only in multisite. Configure site ID:
// wp-config.php
define('FRS_FLUENTCRM_SITE_ID', 1);Integrations
Simple Local Avatars
Headshot management using Simple Local Avatars plugin for avatar storage.
Arrive Auto-Populate
Auto-populates loan application URLs for loan officers based on their NMLS number.
Planned Features
Coming Soon
The following features are planned but not yet implemented.
Follow Up Boss Integration
CRM integration for syncing profiles to Follow Up Boss on save.
WordPress Abilities API
AI-ready abilities for profile queries:
frs-users/list-profiles- Query profiles with filtersfrs-users/get-profile- Get single profile by IDfrs-users/search-profiles- Full-text search
Hooks & Filters
Actions
| Hook | Description | Arguments |
|---|---|---|
frs_profile_saved | After profile save | $profile_id, $profile_data |
frs_users_loaded | After plugin init | (none) |
frs_users_api_routes | Add custom REST routes | (none) |
// After profile saved
add_action('frs_profile_saved', function($profile_id, $profile_data) {
// Trigger external sync, notifications, etc.
}, 10, 2);Filters
| Hook | Description | Arguments |
|---|---|---|
frs_site_context | Override site context | $context |
// Override site context dynamically
add_filter('frs_site_context', function($context) {
if (is_page('lending')) {
return '21stcenturylending';
}
return $context;
});CLI Commands
# Check site context
wp frs-users site-context
# Setup sync between hub and marketing sites
wp frs-users setup-sync --hub-url=https://myhub21.com
wp frs-users setup-sync --generate-secret
# Sync profiles from hub
wp frs-users sync-from-hub [--type=loan_originator] [--dry-run]
# List profiles
wp frs-users list-profiles [--type=loan_originator]
wp frs-users list-guests
# Profile utilities
wp frs-users create-user <profile_id>
wp frs-users generate-slugs
wp frs-users generate-qr-codes [--force]
wp frs-users generate-vcards [--type=loan_originator]
# Migrations
wp frs-users migrate-fields [--dry-run]
wp frs-users cleanup-fields [--dry-run]Admin Pages
| Page | Location |
|---|---|
| All Profiles | Users → FRS Profiles |
| Add Profile | Users → Add FRS Profile |
| Edit Profile | Users → FRS Profiles → Edit |
| Import/Export | Users → Import/Export |
Code Examples
Get Profile by User ID
use FRSUsers\Models\Profile;
$profile = Profile::get_by_user_id($user_id);
if ($profile) {
echo $profile->get('first_name');
echo $profile->get('frs_nmls_id');
}Create Profile
use FRSUsers\Models\Profile;
$profile = new Profile();
$profile->set('user_id', $user_id);
$profile->set('first_name', 'John');
$profile->set('last_name', 'Doe');
$profile->set('frs_role', 'loan_officer');
$profile->save();Query Profiles
use FRSUsers\Core\ProfileApi;
$api = ProfileApi::get_instance();
$profiles = $api->get_profiles([
'role' => 'loan_officer',
'department' => 'Sales',
'per_page' => 20
]);File Structure
frs-wp-users/
├── frs-wp-users.php # Main plugin file
├── plugin.php # Plugin class
├── includes/
│ ├── Core/ # Core services
│ │ ├── Roles.php # Role/context configuration
│ │ ├── ProfileApi.php # REST API handler
│ │ ├── ProfileStorage.php
│ │ ├── ProfileSync.php # Webhook synchronization
│ │ ├── CLI.php # WP-CLI commands
│ │ └── Template.php # URL routing
│ ├── Models/ # Data models
│ │ ├── Profile.php
│ │ └── UserProfile.php
│ ├── Admin/ # Admin pages (DataViews-based)
│ │ ├── ProfilesAdminPage.php
│ │ ├── ProfileEditPage.php
│ │ └── CsvImportExport.php
│ ├── Controllers/ # Blocks, shortcodes
│ ├── Routes/ # REST API
│ │ └── Api.php
│ ├── Integrations/ # External services
│ │ ├── FluentCRMSync.php
│ │ └── ArriveAutoPopulate.php
│ ├── Abilities/ # WordPress Abilities API (planned)
│ └── Intranet/ # Intranet module (planned)
├── assets/
│ ├── admin/ # React admin interface
│ └── blocks/ # Gutenberg blocks
├── templates/profile/ # Frontend templates
└── database/Migrations/ # Schema migrationsRelated Documentation
- Intranet Module - Directory, org chart, bookmarks
- Profiles API - REST API reference
- User Abilities - AI integration