Adds a crm-like layers over Craft's users
This plugin requires Craft CMS 5.7.0 or later, and PHP 8.2 or later.
You can install this plugin from the Plugin Store or with Composer.
Go to the Plugin Store in your project's Control Panel and search for "Contacts". Then press "Install".
Open your terminal and run the following commands:
# go to the project directory
cd /path/to/my-project.test
# tell Composer to load the plugin
composer require statikbe/craft-contacts
# tell Craft to install the plugin
./craft plugin/install contacts- Contact Management: Create and manage contacts as inactive users
- Advanced Filtering: Save personal and shared filters for quick access
- Export Functionality: Export contacts to XLSX format
- User Conversion: Convert contacts to active users with activation emails
- Field Layout Customization: Control which User fields are visible for contacts
- Relations Table Template: Display related data in clean, formatted tables
The plugin includes a flexible relations table template for displaying related data on contact detail pages.
Include the _relations-table.twig template to display any related data in a formatted table:
{% set columns = [
{label: 'Title', key: 'title', link: true},
{label: 'Status', key: 'status'},
{label: 'Created', key: 'dateCreated', type: 'date'}
] %}
{% include 'contacts/_relations-table' with {
title: 'Related Entries',
columns: columns,
rows: relatedEntries,
emptyMessage: 'No related entries found.'
} %}Each column supports the following properties:
label(string): Column header labelkey(string): Property key to access in row datalink(boolean): Whether to link to element's CP edit URL (default:false)type(string): Format type for cell value (default:'text')
text: Renders value as-is (supports HTML)date: Formats date using|date('short')datetime: Formats datetime using|datetime('short')timestamp: Formats timestamp using|timestamprelation: Resolves relation field and displays title (automatically linked)dropdown: Displays dropdown field label instead of value
{# Get related registrations for this contact #}
{% set registrations = craft.entries()
.section('registrations')
.relatedTo(element)
.all() %}
{% set columns = [
{label: 'Registration', key: 'title', link: true},
{label: 'Course', key: 'course', type: 'relation'},
{label: 'Status', key: 'registrationStatus', type: 'dropdown'},
{label: 'Date', key: 'dateCreated', type: 'date'}
] %}
{% include 'contacts/_relations-table' with {
title: 'Registrations',
columns: columns,
rows: registrations
} %}This will display:
- Registration: Clickable title linking to the registration entry
- Course: Related course title, linking to the course entry
- Status: Human-readable dropdown label (e.g., "Pending Approval")
- Date: Formatted date (e.g., "Jan 15, 2024")
All links open in a new tab to preserve the contact detail page.
For large datasets, enable pagination by passing an element query and setting paginate: true:
{% set columns = [
{label: 'Registration', key: 'title', link: true},
{label: 'Course', key: 'course', type: 'relation'},
{label: 'Date', key: 'dateCreated', type: 'date'}
] %}
{% include 'contacts/_relations-table' with {
title: 'Registrations',
columns: columns,
rows: craft.entries().section('registrations').relatedTo(element), {# Pass query, not .all() #}
paginate: true,
pageSize: 20
} %}Important: When using pagination, pass the element query directly (don't call .all()). The template will handle executing the query with pagination.
Pagination Parameters:
paginate(boolean): Enable pagination (default:false)pageSize(integer): Items per page (default:20)
Pagination works with both element queries and arrays. The template automatically uses Craft's native pagination UI for queries and a custom implementation for arrays. Array pagination uses the relationPage URL parameter to avoid conflicts with CP routing.