## Creating a Custom Integration

This guide walks through adding a custom integration that appears in Alpha Insights → Settings → Integrations and provides its own settings form and save logic.

### Step 1: Extend the Base Class

Create a PHP class that extends `WPDAI_Integration_Base`. You must implement every abstract method: `get_slug()`, `get_label()`, `get_description()`, `is_pro()`, `is_enabled()`, `render_settings()`, and `save_settings( $saved )`.

    <?php
    defined( 'ABSPATH' ) || exit;

    require_once WPD_AI_PATH . 'includes/integrations/WPDAI_Integration_Base.php';

    class My_Custom_Integration extends WPDAI_Integration_Base {

        public function get_slug() {
            return 'my-custom-integration';
        }

        public function get_label() {
            return __( 'My Custom Integration', 'alpha-insights-pro' );
        }

        public function get_description() {
            return __( 'Short description for the card.', 'alpha-insights-pro' );
        }

        public function is_pro() {
            return false; // or true for Pro-only
        }

        public function is_enabled() {
            $settings = get_option( 'my_custom_integration_settings', array() );
            return ! empty( $settings['api_key'] );
        }

        public function render_settings() {
            $settings = get_option( 'my_custom_integration_settings', array() );
            ?>
            <table class="wpd-table fixed widefat">
                <tbody>
                    <tr>
                        <td><label>API Key</label></td>
                        <td>
                            <input type="text" name="my_custom_integration_settings[api_key]"
                                value="<?php echo esc_attr( $settings['api_key'] ?? '' ); ?>" class="wpd-input">
                        </td>
                    </tr>
                </tbody>
            </table>
            <?php
        }

        public function save_settings( $saved ) {
            if ( isset( $_POST['my_custom_integration_settings'] ) && is_array( $_POST['my_custom_integration_settings'] ) ) {
                $data = map_deep( wp_unslash( $_POST['my_custom_integration_settings'] ), 'sanitize_text_field' );
                $saved['My Custom Integration'] = update_option( 'my_custom_integration_settings', $data );
            }
            return $saved;
        }
    }

### Step 2: Register Metadata (Optional but Recommended)

So that your integration appears in the grid with a label, description, logo, and category (and so free users can see it as Pro if you use `is_pro()`), register metadata on `wpd_ai_register_integration_metadata`. Pass the manager instance; it has `register_integration_metadata( $slug, $args )`.

    add_action( 'wpd_ai_register_integration_metadata', function( $manager ) {
        $manager->register_integration_metadata( 'my-custom-integration', array(
            'label'       => __( 'My Custom Integration', 'alpha-insights-pro' ),
            'description' => __( 'Short description for the card.', 'alpha-insights-pro' ),
            'is_pro'      => false,
            'logo_url'    => 'https://example.com/logo.png', // optional
            'category'    => __( 'Custom', 'alpha-insights-pro' ), // optional
            'url'         => '', // optional; override link when card is clicked
        ) );
    }, 10, 1 );

If you only register an instance and not metadata, the manager will still show your integration (it can derive label from the instance), but registering metadata ensures the card shows the right category and logo and keeps behavior consistent with built-in integrations.

### Step 3: Register the Instance

On `wpd_ai_register_integrations`, instantiate your class and pass it to the manager's `register_integration( $slug, $instance )`. The slug must match the one used in metadata (if any) and in `get_slug()`.

    add_action( 'wpd_ai_register_integrations', function( $manager ) {
        $manager->register_integration( 'my-custom-integration', new My_Custom_Integration() );
    }, 10, 1 );

Load your class file before this runs (e.g. in your plugin's bootstrap or on `plugins_loaded`). The base class constructor calls `setup_hooks()`, which adds your `save_settings` to the `wpd_ai_save_settings` filter, so saving the main settings form will call your `save_settings( $saved )`.

### Step 4: Sanitize and Capability Checks

In `save_settings()`:

- Use `wp_unslash()` on `$_POST` data, then sanitize (e.g. `sanitize_text_field`, `map_deep( ..., 'sanitize_text_field' )`). Do not trust raw `$_POST`.
- The main settings form is already behind a capability check; if you add nonces, use `wp_verify_nonce()` and `current_user_can()` as appropriate for your flow.

In `render_settings()`, escape all output (e.g. `esc_attr()`, `esc_html()`) for any value that comes from the database or user input.

### Complete Example (Theme or Plugin)

In your theme or plugin, load the integration file and hook both metadata and instance registration:

    // Load the integration class
    require_once get_template_directory() . '/includes/my-custom-integration.php';

    add_action( 'wpd_ai_register_integration_metadata', function( $manager ) {
        $manager->register_integration_metadata( 'my-custom-integration', array(
            'label'       => __( 'My Custom Integration', 'alpha-insights-pro' ),
            'description' => __( 'Connect to my service.', 'alpha-insights-pro' ),
            'is_pro'      => false,
            'category'    => __( 'Custom', 'alpha-insights-pro' ),
        ) );
    }, 10, 1 );

    add_action( 'wpd_ai_register_integrations', function( $manager ) {
        $manager->register_integration( 'my-custom-integration', new My_Custom_Integration() );
    }, 10, 1 );

After this, open Alpha Insights → Settings → Integrations. Your integration appears as a card; clicking it shows your settings form, and saving the page runs your `save_settings()` and updates the option.

### Optional: Override setup_hooks()

The base class `setup_hooks()` adds `save_settings` to `wpd_ai_save_settings`. You can override `setup_hooks()` to add more hooks (e.g. AJAX, admin scripts) but should still call `parent::setup_hooks()` so save continues to work.

### Optional: Custom Settings URL

`get_settings_url()` on the base class returns the URL to this integration's settings (`?page=...&subpage=integrations&integrations=slug`). You can override it if you need a different destination (e.g. a separate admin page). If you use a fully custom URL, set `url` in metadata so the card links there instead of `?integrations=slug`.

### Related Documentation

- Integrations Overview – How the system works
- Integration Base Class Reference – All methods and signatures
- Hooks and Registration – Full hook and filter reference
- Filter: wpd_ai_save_settings – How settings save is applied