PPress 插件开发指南

1. 插件目录结构
-------------
必需文件:
plugins/installed/plugin_name/
├── plugin.json         # 插件配置文件
├── __init__.py        # 插件主类文件
├── static/            # 静态资源目录
│   ├── css/          # CSS文件
│   ├── js/           # JavaScript文件
│   └── images/       # 图片资源
├── templates/         # 模板文件目录
└── README.md         # 插件说明文档

 

2. plugin.json 配置说明
--------------------
{
    "name": "插件名称",
    "description": "插件描述",
    "version": "版本号",
    "author": "作者",
    "author_url": "作者主页",
    "plugin_class": "Plugin",  # 插件主类名称
    "enabled": true           # 是否默认启用
}

 

3. 插件主类开发
-------------
```python
from app.plugins import PluginBase

 

class Plugin(PluginBase):
    # 默认设置
    default_settings = {
        'setting_key': 'default_value'
    }
   
    def __init__(self):
        super().__init__()
       
        # 注册路由
        @self.route('/plugin/my_plugin/api', methods=['GET'])
        def my_api():
            return jsonify({'status': 'ok'})
           
    def init_app(self, app):
        """初始化插件"""
        super().init_app(app)
       
        # 注册模板函数
        app.jinja_env.globals['my_function'] = self.my_function
       
    def get_settings_template(self):
        """获取设置页面模板"""
        return self.render_template('settings.html')
       
    def save_settings(self, form_data):
        """保存插件设置"""
        try:
            settings = {
                'key': form_data.get('key')
            }
            self.update_settings(settings)
            return True, '保存成功'
        except Exception as e:
            return False, str(e)
```

 

4. 模板开发
---------
settings.html 示例:
```html
<form class="space-y-8">
    <div class="bg-white rounded-lg shadow-sm p-6">
        <h3 class="text-lg font-medium">插件设置</h3>
        <div class="space-y-4">
            <inputtype="text" name="key"
                   value="{{ settings.key }}"
                   class="form-input">
        </div>
    </div>
</form>
```

 

5. 静态资源
---------
```javascript
// static/js/plugin.js
function initPlugin() {
    // 插件初始化代码
}

 

// 注册到全局
window.myPlugin = {
    init: initPlugin
}
```

 

6. 插件功能实现
------------
1. 路由注册:
```python
@self.route('/plugin/name/path', methods=['GET'])
def handler():
    return 'ok'
```

 

2. 模板函数:
```python
def my_template_function():
    return 'result'
   
app.jinja_env.globals['func_name'] = my_template_function
```

 

3. 数据库操作:
```python
from app import db
from app.models import Article

 

def get_data():
    return Article.query.all()
```

 

4. 缓存使用:
```python
from app.utils.cache_manager import cache_manager

 

@cache_manager.cached(key='my_cache_key', ttl=3600)
def cached_function():
    return expensive_operation()
```

 

7. 插件通信机制
------------
1. 事件监听:
```python
@self.on_event('article.created')
def handle_article_created(article):
    # 处理文章创建事件
    pass
```

 

2. 信号处理:
```python
from blinker import signal

 

# 定义信号
my_signal = signal('my-signal')

 

# 监听信号
@my_signal.connect
def handle_signal(sender, **kwargs):
    pass
```

 

8. 最佳实践
---------
1. 性能优化
- 合理使用缓存
- 避免重复查询
- 异步处理耗时操作

 

2. 安全考虑
- 验证用户权限
- 过滤用户输入
- 防止XSS攻击
- 使用CSRF保护

 

3. 代码规范
- 遵循PEP8规范
- 添加适当注释
- 错误处理完善
- 日志记录关键信息

 

4. 兼容性
- 考虑不同Python版本
- 考虑不同数据库
- 考虑不同操作系统

 

9. 示例插件
---------
1. 文章推荐插件:
```python
class ArticleRecommender(PluginBase):
    def get_recommendations(self, article_id):
        # 基于标签和分类推荐相关文章
        article = Article.query.get(article_id)
        return Article.query.filter(
            Article.category_id == article.category_id,
            Article.id != article_id
        ).limit(3).all()
```

 

2. 编辑器插件:
```python
class TinyMCEEditor(PluginBase):
    def init_app(self, app):
        # 注册编辑器资源
        app.jinja_env.globals['editor_css'] = self.get_css()
        app.jinja_env.globals['editor_js'] = self.get_js()
```

 

10. 注意事项
----------
1. 插件命名规范
- 使用小写字母
- 下划线分隔单词
- 避免与系统冲突

 

2. 资源管理
- 合理组织静态文件
- 及时清理临时文件
- 注意资源释放

 

3. 错误处理
- 优雅处理异常
- 提供友好提示
- 记录错误日志

 

4. 版本控制
- 语义化版本号
- 向下兼容
- 更新日志完整

 

11. 插件生命周期
------------
1. 初始化阶段:
```python
def init_app(self, app):
    """插件初始化时调用"""
    super().init_app(app)
    # 初始化数据库
    self.init_db()
    # 注册路由
    self.register_routes()
    # 注册模板函数
    self.register_template_functions()
```

 

2. 启用/禁用:
```python
def enable(self):
    """插件启用时调用"""
    # 创建数据表
    self.create_tables()
    # 初始化数据
    self.init_data()

 

def disable(self):
    """插件禁用时调用"""
    # 清理数据
    self.cleanup()
```

 

3. 卸载:
```python
def uninstall(self):
    """插件卸载时调用"""
    # 删除数据表
    self.drop_tables()
    # 删除配置
    self.remove_settings()
    # 清理文件
    self.cleanup_files()
```

 

12. 插件依赖管理:

 

1. 声明依赖:
```json
{
    "name": "my_plugin",
    "dependencies": {
        "required": ["plugin_a", "plugin_b>=1.0.0"],
        "optional": ["plugin_c"]
    }
}
```

 

2. 依赖检查:
```python
def check_dependencies(self):
    """检查依赖是否满足"""
    for plugin_name in self.dependencies['required']:
        if not self.is_plugin_enabled(plugin_name):
            raise DependencyError(f"依赖插件 {plugin_name} 未启用")
```

 

3. 版本兼容:
```python
def check_compatibility(self):
    """检查版本兼容性"""
    if not self.is_compatible_with_app():
        raise CompatibilityError("插件与当前应用版本不兼容")
```

 

13. 配置管理:

 

1. 配置定义:
```python
class PluginConfig:
    """插件配置定义"""
    PLUGIN_NAME = 'my_plugin'
    PLUGIN_VERSION = '1.0.0'
   
    # 数据库配置
    DB_PREFIX = 'plugin_'
   
    # 缓存配置
    CACHE_PREFIX = 'plugin_cache_'
    CACHE_TTL = 3600
   
    # 自定义配置
    CUSTOM_SETTING = 'default_value'
```

 

2. 配置验证:
```python
def validate_config(self, config):
    """验证配置有效性"""
    if not isinstance(config.get('key'), str):
        raise ValueError("配置项 key 必须是字符串")
```

 

3. 配置更新:
```python
def update_config(self, new_config):
    """更新配置"""
    self.validate_config(new_config)
    self.config.update(new_config)
    self.save_config()
```