Skip to content

huangwb8/m2w

Repository files navigation

m2w: Markdown to WordPress

Automatically upload and update local markdown to WordPress based on REST API/Password via Python

🌟🌟🌟 Welcome m2w 2.6! REST uploads are sturdier (taxonomy cache/term_exists fixes, clearer errors) with configurable timeouts, the Password mode got a cleaner module layout while keeping old entry points working, vibe coding is used across the board, and you can filter out local files (e.g., AGENTS.md) in myblog.py to skip upload/update.

Chinese tutorial: Docker系列 WordPress系列 WordPress上传或更新Markdown的最佳实践-m2w 2.0

Table of Contents

Background

m2w is a tool for automatically uploading or updating local Markdown to WordPress via Python, based on REST API (2.5+) or Password.

m2w has these features:

  • Support REST API, which is safer then conventional password!
  • Use config/user.json to maintain the user information in a little different way comparing with m2w 1.0.
  • You can just keep your file structures locally as you like.
  • You can manage lots of websites at the same time via multiple legacy_*.json.
  • 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).
  • Ignore repeated new markdown files for uploading (v2.2.4+)

What's new in 2.6 vs 2.5

  • REST API uploads are more reliable: unified taxonomy cache handling, term_exists fixes, clearer errors, and no more infinite retries on updates.
  • REST requests now honor a configurable timeout (default 30s) so you can tune slow sites instead of hard failures.
  • Password mode was refactored into m2w.password.* modules while keeping up_password for backward compatibility.
  • Project maintenance follows vibe coding practices to keep the codebase consistent and lightweight.
  • You can exclude specific local files in myblog.py so they never enter the upload/update pipeline (useful for docs like AGENTS.md, CLAUDE.md, etc.).

Install

Miniconda is recommended to manage Python version and related dependencies.

  • Python >= 3.7.6
  • Runtime dependencies: python-frontmatter>=1.0.0, markdown>=3.3.6, python-wordpress-xmlrpc>=2.3, httpx>=0.24.0 (see requirements.txt)
  • Packaging now follows PEP 621 in pyproject.toml (setuptools); setup.py remains only for compatibility.

After 2022-12-10, m2w was uploaded onto PyPi. Install it via:

pip install m2w
# or pin a version
pip install -i https://pypi.org/simple m2w==2.6.2

From source, you can use the modern build flow:

python -m pip install --upgrade build
python -m build                      # generate wheel + sdist under dist/
python -m pip install dist/m2w-*.whl # install the built artifact
# editable install for development
python -m pip install -e .

Usage

Enable REST API

This step is needed only when you want to use the REST API mode.

  • If any, please allow Application password of WordPress in Wordfence:

WBrffVs5Ty

  • Go to personal settings and add a new REST API:

sq7kG7Vsqp

  • 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:

GddR0nP8mn

Use m2w

  1. Install m2w from PyPi or this Github repotory.
  2. Build a myblog.py file (or other names you like) in <path01>. Here is the demo. Create <path02>/config/user.json and set path_m2w as <path02> in myblog.py:
path_m2w = '<path02>' # Absolute path of m2w config folder
  1. Define <path02>/config/user.json. You can add many websites like web01! Please go to the demo for more details. Here are some interpretations:
  • user.json for REST API mode:
"web01": {
        "domain": "https://domain-01.com",
        "username": "username-01",
        "application_password": "password-01",
        "path_markdown": [
            "E:/Github/m2w/@test/main",
            "E:/Github/m2w/@test/main2"
        ],
        "post_metadata": {
            "category": ["test"],
            "tag": ["test"],
            "status": "publish"
        },
        "path_legacy_json": "/config/legacy"
    }
  • user.json for Password mode:
"web01": {
        "domain": "https://domain-01.com",
        "username": "username-01",
        "password": "password-01",
        "path_markdown": [
            "E:/Github/m2w/@test/main",
            "E:/Github/m2w/@test/main2"
        ],
        "post_metadata": {
            "category": ["test"],
            "tag": ["test"],
            "status": "publish"
        },
        "path_legacy_json": "/config/legacy"
    }
  • domain, username, application_password/password: The information of your WordPress site and account. application_password is REST API, and password is the conventional passord of your account. if both application_password and password exit, only application_password is available for m2w.
  • path_markdown: Add as much top folders as you want!
  • post_metadata/path_legacy_json: Set default if you don't know what they are.
  1. Run myblog.py like:
python <path01>/myblog.py

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.

Ignore unwanted files

  • Default ignore list in myblog.py: ["AGENTS.md", "CLAUDE.md"] (avoid uploading AI helper docs).
  • You can add globs (e.g., "**/draft-*.md", "notes/**") or regex prefixed with re: (e.g., "re:.*/temp-.*\\.md$").
  • Leave ignore_files empty/remove it to scan all markdown files (backward compatible for older scripts).

Demo

This demo is conducted in Win10 with VScode.

As shown in the following GIF, all changed or brand-new markdowns can be automatically updated/upload via just a simple command python myblog.py!

image-20230609173358533

LOG

  • 2025-12-22: Release v2.6.2 with default ignore list (AGENTS.md/CLAUDE.md), glob/re: regex support, and verbose logs when files are skipped; backward compatibility when ignore_files is absent.
  • 2025-12-21: Release v2.6.1 with REST API robustness fixes (taxonomy cache/term_exists handling, better errors), configurable REST timeout (defaults to 30s), and a refactored Password mode module layout that keeps backward compatibility.
  • 2025-12-12:Merge changes from Fix duplicate upload issue for special character filenames and release v2.5.14. Thanks @xiehs211!
  • 2024-11-13:Optimize optimize strategy for .md removement. Detail. Thanks linglilongyi!
  • 2023-06-05: m2w 2.0 was frozen at v2.2.11. Enjoy m2w 2.5+ from now on!
  • 2022-12-14m2w.py is the same name as m2w package, which would bring some bugs. I change the name of the demo script as myblog.py.
  • 2022-12-10:Upload m2w 2 to PyPi. You can install m2w 2 with code (in Shell) like pip install -i https://pypi.org/simple m2w. The project url is https://pypi.org/project/m2w.
  • 2022-12-08:Ignore repeated uploading of new markdown based on their file names. Update ot m2w 2.2.4 (Strongly recommended)!
  • 2022-12-06:Optimized parameter space of m2w, which make it more flexible. Update ot m2w 2.2!
  • 2022-12-03:Brand-new m2w 2.0!
  • 2022-11-13:Add error control for the Client function, which is helpful to avoid legacy bugs if the connection to the WordPress website is not available.
  • Before: Create m2w project.

TO-DO

  • shuoshuo and page update & upload

  • Enhanced markdown support: python-markdown to markdown-it-py

  • Support Hexo-like YAML head:

title: I Love You
tags:
  - You
  - I
  - Love
categories:
  - Note
date: 2023-11-08 16:38:31
update: 2023-11-08 16:40:31
--
  • Develop GUI across OS

Related Efforts

Maintainers

Contributing

Feel free to dive in! Open an issue or submit PRs. m2w follows the Contributor Covenant Code of Conduct.

License

This software depends on other packages that may be licensed under different open source licenses.

m2w is released under the MIT license. See LICENSE for details.

FOSSA Status

More

Applications similar to m2w

About

Automatically upload and update local markdown to WordPress via Python

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors 6

Languages