Skip to main content

Django Blog Plus

Enhanced features for 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

pip install django-blog-plus

Quick Start

  1. Add to your INSTALLED_APPS:
INSTALLED_APPS = [
    # ...
    'smart_media',
    'ckeditor',
    'ckeditor_uploader',
    'lotus',  # django-blog-lotus
    'django_blog_plus',
    # ...
]
  1. Configure settings (optional):
#############################################################
# 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"],
        ],
    },
}
  1. Add URL patterns:
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')),
    # ...
]
  1. Run migrations:
python manage.py migrate django_blog_plus
  1. Add context processor (for blog categories in templates):
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

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

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

{% 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

# 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 for the full changelog.

License

This project is licensed under the MIT License - see the LICENSE file for details.

Contributing

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

Metadata

Release files for django-blog-plus 1.0.13

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for django-blog-plus 1.0.13
File Size Uploaded Provenance Actions
django_blog_plus-1.0.13.tar.gz 83.9 kB Without provenance Details for django_blog_plus-1.0.13.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for django-blog-plus 1.0.13
File Interpreter ABI Platform Actions
django_blog_plus-1.0.13-py3-none-any.whl Python 3 none any Details for django_blog_plus-1.0.13-py3-none-any.whl

Total release size: 179.2 kB

Release files / django_blog_plus-1.0.13.tar.gz

Download URL django_blog_plus-1.0.13.tar.gz
Size 83.9 kB
Tags Source
SHA-256 checksum
How to use checksums
957f6cbe3b0ffda06e5fa9f785e559926e5b8641677f8cbf6d95250eb3e02173
BLAKE2b-256 checksum
How to use checksums
cfa451c326d24db0af4b178ac967c4a150a90554c57d28f7a4c04b87dddc6885
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.10.11

Release files / django_blog_plus-1.0.13-py3-none-any.whl

Download URL django_blog_plus-1.0.13-py3-none-any.whl
Size 95.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
601583444bbd9d48394b71fd53124378cba003401ec620bf6ffa6b92f2cadf50
BLAKE2b-256 checksum
How to use checksums
643da6876549d2996acca44b32da53017f575b90574420e2d4a5d68f5d91fbe7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.10.11

Security for django-blog-plus 1.0.13

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page