Initial commit: WordPress publishing tools
This commit is contained in:
commit
a2165c6934
|
|
@ -0,0 +1,11 @@
|
|||
#wordpress 凭据
|
||||
WORDPRESS_URL=https://podcaster.seekkey.tech
|
||||
WORDPRESS_AUTH_METHOD=application_password
|
||||
WORDPRESS_USERNAME=ben
|
||||
WORDPRESS_APP_PASSWORD=EZSb Ujzk 80ns 6U1a sATw gPsR
|
||||
|
||||
# judy 用户凭据
|
||||
JUDY_USERNAME=judy
|
||||
JUDY_APP_PASSWORD=EZSb Ujzk 80ns 6U1a sATw gPsR
|
||||
JUDY_UUID=9b6abf63-1ff2-4c82-8b9c-449a362d1b73
|
||||
JUDY_USER_ID=5
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
# WordPress 站点配置
|
||||
WORDPRESS_URL=https://your-wordpress-site.com
|
||||
WORDPRESS_USERNAME=your-username
|
||||
WORDPRESS_APP_PASSWORD=your-app-password
|
||||
|
||||
# 可选:其他用户凭据
|
||||
# JUDY_USERNAME=judy
|
||||
# JUDY_APP_PASSWORD=your-judy-app-password
|
||||
|
|
@ -0,0 +1,144 @@
|
|||
# WordPress 远程发布工具
|
||||
|
||||
这是一个用于远程操作 WordPress 网站的内容发布工具,通过 WordPress REST API 实现文章、分类、标签等内容的自动化管理。
|
||||
|
||||
## 功能特性
|
||||
|
||||
- 📝 **文章管理**: 创建、更新、删除文章
|
||||
- 📂 **分类管理**: 创建和管理文章分类
|
||||
- 🏷️ **标签管理**: 创建和管理文章标签
|
||||
- 🖼️ **媒体管理**: 上传和管理媒体文件
|
||||
- 🔐 **安全认证**: 使用 WordPress 应用密码进行安全认证
|
||||
|
||||
## 快速开始
|
||||
|
||||
### 1. 安装依赖
|
||||
|
||||
```bash
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
### 2. 配置环境变量
|
||||
|
||||
复制 `.env` 文件并填写你的 WordPress 站点信息:
|
||||
|
||||
```bash
|
||||
cp .env.example .env
|
||||
```
|
||||
|
||||
编辑 `.env` 文件:
|
||||
|
||||
```env
|
||||
# WordPress 站点配置
|
||||
WORDPRESS_URL=https://your-wordpress-site.com
|
||||
WORDPRESS_USERNAME=your-username
|
||||
WORDPRESS_APP_PASSWORD=your-app-password
|
||||
```
|
||||
|
||||
### 3. 测试连接
|
||||
|
||||
```bash
|
||||
python test_wp_api.py
|
||||
```
|
||||
|
||||
### 4. 发布内容
|
||||
|
||||
```bash
|
||||
python publish_post.py
|
||||
```
|
||||
|
||||
## 文件说明
|
||||
|
||||
- **`test_wp_api.py`**: API 连接测试脚本
|
||||
- **`wp_api_examples.py`**: 完整的 API 操作示例
|
||||
- **`publish_post.py`**: 简化的内容发布工具
|
||||
- **`.env`**: 环境配置文件
|
||||
- **`requirements.txt`**: Python 依赖包
|
||||
|
||||
## 使用示例
|
||||
|
||||
### 发布文章
|
||||
|
||||
```python
|
||||
from publish_post import WordPressPublisher
|
||||
|
||||
wp = WordPressPublisher()
|
||||
|
||||
# 发布文章
|
||||
result = wp.publish_post(
|
||||
title="我的新文章",
|
||||
content="<p>这是文章内容</p>",
|
||||
excerpt="文章摘要",
|
||||
status="publish" # 或 "draft" 保存为草稿
|
||||
)
|
||||
```
|
||||
|
||||
### 创建分类和标签
|
||||
|
||||
```python
|
||||
# 创建分类
|
||||
category = wp.create_category("技术分享", "技术相关的文章分类")
|
||||
|
||||
# 创建标签
|
||||
tag = wp.create_tag("Python", "Python 编程相关")
|
||||
|
||||
# 发布文章时指定分类和标签
|
||||
wp.publish_post(
|
||||
title="Python 教程",
|
||||
content="<p>Python 编程教程内容</p>",
|
||||
categories=[category['id']],
|
||||
tags=[tag['id']]
|
||||
)
|
||||
```
|
||||
|
||||
## WordPress 应用密码设置
|
||||
|
||||
1. 登录 WordPress 后台
|
||||
2. 进入 **用户 -> 个人资料**
|
||||
3. 滚动到 **应用密码** 部分
|
||||
4. 输入应用名称(如 "API 工具")
|
||||
5. 点击 **添加新应用密码**
|
||||
6. 复制生成的密码到 `.env` 文件中
|
||||
|
||||
## API 权限要求
|
||||
|
||||
确保你的 WordPress 用户具有以下权限:
|
||||
- 发布文章
|
||||
- 编辑文章
|
||||
- 删除文章
|
||||
- 管理分类和标签
|
||||
- 上传媒体文件
|
||||
|
||||
通常需要 **编辑者** 或 **管理员** 角色。
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. **HTTPS**: 建议使用 HTTPS 连接以确保安全
|
||||
2. **应用密码**: 使用应用密码而非普通登录密码
|
||||
3. **权限**: 确保用户具有相应的操作权限
|
||||
4. **测试**: 建议先在测试环境中验证功能
|
||||
|
||||
## 故障排除
|
||||
|
||||
### 认证失败
|
||||
- 检查用户名和应用密码是否正确
|
||||
- 确认应用密码格式正确(移除空格)
|
||||
- 验证用户是否有足够权限
|
||||
|
||||
### 连接超时
|
||||
- 检查网络连接
|
||||
- 确认 WordPress 站点是否正常运行
|
||||
- 验证 URL 是否正确
|
||||
|
||||
### 权限不足
|
||||
- 确保用户为编辑者或管理员角色
|
||||
- 检查 WordPress REST API 是否启用
|
||||
|
||||
## 相关资源
|
||||
|
||||
- [WordPress REST API 官方文档](https://developer.wordpress.org/rest-api/)
|
||||
- [WordPress 应用密码设置指南](https://wordpress.org/support/article/application-passwords/)
|
||||
|
||||
---
|
||||
|
||||
**项目目标**: 为远程 WordPress 网站提供简单、安全的内容发布解决方案。
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
#!/bin/bash
|
||||
# 代理控制脚本
|
||||
|
||||
proxy_on() {
|
||||
export https_proxy="https://100.86.9.29:7890"
|
||||
echo "✅ 代理已启用: $https_proxy"
|
||||
}
|
||||
|
||||
proxy_off() {
|
||||
unset http_proxy https_proxy all_proxy
|
||||
echo "✅ 代理已禁用"
|
||||
}
|
||||
|
||||
proxy_status() {
|
||||
if [ -n "$https_proxy" ]; then
|
||||
echo "🔵 代理状态: 启用 - $https_proxy"
|
||||
else
|
||||
echo "⚪ 代理状态: 禁用"
|
||||
fi
|
||||
}
|
||||
|
||||
# 根据参数执行对应操作
|
||||
case "$1" in
|
||||
"on")
|
||||
proxy_on
|
||||
;;
|
||||
"off")
|
||||
proxy_off
|
||||
;;
|
||||
"status")
|
||||
proxy_status
|
||||
;;
|
||||
*)
|
||||
echo "用法: source proxy_control.sh [on|off|status]"
|
||||
echo " on - 启用代理"
|
||||
echo " off - 禁用代理"
|
||||
echo " status - 查看代理状态"
|
||||
;;
|
||||
esac
|
||||
|
|
@ -0,0 +1,167 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
WordPress 内容发布工具
|
||||
简化的内容发布脚本
|
||||
"""
|
||||
|
||||
import os
|
||||
import requests
|
||||
from requests.auth import HTTPBasicAuth
|
||||
from dotenv import load_dotenv
|
||||
from datetime import datetime
|
||||
|
||||
# 加载环境变量
|
||||
load_dotenv()
|
||||
|
||||
class WordPressPublisher:
|
||||
def __init__(self):
|
||||
self.wp_url = os.getenv('WORDPRESS_URL')
|
||||
self.wp_user = os.getenv('WORDPRESS_USERNAME')
|
||||
self.wp_password = os.getenv('WORDPRESS_APP_PASSWORD')
|
||||
|
||||
if self.wp_password:
|
||||
self.wp_password = self.wp_password.replace(" ", "")
|
||||
|
||||
if not all([self.wp_url, self.wp_user, self.wp_password]):
|
||||
raise ValueError("请在 .env 文件中配置 WORDPRESS_URL, WORDPRESS_USERNAME, WORDPRESS_APP_PASSWORD")
|
||||
|
||||
self.api_url = f"{self.wp_url.rstrip('/')}/wp-json/wp/v2"
|
||||
self.auth = HTTPBasicAuth(self.wp_user, self.wp_password)
|
||||
|
||||
def publish_post(self, title, content, excerpt="", categories=None, tags=None, status="publish"):
|
||||
"""
|
||||
发布文章
|
||||
|
||||
Args:
|
||||
title (str): 文章标题
|
||||
content (str): 文章内容 (HTML)
|
||||
excerpt (str): 文章摘要
|
||||
categories (list): 分类ID列表
|
||||
tags (list): 标签ID列表
|
||||
status (str): 文章状态 (draft, publish, private)
|
||||
|
||||
Returns:
|
||||
dict: 创建的文章信息
|
||||
"""
|
||||
post_data = {
|
||||
'title': title,
|
||||
'content': content,
|
||||
'excerpt': excerpt,
|
||||
'status': status
|
||||
}
|
||||
|
||||
if categories:
|
||||
post_data['categories'] = categories
|
||||
if tags:
|
||||
post_data['tags'] = tags
|
||||
|
||||
response = requests.post(
|
||||
f"{self.api_url}/posts",
|
||||
json=post_data,
|
||||
auth=self.auth
|
||||
)
|
||||
|
||||
if response.status_code == 201:
|
||||
post = response.json()
|
||||
print(f"✅ 文章发布成功!")
|
||||
print(f" 标题: {post['title']['rendered']}")
|
||||
print(f" 链接: {post['link']}")
|
||||
print(f" 状态: {post['status']}")
|
||||
return post
|
||||
else:
|
||||
print(f"❌ 文章发布失败: {response.status_code}")
|
||||
print(f" 错误信息: {response.text}")
|
||||
return None
|
||||
|
||||
def get_categories(self):
|
||||
"""获取所有分类"""
|
||||
response = requests.get(f"{self.api_url}/categories")
|
||||
if response.status_code == 200:
|
||||
return response.json()
|
||||
return []
|
||||
|
||||
def get_tags(self):
|
||||
"""获取所有标签"""
|
||||
response = requests.get(f"{self.api_url}/tags")
|
||||
if response.status_code == 200:
|
||||
return response.json()
|
||||
return []
|
||||
|
||||
def create_category(self, name, description=""):
|
||||
"""创建新分类"""
|
||||
category_data = {
|
||||
'name': name,
|
||||
'description': description
|
||||
}
|
||||
|
||||
response = requests.post(
|
||||
f"{self.api_url}/categories",
|
||||
json=category_data,
|
||||
auth=self.auth
|
||||
)
|
||||
|
||||
if response.status_code == 201:
|
||||
category = response.json()
|
||||
print(f"✅ 分类创建成功: {category['name']} (ID: {category['id']})")
|
||||
return category
|
||||
else:
|
||||
print(f"❌ 分类创建失败: {response.status_code}")
|
||||
return None
|
||||
|
||||
def create_tag(self, name, description=""):
|
||||
"""创建新标签"""
|
||||
tag_data = {
|
||||
'name': name,
|
||||
'description': description
|
||||
}
|
||||
|
||||
response = requests.post(
|
||||
f"{self.api_url}/tags",
|
||||
json=tag_data,
|
||||
auth=self.auth
|
||||
)
|
||||
|
||||
if response.status_code == 201:
|
||||
tag = response.json()
|
||||
print(f"✅ 标签创建成功: {tag['name']} (ID: {tag['id']})")
|
||||
return tag
|
||||
else:
|
||||
print(f"❌ 标签创建失败: {response.status_code}")
|
||||
return None
|
||||
|
||||
def main():
|
||||
"""示例用法"""
|
||||
try:
|
||||
wp = WordPressPublisher()
|
||||
|
||||
# 示例:发布一篇文章
|
||||
title = f"测试文章 - {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}"
|
||||
content = """
|
||||
<h2>这是一个测试文章</h2>
|
||||
<p>这是文章的内容。你可以使用 HTML 标签来格式化内容。</p>
|
||||
<ul>
|
||||
<li>支持列表</li>
|
||||
<li>支持链接和图片</li>
|
||||
<li>支持各种 HTML 元素</li>
|
||||
</ul>
|
||||
"""
|
||||
excerpt = "这是一个通过 API 发布的测试文章"
|
||||
|
||||
# 发布为草稿,避免直接发布到生产环境
|
||||
result = wp.publish_post(
|
||||
title=title,
|
||||
content=content,
|
||||
excerpt=excerpt,
|
||||
status="draft" # 使用 "publish" 来直接发布
|
||||
)
|
||||
|
||||
if result:
|
||||
print(f"\n📝 文章ID: {result['id']}")
|
||||
print(f"🔗 编辑链接: {result['link'].replace('?preview=true', '')}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ 错误: {e}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
requests>=2.31.0
|
||||
python-dotenv>=1.0.0
|
||||
|
|
@ -0,0 +1,227 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
WordPress REST API 测试脚本
|
||||
"""
|
||||
|
||||
import os
|
||||
import requests
|
||||
import json
|
||||
from requests.auth import HTTPBasicAuth
|
||||
from dotenv import load_dotenv
|
||||
|
||||
# 加载环境变量
|
||||
load_dotenv()
|
||||
|
||||
# WordPress 配置信息
|
||||
WP_URL = os.getenv('WORDPRESS_URL')
|
||||
WP_USER = os.getenv('WORDPRESS_USERNAME')
|
||||
WP_APP_PASSWORD = os.getenv('WORDPRESS_APP_PASSWORD')
|
||||
|
||||
# 移除密码中的空格
|
||||
if WP_APP_PASSWORD:
|
||||
WP_APP_PASSWORD = WP_APP_PASSWORD.replace(" ", "")
|
||||
|
||||
# 检查必需的环境变量
|
||||
if not all([WP_URL, WP_USER, WP_APP_PASSWORD]):
|
||||
print("❌ 错误: 请在 .env 文件中配置 WORDPRESS_URL, WORDPRESS_USERNAME, WORDPRESS_APP_PASSWORD")
|
||||
exit(1)
|
||||
|
||||
class WordPressAPITester:
|
||||
def __init__(self, url, username, app_password):
|
||||
self.base_url = url.rstrip('/')
|
||||
self.api_url = f"{self.base_url}/wp-json/wp/v2"
|
||||
self.username = username
|
||||
self.app_password = app_password
|
||||
self.auth = HTTPBasicAuth(username, app_password)
|
||||
|
||||
def test_connection(self):
|
||||
"""测试基本连接"""
|
||||
print("🔍 测试 WordPress REST API 连接...")
|
||||
try:
|
||||
response = requests.get(f"{self.base_url}/wp-json", timeout=10)
|
||||
if response.status_code == 200:
|
||||
data = response.json()
|
||||
print(f"✅ 连接成功!")
|
||||
print(f" 站点名称: {data.get('name', 'N/A')}")
|
||||
print(f" 描述: {data.get('description', 'N/A')}")
|
||||
print(f" URL: {data.get('url', 'N/A')}")
|
||||
print(f" WordPress版本: {data.get('gmt_offset', 'N/A')}")
|
||||
return True
|
||||
else:
|
||||
print(f"❌ 连接失败: HTTP {response.status_code}")
|
||||
return False
|
||||
except requests.exceptions.RequestException as e:
|
||||
print(f"❌ 连接错误: {e}")
|
||||
return False
|
||||
|
||||
def test_authentication(self):
|
||||
"""测试认证"""
|
||||
print("\n🔐 测试用户认证...")
|
||||
try:
|
||||
response = requests.get(f"{self.api_url}/users/me", auth=self.auth, timeout=10)
|
||||
if response.status_code == 200:
|
||||
user_data = response.json()
|
||||
print(f"✅ 认证成功!")
|
||||
print(f" 用户ID: {user_data.get('id')}")
|
||||
print(f" 用户名: {user_data.get('username')}")
|
||||
print(f" 显示名称: {user_data.get('name')}")
|
||||
print(f" 邮箱: {user_data.get('email')}")
|
||||
print(f" 角色: {', '.join(user_data.get('roles', []))}")
|
||||
return True
|
||||
else:
|
||||
print(f"❌ 认证失败: HTTP {response.status_code}")
|
||||
if response.status_code == 401:
|
||||
print(" 可能的原因: 用户名或应用密码错误")
|
||||
elif response.status_code == 403:
|
||||
print(" 可能的原因: 用户权限不足")
|
||||
return False
|
||||
except requests.exceptions.RequestException as e:
|
||||
print(f"❌ 认证错误: {e}")
|
||||
return False
|
||||
|
||||
def test_posts_endpoint(self):
|
||||
"""测试文章端点"""
|
||||
print("\n📝 测试文章端点...")
|
||||
try:
|
||||
# 获取文章列表
|
||||
response = requests.get(f"{self.api_url}/posts?per_page=5", timeout=10)
|
||||
if response.status_code == 200:
|
||||
posts = response.json()
|
||||
print(f"✅ 文章端点正常! 找到 {len(posts)} 篇文章")
|
||||
for i, post in enumerate(posts[:3], 1):
|
||||
print(f" {i}. {post.get('title', {}).get('rendered', 'N/A')} (ID: {post.get('id')})")
|
||||
return True
|
||||
else:
|
||||
print(f"❌ 文章端点失败: HTTP {response.status_code}")
|
||||
return False
|
||||
except requests.exceptions.RequestException as e:
|
||||
print(f"❌ 文章端点错误: {e}")
|
||||
return False
|
||||
|
||||
def test_categories_endpoint(self):
|
||||
"""测试分类端点"""
|
||||
print("\n📂 测试分类端点...")
|
||||
try:
|
||||
response = requests.get(f"{self.api_url}/categories", timeout=10)
|
||||
if response.status_code == 200:
|
||||
categories = response.json()
|
||||
print(f"✅ 分类端点正常! 找到 {len(categories)} 个分类")
|
||||
for i, cat in enumerate(categories[:3], 1):
|
||||
print(f" {i}. {cat.get('name')} (ID: {cat.get('id')}, 文章数: {cat.get('count')})")
|
||||
return True
|
||||
else:
|
||||
print(f"❌ 分类端点失败: HTTP {response.status_code}")
|
||||
return False
|
||||
except requests.exceptions.RequestException as e:
|
||||
print(f"❌ 分类端点错误: {e}")
|
||||
return False
|
||||
|
||||
def test_media_endpoint(self):
|
||||
"""测试媒体端点"""
|
||||
print("\n🖼️ 测试媒体端点...")
|
||||
try:
|
||||
response = requests.get(f"{self.api_url}/media?per_page=5", timeout=10)
|
||||
if response.status_code == 200:
|
||||
media = response.json()
|
||||
print(f"✅ 媒体端点正常! 找到 {len(media)} 个媒体文件")
|
||||
for i, item in enumerate(media[:3], 1):
|
||||
print(f" {i}. {item.get('title', {}).get('rendered', 'N/A')} (类型: {item.get('media_type')})")
|
||||
return True
|
||||
else:
|
||||
print(f"❌ 媒体端点失败: HTTP {response.status_code}")
|
||||
return False
|
||||
except requests.exceptions.RequestException as e:
|
||||
print(f"❌ 媒体端点错误: {e}")
|
||||
return False
|
||||
|
||||
def test_write_permissions(self):
|
||||
"""测试写入权限"""
|
||||
print("\n✏️ 测试写入权限...")
|
||||
try:
|
||||
# 尝试创建一个测试文章草稿
|
||||
test_post = {
|
||||
'title': 'API测试文章 - 请删除',
|
||||
'content': '这是一个API测试文章,可以安全删除。',
|
||||
'status': 'draft' # 草稿状态,不会公开发布
|
||||
}
|
||||
|
||||
response = requests.post(
|
||||
f"{self.api_url}/posts",
|
||||
json=test_post,
|
||||
auth=self.auth,
|
||||
timeout=10
|
||||
)
|
||||
|
||||
if response.status_code == 201:
|
||||
created_post = response.json()
|
||||
post_id = created_post.get('id')
|
||||
print(f"✅ 写入权限正常! 创建了测试文章 (ID: {post_id})")
|
||||
|
||||
# 立即删除测试文章
|
||||
delete_response = requests.delete(
|
||||
f"{self.api_url}/posts/{post_id}?force=true",
|
||||
auth=self.auth,
|
||||
timeout=10
|
||||
)
|
||||
|
||||
if delete_response.status_code == 200:
|
||||
print(f"✅ 测试文章已清理 (ID: {post_id})")
|
||||
else:
|
||||
print(f"⚠️ 测试文章创建成功但清理失败 (ID: {post_id}),请手动删除")
|
||||
|
||||
return True
|
||||
else:
|
||||
print(f"❌ 写入权限测试失败: HTTP {response.status_code}")
|
||||
if response.status_code == 401:
|
||||
print(" 可能的原因: 认证失败")
|
||||
elif response.status_code == 403:
|
||||
print(" 可能的原因: 用户没有发布文章的权限")
|
||||
return False
|
||||
|
||||
except requests.exceptions.RequestException as e:
|
||||
print(f"❌ 写入权限测试错误: {e}")
|
||||
return False
|
||||
|
||||
def run_all_tests(self):
|
||||
"""运行所有测试"""
|
||||
print("🚀 开始 WordPress REST API 全面测试\n")
|
||||
print(f"测试目标: {self.base_url}")
|
||||
print(f"用户: {self.username}")
|
||||
print("=" * 50)
|
||||
|
||||
tests = [
|
||||
self.test_connection,
|
||||
self.test_authentication,
|
||||
self.test_posts_endpoint,
|
||||
self.test_categories_endpoint,
|
||||
self.test_media_endpoint,
|
||||
self.test_write_permissions
|
||||
]
|
||||
|
||||
passed = 0
|
||||
total = len(tests)
|
||||
|
||||
for test in tests:
|
||||
if test():
|
||||
passed += 1
|
||||
|
||||
print("\n" + "=" * 50)
|
||||
print(f"📊 测试结果: {passed}/{total} 项测试通过")
|
||||
|
||||
if passed == total:
|
||||
print("🎉 所有测试通过! WordPress REST API 工作正常")
|
||||
elif passed >= total * 0.8:
|
||||
print("⚠️ 大部分测试通过,但有一些问题需要注意")
|
||||
else:
|
||||
print("❌ 多项测试失败,请检查配置和权限")
|
||||
|
||||
return passed, total
|
||||
|
||||
def main():
|
||||
"""主函数"""
|
||||
tester = WordPressAPITester(WP_URL, WP_USER, WP_APP_PASSWORD)
|
||||
tester.run_all_tests()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
|
@ -0,0 +1,374 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
WordPress REST API 使用示例
|
||||
演示常见的WordPress操作
|
||||
"""
|
||||
|
||||
import os
|
||||
import requests
|
||||
import json
|
||||
from requests.auth import HTTPBasicAuth
|
||||
from datetime import datetime
|
||||
from dotenv import load_dotenv
|
||||
|
||||
# 加载环境变量
|
||||
load_dotenv()
|
||||
|
||||
# WordPress 配置信息
|
||||
WP_URL = os.getenv('WORDPRESS_URL')
|
||||
WP_USER = os.getenv('WORDPRESS_USERNAME')
|
||||
WP_APP_PASSWORD = os.getenv('WORDPRESS_APP_PASSWORD')
|
||||
|
||||
# 移除密码中的空格
|
||||
if WP_APP_PASSWORD:
|
||||
WP_APP_PASSWORD = WP_APP_PASSWORD.replace(" ", "")
|
||||
|
||||
# 检查必需的环境变量
|
||||
if not all([WP_URL, WP_USER, WP_APP_PASSWORD]):
|
||||
print("❌ 错误: 请在 .env 文件中配置 WORDPRESS_URL, WORDPRESS_USERNAME, WORDPRESS_APP_PASSWORD")
|
||||
exit(1)
|
||||
|
||||
class WordPressAPI:
|
||||
def __init__(self, url, username, app_password):
|
||||
self.base_url = url.rstrip('/')
|
||||
self.api_url = f"{self.base_url}/wp-json/wp/v2"
|
||||
self.username = username
|
||||
self.app_password = app_password
|
||||
self.auth = HTTPBasicAuth(username, app_password)
|
||||
|
||||
def get_posts(self, per_page=10, status='publish'):
|
||||
"""获取文章列表"""
|
||||
params = {
|
||||
'per_page': per_page,
|
||||
'status': status
|
||||
}
|
||||
response = requests.get(f"{self.api_url}/posts", params=params)
|
||||
if response.status_code == 200:
|
||||
return response.json()
|
||||
else:
|
||||
print(f"获取文章失败: {response.status_code}")
|
||||
return None
|
||||
|
||||
def get_post_by_id(self, post_id):
|
||||
"""根据ID获取特定文章"""
|
||||
response = requests.get(f"{self.api_url}/posts/{post_id}")
|
||||
if response.status_code == 200:
|
||||
return response.json()
|
||||
else:
|
||||
print(f"获取文章失败: {response.status_code}")
|
||||
return None
|
||||
|
||||
def create_post(self, title, content, status='draft', categories=None, tags=None):
|
||||
"""创建新文章"""
|
||||
post_data = {
|
||||
'title': title,
|
||||
'content': content,
|
||||
'status': status
|
||||
}
|
||||
|
||||
if categories:
|
||||
post_data['categories'] = categories
|
||||
if tags:
|
||||
post_data['tags'] = tags
|
||||
|
||||
response = requests.post(
|
||||
f"{self.api_url}/posts",
|
||||
json=post_data,
|
||||
auth=self.auth
|
||||
)
|
||||
|
||||
if response.status_code == 201:
|
||||
return response.json()
|
||||
else:
|
||||
print(f"创建文章失败: {response.status_code}")
|
||||
print(response.text)
|
||||
return None
|
||||
|
||||
def update_post(self, post_id, title=None, content=None, status=None):
|
||||
"""更新文章"""
|
||||
update_data = {}
|
||||
if title:
|
||||
update_data['title'] = title
|
||||
if content:
|
||||
update_data['content'] = content
|
||||
if status:
|
||||
update_data['status'] = status
|
||||
|
||||
response = requests.post(
|
||||
f"{self.api_url}/posts/{post_id}",
|
||||
json=update_data,
|
||||
auth=self.auth
|
||||
)
|
||||
|
||||
if response.status_code == 200:
|
||||
return response.json()
|
||||
else:
|
||||
print(f"更新文章失败: {response.status_code}")
|
||||
return None
|
||||
|
||||
def delete_post(self, post_id, force=False):
|
||||
"""删除文章"""
|
||||
params = {'force': 'true'} if force else {}
|
||||
response = requests.delete(
|
||||
f"{self.api_url}/posts/{post_id}",
|
||||
params=params,
|
||||
auth=self.auth
|
||||
)
|
||||
|
||||
if response.status_code == 200:
|
||||
return response.json()
|
||||
else:
|
||||
print(f"删除文章失败: {response.status_code}")
|
||||
return None
|
||||
|
||||
def get_categories(self):
|
||||
"""获取分类列表"""
|
||||
response = requests.get(f"{self.api_url}/categories")
|
||||
if response.status_code == 200:
|
||||
return response.json()
|
||||
else:
|
||||
print(f"获取分类失败: {response.status_code}")
|
||||
return None
|
||||
|
||||
def create_category(self, name, description="", parent=0):
|
||||
"""创建新分类"""
|
||||
category_data = {
|
||||
'name': name,
|
||||
'description': description,
|
||||
'parent': parent
|
||||
}
|
||||
|
||||
response = requests.post(
|
||||
f"{self.api_url}/categories",
|
||||
json=category_data,
|
||||
auth=self.auth
|
||||
)
|
||||
|
||||
if response.status_code == 201:
|
||||
return response.json()
|
||||
else:
|
||||
print(f"创建分类失败: {response.status_code}")
|
||||
return None
|
||||
|
||||
def get_tags(self):
|
||||
"""获取标签列表"""
|
||||
response = requests.get(f"{self.api_url}/tags")
|
||||
if response.status_code == 200:
|
||||
return response.json()
|
||||
else:
|
||||
print(f"获取标签失败: {response.status_code}")
|
||||
return None
|
||||
|
||||
def create_tag(self, name, description=""):
|
||||
"""创建新标签"""
|
||||
tag_data = {
|
||||
'name': name,
|
||||
'description': description
|
||||
}
|
||||
|
||||
response = requests.post(
|
||||
f"{self.api_url}/tags",
|
||||
json=tag_data,
|
||||
auth=self.auth
|
||||
)
|
||||
|
||||
if response.status_code == 201:
|
||||
return response.json()
|
||||
else:
|
||||
print(f"创建标签失败: {response.status_code}")
|
||||
return None
|
||||
|
||||
def upload_media(self, file_path, title=None, alt_text=None):
|
||||
"""上传媒体文件"""
|
||||
if not os.path.exists(file_path):
|
||||
print(f"文件不存在: {file_path}")
|
||||
return None
|
||||
|
||||
filename = os.path.basename(file_path)
|
||||
|
||||
with open(file_path, 'rb') as f:
|
||||
files = {
|
||||
'file': (filename, f, 'application/octet-stream')
|
||||
}
|
||||
|
||||
data = {}
|
||||
if title:
|
||||
data['title'] = title
|
||||
if alt_text:
|
||||
data['alt_text'] = alt_text
|
||||
|
||||
response = requests.post(
|
||||
f"{self.api_url}/media",
|
||||
files=files,
|
||||
data=data,
|
||||
auth=self.auth
|
||||
)
|
||||
|
||||
if response.status_code == 201:
|
||||
return response.json()
|
||||
else:
|
||||
print(f"上传媒体失败: {response.status_code}")
|
||||
return None
|
||||
|
||||
def get_media(self, per_page=10):
|
||||
"""获取媒体列表"""
|
||||
params = {'per_page': per_page}
|
||||
response = requests.get(f"{self.api_url}/media", params=params)
|
||||
if response.status_code == 200:
|
||||
return response.json()
|
||||
else:
|
||||
print(f"获取媒体失败: {response.status_code}")
|
||||
return None
|
||||
|
||||
def search_posts(self, search_term, per_page=10):
|
||||
"""搜索文章"""
|
||||
params = {
|
||||
'search': search_term,
|
||||
'per_page': per_page
|
||||
}
|
||||
response = requests.get(f"{self.api_url}/posts", params=params)
|
||||
if response.status_code == 200:
|
||||
return response.json()
|
||||
else:
|
||||
print(f"搜索文章失败: {response.status_code}")
|
||||
return None
|
||||
|
||||
def demo_basic_operations():
|
||||
"""演示基本操作"""
|
||||
print("🚀 WordPress REST API 基本操作演示\n")
|
||||
|
||||
wp = WordPressAPI(WP_URL, WP_USER, WP_APP_PASSWORD)
|
||||
|
||||
# 1. 获取现有文章
|
||||
print("📝 获取现有文章...")
|
||||
posts = wp.get_posts(per_page=5)
|
||||
if posts:
|
||||
print(f"找到 {len(posts)} 篇文章:")
|
||||
for post in posts:
|
||||
print(f" - {post['title']['rendered']} (ID: {post['id']})")
|
||||
else:
|
||||
print("没有找到文章")
|
||||
|
||||
# 2. 获取分类
|
||||
print("\n📂 获取分类...")
|
||||
categories = wp.get_categories()
|
||||
if categories:
|
||||
print(f"找到 {len(categories)} 个分类:")
|
||||
for cat in categories:
|
||||
print(f" - {cat['name']} (ID: {cat['id']}, 文章数: {cat['count']})")
|
||||
|
||||
# 3. 获取标签
|
||||
print("\n🏷️ 获取标签...")
|
||||
tags = wp.get_tags()
|
||||
if tags:
|
||||
print(f"找到 {len(tags)} 个标签:")
|
||||
for tag in tags[:5]: # 只显示前5个
|
||||
print(f" - {tag['name']} (ID: {tag['id']}, 使用次数: {tag['count']})")
|
||||
else:
|
||||
print("没有找到标签")
|
||||
|
||||
# 4. 获取媒体文件
|
||||
print("\n🖼️ 获取媒体文件...")
|
||||
media = wp.get_media(per_page=5)
|
||||
if media:
|
||||
print(f"找到 {len(media)} 个媒体文件:")
|
||||
for item in media:
|
||||
print(f" - {item['title']['rendered']} (类型: {item['media_type']})")
|
||||
|
||||
print("\n✅ 基本操作演示完成!")
|
||||
|
||||
def demo_create_content():
|
||||
"""演示内容创建"""
|
||||
print("\n🎨 WordPress 内容创建演示\n")
|
||||
|
||||
wp = WordPressAPI(WP_URL, WP_USER, WP_APP_PASSWORD)
|
||||
|
||||
# 创建测试分类
|
||||
print("📂 创建测试分类...")
|
||||
test_category = wp.create_category(
|
||||
name="API测试分类",
|
||||
description="这是通过API创建的测试分类"
|
||||
)
|
||||
|
||||
if test_category:
|
||||
category_id = test_category['id']
|
||||
print(f"✅ 分类创建成功 (ID: {category_id})")
|
||||
|
||||
# 创建测试标签
|
||||
print("\n🏷️ 创建测试标签...")
|
||||
test_tag = wp.create_tag(
|
||||
name="API测试",
|
||||
description="API测试标签"
|
||||
)
|
||||
|
||||
if test_tag:
|
||||
tag_id = test_tag['id']
|
||||
print(f"✅ 标签创建成功 (ID: {tag_id})")
|
||||
|
||||
# 创建测试文章
|
||||
print("\n📝 创建测试文章...")
|
||||
current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
test_post = wp.create_post(
|
||||
title=f"API测试文章 - {current_time}",
|
||||
content=f"""
|
||||
<h2>这是通过WordPress REST API创建的测试文章</h2>
|
||||
<p>创建时间: {current_time}</p>
|
||||
<p>这篇文章演示了如何使用WordPress REST API进行内容管理:</p>
|
||||
<ul>
|
||||
<li>创建文章</li>
|
||||
<li>设置分类和标签</li>
|
||||
<li>使用HTML格式的内容</li>
|
||||
</ul>
|
||||
<p><strong>注意:</strong> 这是一个测试文章,可以安全删除。</p>
|
||||
""",
|
||||
status='draft', # 草稿状态
|
||||
categories=[category_id],
|
||||
tags=[tag_id]
|
||||
)
|
||||
|
||||
if test_post:
|
||||
post_id = test_post['id']
|
||||
print(f"✅ 文章创建成功 (ID: {post_id})")
|
||||
print(f" 标题: {test_post['title']['rendered']}")
|
||||
print(f" 状态: {test_post['status']}")
|
||||
print(f" 链接: {test_post['link']}")
|
||||
|
||||
# 询问是否删除测试内容
|
||||
print("\n🗑️ 清理测试内容...")
|
||||
|
||||
# 删除测试文章
|
||||
if wp.delete_post(post_id, force=True):
|
||||
print(f"✅ 测试文章已删除 (ID: {post_id})")
|
||||
|
||||
# 删除测试分类和标签需要小心,因为可能有其他内容在使用
|
||||
print("⚠️ 测试分类和标签保留,请手动删除如果不需要")
|
||||
|
||||
else:
|
||||
print("❌ 文章创建失败")
|
||||
else:
|
||||
print("❌ 标签创建失败")
|
||||
else:
|
||||
print("❌ 分类创建失败")
|
||||
|
||||
print("\n✅ 内容创建演示完成!")
|
||||
|
||||
def main():
|
||||
"""主函数"""
|
||||
print("WordPress REST API 使用示例")
|
||||
print("=" * 40)
|
||||
|
||||
# 基本操作演示
|
||||
demo_basic_operations()
|
||||
|
||||
# 内容创建演示
|
||||
demo_create_content()
|
||||
|
||||
print("\n🎉 所有演示完成!")
|
||||
print("\n💡 提示:")
|
||||
print("- 所有创建的测试内容都已清理")
|
||||
print("- 你可以修改这个脚本来适应你的具体需求")
|
||||
print("- 更多API文档: https://developer.wordpress.org/rest-api/")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
#!/bin/bash
|
||||
# WordPress 发布脚本 - 无代理环境
|
||||
|
||||
# 临时禁用代理
|
||||
unset http_proxy https_proxy all_proxy
|
||||
|
||||
echo "🚀 WordPress 内容发布工具"
|
||||
echo "=================================="
|
||||
|
||||
# 检查参数
|
||||
if [ "$1" = "test" ]; then
|
||||
echo "📋 执行 API 连接测试..."
|
||||
python3 test_wp_api.py
|
||||
elif [ "$1" = "publish" ]; then
|
||||
echo "📝 执行内容发布..."
|
||||
python3 publish_post.py
|
||||
elif [ "$1" = "examples" ]; then
|
||||
echo "📚 执行 API 示例..."
|
||||
python3 wp_api_examples.py
|
||||
else
|
||||
echo "用法: ./wp_publish.sh [test|publish|examples]"
|
||||
echo " test - 测试 API 连接"
|
||||
echo " publish - 发布内容"
|
||||
echo " examples - 运行 API 示例"
|
||||
fi
|
||||
Loading…
Reference in New Issue