django-blog-plus 1.0.11
Enhanced features for django-blog-lotus: CTAs, cover styling, webhooks, and more
Requires Python: >=3.10
Keywords: django, blog, lotus, cms, cta, webhook

# Django Blog Plus

Enhanced features for [django-blog-lotus](https://github.com/emencia/django-blog-lotus), providing additional functionality for professional blogging.

## Features

- **Call to Action (CTA) Blocks**: Create reusable CTA components and assign them to articles
- **Article Cover Styling**: Customize cover image backgrounds with preset or custom colors
- **View Tracking**: Track article views for popular/trending widgets
- **Webhook API**: Create and update articles programmatically via REST API
- **Scheduled Publishing**: Automatically publish draft articles at scheduled times
- **RSS/Atom Feeds**: Full syndication support with category feeds
- **SEO Enhancements**: Sitemaps, reading time, heading optimization
- **Premium Templates**: Modern, responsive blog templates

## Installation

```bash
pip install django-blog-plus
```

## Quick Start

1. Add to your `INSTALLED_APPS`:

```python
INSTALLED_APPS = [
    # ...
    'smart_media',
    'ckeditor',
    'ckeditor_uploader',
    'lotus',  # django-blog-lotus
    'django_blog_plus',
    # ...
]
```

2. Configure settings (optional):

```python
#############################################################
# Smart Media (required by django-blog-lotus)
#############################################################
from smart_media.settings import *  # noqa: E402,F401,F403

#############################################################
# Lotus (django-blog-lotus)
#############################################################
from lotus.settings import *  # noqa: E402,F401,F403

SITE_ID = 1  # Required by django.contrib.sites (used by lotus)

#############################################################
# Django Blog Plus
#############################################################
DJANGO_BLOG_PLUS = {
    'SITE_NAME': 'My Blog',
    'SITE_DESCRIPTION': 'A blog about interesting things',
    'WEBHOOK_SECRET': 'your-secret-key',
    'ARTICLE_PUBLISHED_WEBHOOK_URL': '',  # Optional Zapier/n8n webhook
    'BASE_TEMPLATE': 'base.html',  # Your project's base template
    'DEFAULT_COVER_BG_COLOR': '#f8f9fa',
}

#############################################################
# CKEditor configuration
#############################################################
CKEDITOR_UPLOAD_PATH = "uploads/"
CKEDITOR_ALLOW_NONIMAGE_FILES = False
CKEDITOR_RESTRICT_BY_DATE = False
CKEDITOR_IMAGE_BACKEND = "ckeditor_uploader.backends.PillowBackend"
CKEDITOR_BROWSE_SHOW_DIRS = True

# Suppress CKEditor deprecation warning (known issue, upgrade to CKEditor 5 planned)
SILENCED_SYSTEM_CHECKS = ['ckeditor.W001']

CKEDITOR_CONFIGS = {
    "lotus": {
        "width": "100%",
        "height": 400,
        "language": "{{ language }}",
        "skin": "moono-lisa",
        "startupOutlineBlocks": True,
        "extraPlugins": "image2",
        "image_previewText": True,
        "removePlugins": "stylesheetparser",
        "allowedContent": True,
        "toolbar": "Default",
        "toolbar_Default": [
            ["Undo", "Redo"],
            ["ShowBlocks"],
            ["Format", "Styles"],
            ["RemoveFormat"],
            "/",
            ["Bold", "Italic", "Underline", "-", "Subscript", "Superscript"],
            ["JustifyLeft", "JustifyCenter", "JustifyRight"],
            ["TextColor"],
            ["Link", "Unlink"],
            ["Image", "-", "NumberedList", "BulletedList", "-", "Table", "-", "CreateDiv", "HorizontalRule"],
            ["Source"],
        ],
    },
}
```

3. Add URL patterns:

```python
from django.urls import path, include

urlpatterns = [
    # ...
    # CKEditor for rich text editing in blog
    path('ckeditor/', include('ckeditor_uploader.urls')),
    # Blog
    path('blog/', include('lotus.urls')),
    path('api/blog/', include('django_blog_plus.urls')),
    # ...
]
```

4. Run migrations:

```bash
python manage.py migrate django_blog_plus
```

5. Add context processor (for blog categories in templates):

```python
TEMPLATES = [
    {
        # ...
        'OPTIONS': {
            'context_processors': [
                # ...
                'django_blog_plus.context_processors.blog_categories',
                'django_blog_plus.context_processors.django_blog_plus_config',
            ],
        },
    },
]
```

## Configuration Reference

| Setting | Default | Description |
| ------- | ------- | ----------- |
| `SITE_NAME` | `'Blog'` | Site name for RSS feeds |
| `SITE_DESCRIPTION` | `''` | Site description for RSS feeds |
| `WEBHOOK_SECRET` | `None` | Bearer token for webhook API authentication |
| `ARTICLE_PUBLISHED_WEBHOOK_URL` | `''` | URL to call when articles are published |
| `BASE_TEMPLATE` | `'base.html'` | Base template that blog templates extend |
| `DEFAULT_COVER_BG_COLOR` | `'#f8f9fa'` | Default background color for article covers |
| `COVER_BG_COLORS` | (preset list) | Available background color choices |

When the context processor `django_blog_plus.context_processors.django_blog_plus_config` is enabled, these options are available in templates as `django_blog_plus_*` context variables: `django_blog_plus_site_name`, `django_blog_plus_site_description`, `django_blog_plus_base_template`, `django_blog_plus_primary_color`, `django_blog_plus_default_cover_bg_color`, `django_blog_plus_cover_bg_colors`, `django_blog_plus_language_code`. Sensitive options (`WEBHOOK_SECRET`, `ARTICLE_PUBLISHED_WEBHOOK_URL`) are not exposed in context.

## Webhook API

### Create Article

```bash
curl -X POST https://yoursite.com/api/blog/webhook/ \
  -H "Authorization: Bearer YOUR_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "My Article",
    "content": "<h2>Hello</h2><p>World</p>",
    "category_slug": "news",
    "status": "published"
  }'
```

### Update Article

```bash
curl -X PATCH https://yoursite.com/api/blog/webhook/update/ \
  -H "Authorization: Bearer YOUR_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
    "article_url": "/blog/2024/01/15/my-article/",
    "title": "Updated Title"
  }'
```

See `/api/blog/webhook/info/` for full API documentation.

## Template Tags

```django
{% load django_blog_plus %}

{# Reading time #}
{% reading_time article.content %} min read

{# Previous/Next navigation #}
{% get_adjacent_articles article as nav %}
{% if nav.previous %}Previous: {{ nav.previous.title }}{% endif %}

{# Article CTA #}
{% get_article_cta article.id as cta %}
{% if cta %}{{ cta.title }}{% endif %}

{# Popular articles #}
{% get_popular_articles 5 as popular %}

{# Cover background color #}
{{ article|article_cover_bg }}
```

## Management Commands

```bash
# Publish scheduled articles (run via cron)
python manage.py publish_scheduled_articles

# Clean up placeholder images
python manage.py remove_blog_placeholder_images --dry-run
```

## Changelog

See [CHANGELOG.md](CHANGELOG.md) for the full changelog.

## License

This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.

## Contributing

Contributions are welcome! Please open an issue or pull request on GitHub.