For technically-inclined webmasters who want to extend SocietyPress beyond what the admin lets you do — add a custom page-builder widget, hook the society sidebar to add an entry, build a child theme that talks to plugin internals, or just understand the surface area.
If you're not a developer, skip this. The other module guides cover everything you need to run the platform.
Architecture in one paragraph
SocietyPress is a single-file plugin (societypress.php, ~80,000 lines) plus a parent theme (Code/theme/) plus five child themes. Function-based PHP — there are a couple of unavoidable classes (the nav walker, the WP_List_Table subclasses, the Walker_Nav_Menu requirement) but the rest is functions. ~60 custom database tables prefixed sp_. Inline JS — no jQuery dependency except where wpColorPicker forces it. Inline CSS in admin pages, separate CSS file for the parent theme.
Shortcodes
Every public-facing module surfaces a shortcode. Page-builder widgets are wrappers around these, so you can use either.
| Shortcode | What it does | |---|---| | [societypress_join] | Join form / new-member signup | | [societypress_volunteers] | Volunteer-opportunity board | | [sp_donate] | Public donation form (Stripe + PayPal) | | [sp_database_subscriptions] | Members-area gateway to paid databases | | [sp_help_request_submit] | Public Help Request submission form | | [sp_help_requests_archive] | Public archive of help requests | | [sp_lineage_apply] | Lineage-program application form | | [sp_lineage_my_applications] | Logged-in member's lineage applications | | [sp_lineage_roster] | Public roster of approved lineage members | | [sp_my_research_assignments] | Researcher dashboard (claimed cases + open queue) | | [sp_my_research_cases] | Member's submitted research cases | | [sp_my_volunteer_hours] | Member's volunteer-hours summary | | [sp_picture_wall] | Public Picture Wall (member-submitted ancestor portraits) | | [sp_picture_wall_submit] | Picture Wall submission form | | [sp_research_request] | Paid Research Services intake | | [sp_society_sidebar] | Auto-assembled member-portal nav |
Every shortcode accepts attributes documented in its module guide.
Page-builder widgets
Same surface, dragged via the page builder. Attributes on a widget become attributes on the corresponding shortcode.
Widget types are registered through the sp_builder_widget_types filter (see Hooks below). To add your own widget in a child theme, hook the filter and register a render function.
Filters
SocietyPress exposes three filters that child themes and add-ons can hook.
sp_society_sidebar_items — array
Filters the auto-assembled member-portal sidebar items. Each item is an associative array with label, url, module, icon, login_required. Hook to add, remove, rename, or re-order entries.
add_filter( 'sp_society_sidebar_items', function ( $items ) {
// Add a custom entry
$items[] = [
'label' => __( 'Annual Banquet', 'my-child-theme' ),
'url' => home_url( '/banquet/' ),
'module' => null,
'icon' => 'dashicons-cake',
'login_required' => false,
];
// Remove the Store entry
$items = array_filter( $items, fn( $i ) => $i['url'] !== home_url( '/store/' ) );
return array_values( $items );
} );
sp_admin_capability_map — array
Maps admin menu slugs to required capabilities. Hook to grant a custom capability access to a SocietyPress admin page.
sp_builder_widget_types — array
Register page-builder widgets. Each entry has label, description, and a fields array describing its settings.
add_filter( 'sp_builder_widget_types', function ( array $types ) {
$types['my_custom_widget'] = [
'label' => 'My Custom Widget',
'description' => 'Does my custom thing.',
'fields' => [
'show_header' => [
'label' => 'Show header',
'type' => 'checkbox',
'default' => true,
],
],
];
return $types;
} );
function sp_render_builder_widget_my_custom_widget( array $s ): void {
if ( ! empty( $s['show_header'] ) ) echo '<h2>Hello!</h2>';
// ... your render ...
}
The render function name follows the convention sp_render_builder_widget_{type} — must be globally available.
REST endpoints
| Endpoint | Method | What | |---|---|---| | /wp-json/societypress/v1/health | GET | Returns plugin version, db schema version, enabled modules. Useful for monitoring. | | /wp-json/societypress/v1/webhooks/stripe | POST | Stripe webhook receiver. Signature-verified via the stripe_webhook_secret setting. Handles checkout.session.completed, invoice.paid, customer.subscription.deleted. |
AJAX endpoints
80+ AJAX endpoints under wp_ajax_sp_*. Most are admin-only; some have wp_ajax_nopriv_* counterparts for public flows. Patterns:
- Cart actions:
sp_cart_add,sp_cart_get,sp_cart_update,sp_cart_remove - Donations:
sp_donate_paypal_create_order,sp_donate_paypal_capture - Help Requests:
sp_help_endorse,sp_help_mark_resolved - Member admin:
sp_member_detail,sp_save_account,sp_delete_members_batch,sp_import_members_batch - Events:
sp_register_for_event,sp_admin_update_attendance,sp_admin_bulk_attendance,sp_admin_cancel_registration - Library:
sp_library_item_detail,sp_library_enrich_batch - Voting:
sp_submit_vote,sp_export_ballot_results - Surname Research:
sp_surname_contact - Search:
sp_unified_search(cross-module search) - Exports:
sp_export_*family (members, donations, library, events, etc.) - Stripe / PayPal:
sp_store_create_payment_intent,sp_store_create_paypal_order,sp_store_capture_paypal_order,sp_store_finalize_stripe,sp_admin_refund_payment,sp_admin_refund_store_order
Each endpoint expects a nonce. Look at the corresponding shortcode / admin page render to see the nonce action name.
Module-enabled API
Every module is checked via sp_module_enabled( 'slug' ):
if ( sp_module_enabled( 'donations' ) ) {
// Donations module is active
}
Module slugs: events, library, newsletters, resources, governance, store, donations, blast_email, gallery, records, help_requests, documents, voting, lineage, research_services. Always-on: members (no flag — always returns true).
Custom tables
{$wpdb->prefix}sp_* — about 60 tables. Highlights:
- Members:
sp_members,sp_member_meta,sp_member_notes,sp_membership_tiers,sp_member_payments,sp_member_relationships,sp_member_research_areas,sp_member_surnames,sp_pending_profile_changes,sp_renewal_reminders - Events:
sp_events,sp_event_categories,sp_event_registrations,sp_event_reminders,sp_event_slots,sp_event_speakers,sp_event_speaker_assignments,sp_ical_feeds - Library:
sp_library_items,sp_library_categories - Records:
sp_records,sp_record_collections,sp_record_collection_fields,sp_record_values - Donations:
sp_donations,sp_campaigns - Store:
sp_orders,sp_order_items,sp_store_products - Voting:
sp_ballots,sp_ballot_questions,sp_ballot_choices,sp_ballot_votes - Governance:
sp_committees,sp_meetings,sp_volunteer_opportunities,sp_volunteer_signups,sp_volunteer_roles,sp_volunteer_hours,sp_groups,sp_group_members - Help / Research:
sp_help_requests,sp_help_responses,sp_research_cases,sp_research_invoices,sp_research_messages - Lineage:
sp_lineage_programs,sp_lineage_applications,sp_lineage_proofs - Other:
sp_documents,sp_document_categories,sp_newsletters,sp_resources,sp_resource_categories,sp_blast_emails,sp_email_log,sp_photo_albums,sp_photo_album_items,sp_audit_log,sp_access_log,sp_backups
Use $wpdb->prefix . 'sp_<table>' to reference. Always use $wpdb->prepare() for any user-input interpolation.
Capabilities
Custom capabilities map to admin sections:
sp_manage_settings— Settings, Modules, User Accesssp_manage_members— Members, Member Levels, Importssp_manage_content— Events, Library, Newsletters, Documents, Help Requests, Lineage, Research Cases, Picture Wallsp_manage_records— Records collections + importsp_manage_finances— Donations, Campaigns, Orders, Store Products, Financessp_manage_governance— Committees, Meetings, Volunteer Roster, Volunteer Opportunitiessp_manage_voting— Ballots, Voting Resultssp_view_reports— Reports, Annual Report, Audit Log
Roles are configured at SocietyPress → User Access. Admin (manage_options) inherits all sp_* capabilities automatically.
Volunteer-hours source-linking
Every helping action writes to sp_volunteer_hours with two attribution columns:
source_type— one of:help_request,research_case,committee,event,meeting,library_duty,othersource_id— the FK to whichever table the source row lives in
To add a new source type from a child theme or add-on, just write to the table with your custom source_type string. The volunteer-hours summary widget groups by source_type, so your custom type will show up alongside the built-ins.
Encryption
Sensitive settings (Stripe secret key, PayPal secret, SMTP password) are encrypted at rest via libsodium (XChaCha20-Poly1305). API:
sp_encrypt( $plaintext )— returns base64-encoded ciphertext.sp_decrypt( $ciphertext )— returns plaintext or empty string.sp_setting_encrypt( $key, $value )— encrypt and save to societypress_settings.sp_setting_decrypt( $key )— pull from societypress_settings, decrypt, return.
The encryption key is derived from AUTH_KEY + SECURE_AUTH_KEY in wp-config.php. Don't change those constants unless you're prepared to lose access to encrypted secrets — there's a fallback path that generates a random key when wp-config secrets are missing, but it's not the recommended path.
Translation
All user-facing strings are wrapped in __(), esc_html__(), esc_attr__(), or sprintf() with text domain societypress. The .pot file lives at Code/plugin/languages/societypress.pot (~330KB, ~4,500+ translatable strings).
To translate: copy the .pot to your locale (societypress-{locale}.po), translate via Poedit / Loco Translate / your tool of choice, save the .mo next to it. WordPress picks it up automatically.
Coding conventions
- WordPress coding standards (snake_case function names,
sp_*prefix on plugin functions). - Functions, not classes (with the unavoidable exceptions noted above).
wpdb->prepare()for any user-input interpolation. Bare interpolation only for$wpdb->prefixand constants.- Nonces on every form.
check_admin_refererfor admin POSTs,check_ajax_refererfor AJAX. current_user_can( 'sp_manage_*' )(ormanage_optionsfor admin) at the top of every admin handler.- All output through
esc_html(),esc_attr(),esc_url(),wp_kses_post(). Never echo user input raw. - Inline CSS allowed (the project is single-file by design); avoid inline styles in PHP templates that aren't dynamically computed.
Where to file bugs / contribute
Bug reports: GitHub Issues at SocietyPressFoundation/SocietyPress.
This is a solo-maintained project. Contributions are reviewed but the bar is high — see CONTRIBUTING.md in the repo root.