WP Manifestindependent plugin directory
manifest / forms / lh-crm

LH Customer Relationship Management

Do contact forms the LocalHero way

by Peter Shaw · github.com/lhero-org/lh-crm · website

0stars
0forks

Install

No release zip yet. The repository archive installs, but the folder name will carry the branch suffix and updates will not flow:

wp plugin install https://github.com/lhero-org/lh-crm/archive/refs/heads/main.zip

A contact form and enquiry management plugin for LocalHero WordPress Multisite deployments.

Description

LH CRM provides contact forms and enquiry tracking for community organisations running the LocalHero platform. It integrates deeply with BuddyPress for user provisioning, group management, in-app notifications, and activity streams. Task management has moved to the standalone lh-tasks plugin.

Installation

  1. Upload the lh-crm folder to /wp-content/plugins/
  2. Network-activate the plugin through the Network Admin Plugins screen
  3. Ensure lh-user-provisioning is also network-activated for full user creation support

Requirements

  • WordPress 6.0+
  • PHP 8.0+
  • BuddyPress (network-activated)
  • LH User Provisioning (recommended)

Directory Structure

lh-crm/
├── lh-crm.php              Main plugin file (bootstrap only)
├── assets/scripts/         Frontend and editor JavaScript
├── includes/               CRM-specific classes
├── languages/              Translation files
├── libraries/              Drop-in utility classes (no CRM dependency)
└── partials/               PHP view partials

Admin Interface

Contact Forms (lh-crm-form CPT)

Registered under the Contact Forms menu. Each form post configures:

Meta key Description
_lh_crm-fe_full_name-hide Hide the full name field on the frontend form
_lh_crm-fe_message-hide Hide the message field on the frontend form
_lh_crm-form_submit_button Submit button label
_lh_crm-field_group BuddyPress xProfile field group ID to display on the form
_lh_crm-default_category Default enquiry category term ID applied to new enquiries
_lh_crm-recipient_id User ID of the staff member who receives enquiries (required)
_lh_crm-group_id BuddyPress group ID to invite/add the submitter to
_lh_crm-group_action Group action: add_to_group, email_invite, or silent_invite
_lh_crm-bp_notification_recipients Array of user IDs to receive BP in-app notifications
_lh_crm-notification_id Post ID of the bp-email notification template
_lh_crm-response_id Post ID of the form response template shown after submission

Enquiries (lh_crm_enquiry_post CPT)

Enquiries are created on frontend form submission. Custom statuses:

Status Description
lh_crm-new_enq Newly received enquiry
lh_crm-prog_enq In progress
lh_crm-pending_enq Pending further action
lh_crm-res_enq Resolved
lh_crm-clos_enq Closed

Enquiry meta:

Meta key Description
_lh_crm-reference Deduplication key generated client-side
_lh_crm-page_id Post ID of the page the form was submitted from
_lh_crm-referrer HTTP referrer URL at time of submission
_lh_crm-enquiry_notes Staff notes (admin only)
_lh_crm-status-{slug}-at UTC timestamp of most recent transition to each status

Hooks and Filters

Actions

Hook Arguments Description
lh_crm_enquiry_created $post_id, $form_id, $user Fired after a new enquiry post is created
lh_crm_http_post_after_user $user Fired after user resolution during form submission

Filters

Hook Arguments Description
lh_crm_message_title $title, $user Filter the enquiry post title
lh_crm_message_content $content, $user Filter the enquiry post content
lh_crm_user_summary $content, $user Filter the user summary token used in notification templates
lh_crm_enquiry_action $action, $page_id, $user_id Filter the enquiry action string
lh_crm_send_notification_tokens $tokens, $user Filter the token array used in notification email templates
lh_crm-form-after_full_name $html, $atts Filter form HTML after the full name field
lh_crm-form-after_frontend_email $html, $atts Filter form HTML after the email field
lh_crm-form-after_frontend_subject $html, $atts Filter form HTML after the subject field
lh_crm-form-after_frontend_submit $html, $atts Filter form HTML after the submit button

Shortcode

[lh_crm_form postid="123" subject_type="hidden" subject_value="Enquiry" message_placeholder="Your message"]
Attribute Default Description
postid Post ID of the lh-crm-form post (required)
subject_type text Input type for subject field: text or hidden
subject_value Default value for the subject field
message_placeholder Your Message Placeholder text for the message textarea
action_url current URL Form action URL

Also available as a Gutenberg block: lh-crm/form.

Cron Jobs

Hook Schedule Description
lh_crm_initial_run Once on activation Runs initial capability setup
lh_crm_wakeup Hourly Activates future-dated enquiries; triggers relationship resync

Database Tables

No custom tables. All data stored in standard WordPress posts, postmeta, and term_relationships tables. Relationship graph triples written to lh_relationships via LH_Relationships_Store if lh-relationships is active.

Constants

None. Version is accessed via LH_Crm_plugin::plugin_version().

Changelog

1.5.0 — 2026-07-05

  • Removed the lh_crm-task_post CPT and its admin UI in favour of the standalone lh-tasks plugin, now the shared task queue used across the plugin suite. Existing task records were migrated by hand prior to this release.
  • Removed the stale lh_crm-task_post reference from the commented-out destructive cleanup block in uninstall.php

1.4.0 — 2026-06-21

  • Refactored monolithic main file into separate include classes: LH_Crm_form_submission_class, LH_Crm_notifications_class, LH_Crm_relationships_class, LH_Crm_activity_class, LH_Crm_mcp_abilities_class
  • Added lh-crm/query-enquiries MCP ability with filtering by status, form, author, category, search, and site
  • Moved drop-in utility classes to libraries/ directory
  • Consolidated two partials/ directories into single root partials/
  • Added languages/ directory, readme.md, corrected readme.txt (was a copy from an unrelated plugin)
  • Added uninstall.php
  • Added register_post_meta() calls to enquiry and contact form post type classes
  • Registered post meta for all enquiry and contact form meta keys
  • Added plugin_version() identity method
  • Added ensure_user_is_added() legacy fallback for when lh-user-provisioning is absent
  • Added apply_filters('lh_crm_init_plugin', true) gate to plugins_init()
  • Fixed menu label from "Contact Forms" to "CRM"
  • Fixed dead _lh_crm-request_email post meta fallback removed from show_column_content()
  • Removed dead ensure_user_login() and get_role_names() methods
  • Removed empty LH_Crm_user_flags_taxonomy_class stub
  • Removed completed migrate_enquiry_activity() migration function
  • Replaced direct BP activity DB query in get_ids_of_non_site_activities() with bp_activity_get() + filter_query
  • Fixed 75 i18n calls incorrectly using return_plugin_namespace() as text domain — replaced with return_plugin_text_domain()
  • Fixed wp_unslash() missing on $_POST reads throughout form submission and metabox save handlers
  • Fixed missing ABSPATH guards in partials and library files
  • Fixed unescaped output on get_edit_post_link, bp_members_get_user_url, add_query_arg, get_permalink in admin columns
  • Fixed _e()esc_html_e() in task and contact form classes
  • Fixed wp_die() output now uses esc_html__()
  • Fixed ordered %1$s/%2$s placeholders and added translators comments in add_enquiry()
  • Fixed stale include path for lh-register-file-class.php after move to libraries/
  • Fixed suppress_filters → accepted false positive (intentional, filters this plugin's admin dropdowns)
  • Bumped Requires at least to 6.9 for abilities API; added License header
  • public keyword on instance properties (was var)

1.32 — 2026-06-21

  • Refactored monolithic main file into separate include classes: LH_Crm_form_submission_class, LH_Crm_notifications_class, LH_Crm_relationships_class, LH_Crm_activity_class
  • Moved drop-in utility classes (LH_Post_ip_address_taxonoy_class, LH_Post_user_agent_class, LH_Register_file_class) from includes/ to libraries/
  • Consolidated two partials/ directories into single root partials/
  • Removed dead _lh_crm-request_email post meta fallback from show_column_content() — value was never written anywhere
  • Added languages/ directory