A comprehensive example demonstrating all major plugin interfaces available in the Open edX platform. This repository shows how to extend Open edX functionality without modifying core platform code.
- What This Repository Demonstrates
- Plugin Types & Official Documentation
- Quick Start Guide
- Learning Path for New Plugin Developers
- Repository Structure
- Development Workflows
- Integration Examples
- Troubleshooting
- Additional Resources
This sample plugin showcases the Open edX Hooks Extension Framework, which allows you to extend the platform in a stable and maintainable way. The framework provides two main types of hooks:
- Events: React to things happening in the platform (e.g., when a course is published)
- Filters: Modify platform behavior (e.g., change where course about pages redirect)
Key Concept: All extensions are implemented as standard Django plugins that integrate seamlessly with edx-platform.
Official Documentation: Hooks Extension Framework Overview
Plugin Type | What It Does | Official Documentation | Sample Code | When To Use |
---|---|---|---|---|
Django App Plugin | Add models, APIs, views, and business logic | How to create a plugin app | backend/ |
Adding new functionality, APIs, or data models |
Events (Signals) | React to platform events | Open edX Events Guide | backend/sample_plugin/signals.py |
Integrating with external systems, audit logging |
Filters | Modify platform behavior | Using Open edX Filters | backend/sample_plugin/pipeline.py |
Customizing business logic, URL redirects |
Frontend Slots | Customize MFE interfaces | Frontend Plugin Slots | frontend/ |
UI customization, adding new components |
Tutor Plugin | Deploy plugins easily | Tutor Plugin Development | tutor/ |
Simplified deployment and configuration |
- Platform Setup: Follow the Open edX Development Setup
- Understanding: Read the Platform Overview
# Backend Plugin Setup
tutor mounts add lms:$PWD/backend:/openedx/sample-plugin-backend
tutor dev launch
tutor dev exec lms pip install -e ../sample-plugin-backend
tutor dev exec lms python manage.py lms migrate
tutor dev restart lms
# Frontend Plugin Setup (for learner-dashboard MFE development)
npm install $PWD/frontend
# Add env.config.jsx and module.config.js (see frontend/README.md)
npm start
# In your edx-platform directory
pip install -e /path/to/sample-plugin/backend
# Enable Learner Dashboard MFE
# Go to http://localhost:18000/admin/waffle/flag/
# Create flag: learner_home_mfe.enabled = Yes
# Run migrations
python manage.py lms migrate
- Backend: Visit
http://localhost:18000/sample-plugin/api/v1/course-archive-status/
- Frontend: Check learner dashboard for archive/unarchive functionality
- Events: Check logs for course catalog change events
- Filters: Course about page URLs should redirect to example.com
- Start here: Hooks Extension Framework
- Deep dive: OEP-50: Hooks Extension Framework
Use the table above to identify which type of plugin matches your needs. You can combine multiple types in one plugin.
- Backend: Start with
backend/sample_plugin/apps.py
to understand plugin registration - Events: Examine
backend/sample_plugin/signals.py
for event handling patterns - Filters: Review
backend/sample_plugin/pipeline.py
for behavior modification - Frontend: Explore
frontend/src/plugin.jsx
for UI customization
Follow the Quick Start Guide to see everything working together.
Each directory contains detailed README.md files with adaptation guidance.
sample-plugin/
├── README.md # This file - overview and quick start
├── backend/
│ ├── README.md # Backend plugin detailed guide
│ ├── sample_plugin/
│ │ ├── apps.py # Django plugin configuration
│ │ ├── models.py # Database models example
│ │ ├── views.py # REST API endpoints
│ │ ├── signals.py # Event handlers (Open edX Events)
│ │ ├── pipeline.py # Filter implementations (Open edX Filters)
│ │ ├── settings/ # Plugin settings configuration
│ │ └── urls.py # URL routing
│ └── tests/ # Comprehensive test examples
├── frontend/
│ ├── README.md # Frontend plugin detailed guide
│ ├── src/
│ │ ├── plugin.jsx # React component for MFE slot
│ │ └── index.jsx # Export configuration
│ └── package.json # NPM package configuration
└── tutor/
├── README.md # Tutor deployment guide
└── sample_plugin.py # Tutor plugin configuration
- Setup: Follow backend setup in Quick Start
- Development:
- Modify models in
models.py
- Add API endpoints in
views.py
- Implement event handlers in
signals.py
- Create filters in
pipeline.py
- Modify models in
- Testing:
cd backend && make test
- Quality:
cd backend && make quality
Detailed Guide: See backend/README.md
- Setup: Follow frontend setup in Quick Start
- Development:
- Modify React components in
frontend/src/
- Test with local MFE development server
- Modify React components in
- Testing: Integration testing with MFE
Detailed Guide: See frontend/README.md
This sample shows how backend and frontend plugins work together:
- Backend provides API endpoints for course archive status
- Frontend consumes these APIs to show archive/unarchive UI
- Events log when course information changes
- Filters modify course about page URLs
# backend/sample_plugin/views.py - Provides API
class CourseArchiveStatusViewSet(viewsets.ModelViewSet):
# API implementation
// frontend/src/plugin.jsx - Consumes API
const response = await client.get(
`${lmsBaseUrl}/sample-plugin/api/v1/course-archive-status/`
);
# Events: Log course changes
@receiver(COURSE_CATALOG_INFO_CHANGED)
def log_course_info_changed(signal, sender, catalog_info, **kwargs):
logging.info(f"{catalog_info.course_key} has been updated!")
# Filters: Modify course about URLs
class ChangeCourseAboutPageUrl(PipelineStep):
def run_filter(self, url, org, **kwargs):
# Custom URL logic
Plugin not loading:
- Verify
setup.py
entry points are correct - Check that plugin app is in INSTALLED_APPS (should be automatic)
- Review Django app plugin configuration in
apps.py
Events not firing:
- Confirm signal receivers are imported in
apps.py
ready() method - Check event is being sent by platform (some events only fire in specific contexts)
- Verify event data structure matches your handler signature
Filters not working:
- Ensure filter is registered in Django settings
- Check that filter step class inherits from
PipelineStep
- Verify
run_filter
method returns correct dictionary format
Frontend plugin not appearing:
- Check MFE slot configuration in
env.config.jsx
- Verify plugin is installed (
npm install
) - Ensure slot exists in target MFE (check MFE documentation)
- Documentation: Start with official docs linked in the Plugin Types table
- Community: Open edX Community Slack
- Forums: Open edX Discuss Forums
- Issues: Create issues in this repository for sample-specific problems
- Platform: Open edX Developer Documentation
- Architecture: OEP-49: Django App Patterns
- Events: Open edX Events Reference
- Filters: Open edX Filters Reference
- Frontend: Available Frontend Plugin Slots
- Cookiecutter: Django App Template for creating new plugins
- Examples: Other Open edX plugins in the openedx organization
- Best Practices: OEP Index for architectural guidance
- Working Integration: Complete example showing all plugin types working together
- Real Business Logic: Realistic course archiving functionality vs. hello-world examples
- Development Workflow: End-to-end development and testing process
- Troubleshooting: Common plugin development issues and solutions