=====================================
Tutorial: Creating a Simple Plugin
=====================================
.. admonition:: What you'll learn
In this tutorial, you'll learn how to create a simple custom plugin for django-resume
in your own Django project. We'll build a "Motto" plugin that displays
an inspirational quote or personal motto on a resume.
.. admonition:: Prerequisites
- Basic understanding of Django forms and templates
- Familiarity with Python classes and inheritance
- A Django project with django-resume installed as a third-party package
.. admonition:: Working Example Available
A complete motto plugin implementation is already included in the django-resume
example project. To see it in action, enable example plugins in your settings:
.. code-block:: python
# settings.py
DJANGO_RESUME_ENABLE_EXAMPLE_PLUGINS = True
Then restart your server to see the motto and certifications plugins.
Overview
========
Simple plugins in django-resume are Python classes that define how specific sections
of a resume are displayed and edited. Each plugin handles its own data,
provides a single form for editing, and renders content using templates.
Custom plugins are defined as normal Python modules in your project and use
template files stored on disk. django-resume no longer supports creating
plugins from database rows.
In this tutorial, we'll create a plugin to display a personal motto or inspirational
quote, including the quote text and an optional attribution.
Step 1: Understanding Simple vs List Plugins
============================================
django-resume provides two base plugin types:
- **SimplePlugin**: For plugins with a single form and straightforward data structure (like "About", "Contact Info", or personal mottos)
- **ListPlugin**: For plugins that manage lists of items (like multiple projects, certifications, or jobs)
Since a motto is typically a single piece of content, we'll use ``SimplePlugin`` as our base.
Step 2: Create the Plugin Module
================================
Create a new Django app or module in your project for custom plugins:
.. code-block:: bash
# If you don't have a plugins app yet, create one
python manage.py startapp plugins
# Or create a simple module directory
mkdir myproject/plugins
touch myproject/plugins/__init__.py
touch myproject/plugins/motto.py
For this tutorial, we'll assume you have a ``plugins`` app or module in your project.
The plugin code lives in your repository, not in the database.
Step 3: Define the Form
=======================
First, let's create a form to define what data our plugin will collect:
.. code-block:: python
# myproject/plugins/motto.py (or plugins/motto.py)
from django import forms
from django_resume.plugins.base import SimplePlugin
class MottoForm(forms.Form):
"""Form for the motto plugin."""
title = forms.CharField(
label="Section Title",
max_length=100,
initial="My Motto",
help_text="The heading for this section"
)
quote = forms.CharField(
label="Motto/Quote",
max_length=500,
widget=forms.Textarea(attrs={'rows': 3}),
initial="Stay curious, stay humble, keep learning.",
help_text="Your personal motto or favorite inspirational quote"
)
attribution = forms.CharField(
label="Attribution",
max_length=200,
required=False,
help_text="Author of the quote (optional)"
)
Step 4: Implement the Plugin Class
==================================
Now let's create the main plugin class:
.. code-block:: python
class MottoPlugin(SimplePlugin):
name: str = "motto"
verbose_name: str = "Personal Motto"
admin_form_class = inline_form_class = MottoForm
# AI prompt for LLM-based content generation
prompt = """
Create a django-resume plugin to display a personal motto or inspirational quote.
The plugin should include the quote text and an optional attribution.
The plugin should display the motto prominently with clean typography
and allow users to edit the content inline. Keep the design simple
and elegant.
"""
That's it! Simple plugins require much less code than list plugins because:
- No need for position management
- No need for individual item forms
- No need for complex context setup
- Single form handles all the data
Step 5: Create Templates
========================
Create the template directory structure for your plugin in your project:
.. code-block:: bash
# Create templates in your project's template directory
mkdir -p templates/django_resume/plugins/motto/plain
Now create the content template:
.. code-block:: html
{% if show_edit_button %}
Create the form template:
.. code-block:: html
Step 6: Register Your Plugin
=============================
Register your custom plugin in your Django app. Choose the method that best fits your project structure.
**Option A: Register in Django App Config (Recommended)**
If you created a ``plugins`` app, register your plugin in its ``apps.py``:
.. code-block:: python
# plugins/apps.py
from django.apps import AppConfig
class PluginsConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'plugins'
def ready(self):
# Import and register your custom plugins
from django_resume.plugins import plugin_registry
from .motto import MottoPlugin
plugin_registry.register(MottoPlugin)
Make sure your ``plugins`` app is added to ``INSTALLED_APPS`` in your ``settings.py``:
.. code-block:: python
# settings.py
INSTALLED_APPS = [
# ... other apps ...
'django_resume',
'plugins', # Your custom plugins app
]
**Option B: Register in Your Main App's Ready Method**
.. code-block:: python
# myproject/apps.py
from django.apps import AppConfig
class MyprojectConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'myproject'
def ready(self):
from django_resume.plugins import plugin_registry
from .plugins.motto import MottoPlugin
plugin_registry.register(MottoPlugin)
Step 7: Add Plugin to Resume Template
=====================================
**Important:** Simple plugins work differently than list plugins regarding template inclusion.
**For CV Templates (Recommended)**
The CV page (``CvPage``) loads ALL registered plugins automatically (its ``section_names`` is ``"__all__"``), so their context is available to ``resume_cv.html``. Simply add your plugin to the CV template:
.. code-block:: html
{% include motto.templates.main %}
**For Detail Templates**
The detail page (``CoverLetterPage``) only loads the plugins listed in its ``section_names``: ``["about", "identity", "cover", "theme"]``. Your custom plugin will NOT appear automatically.
**Template Context Variables**
Your plugin data will be available in templates under the plugin name:
.. code-block:: html
{{ motto.title }}
{{ motto.quote }}
{{ motto.attribution }}
{{ motto.edit_url }}
{{ motto.templates.main }}
Step 8: Test Your Plugin
========================
Start your development server and test the plugin:
.. code-block:: bash
python manage.py runserver
Navigate to your resume and you should see the new Motto section.
Test both the admin interface and inline editing functionality.
Step 9: Add Styling (Optional)
==============================
Add CSS to style your plugin by creating styles in your project's CSS files:
.. code-block:: css
/* Example styling using django-resume design system */
#motto .motto-quote {
font-style: italic;
margin: var(--s0) 0;
padding: var(--s0);
border-left: var(--border-thin) solid var(--color-brightblue);
background-color: var(--color-ultralightgrey);
border-radius: var(--s-4);
}
#motto .motto-quote p {
margin: 0 0 var(--s-1) 0;
font-weight: 300;
line-height: 1.4;
}
#motto .motto-quote cite {
font-size: var(--s-1);
color: var(--color-middlegrey);
font-style: normal;
display: block;
text-align: right;
}
**Use Design System Variables**
django-resume includes a comprehensive CSS design system with variables for spacing, colors, and typography. Use these variables instead of hardcoded values for consistency:
- Spacing: ``var(--s-2)``, ``var(--s-1)``, ``var(--s0)``, ``var(--s1)``, ``var(--s2)``
- Colors: ``var(--color-brightblue)``, ``var(--color-middlegrey)``, ``var(--color-ultralightgrey)``
- Borders: ``var(--border-thin)``, ``var(--border-color)``
Key Differences from List Plugins
=================================
Simple plugins are much easier to create because they:
**Don't need:**
- Position management (``set_initial_position``, ``get_max_position``)
- Item-specific context setup (``set_context`` method)
- Multiple form classes (just one form handles everything)
- Complex template structure with separate item templates
**Do need:**
- Single form class that extends ``forms.Form``
- Plugin class that extends ``SimplePlugin``
- Two templates: ``content.html`` and ``form.html``
- Registration in Django app config
**Template Access:**
- Data is accessed directly via plugin name: ``{{ motto.title }}``
- Edit URL is available as ``{{ motto.edit_url }}``
- Show edit button via ``{{ show_edit_button }}``
Next Steps
==========
Congratulations! You've created a simple custom plugin. Here are some ways to extend it:
1. **Add validation**: Ensure quote isn't too long for good display
2. **Add formatting**: Support for italic/bold text in quotes
3. **Add categories**: Different types of quotes (professional, personal, etc.)
4. **Add multiple quotes**: Convert to a list plugin for multiple mottos
For more complex plugins with lists of items, see:
- :doc:`creating_list_plugins` - Tutorial for list-based plugins
- :doc:`../ref/plugins` - Complete plugin API reference
- :doc:`../ref/simple_plugin` - SimplePlugin-specific documentation
Troubleshooting
===============
**Plugin not appearing in templates**
1. Check plugin registration in ``apps.py`` and restart your server
2. Verify you're using the CV template (``resume_cv.html``) which loads all plugins
3. If using the detail page, your plugin won't appear unless it is added to ``CoverLetterPage.section_names``
4. Test plugin registration in Django shell: ``from django_resume.plugins import plugin_registry; print(plugin_registry.get_plugin('motto'))``
**Templates not found**
Check that your template directory structure matches the expected pattern:
``templates/django_resume/plugins/{plugin_name}/plain/content.html`` and ``form.html``
**Context variables not working**
1. Ensure you're accessing data with the plugin name: ``{{ motto.title }}`` not ``{{ title }}``
2. Verify plugin is properly registered and appears in context debug output
3. Check that you're using the correct template (CV template loads all plugins automatically)
**Edit button not working**
1. Verify HTMX attributes use specific targets: ``hx-target="#motto"`` not ``hx-target="closest section"``
2. Check that ``{{ motto.edit_url }}`` is not empty
3. Ensure CSRF token is properly configured in the page header
**Styling issues**
1. Use django-resume CSS design system variables for consistency
2. Include your custom CSS in the template using ``{% load static %}`` and ```` tags
3. Check browser dev tools for CSS conflicts or missing styles