# Extending AjaxPress

## PHP Filters

### Disable Navigation Conditionally

Use the `ajaxpress_navigation` filter to disable SPA on specific pages:

```php
add_filter('ajaxpress_navigation', function ($enabled) {
    // Disable on WooCommerce checkout
    if (function_exists('is_checkout') && is_checkout()) {
        return false;
    }
    return $enabled;
});
```

### Override License Check

Use `ajaxpress_is_license_active` to override the license check for development or custom licensing:

```php
add_filter('ajaxpress_is_license_active', '__return_true');
```

### Modify Default Settings

Use `ajaxpress_default_options` to change the default values for settings:

```php
add_filter('ajaxpress_default_options', function ($defaults) {
    $defaults['enable_prefetch'] = true;
    $defaults['progressbar_color'] = '#ff6600';
    return $defaults;
});
```

## Purging Cloudflare Cache

### From PHP

```php
// Purge specific URLs
ajaxpress_purge_cache([
    home_url('/'),
    home_url('/blog/'),
    get_permalink($post_id),
]);

// Purge everything
ajaxpress_purge_cache();
```

### From JavaScript (Admin)

Use the REST API directly:

```javascript
fetch('/wp-json/ajaxpress/cf/purge', {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json',
        'X-WP-Nonce': wpApiSettings.nonce
    },
    body: JSON.stringify({
        urls: ['https://example.com/page/']
    })
});
```

## Detecting AJAX Requests

Check if the current request is an AjaxPress SPA navigation:

```php
if (AjaxPress\Templates::is_ajax_request()) {
    // This is an AJAX-loaded page
    // Modify output, skip heavy queries, etc.
}
```

## Persistent Elements

### HTML Attribute (Recommended)

```html
<div data-ajaxpress-persist>
    <audio src="podcast.mp3" controls></audio>
</div>
```

### CSS Class

```html
<div class="ajaxpress-persist">
    <video src="stream.mp4"></video>
</div>
```

### Via Settings

Add custom selectors in **Settings > AjaxPress > Advanced > Media Players**:

```
#my-audio-player
.sticky-widget
[data-keep-alive]
```

## Excluding Links from SPA

### HTML Attribute

Add a data attribute to force normal navigation:

```html
<a href="/checkout" data-no-ajaxpress>Checkout</a>
```

### Via Settings

Add URL patterns in **Settings > AjaxPress > Advanced > Exclude Links**:

```
/checkout
/payment
/external-app/*
```

### Via CSS Class

Links inside excluded elements are also excluded:

```html
<nav class="ajaxpress-exclude">
    <a href="/page">This link loads normally</a>
</nav>
```

## Custom Loader Styling

Override loader styles using custom CSS (via the settings page or your theme):

```css
/* Custom progress bar */
.ajaxpress-progressbar {
    border-radius: 0 !important;
    box-shadow: 0 0 10px rgba(59, 130, 246, 0.5);
}

/* Custom spinner overlay */
.ajaxpress-spinner {
    backdrop-filter: blur(4px);
}
```

## Integration with Other Plugins

### Cache Plugins

AjaxPress is compatible with cache plugins out of the box. The SPA navigation works with cached HTML because it loads full pages (not partial content).

If you have a cache plugin and Cloudflare edge caching enabled, purge both caches when content changes:

```php
add_action('save_post', function ($post_id) {
    // Purge AjaxPress Cloudflare cache
    ajaxpress_purge_cache([get_permalink($post_id)]);
    
    // Your cache plugin's purge function
    // wp_rocket_clean_post($post_id);
});
```

### Page Builders

AjaxPress works with all major page builders (Elementor, Bricks, Beaver Builder, WPBakery, etc.) without configuration. The iframe-based architecture ensures page builder scripts execute normally in each loaded page.

### Analytics

SPA navigation doesn't trigger standard page views. If your analytics relies on full page loads, add tracking to the navigation event:

```javascript
// Listen for AjaxPress navigation
window.addEventListener('message', function(event) {
    if (event.data && event.data.type === 'AJAXPRESS_NAV') {
        // Track page view
        gtag('event', 'page_view', {
            page_location: event.data.url,
            page_title: event.data.title
        });
    }
});
```

Note: Place this script in the parent frame (outside the AjaxPress iframe) or use `markAsAjaxPressListener()` to prevent it from being cleaned up during navigation.
