Save Big: Bundle all Skunk products and save up to 57%

Docs/Developers/Getting Started

Developer Guide - Getting Started

SkunkCRM is built with extensibility in mind. This guide will help you get started with developing extensions, integrations, and customizations for SkunkCRM.

Architecture Overview

SkunkCRM follows WordPress plugin best practices and provides multiple extension points:

  • Hooks & Filters: Over 100 action and filter hooks for maximum extensibility
  • REST API: Comprehensive REST API for integrations
  • Database Access: Direct database access with custom tables
  • Class System: Object-oriented architecture with dependency injection

Quick Start

1. Basic Hook Usage

The simplest way to extend SkunkCRM is through WordPress hooks:

functions.phpphp
1// Add to your theme's functions.php or custom plugin
2
3// Log when contacts are created
4add_action('skunkcrm_after_contact_create', function($contact_id, $data) {
5    error_log("New contact created: {$data['name']} (ID: $contact_id)");
6});
7
8// Modify contact data before saving
9add_filter('skunkcrm_contact_data_before_save', function($data, $contact_id) {
10    // Auto-format phone numbers
11    if (isset($data['phone'])) {
12        $data['phone'] = preg_replace('/[^0-9]/', '', $data['phone']);
13        $data['phone'] = preg_replace('/(\d{3})(\d{3})(\d{4})/', '($1) $2-$3', $data['phone']);
14    }
15    return $data;
16}, 10, 2);
17
18// Add custom contact statuses
19add_filter('skunkcrm_contact_status_options', function($statuses) {
20    $statuses['vip'] = 'VIP Customer';
21    $statuses['partner'] = 'Business Partner';
22    return $statuses;
23});

2. REST API Integration

Powerful REST API Ready for Integration

SkunkCRM provides a comprehensive REST API designed for seamless integrations and external access. Build powerful integrations with full CRUD operations, secure authentication, and real-time webhook support.

🔧
Full CRUD Operations

Complete control over contacts, deals, and activities

🔐
Secure Authentication

WordPress Application Passwords with permission controls

Rate Limiting

Built-in protection and performance optimization

📡
JSON API

Clean, RESTful endpoints with consistent responses

🎯
Webhook Support

Real-time integrations and event notifications

📖 Explore Complete API Documentation →

Get started with examples, authentication guides, and interactive endpoint testing.

3. Custom Plugin Structure

Create a structured plugin to extend SkunkCRM:

functions.phpphp
1<?php
2/**
3 * Plugin Name: SkunkCRM Extension
4 * Description: Custom extensions for SkunkCRM
5 * Version: 1.0.0
6 */
7
8// Prevent direct access
9if (!defined('ABSPATH')) {
10    exit;
11}
12
13class SkunkCRM_Extension {
14    
15    public function __construct() {
16        add_action('plugins_loaded', [$this, 'init']);
17    }
18    
19    public function init() {
20        // Ensure SkunkCRM is active
21        if (!class_exists('SkunkCRM')) {
22            add_action('admin_notices', [$this, 'missing_skunkcrm_notice']);
23            return;
24        }
25        
26        // Initialize your extensions
27        $this->init_hooks();
28        $this->init_rest_api();
29        $this->init_admin_pages();
30    }
31    
32    private function init_hooks() {
33        // Contact management hooks
34        add_action('skunkcrm_after_contact_create', [$this, 'on_contact_created'], 10, 2);
35        add_filter('skunkcrm_contact_data_before_save', [$this, 'modify_contact_data'], 10, 2);
36        
37        // Automation hooks
38        add_filter('skunkcrm_automation_action_types', [$this, 'add_custom_actions']);
39        add_action('skunkcrm_before_automation_execute', [$this, 'log_automation'], 10, 3);
40    }
41    
42    private function init_rest_api() {
43        add_action('rest_api_init', [$this, 'register_custom_endpoints']);
44    }
45    
46    private function init_admin_pages() {
47        add_action('admin_menu', [$this, 'add_admin_menu']);
48    }
49    
50    public function on_contact_created($contact_id, $data) {
51        // Custom logic when contact is created
52        $this->sync_to_external_system($contact_id, $data);
53    }
54    
55    public function modify_contact_data($data, $contact_id) {
56        // Add custom validation or data transformation
57        if (isset($data['email']) && !empty($data['email'])) {
58            $data['email_domain'] = substr(strrchr($data['email'], "@"), 1);
59        }
60        return $data;
61    }
62    
63    public function add_custom_actions($actions) {
64        $actions['send_to_crm'] = 'Send to External CRM';
65        $actions['create_calendar_event'] = 'Create Calendar Event';
66        return $actions;
67    }
68    
69    public function register_custom_endpoints() {
70        register_rest_route('skunkcrm-extension/v1', '/sync', [
71            'methods' => 'POST',
72            'callback' => [$this, 'sync_endpoint'],
73            'permission_callback' => [$this, 'check_permissions']
74        ]);
75    }
76    
77    public function sync_endpoint($request) {
78        // Custom API endpoint
79        $contact_id = $request->get_param('contact_id');
80        
81        // Sync logic here
82        $result = $this->sync_contact($contact_id);
83        
84        return new WP_REST_Response($result, 200);
85    }
86    
87    public function missing_skunkcrm_notice() {
88        echo '<div class="notice notice-error"><p>SkunkCRM Extension requires SkunkCRM to be installed and activated.</p></div>';
89    }
90    
91    private function sync_to_external_system($contact_id, $data) {
92        // Implement external system integration
93    }
94    
95    private function sync_contact($contact_id) {
96        // Implement sync logic
97        return ['success' => true, 'contact_id' => $contact_id];
98    }
99    
100    public function check_permissions() {
101        return current_user_can('manage_options');
102    }
103}
104
105new SkunkCRM_Extension();

Common Extension Patterns

1. External System Integration

functions.phpphp
1class SkunkCRM_Mailchimp_Integration {
2    
3    private $api_key;
4    private $list_id;
5    
6    public function __construct($api_key, $list_id) {
7        $this->api_key = $api_key;
8        $this->list_id = $list_id;
9        
10        // Sync contacts to Mailchimp when created/updated
11        add_action('skunkcrm_after_contact_create', [$this, 'sync_to_mailchimp'], 10, 2);
12        add_action('skunkcrm_after_contact_update', [$this, 'update_in_mailchimp'], 10, 3);
13        add_action('skunkcrm_after_contact_delete', [$this, 'remove_from_mailchimp'], 10, 2);
14    }
15    
16    public function sync_to_mailchimp($contact_id, $data) {
17        if (empty($data['email'])) {
18            return;
19        }
20        
21        $mailchimp_data = [
22            'email_address' => $data['email'],
23            'status' => 'subscribed',
24            'merge_fields' => [
25                'FNAME' => $this->get_first_name($data['name']),
26                'LNAME' => $this->get_last_name($data['name']),
27                'COMPANY' => $data['company'] ?? '',
28                'PHONE' => $data['phone'] ?? ''
29            ],
30            'tags' => ['skunkcrm']
31        ];
32        
33        $this->mailchimp_api_call("lists/{$this->list_id}/members", $mailchimp_data);
34    }
35    
36    public function update_in_mailchimp($contact_id, $new_data, $old_data) {
37        // Update subscriber in Mailchimp
38        if (!empty($new_data['email'])) {
39            $subscriber_hash = md5(strtolower($new_data['email']));
40            $this->mailchimp_api_call(
41                "lists/{$this->list_id}/members/{$subscriber_hash}",
42                ['merge_fields' => ['FNAME' => $this->get_first_name($new_data['name'])]],
43                'PATCH'
44            );
45        }
46    }
47    
48    private function mailchimp_api_call($endpoint, $data, $method = 'POST') {
49        $url = "https://us1.api.mailchimp.com/3.0/{$endpoint}";
50        
51        return wp_remote_request($url, [
52            'method' => $method,
53            'headers' => [
54                'Authorization' => 'Basic ' . base64_encode('user:' . $this->api_key),
55                'Content-Type' => 'application/json'
56            ],
57            'body' => json_encode($data)
58        ]);
59    }
60}

2. Custom Automation Actions

functions.phpphp
1class SkunkCRM_Custom_Automation_Actions {
2    
3    public function __construct() {
4        add_filter('skunkcrm_automation_action_types', [$this, 'add_action_types']);
5        add_filter('skunkcrm_custom_action_type', [$this, 'handle_custom_action'], 10, 4);
6    }
7    
8    public function add_action_types($actions) {
9        $actions['send_sms'] = 'Send SMS';
10        $actions['create_deal'] = 'Create Deal';
11        $actions['assign_to_user'] = 'Assign to User';
12        $actions['add_to_sequence'] = 'Add to Email Sequence';
13        return $actions;
14    }
15    
16    public function handle_custom_action($result, $action_type, $config, $contact) {
17        switch ($action_type) {
18            case 'send_sms':
19                return $this->send_sms($config, $contact);
20            case 'create_deal':
21                return $this->create_deal($config, $contact);
22            case 'assign_to_user':
23                return $this->assign_to_user($config, $contact);
24            case 'add_to_sequence':
25                return $this->add_to_sequence($config, $contact);
26        }
27        return $result;
28    }
29    
30    private function send_sms($config, $contact) {
31        if (empty($contact['phone'])) {
32            return ['success' => false, 'error' => 'No phone number'];
33        }
34        
35        $message = str_replace('{name}', $contact['name'], $config['message']);
36        
37        // Use Twilio, TextMagic, or other SMS service
38        return $this->sms_service_send($contact['phone'], $message);
39    }
40    
41    private function create_deal($config, $contact) {
42        global $wpdb;
43        
44        $deal_data = [
45            'title' => str_replace('{contact_name}', $contact['name'], $config['title']),
46            'amount' => $config['amount'] ?? 0,
47            'stage' => $config['stage'] ?? 'prospecting',
48            'contact_id' => $contact['id'],
49            'assigned_to' => $config['assigned_to'] ?? get_current_user_id(),
50            'created_at' => current_time('mysql')
51        ];
52        
53        $result = $wpdb->insert(
54            $wpdb->prefix . 'skunk_deals',
55            $deal_data,
56            ['%s', '%f', '%s', '%d', '%d', '%s']
57        );
58        
59        return [
60            'success' => $result !== false,
61            'deal_id' => $wpdb->insert_id
62        ];
63    }
64}

3. Contact Data Enhancement

functions.phpphp
1class SkunkCRM_Data_Enrichment {
2    
3    public function __construct() {
4        add_filter('skunkcrm_contact_data_before_save', [$this, 'enrich_contact_data'], 20, 2);
5        add_action('skunkcrm_after_contact_create', [$this, 'background_enrichment'], 10, 2);
6    }
7    
8    public function enrich_contact_data($data, $contact_id) {
9        // Real-time enrichment for critical fields
10        if (isset($data['email']) && !empty($data['email'])) {
11            $domain = substr(strrchr($data['email'], "@"), 1);
12            $data['email_domain'] = $domain;
13            
14            // Check if it's a business email
15            $personal_domains = ['gmail.com', 'yahoo.com', 'hotmail.com', 'outlook.com'];
16            $data['is_business_email'] = !in_array($domain, $personal_domains);
17        }
18        
19        // Auto-format phone numbers
20        if (isset($data['phone']) && !empty($data['phone'])) {
21            $data['phone'] = $this->format_phone_number($data['phone']);
22        }
23        
24        // Capitalize names
25        if (isset($data['name'])) {
26            $data['name'] = ucwords(strtolower($data['name']));
27        }
28        
29        return $data;
30    }
31    
32    public function background_enrichment($contact_id, $data) {
33        // Schedule background enrichment
34        wp_schedule_single_event(time() + 60, 'skunkcrm_enrich_contact', [$contact_id]);
35    }
36    
37    private function format_phone_number($phone) {
38        // Remove all non-numeric characters
39        $phone = preg_replace('/[^0-9]/', '', $phone);
40        
41        // Format as (XXX) XXX-XXXX for US numbers
42        if (strlen($phone) === 10) {
43            return preg_replace('/(\d{3})(\d{3})(\d{4})/', '($1) $2-$3', $phone);
44        }
45        
46        return $phone;
47    }
48}
49
50// Register the enrichment hook
51add_action('skunkcrm_enrich_contact', function($contact_id) {
52    // Fetch additional data from external APIs
53    $contact = SkunkCRM_Contacts::get_by_id($contact_id);
54    
55    if ($contact && !empty($contact['email'])) {
56        // Example: Enrich with Clearbit, FullContact, etc.
57        $enriched_data = fetch_from_clearbit($contact['email']);
58        
59        if ($enriched_data) {
60            SkunkCRM_Contacts::update($contact_id, [
61                'company' => $enriched_data['company'] ?? $contact['company'],
62                'title' => $enriched_data['title'] ?? null,
63                'linkedin' => $enriched_data['linkedin'] ?? null
64            ]);
65        }
66    }
67});

Development Guidelines

1. Hook Usage Best Practices

  • Use appropriate priority: Default is 10, use higher numbers to run later
  • Check for plugin existence: Always verify SkunkCRM is active
  • Handle errors gracefully: Don't break core functionality
  • Follow WordPress standards: Use WordPress coding standards

2. Performance Considerations

  • Avoid heavy operations in hooks: Use background processing for intensive tasks
  • Cache external API calls: Implement proper caching mechanisms
  • Use transients: For temporary data storage
  • Database optimization: Use proper indexes and queries

3. Security Best Practices

  • Sanitize all inputs: Use WordPress sanitization functions
  • Validate permissions: Check user capabilities
  • Escape outputs: Prevent XSS attacks
  • Use nonces: For form submissions

4. Testing Your Extensions

functions.phpphp
1// Example test for contact creation hook
2class Test_SkunkCRM_Extension extends WP_UnitTestCase {
3    
4    public function test_contact_creation_hook() {
5        // Create a contact
6        $contact_data = [
7            'name' => 'Test Contact',
8            'email' => 'test@example.com',
9            'status' => 'prospect'
10        ];
11        
12        $contact_id = SkunkCRM_Contacts::create($contact_data);
13        
14        // Verify your hook ran
15        $this->assertTrue(did_action('skunkcrm_after_contact_create') > 0);
16        
17        // Verify your modifications
18        $contact = SkunkCRM_Contacts::get_by_id($contact_id);
19        $this->assertEquals('example.com', $contact['email_domain']);
20    }
21}

Next Steps

  1. Explore the Hooks & Filters Reference for complete documentation
  2. Check out the REST API Documentation for integration details
  3. Contact our support team for developer assistance and questions

Resources

Was this page helpful?