SDK Reference
Admin API

Admin API

Extend the admin dashboard with custom pages, settings panels, and UI elements.

Admin Pages

sdk.admin.registerPage(slug, config)

Add a custom page to the admin dashboard.

sdk.admin.registerPage('analytics', {
  title: 'Analytics Dashboard',
  icon: '📊',
  
  render: async (context) => {
    // context.request - the request object
    // context.user - current admin user
    
    return `
      <div class="analytics-page">
        <h1>Analytics Dashboard</h1>
        <div class="stats-grid">
          <div class="stat-card">
            <h3>Total Views</h3>
            <span class="stat-value">12,345</span>
          </div>
          <div class="stat-card">
            <h3>Posts</h3>
            <span class="stat-value">89</span>
          </div>
        </div>
      </div>
    `;
  }
});

The page will be accessible at /admin/analytics.

Page with Actions

sdk.admin.registerPage('bulk-actions', {
  title: 'Bulk Actions',
  icon: '⚡',
  
  render: async () => {
    return `
      <div class="bulk-actions">
        <h1>Bulk Actions</h1>
        
        <div class="action-card">
          <h3>Regenerate Thumbnails</h3>
          <p>Regenerate all image thumbnails</p>
          <button onclick="runAction('regenerate-thumbnails')">Run</button>
        </div>
        
        <div class="action-card">
          <h3>Clear Cache</h3>
          <p>Clear all cached content</p>
          <button onclick="runAction('clear-cache')">Run</button>
        </div>
        
        <div id="result"></div>
      </div>
      
      <script>
        async function runAction(action) {
          const result = document.getElementById('result');
          result.textContent = 'Running...';
          
          const response = await fetch('/api/admin/actions/' + action, {
            method: 'POST'
          });
          
          const data = await response.json();
          result.textContent = data.message;
        }
      </script>
    `;
  }
});

Settings Panels

sdk.admin.registerSettings(id, config)

Add a settings panel in the admin settings page.

sdk.admin.registerSettings('seo-settings', {
  title: 'SEO Settings',
  icon: '🔍',
  
  fields: [
    {
      key: 'metaTitle',
      type: 'text',
      label: 'Default Meta Title',
      placeholder: '{{ siteName }} - {{ pageTitle }}'
    },
    {
      key: 'metaDescription',
      type: 'textarea',
      label: 'Default Meta Description',
      maxLength: 160
    },
    {
      key: 'enableOgTags',
      type: 'boolean',
      label: 'Enable Open Graph Tags',
      default: true
    },
    {
      key: 'twitterHandle',
      type: 'text',
      label: 'Twitter Handle',
      placeholder: '@yoursite'
    },
    {
      key: 'robotsTxt',
      type: 'textarea',
      label: 'Custom robots.txt',
      rows: 10
    }
  ],
  
  // Called when settings are saved
  onSave: async (values) => {
    // Validate or transform values
    return values;
  }
});

Field Types

TypeDescriptionOptions
textSingle line inputplaceholder, maxLength
textareaMulti-line textrows, maxLength
numberNumeric inputmin, max, step
booleanToggle switch-
selectDropdownoptions
multiselectMultiple selectoptions
colorColor picker-
imageImage upload-
codeCode editorlanguage
jsonJSON editor-

Dashboard Widgets

sdk.admin.registerDashboardWidget(id, config)

Add a widget to the admin dashboard home.

sdk.admin.registerDashboardWidget('quick-stats', {
  title: 'Quick Stats',
  size: 'medium', // 'small', 'medium', 'large', 'full'
  
  render: async () => {
    const posts = await sdk.content.countPosts();
    const categories = await sdk.content.countCategories();
    
    return `
      <div class="quick-stats">
        <div class="stat">
          <span class="stat-label">Posts</span>
          <span class="stat-value">${posts}</span>
        </div>
        <div class="stat">
          <span class="stat-label">Categories</span>
          <span class="stat-value">${categories}</span>
        </div>
      </div>
    `;
  },
  
  // Optional: refresh interval in seconds
  refreshInterval: 60
});

Activity Feed Widget

sdk.admin.registerDashboardWidget('activity-feed', {
  title: 'Recent Activity',
  size: 'large',
  
  render: async () => {
    const activities = await sdk.storage.get('recent_activities') || [];
    
    let html = '<ul class="activity-feed">';
    
    activities.slice(0, 10).forEach(activity => {
      html += `
        <li class="activity-item">
          <span class="activity-icon">${activity.icon}</span>
          <span class="activity-text">${activity.text}</span>
          <time class="activity-time">${sdk.utils.timeAgo(activity.timestamp)}</time>
        </li>
      `;
    });
    
    html += '</ul>';
    return html;
  }
});

Admin Menu

sdk.admin.addMenuItem(config)

Add an item to the admin sidebar menu.

sdk.admin.addMenuItem({
  id: 'my-plugin-menu',
  label: 'My Plugin',
  icon: '🔧',
  href: '/admin/my-plugin',
  position: 50, // Lower = higher in menu
  
  // Optional: sub-menu items
  children: [
    { id: 'settings', label: 'Settings', href: '/admin/my-plugin/settings' },
    { id: 'reports', label: 'Reports', href: '/admin/my-plugin/reports' }
  ]
});

Admin Notices

sdk.admin.addNotice(config)

Display a notice in the admin area.

// Info notice
sdk.admin.addNotice({
  type: 'info',
  message: 'New features available! Check the changelog.',
  dismissible: true
});
 
// Warning notice
sdk.admin.addNotice({
  type: 'warning',
  message: 'Your license expires in 7 days.',
  dismissible: false
});
 
// Error notice
sdk.admin.addNotice({
  type: 'error',
  message: 'Failed to connect to external service.',
  dismissible: true
});
 
// Success notice
sdk.admin.addNotice({
  type: 'success',
  message: 'All changes saved successfully!',
  dismissible: true,
  timeout: 5000 // Auto-dismiss after 5 seconds
});

Content Type Customization

sdk.admin.extendPostEditor(config)

Add fields to the post editor.

sdk.admin.extendPostEditor({
  section: 'sidebar', // 'main', 'sidebar', 'bottom'
  
  render: (post) => {
    return `
      <div class="custom-fields-panel">
        <h4>Custom Fields</h4>
        
        <div class="field">
          <label>Reading Time (minutes)</label>
          <input type="number" name="customFields.readTime" value="${post?.customFields?.readTime || ''}">
        </div>
        
        <div class="field">
          <label>Sponsored Content</label>
          <input type="checkbox" name="customFields.sponsored" ${post?.customFields?.sponsored ? 'checked' : ''}>
        </div>
      </div>
    `;
  },
  
  // Validate/transform before save
  onSave: async (post, formData) => {
    post.customFields = post.customFields || {};
    post.customFields.readTime = parseInt(formData.get('customFields.readTime')) || null;
    post.customFields.sponsored = formData.get('customFields.sponsored') === 'on';
    return post;
  }
});

Admin Actions

sdk.admin.registerAction(name, handler)

Register a custom admin action.

sdk.admin.registerAction('export-posts', async (params, context) => {
  const posts = await sdk.content.getPosts({ limit: 1000 });
  
  // Generate export
  const csv = generateCSV(posts.items);
  
  return {
    success: true,
    download: {
      filename: 'posts-export.csv',
      content: csv,
      contentType: 'text/csv'
    }
  };
});
 
// Can be triggered from admin UI or via API
// POST /api/admin/actions/export-posts

Example: Complete Plugin Admin

module.exports = async function(sdk) {
  
  // Add menu item
  sdk.admin.addMenuItem({
    id: 'newsletter',
    label: 'Newsletter',
    icon: '📧',
    href: '/admin/newsletter',
    children: [
      { id: 'subscribers', label: 'Subscribers', href: '/admin/newsletter/subscribers' },
      { id: 'campaigns', label: 'Campaigns', href: '/admin/newsletter/campaigns' },
      { id: 'settings', label: 'Settings', href: '/admin/newsletter/settings' }
    ]
  });
  
  // Main page
  sdk.admin.registerPage('newsletter', {
    title: 'Newsletter Dashboard',
    icon: '📧',
    render: async () => {
      const subscribers = await sdk.storage.get('newsletter_subscribers') || [];
      const campaigns = await sdk.storage.get('newsletter_campaigns') || [];
      
      return `
        <div class="newsletter-dashboard">
          <h1>Newsletter</h1>
          <div class="stats-row">
            <div class="stat-card">
              <h3>Subscribers</h3>
              <span>${subscribers.length}</span>
            </div>
            <div class="stat-card">
              <h3>Campaigns</h3>
              <span>${campaigns.length}</span>
            </div>
          </div>
        </div>
      `;
    }
  });
  
  // Subscribers page
  sdk.admin.registerPage('newsletter/subscribers', {
    title: 'Subscribers',
    render: async () => {
      const subscribers = await sdk.storage.get('newsletter_subscribers') || [];
      
      let html = `
        <h1>Subscribers</h1>
        <table class="admin-table">
          <thead>
            <tr>
              <th>Email</th>
              <th>Subscribed</th>
              <th>Actions</th>
            </tr>
          </thead>
          <tbody>
      `;
      
      subscribers.forEach(sub => {
        html += `
          <tr>
            <td>${sub.email}</td>
            <td>${sdk.utils.formatDate(sub.subscribedAt)}</td>
            <td>
              <button onclick="removeSubscriber('${sub.email}')">Remove</button>
            </td>
          </tr>
        `;
      });
      
      html += '</tbody></table>';
      return html;
    }
  });
  
  // Settings
  sdk.admin.registerSettings('newsletter-settings', {
    title: 'Newsletter Settings',
    fields: [
      { key: 'fromName', type: 'text', label: 'From Name' },
      { key: 'fromEmail', type: 'text', label: 'From Email' },
      { key: 'confirmationSubject', type: 'text', label: 'Confirmation Email Subject' },
      { key: 'confirmationBody', type: 'textarea', label: 'Confirmation Email Body' }
    ]
  });
  
  // Dashboard widget
  sdk.admin.registerDashboardWidget('newsletter-stats', {
    title: 'Newsletter',
    size: 'small',
    render: async () => {
      const subscribers = await sdk.storage.get('newsletter_subscribers') || [];
      return `<p><strong>${subscribers.length}</strong> subscribers</p>`;
    }
  });
  
  return {};
};