{"id":37318649,"url":"https://github.com/huangwb8/m2w","last_synced_at":"2026-01-24T17:03:51.363Z","repository":{"id":64149575,"uuid":"484779350","full_name":"huangwb8/m2w","owner":"huangwb8","description":"Automatically upload and update local markdown to WordPress via Python","archived":false,"fork":false,"pushed_at":"2025-12-21T08:26:55.000Z","size":206,"stargazers_count":44,"open_issues_count":2,"forks_count":18,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-01-16T11:34:09.358Z","etag":null,"topics":["markdown","python","vscode","wordpress"],"latest_commit_sha":null,"homepage":"https://pypi.org/project/m2w/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/huangwb8.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.MD","contributing":null,"funding":null,"license":"license.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2022-04-23T15:06:27.000Z","updated_at":"2025-12-29T22:04:14.000Z","dependencies_parsed_at":"2024-11-28T15:19:25.336Z","dependency_job_id":"b00e4170-35fa-4c9a-bd33-406fb33d0be7","html_url":"https://github.com/huangwb8/m2w","commit_stats":{"total_commits":123,"total_committers":4,"mean_commits":30.75,"dds":0.07317073170731703,"last_synced_commit":"69fac39c53abf766857da3022dd9988d26ddd930"},"previous_names":[],"tags_count":42,"template":false,"template_full_name":null,"purl":"pkg:github/huangwb8/m2w","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/huangwb8%2Fm2w","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/huangwb8%2Fm2w/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/huangwb8%2Fm2w/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/huangwb8%2Fm2w/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/huangwb8","download_url":"https://codeload.github.com/huangwb8/m2w/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/huangwb8%2Fm2w/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28732218,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-24T10:24:43.181Z","status":"ssl_error","status_checked_at":"2026-01-24T10:24:36.112Z","response_time":89,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["markdown","python","vscode","wordpress"],"created_at":"2026-01-16T03:14:40.443Z","updated_at":"2026-01-24T17:03:51.334Z","avatar_url":"https://github.com/huangwb8.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"### [English](README.md) | [简体中文](README.zh-CN.md)\n\n# m2w: Markdown to WordPress\n\n\u003cp align=\"left\"\u003e\n\u003ca href=\"\"\u003e\u003cimg src=\"https://img.shields.io/badge/python-3.7%2B-orange\"\u003e\u003c/a\u003e\n\u003ca href=\"\"\u003e\u003cimg src=\"https://img.shields.io/badge/platform-Windows%7Clinux%7CMacOS-brightgreen\"\u003e\u003c/a\u003e\n\u003ca href=\"\"\u003e\u003cimg src=\"https://img.shields.io/github/downloads/huangwb8/m2w/total\"\u003e\u003c/a\u003e\n\u003ca href=\"\"\u003e\u003cimg src=\"https://img.shields.io/github/stars/huangwb8/m2w?style=social\"\u003e\u003c/a\u003e\n\u003ca href=\"https://app.fossa.com/projects/git%2Bgithub.com%2Fhuangwb8%2Fm2w?ref=badge_shield\" alt=\"FOSSA Status\"\u003e\u003cimg src=\"https://app.fossa.com/api/projects/git%2Bgithub.com%2Fhuangwb8%2Fm2w.svg?type=shield\"/\u003e\u003c/a\u003e\n\u003c/p\u003e\nAutomatically upload and update local markdown to WordPress based on REST API/Password via Python\n\n:star2::star2::star2: Welcome m2w 2.7.2! LaTeX math rendering, tables, and GFM Admonition support now available. Current v2.7.2 also features rate limiting, resumable uploads, and batch processing for safe mass uploads of 1000+ articles!\n\nChinese tutorial: [Docker系列 WordPress系列 WordPress上传或更新Markdown的最佳实践-m2w 2.0](https://blognas.hwb0307.com/linux/docker/2813)\n\n\n## Table of Contents\n\n- [m2w: Markdown to WordPress](#m2w-markdown-to-wordpress)\n  - [Table of Contents](#table-of-contents)\n  - [Background](#background)\n  - [Install](#install)\n  - [Usage](#usage)\n    - [Enable REST API](#enable-rest-api)\n    - [Use m2w](#use-m2w)\n  - [Demo](#demo)\n  - [LOG](#log)\n  - [Related Efforts](#related-efforts)\n  - [Maintainers](#maintainers)\n  - [Contributing](#contributing)\n  - [License](#license)\n  - [More](#more)\n\n## Background\n\n`m2w` is a tool for automatically uploading or updating local Markdown to WordPress via Python, based on REST API (`2.5+`) or Password.\n\n`m2w` has these features:\n\n+ **Support REST API**, which is safer then conventional password!\n+ Use `config/user.json` to maintain the user information in a little different way comparing with `m2w 1.0`.\n+ You can just keep your file structures locally as you like.\n+ You can manage lots of websites at the same time via multiple `legacy_*.json`.\n+ All you need to deal with is a single python script `myblog.py` instead of two (`update.py` and `upload.py` in `m2w 1.0`).\n+ Ignore repeated new markdown files for uploading (`v2.2.4+`)\n+ **LaTeX math rendering** (`v2.7.2+`): Support for inline math (`$...$`) and display math (`$$...$$`, `\\begin...\\end{}`) formulas\n+ **Markdown tables** (`v2.7.2+`): Native table support for better content formatting\n+ **GFM Admonition** (`v2.7.2+`, optional): GitHub-style callout boxes (`\u003e [!NOTE]`, `\u003e [!TIP]`, etc.) - requires `pip install m2w[admonition]`\n+ **Rate limiting \u0026 batch processing** (`v2.7+`): Prevent server bans with configurable delays, batch processing, and exponential backoff for HTTP 429 errors\n+ **Resumable uploads** (`v2.7+`): Progress tracking saves your work—interrupt and resume without losing progress\n\n## Install\n\n\u003e [Miniconda](https://docs.conda.io/en/latest/miniconda.html) is recommended to manage Python version and related dependencies.\n\n- Python \u003e= 3.7.6\n- Runtime dependencies: `python-frontmatter\u003e=1.0.0`, `markdown\u003e=3.3.6`, `python-wordpress-xmlrpc\u003e=2.3`, `httpx\u003e=0.24.0` (see `requirements.txt`)\n- Packaging now follows PEP 621 in `pyproject.toml` (setuptools); `setup.py` remains only for compatibility.\n\nAfter 2022-12-10, `m2w` was uploaded onto [PyPi](https://pypi.org/project/m2w/). Install it via:\n\n```bash\npip install m2w\n# or pin a version\npip install -i https://pypi.org/simple m2w==2.7.2\n\n# For GFM Admonition support (optional)\npip install m2w[admonition]\n```\n\nFrom source, you can use the modern build flow:\n\n```bash\npython -m pip install --upgrade build\npython -m build                      # generate wheel + sdist under dist/\npython -m pip install dist/m2w-*.whl # install the built artifact\n# editable install for development\npython -m pip install -e .\n```\n\n## Usage\n\n### Enable REST API\n\n\u003e This step is needed only **when you want to use the REST API mode**.\n\n+ If any, please allow Application password of WordPress in Wordfence:\n\n![WBrffVs5Ty](https://chevereto.hwb0307.com/images/2023/06/05/WBrffVs5Ty.png)\n\n+ Go to personal settings and add a new REST API: \n\n![sq7kG7Vsqp](https://chevereto.hwb0307.com/images/2023/06/05/sq7kG7Vsqp.png)\n\n+ Please record the new REST API in a safe place. If you forget it or suspect its safety, please remove the old API and create a new one:\n\n![GddR0nP8mn](https://chevereto.hwb0307.com/images/2023/06/05/GddR0nP8mn.png)\n\n### Use m2w\n\n1. Install m2w from PyPi or this Github repotory. \n2. Build a `myblog.py` file (or other names you like) in `\u003cpath01\u003e`. Here is the [demo](https://github.com/huangwb8/m2w/blob/main/myblog.py). Create `\u003cpath02\u003e/config/user.json` and set `path_m2w` as `\u003cpath02\u003e` in `myblog.py`:\n\n```python\npath_m2w = '\u003cpath02\u003e' # Absolute path of m2w config folder\n```\n\n3. Define `\u003cpath02\u003e/config/user.json`.  You can add many websites like `web01`!  Please go to the [demo](https://github.com/huangwb8/m2w/blob/main/config/user.json) for more details. Here are some interpretations: \n  + **user.json** for REST API mode:\n\n\n```json\n\"web01\": {\n        \"domain\": \"https://domain-01.com\",\n        \"username\": \"username-01\",\n        \"application_password\": \"password-01\",\n        \"path_markdown\": [\n            \"E:/Github/m2w/@test/main\",\n            \"E:/Github/m2w/@test/main2\"\n        ],\n        \"post_metadata\": {\n            \"category\": [\"test\"],\n            \"tag\": [\"test\"],\n            \"status\": \"publish\"\n        },\n        \"path_legacy_json\": \"/config/legacy\"\n    }\n```\n\n+ **user.json** for Password mode: \n\n\n```json\n\"web01\": {\n        \"domain\": \"https://domain-01.com\",\n        \"username\": \"username-01\",\n        \"password\": \"password-01\",\n        \"path_markdown\": [\n            \"E:/Github/m2w/@test/main\",\n            \"E:/Github/m2w/@test/main2\"\n        ],\n        \"post_metadata\": {\n            \"category\": [\"test\"],\n            \"tag\": [\"test\"],\n            \"status\": \"publish\"\n        },\n        \"path_legacy_json\": \"/config/legacy\"\n    }\n```\n\n  + **domain, username, application_password/password**: The information of your WordPress site and account. `application_password` is REST API, and `password` is the conventional password of your account. If both `application_password` and `password` exist, only `application_password` is available for m2w.\n  + **path_markdown**: Add as much top folders as you want! \n  + **post_metadata/path_legacy_json**: Set default if you don't know what they are. \n\n4. Run `myblog.py` like: \n\n```bash\npython \u003cpath01\u003e/myblog.py\n```\n\n\u003e Need to ignore local helper files? In `myblog.py` set `ignore_files = [\"AGENTS.md\", \"CLAUDE.md\"]` (globs and `re:` regex supported). No user.json edits required.\n\n### Ignore unwanted files\n\n- Default ignore list in `myblog.py`: `[\"AGENTS.md\", \"CLAUDE.md\"]` (avoid uploading AI helper docs).\n- You can add globs (e.g., `\"**/draft-*.md\"`, `\"notes/**\"`) or regex prefixed with `re:` (e.g., `\"re:.*/temp-.*\\\\.md$\"`).\n- Leave `ignore_files` empty/remove it to scan all markdown files (backward compatible for older scripts).\n\n### Rate limiting and resumable uploads (v2.7+)\n\nWhen uploading a large number of articles (e.g., 1000+), you may want to enable rate limiting to avoid server bans:\n\n```python\n# In myblog.py\nrate_limit_enabled = True      # Enable rate limiting\nrequest_delay = 1.0            # Delay between requests (seconds)\nbatch_size = 10                # Files per batch\nbatch_delay = 5.0              # Delay between batches (seconds)\nmax_429_retries = 5            # Max retries on HTTP 429\ninitial_backoff = 2.0          # Initial backoff time (seconds)\n\nprogress_enabled = True        # Enable progress saving\nprogress_file = None           # None = same dir as legacy.json\n```\n\n**Recommended configurations:**\n- **Conservative** (strict servers): `request_delay=2.0`, `batch_size=5`, `batch_delay=10.0`\n- **Balanced** (recommended): `request_delay=1.0`, `batch_size=10`, `batch_delay=5.0`\n- **Aggressive** (lenient servers): `request_delay=0.5`, `batch_size=20`, `batch_delay=3.0`\n\n### Frontmatter options\n\nYou can use frontmatter in your Markdown files to control article behavior:\n\n```yaml\n---\ntitle: Your Article Title\nslug: custom-url-alias\nstatus: publish\npost_type: post\ncategory: [Technology]\ntag: [python, wordpress]\n---\n```\n\n**Available fields:**\n\n| Field | Description | Example |\n|-------|-------------|---------|\n| `title` | Article title (used for matching existing articles) | `title: My First Post` |\n| `slug` | Custom URL alias | `slug: my-custom-url` |\n| `status` | Article status: `publish`, `draft`, `delete` | `status: publish` |\n| `post_type` | Content type: `post`, `page`, or custom types like `shuoshuo` | `post_type: shuoshuo` |\n| `category` | Article categories | `category: [Tech, Python]` |\n| `tag` | Article tags | `tag: [code, tutorial]` |\n\n**Examples:**\n\nCreate a shuoshuo (status update):\n```yaml\n---\ntitle: Today's weather is nice!\npost_type: shuoshuo\nslug: shuoshuo-2025-01-24\nstatus: publish\n---\n```\n\nSet custom URL alias:\n```yaml\n---\ntitle: My Article\nslug: my-custom-url\nstatus: publish\n---\n```\n\nDelete an article:\n```yaml\n---\ntitle: Old Article\nstatus: delete\n---\n```\n\n\u003e **Note**: When `status: delete` is set, the article will be deleted from WordPress and the local Markdown file will be removed. Use with caution!`\n\n## Demo\n\n\u003e This demo is conducted in Win10 with [VScode](https://code.visualstudio.com/).\n\nAs shown in the following GIF, all changed or brand-new markdowns can be automatically updated/upload via just a simple command `python myblog.py`!\n\n![image-20230609173358533](https://chevereto.hwb0307.com/images/2023/06/09/image-20230609173358533.png)\n\n## Changelog\n\nSee [CHANGELOG.MD](CHANGELOG.MD) for the complete version history.\n\n**Current release: v2.7.2** (2026-01-24)\n- LaTeX math rendering support ($...$ and $$...$$ / \\begin...\\end{})\n- Markdown tables support\n- GFM Admonition support (optional, requires `pip install m2w[admonition]`)\n- Thanks to [@Mareep-YANG](https://github.com/Mareep-YANG) for contributing via [PR #20](https://github.com/huangwb8/m2w/pull/20)!\n\n## Related Efforts\n\n- [nefu-ljw/python-markdown-to-wordpress](https://github.com/nefu-ljw/python-markdown-to-wordpress)\n\n## Maintainers\n\n+ [@huangwb8](https://t.me/hwb0307) - Project founder\n+ [@FoxSuzuran](https://github.com/FoxSuzuran) - Core maintainer\n+ [@Mareep-YANG](https://github.com/Mareep-YANG) - LaTeX math, tables, and GFM Admonition support ([PR #20](https://github.com/huangwb8/m2w/pull/20))\n+ [@Shulelk](https://github.com/Shulelk) - Custom post types, URL aliases, and status control features ([PR #21](https://github.com/huangwb8/m2w/pull/21))\n\n## Contributing\n\n\u003e Feel free to dive in! [Open an issue](https://github.com/huangwb8/m2w/issues/new) or submit PRs. m2w follows the [Contributor Covenant](http://contributor-covenant.org/version/1/3/0/) Code of Conduct.\n\n\u003ca href=\"https://github.com/huangwb8/m2w/graphs/contributors\"\u003e\n  \u003cimg src=\"https://contrib.rocks/image?repo=huangwb8/m2w\" /\u003e\n\u003c/a\u003e\n\n## License\n\nThis software depends on other packages that may be licensed under different open source licenses. \n\nm2w is released under the MIT license. See [LICENSE](https://github.com/huangwb8/m2w/blob/main/license.txt) for details.\n\n\n[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fhuangwb8%2Fm2w.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2Fhuangwb8%2Fm2w?ref=badge_large)\n\n## More\n\n\u003e Applications similar to m2w\n\n+  [nefu-ljw/python-markdown-to-wordpress](https://github.com/nefu-ljw/python-markdown-to-wordpress): The root project of m2w!\n+  [WordPressXMLRPCTools](https://github.com/zhaoolee/WordPressXMLRPCTools): Manage WordPress posts in Hexo way.\n+  [markpress](https://github.com/skywind3000/markpress):  Write WordPress in Markdown in Your Favorite Text Editor\n+  [wordpress-markdown-blog-loader](https://pypi.org/project/wordpress-markdown-blog-loader/): This utility loads markdown blogs into WordPress as a post. It allows you to work on your blog in your favorite editor and keeps all your blogs in git.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhuangwb8%2Fm2w","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhuangwb8%2Fm2w","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhuangwb8%2Fm2w/lists"}