Feature: PushMD - Media upload & upsert support for push-only staging workflow
评估
- 难度
- 5/5
- 预计耗时
- 一周以上
- 新手友好度
- 35/100
调研方向
先从 push 同步路径和所提到的 export_media_content() 行为开始,然后跟踪 WordPress 上传内容的处理方式。将提议的 media/ 工作流、验证规则、URL 重写、upsert 行为以及 pull 清理作为验收标准;该 issue 未指明实现文件或测试,因此需要进行项目探索。
由索引模型根据 Issue 内容生成。
描述
Summary / Context
Currently, Push MD allows Markdown-first teams and AI coding agents to clone, edit, and push WordPress posts, pages, and templates. However, there is no support for managing post image assets through Git. When an author or agent creates a new post locally that includes diagrams, screenshots, quote cards, or a featured image, they must manually upload those images via WP-Admin and copy the resulting URLs back into Markdown before pushing.
I propose adding native Git media support to Push MD using a push-only staging directory (media/). Authors can drop image binaries into media/, reference them using relative paths in Markdown or Gutenberg blocks, and push via Git. Push MD handles fail-closed image validation, uploads/upserts the files into the WordPress Media Library, rewrites all inline content & block references to absolute WordPress attachment URLs, and cleans up the staging files on git pull to keep local checkouts lightweight.
Why Media Upload Support is Useful
- Complete Offline & Agent Workflows: Coding agents and local Markdown editors (Obsidian, VS Code, Cursor) can create complete posts - text and images - in a single Git commit without requiring manual WP-Admin file uploads.
- Lean Local Repositories (Push-Only Staging): By operating
media/as a push-only staging area, binary image blobs do not accumulate in Git history or bloat local checkouts over time. - In-Place Image Versioning: Updating an existing image via Git overwrites the file on disk and regenerates WordPress image metadata without creating duplicate attachment records (
image-1.png,image-2.png). - Automatic Attachment Metadata: Alt text, image titles, and
<figcaption>captions written in Markdown or HTML automatically populate WordPress attachment metadata.
Proposed Architecture & Workflow
1. The media/ Staging Directory
- A
media/directory is present in the repository tree (maintained via amedia/.gitkeepplaceholder). - Authors place image files directly under
media/(e.g.media/architecture-diagram.png). - In post Markdown, images are referenced using standard relative syntax:
---
title: "New Product Launch"
featured_image: "../media/hero.webp"
---

2. Push-Time Ingestion & URL Rewriting
When a commit is pushed to trunk:
- Upfront Payload Ingestion: Push MD detects files in
media/, validates them, and uploads them to the WordPress Uploads folder, creating or updating attachment records. - Contextual Metadata Assignment: Alt text (
), titles ("Title Text"), and figure captions (<figcaption>...</figcaption>) in post markup populate_wp_attachment_image_alt,post_title, andpost_excerpton the corresponding attachment. - Multi-Format Content Rewriting: Relative
media/paths are rewritten to absolute WordPress upload URLs across:- Markdown image syntax:
 - HTML attributes:
src,href,poster,srcsetacross<img>,<source>,<figure>, and<a>tags - Gutenberg Block comment JSON metadata:
<!-- wp:image {"id":0,"url":"../media/chart.png"} -->(updatesid,mediaId, andurlfields) - Front matter
featured_image(assigns post thumbnail attachment ID)
- Markdown image syntax:
- Filename-Based Re-Linking: If a Markdown post is pushed in a later commit referencing
media/existing-chart.png(where the binary is no longer in the commit tree), Push MD resolvesexisting-chart.pngagainst existing Media Library attachments by filename and links it cleanly.
3. Automatic Working Tree Cleanup (git pull)
- Binary images are ingested into the WordPress Media Library on push.
- To prevent binary bloat, Push MD does not export the Media Library into Git on clone/fetch (
export_media_content()returns an empty array). - On the next
git pull, repository synchronization notices the pushed image files are no longer exported by WordPress and creates a sync commit that deletes the staging image files from the Git tree while preservingmedia/.gitkeep. - Git fast-forwards the local working directory, automatically deleting the local
media/image.pngfile while keeping themedia/folder intact.
4. In-Place Upserts (Image Versioning)
- Standard WordPress
wp_upload_bits()renames same-named uploads toimage-1.png,image-2.png, creating duplicate attachment records. - Push MD checks if an attachment with the exact filename already exists. If found:
- Overwrites the file on disk (
get_attached_file()) in-place. - Regenerates image metadata (dimensions, thumbnails) via
wp_generate_attachment_metadata(). - Returns the existing attachment ID and URL, preserving existing post references.
- Overwrites the file on disk (
Security, Validation & Safety Model
Push MD operates on a strict fail-closed safety model:
- Extension Whitelist: Only
.png,.jpg,.jpeg,.gif, and.webpextensions are accepted. - Binary MIME Type Detection: Validates raw binary headers using
finfo_bufferwith fallback magic-number inspection (\x89PNG\r\n\x1a\n,\xFF\xD8\xFF,GIF87a/GIF89a,RIFF...WEBP) to prevent extension spoofing or execution of non-image payloads. - Path Traversal Protection: Rejects paths containing
..or attempted directory escapes outsidemedia/. - WordPress Capability Checks: Media upload processing runs within the authenticated user session, respecting WordPress editorial capabilities.
- Non-Image Filtering: Non-image placeholder files in
media/(such as.gitkeep) are skipped during ingestion without raising validation errors.
Why not WordPress media REST API?
I implemented this using REST API initially, but that requires additional maintenance, authentication and integration. Doing it via PushMD is much cleaner approach.
- 主要语言
- PHP
- 星标
- 22
- 派生
- 5
- PR 合并指标
- 30 天内没有已合并 PR
环境准备
在浏览器里用你自己的 GitHub 账号启动这个项目的开发容器。
- 提供 Dockerfile 或 Docker Compose 文件
- 没有 Pull Request 模板
- 没有贡献指南
从这里开始
- 先读完整个 Issue,再读项目的贡献指南。
- 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
- Fork 仓库,在一个分支上完成修改。
- 提交 Pull Request,并在描述里引用这个 Issue 编号。
Automattic/php-toolkit 的其他 Issue
-
Chore: Bump Docker demo environment PHP file upload size limit to 8MB可能已有人在做 关联的 PR 仍在进行中或已合并。 未关闭
难度 2/5 1-3 小时 新手友好度 84/100
Automattic/php-toolkit#89 ·
-
bug: PushMD - path conflict on duplicate slug for posts in draft可能已有人在做 @niravmehta 于 74 天前认领。 未关闭
难度 3/5 1-2 天 新手友好度 76/100
Automattic/php-toolkit#95 ·
-
Feature: Add Classic Editor & Standard HTML Support for Post Import/Export (PushMd)可能已有人在做 @niravmehta 于 78 天前认领。 未关闭
难度 5/5 一周以上 新手友好度 25/100
Automattic/php-toolkit#91 ·
-
Feature: Add support for .gitignore parsing and system file whitelisting可能已有人在做 关联的 PR 仍在进行中或已合并。 未关闭
难度 4/5 3-5 天 新手友好度 48/100
Automattic/php-toolkit#88 ·
-
Feature: Support arbitrary front matter metadata, categories, tags, author, featured image and SEO fields可能已有人在做 @niravmehta 于 78 天前认领。 未关闭
难度 5/5 一周以上 新手友好度 25/100
Automattic/php-toolkit#87 ·
查看 Automattic/php-toolkit 的全部 Issue
相似的 Issue
-
难度 1/5 1 小时以内 新手友好度 84/100
WordPress/hosting-handbook#506 ·
维护者通常 2 天内回复
-
Installing a plugin with composer_packages installs dev dependencies and breaks the autoloader (Error 500)可能已有人在做 @Boy132 今天认领。 未关闭
难度 2/5 1-3 小时 新手友好度 76/100
维护者通常 1 天内回复
-
nginx: static-file locations drop the security headers, and the dotfile deny is matched after them未关闭bug Low Security
难度 2/5 1-3 小时 新手友好度 78/100
维护者通常 1 天内回复
-
难度 2/5 1-3 小时 新手友好度 78/100
-
难度 1/5 1 小时以内 新手友好度 78/100
backdrop-contrib/commerce#60 ·