<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Content Management Automation Archives - WP-CLI Mastery</title>
	<atom:link href="https://wpclimastery.com/blog/category/content-management-automation/feed/" rel="self" type="application/rss+xml" />
	<link>https://wpclimastery.com/blog/category/content-management-automation/</link>
	<description>Automate WordPress Like a DevOps Pro.</description>
	<lastBuildDate>Mon, 24 Nov 2025 11:16:47 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	

<image>
	<url>https://wpclimastery.com/wp-content/uploads/2025/11/cropped-favicon-32x32.webp</url>
	<title>Content Management Automation Archives - WP-CLI Mastery</title>
	<link>https://wpclimastery.com/blog/category/content-management-automation/</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Bulk Content Operations in WordPress: WP-CLI Advanced Techniques</title>
		<link>https://wpclimastery.com/blog/bulk-content-operations-in-wordpress-wp-cli-advanced-techniques/</link>
		
		<dc:creator><![CDATA[Krasen]]></dc:creator>
		<pubDate>Thu, 05 Feb 2026 09:00:00 +0000</pubDate>
				<category><![CDATA[Content Management Automation]]></category>
		<category><![CDATA[batch content management]]></category>
		<category><![CDATA[bulk content wordpress]]></category>
		<category><![CDATA[wordpress mass edit]]></category>
		<category><![CDATA[wp-cli bulk operations]]></category>
		<category><![CDATA[wpcli content tools]]></category>
		<guid isPermaLink="false">https://wpclimastery.com/?p=141</guid>

					<description><![CDATA[<p>Managing hundreds or thousands of WordPress posts through the admin panel is impossible—updating categories across 500 posts, changing authors on old content, or adding custom fields to existing articles wastes...</p>
<p>The post <a href="https://wpclimastery.com/blog/bulk-content-operations-in-wordpress-wp-cli-advanced-techniques/">Bulk Content Operations in WordPress: WP-CLI Advanced Techniques</a> appeared first on <a href="https://wpclimastery.com">WP-CLI Mastery</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>Managing hundreds or thousands of WordPress posts through the admin panel is impossible—updating categories across 500 posts, changing authors on old content, or adding custom fields to existing articles wastes days of manual clicking.</p>



<p>WP-CLI transforms bulk content operations from tedious manual work into fast, scriptable workflows. Update unlimited posts with one command, batch-assign taxonomies, transform content structure, and automate complex content management tasks.</p>



<p>In this guide, you’ll learn advanced WP-CLI techniques for bulk content operations used by high-volume WordPress publishers managing thousands of posts efficiently.</p>



<h3 class="wp-block-heading" id="why-bulk-operations">Why Bulk Content Operations Matter</h3>



<p><a href="https://wordpress.org/support/article/posts-screen/">WordPress content management</a> at scale requires automation—manual operations don’t work beyond 50-100 posts.</p>



<h4 class="wp-block-heading" id="problems-with-manual-bulk-editing">Problems with Manual Bulk Editing</h4>



<p><strong>Time-consuming</strong>: Updating 1,000 posts manually takes weeks of repetitive work.</p>



<p><strong>Error-prone</strong>: Manual operations introduce inconsistencies and mistakes.</p>



<p><strong>Limited scope</strong>: Can’t perform complex transformations or conditional updates.</p>



<p><strong>No validation</strong>: Can’t preview changes before executing them.</p>



<p><strong>Not repeatable</strong>: Can’t reuse workflows or share processes with team.</p>



<h4 class="wp-block-heading" id="wp-cli-bulk-operation-advantages">WP-CLI Bulk Operation Advantages</h4>



<p><strong>Lightning fast</strong>: Update 10,000 posts in minutes instead of weeks.</p>



<p><strong>Scriptable</strong>: Save complex operations as reusable scripts.</p>



<p><strong>Conditional logic</strong>: Update only posts matching specific criteria.</p>



<p><strong>Preview mode</strong>: Test operations before executing on production data.</p>



<p><strong>Audit trails</strong>: Log all changes for compliance and debugging.</p>



<p>According to <a href="https://contentmarketinginstitute.com/">content management studies</a>, sites with 1,000+ posts save 40+ hours monthly with automated bulk operations.</p>



<h3 class="wp-block-heading" id="post-status">Bulk Post Status Operations</h3>



<p>Manage post publication status at scale.</p>



<h4 class="wp-block-heading" id="bulk-status-changes">Bulk Status Changes</h4>



<div class="sourceCode" id="cb1">
<pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true"></a><span class="co"># Publish all drafts</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true"></a><span class="ex">wp</span> post update <span class="va">$(</span><span class="ex">wp</span> post list --post_status=draft --format=ids<span class="va">)</span> --post_status=publish</span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true"></a></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true"></a><span class="co"># Draft all scheduled posts</span></span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true"></a><span class="ex">wp</span> post update <span class="va">$(</span><span class="ex">wp</span> post list --post_status=future --format=ids<span class="va">)</span> --post_status=draft</span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true"></a></span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true"></a><span class="co"># Unpublish posts older than 2 years</span></span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true"></a><span class="ex">wp</span> post list --post_status=publish --before=<span class="st">"2 years ago"</span> --format=ids <span class="kw">|</span> <span class="fu">xargs</span> wp post update --post_status=draft</span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true"></a></span>
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true"></a><span class="co"># Archive old posts (change status)</span></span>
<span id="cb1-11"><a href="#cb1-11" aria-hidden="true"></a><span class="va">YEAR_AGO=$(</span><span class="fu">date</span> -d <span class="st">"1 year ago"</span> +%Y-%m-%d<span class="va">)</span></span>
<span id="cb1-12"><a href="#cb1-12" aria-hidden="true"></a><span class="ex">wp</span> post update <span class="va">$(</span><span class="ex">wp</span> post list --post_status=publish --before=<span class="st">"</span><span class="va">$YEAR_AGO</span><span class="st">"</span> --format=ids<span class="va">)</span> --post_status=private</span></code></pre>
</div>



<h4 class="wp-block-heading" id="conditional-status-updates">Conditional Status Updates</h4>



<div class="sourceCode" id="cb2">
<pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true"></a><span class="co">#!/bin/bash</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true"></a><span class="co"># update-post-status-by-category.sh</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true"></a></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true"></a><span class="va">CATEGORY_ID=</span>5  # <span class="ex">Posts</span> in this category</span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true"></a><span class="va">TARGET_STATUS=</span><span class="st">"draft"</span></span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true"></a></span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true"></a><span class="co"># Get posts in specific category</span></span>
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true"></a><span class="va">POSTS=$(</span><span class="ex">wp</span> post list --category_id=<span class="va">$CATEGORY_ID</span> --post_status=publish --format=ids<span class="va">)</span></span>
<span id="cb2-9"><a href="#cb2-9" aria-hidden="true"></a></span>
<span id="cb2-10"><a href="#cb2-10" aria-hidden="true"></a><span class="kw">if</span><span class="bu"> [</span> <span class="ot">-z</span> <span class="st">"</span><span class="va">$POSTS</span><span class="st">"</span><span class="bu"> ]</span>; <span class="kw">then</span></span>
<span id="cb2-11"><a href="#cb2-11" aria-hidden="true"></a>    <span class="bu">echo</span> <span class="st">"No posts found in category </span><span class="va">$CATEGORY_ID</span><span class="st">"</span></span>
<span id="cb2-12"><a href="#cb2-12" aria-hidden="true"></a>    <span class="bu">exit</span> 0</span>
<span id="cb2-13"><a href="#cb2-13" aria-hidden="true"></a><span class="kw">fi</span></span>
<span id="cb2-14"><a href="#cb2-14" aria-hidden="true"></a></span>
<span id="cb2-15"><a href="#cb2-15" aria-hidden="true"></a><span class="co"># Count posts</span></span>
<span id="cb2-16"><a href="#cb2-16" aria-hidden="true"></a><span class="va">COUNT=$(</span><span class="bu">echo</span> <span class="va">$POSTS</span> <span class="kw">|</span> <span class="fu">wc</span> -w<span class="va">)</span></span>
<span id="cb2-17"><a href="#cb2-17" aria-hidden="true"></a><span class="bu">echo</span> <span class="st">"Found </span><span class="va">$COUNT</span><span class="st"> posts to update"</span></span>
<span id="cb2-18"><a href="#cb2-18" aria-hidden="true"></a></span>
<span id="cb2-19"><a href="#cb2-19" aria-hidden="true"></a><span class="co"># Update status</span></span>
<span id="cb2-20"><a href="#cb2-20" aria-hidden="true"></a><span class="ex">wp</span> post update <span class="va">$POSTS</span> --post_status=<span class="va">$TARGET_STATUS</span></span>
<span id="cb2-21"><a href="#cb2-21" aria-hidden="true"></a></span>
<span id="cb2-22"><a href="#cb2-22" aria-hidden="true"></a><span class="bu">echo</span> <span class="st">"✓ Updated </span><span class="va">$COUNT</span><span class="st"> posts to </span><span class="va">$TARGET_STATUS</span><span class="st"> status"</span></span></code></pre>
</div>



<p>Learn more about <a href="https://wordpress.org/support/article/post-status/">WordPress post statuses</a>.</p>



<h3 class="wp-block-heading" id="taxonomy-operations">Bulk Taxonomy Assignment</h3>



<p>Assign categories, tags, and custom taxonomies in bulk.</p>



<h4 class="wp-block-heading" id="bulk-category-operations">Bulk Category Operations</h4>



<div class="sourceCode" id="cb3">
<pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true"></a><span class="co"># Add category to all posts</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true"></a><span class="va">CATEGORY_ID=</span>10</span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true"></a><span class="kw">for</span> <span class="ex">post_id</span> in <span class="va">$(</span><span class="ex">wp</span> post list --format=ids<span class="va">)</span><span class="kw">;</span> <span class="kw">do</span></span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true"></a>    <span class="ex">wp</span> post term add <span class="va">$post_id</span> category <span class="va">$CATEGORY_ID</span></span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true"></a><span class="kw">done</span></span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true"></a></span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true"></a><span class="co"># Remove category from all posts</span></span>
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true"></a><span class="kw">for</span> <span class="ex">post_id</span> in <span class="va">$(</span><span class="ex">wp</span> post list --format=ids<span class="va">)</span><span class="kw">;</span> <span class="kw">do</span></span>
<span id="cb3-9"><a href="#cb3-9" aria-hidden="true"></a>    <span class="ex">wp</span> post term remove <span class="va">$post_id</span> category 3</span>
<span id="cb3-10"><a href="#cb3-10" aria-hidden="true"></a><span class="kw">done</span></span>
<span id="cb3-11"><a href="#cb3-11" aria-hidden="true"></a></span>
<span id="cb3-12"><a href="#cb3-12" aria-hidden="true"></a><span class="co"># Replace category across posts</span></span>
<span id="cb3-13"><a href="#cb3-13" aria-hidden="true"></a><span class="va">OLD_CAT=</span>5</span>
<span id="cb3-14"><a href="#cb3-14" aria-hidden="true"></a><span class="va">NEW_CAT=</span>10</span>
<span id="cb3-15"><a href="#cb3-15" aria-hidden="true"></a><span class="va">POSTS=$(</span><span class="ex">wp</span> post list --category=<span class="va">$OLD_CAT</span> --format=ids<span class="va">)</span></span>
<span id="cb3-16"><a href="#cb3-16" aria-hidden="true"></a></span>
<span id="cb3-17"><a href="#cb3-17" aria-hidden="true"></a><span class="kw">for</span> <span class="ex">post_id</span> in <span class="va">$POSTS</span><span class="kw">;</span> <span class="kw">do</span></span>
<span id="cb3-18"><a href="#cb3-18" aria-hidden="true"></a>    <span class="ex">wp</span> post term remove <span class="va">$post_id</span> category <span class="va">$OLD_CAT</span></span>
<span id="cb3-19"><a href="#cb3-19" aria-hidden="true"></a>    <span class="ex">wp</span> post term add <span class="va">$post_id</span> category <span class="va">$NEW_CAT</span></span>
<span id="cb3-20"><a href="#cb3-20" aria-hidden="true"></a><span class="kw">done</span></span>
<span id="cb3-21"><a href="#cb3-21" aria-hidden="true"></a></span>
<span id="cb3-22"><a href="#cb3-22" aria-hidden="true"></a><span class="bu">echo</span> <span class="st">"✓ Category replacement complete"</span></span></code></pre>
</div>



<h4 class="wp-block-heading" id="bulk-tag-operations">Bulk Tag Operations</h4>



<div class="sourceCode" id="cb4">
<pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true"></a><span class="co"># Add tags to all posts without tags</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true"></a><span class="ex">wp</span> post list --format=ids <span class="kw">|</span> <span class="kw">while</span> <span class="bu">read</span> <span class="va">post_id</span>; <span class="kw">do</span></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true"></a>    <span class="va">TAG_COUNT=$(</span><span class="ex">wp</span> post term list <span class="va">$post_id</span> post_tag --format=count<span class="va">)</span></span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true"></a></span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true"></a>    <span class="kw">if</span><span class="bu"> [</span> <span class="st">"</span><span class="va">$TAG_COUNT</span><span class="st">"</span> <span class="ot">-eq</span> 0<span class="bu"> ]</span>; <span class="kw">then</span></span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true"></a>        <span class="bu">echo</span> <span class="st">"Adding tags to post </span><span class="va">$post_id</span><span class="st">"</span></span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true"></a>        <span class="ex">wp</span> post term add <span class="va">$post_id</span> post_tag <span class="st">"general,uncategorized"</span></span>
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true"></a>    <span class="kw">fi</span></span>
<span id="cb4-9"><a href="#cb4-9" aria-hidden="true"></a><span class="kw">done</span></span>
<span id="cb4-10"><a href="#cb4-10" aria-hidden="true"></a></span>
<span id="cb4-11"><a href="#cb4-11" aria-hidden="true"></a><span class="co"># Remove all tags from specific category</span></span>
<span id="cb4-12"><a href="#cb4-12" aria-hidden="true"></a><span class="va">POSTS=$(</span><span class="ex">wp</span> post list --category_name=<span class="st">"old-news"</span> --format=ids<span class="va">)</span></span>
<span id="cb4-13"><a href="#cb4-13" aria-hidden="true"></a><span class="kw">for</span> <span class="ex">post_id</span> in <span class="va">$POSTS</span><span class="kw">;</span> <span class="kw">do</span></span>
<span id="cb4-14"><a href="#cb4-14" aria-hidden="true"></a>    <span class="ex">wp</span> post term remove <span class="va">$post_id</span> post_tag --all</span>
<span id="cb4-15"><a href="#cb4-15" aria-hidden="true"></a><span class="kw">done</span></span></code></pre>
</div>



<h4 class="wp-block-heading" id="smart-auto-categorization">Smart Auto-Categorization</h4>



<div class="sourceCode" id="cb5">
<pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true"></a><span class="co">#!/bin/bash</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true"></a><span class="co"># auto-categorize-by-keywords.sh - Assign categories based on content</span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true"></a></span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true"></a><span class="co"># Define keyword-to-category mapping</span></span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true"></a><span class="bu">declare</span> -A <span class="va">KEYWORDS=(</span></span>
<span id="cb5-6"><a href="#cb5-6" aria-hidden="true"></a>    [<span class="st">"WordPress"</span>]=<span class="st">"5"</span></span>
<span id="cb5-7"><a href="#cb5-7" aria-hidden="true"></a>    [<span class="st">"security"</span>]=<span class="st">"8"</span></span>
<span id="cb5-8"><a href="#cb5-8" aria-hidden="true"></a>    [<span class="st">"performance"</span>]=<span class="st">"12"</span></span>
<span id="cb5-9"><a href="#cb5-9" aria-hidden="true"></a>    [<span class="st">"tutorial"</span>]=<span class="st">"15"</span></span>
<span id="cb5-10"><a href="#cb5-10" aria-hidden="true"></a>)</span>
<span id="cb5-11"><a href="#cb5-11" aria-hidden="true"></a></span>
<span id="cb5-12"><a href="#cb5-12" aria-hidden="true"></a><span class="co"># Search for keywords and assign categories</span></span>
<span id="cb5-13"><a href="#cb5-13" aria-hidden="true"></a><span class="kw">for</span> <span class="ex">KEYWORD</span> in <span class="st">"</span><span class="va">${!KEYWORDS[@]}</span><span class="st">"</span><span class="kw">;</span> <span class="kw">do</span></span>
<span id="cb5-14"><a href="#cb5-14" aria-hidden="true"></a>    <span class="va">CAT_ID=</span><span class="st">"</span><span class="va">${KEYWORDS[$KEYWORD]}</span><span class="st">"</span></span>
<span id="cb5-15"><a href="#cb5-15" aria-hidden="true"></a></span>
<span id="cb5-16"><a href="#cb5-16" aria-hidden="true"></a>    <span class="bu">echo</span> <span class="st">"Processing keyword: </span><span class="va">$KEYWORD</span><span class="st"> → Category </span><span class="va">$CAT_ID</span><span class="st">"</span></span>
<span id="cb5-17"><a href="#cb5-17" aria-hidden="true"></a></span>
<span id="cb5-18"><a href="#cb5-18" aria-hidden="true"></a>    <span class="co"># Find posts containing keyword</span></span>
<span id="cb5-19"><a href="#cb5-19" aria-hidden="true"></a>    <span class="va">POSTS=$(</span><span class="ex">wp</span> post list --s=<span class="st">"</span><span class="va">$KEYWORD</span><span class="st">"</span> --post_status=publish --format=ids<span class="va">)</span></span>
<span id="cb5-20"><a href="#cb5-20" aria-hidden="true"></a></span>
<span id="cb5-21"><a href="#cb5-21" aria-hidden="true"></a>    <span class="kw">for</span> <span class="ex">post_id</span> in <span class="va">$POSTS</span><span class="kw">;</span> <span class="kw">do</span></span>
<span id="cb5-22"><a href="#cb5-22" aria-hidden="true"></a>        <span class="co"># Check if category already assigned</span></span>
<span id="cb5-23"><a href="#cb5-23" aria-hidden="true"></a>        <span class="va">HAS_CAT=$(</span><span class="ex">wp</span> post term list <span class="va">$post_id</span> category --field=term_id <span class="kw">|</span> <span class="fu">grep</span> -c <span class="st">"^</span><span class="va">${CAT_ID}</span><span class="st"><pre wp-pre-tag-4=""></pre>quot;</span><span class="va">)</span></span>
<span id="cb5-24"><a href="#cb5-24" aria-hidden="true"></a></span>
<span id="cb5-25"><a href="#cb5-25" aria-hidden="true"></a>        <span class="kw">if</span><span class="bu"> [</span> <span class="st">"</span><span class="va">$HAS_CAT</span><span class="st">"</span> <span class="ot">-eq</span> 0<span class="bu"> ]</span>; <span class="kw">then</span></span>
<span id="cb5-26"><a href="#cb5-26" aria-hidden="true"></a>            <span class="bu">echo</span> <span class="st">"  Adding category </span><span class="va">$CAT_ID</span><span class="st"> to post </span><span class="va">$post_id</span><span class="st">"</span></span>
<span id="cb5-27"><a href="#cb5-27" aria-hidden="true"></a>            <span class="ex">wp</span> post term add <span class="va">$post_id</span> category <span class="va">$CAT_ID</span></span>
<span id="cb5-28"><a href="#cb5-28" aria-hidden="true"></a>        <span class="kw">fi</span></span>
<span id="cb5-29"><a href="#cb5-29" aria-hidden="true"></a>    <span class="kw">done</span></span>
<span id="cb5-30"><a href="#cb5-30" aria-hidden="true"></a><span class="kw">done</span></span>
<span id="cb5-31"><a href="#cb5-31" aria-hidden="true"></a></span>
<span id="cb5-32"><a href="#cb5-32" aria-hidden="true"></a><span class="bu">echo</span> <span class="st">"✓ Auto-categorization complete"</span></span></code></pre>
</div>



<h3 class="wp-block-heading" id="author-operations">Bulk Author Updates</h3>



<p>Reassign post authorship in bulk.</p>



<h4 class="wp-block-heading" id="change-post-authors">Change Post Authors</h4>



<div class="sourceCode" id="cb6">
<pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true"></a><span class="co"># Reassign all posts from one author to another</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true"></a><span class="va">OLD_AUTHOR_ID=</span>5</span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true"></a><span class="va">NEW_AUTHOR_ID=</span>1</span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true"></a></span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true"></a><span class="ex">wp</span> post update <span class="va">$(</span><span class="ex">wp</span> post list --author=<span class="va">$OLD_AUTHOR_ID</span> --format=ids<span class="va">)</span> --post_author=<span class="va">$NEW_AUTHOR_ID</span></span>
<span id="cb6-6"><a href="#cb6-6" aria-hidden="true"></a></span>
<span id="cb6-7"><a href="#cb6-7" aria-hidden="true"></a><span class="co"># Update posts by author email</span></span>
<span id="cb6-8"><a href="#cb6-8" aria-hidden="true"></a><span class="va">OLD_EMAIL=</span><span class="st">"old@example.com"</span></span>
<span id="cb6-9"><a href="#cb6-9" aria-hidden="true"></a><span class="va">NEW_AUTHOR_ID=</span>2</span>
<span id="cb6-10"><a href="#cb6-10" aria-hidden="true"></a></span>
<span id="cb6-11"><a href="#cb6-11" aria-hidden="true"></a><span class="va">OLD_AUTHOR=$(</span><span class="ex">wp</span> user list --user_email=<span class="va">$OLD_EMAIL</span> --field=ID<span class="va">)</span></span>
<span id="cb6-12"><a href="#cb6-12" aria-hidden="true"></a><span class="ex">wp</span> post update <span class="va">$(</span><span class="ex">wp</span> post list --author=<span class="va">$OLD_AUTHOR</span> --format=ids<span class="va">)</span> --post_author=<span class="va">$NEW_AUTHOR_ID</span></span></code></pre>
</div>



<h4 class="wp-block-heading" id="distribute-posts-across-authors">Distribute Posts Across Authors</h4>



<div class="sourceCode" id="cb7">
<pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true"></a><span class="co">#!/bin/bash</span></span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true"></a><span class="co"># distribute-posts.sh - Evenly distribute posts across authors</span></span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true"></a></span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true"></a><span class="va">AUTHORS=(</span>2 5 8 12<span class="va">)</span>  # <span class="ex">Author</span> IDs</span>
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true"></a><span class="va">POSTS=$(</span><span class="ex">wp</span> post list --post_status=publish --format=ids<span class="va">)</span></span>
<span id="cb7-6"><a href="#cb7-6" aria-hidden="true"></a></span>
<span id="cb7-7"><a href="#cb7-7" aria-hidden="true"></a><span class="co"># Convert to array</span></span>
<span id="cb7-8"><a href="#cb7-8" aria-hidden="true"></a><span class="va">POST_ARRAY=($POSTS)</span></span>
<span id="cb7-9"><a href="#cb7-9" aria-hidden="true"></a><span class="va">TOTAL_POSTS=${#POST_ARRAY[@]}</span></span>
<span id="cb7-10"><a href="#cb7-10" aria-hidden="true"></a><span class="va">AUTHOR_COUNT=${#AUTHORS[@]}</span></span>
<span id="cb7-11"><a href="#cb7-11" aria-hidden="true"></a></span>
<span id="cb7-12"><a href="#cb7-12" aria-hidden="true"></a><span class="bu">echo</span> <span class="st">"Distributing </span><span class="va">$TOTAL_POSTS</span><span class="st"> posts across </span><span class="va">$AUTHOR_COUNT</span><span class="st"> authors..."</span></span>
<span id="cb7-13"><a href="#cb7-13" aria-hidden="true"></a></span>
<span id="cb7-14"><a href="#cb7-14" aria-hidden="true"></a><span class="va">INDEX=</span>0</span>
<span id="cb7-15"><a href="#cb7-15" aria-hidden="true"></a><span class="kw">for</span> <span class="ex">post_id</span> in <span class="st">"</span><span class="va">${POST_ARRAY[@]}</span><span class="st">"</span><span class="kw">;</span> <span class="kw">do</span></span>
<span id="cb7-16"><a href="#cb7-16" aria-hidden="true"></a>    <span class="va">AUTHOR_INDEX=$((</span>INDEX % AUTHOR_COUNT<span class="va">))</span></span>
<span id="cb7-17"><a href="#cb7-17" aria-hidden="true"></a>    <span class="va">AUTHOR_ID=${AUTHORS[$AUTHOR_INDEX]}</span></span>
<span id="cb7-18"><a href="#cb7-18" aria-hidden="true"></a></span>
<span id="cb7-19"><a href="#cb7-19" aria-hidden="true"></a>    <span class="ex">wp</span> post update <span class="va">$post_id</span> --post_author=<span class="va">$AUTHOR_ID</span></span>
<span id="cb7-20"><a href="#cb7-20" aria-hidden="true"></a></span>
<span id="cb7-21"><a href="#cb7-21" aria-hidden="true"></a>    <span class="kw">((</span>INDEX++<span class="kw">))</span></span>
<span id="cb7-22"><a href="#cb7-22" aria-hidden="true"></a><span class="kw">done</span></span>
<span id="cb7-23"><a href="#cb7-23" aria-hidden="true"></a></span>
<span id="cb7-24"><a href="#cb7-24" aria-hidden="true"></a><span class="bu">echo</span> <span class="st">"✓ Post distribution complete"</span></span></code></pre>
</div>



<h3 class="wp-block-heading" id="post-meta">Bulk Post Meta Operations</h3>



<p>Add, update, or delete custom fields across posts.</p>



<h4 class="wp-block-heading" id="add-meta-to-all-posts">Add Meta to All Posts</h4>



<div class="sourceCode" id="cb8">
<pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true"></a><span class="co"># Add custom field to all posts</span></span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true"></a><span class="kw">for</span> <span class="ex">post_id</span> in <span class="va">$(</span><span class="ex">wp</span> post list --format=ids<span class="va">)</span><span class="kw">;</span> <span class="kw">do</span></span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true"></a>    <span class="ex">wp</span> post meta add <span class="va">$post_id</span> featured_priority <span class="st">"normal"</span></span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true"></a><span class="kw">done</span></span>
<span id="cb8-5"><a href="#cb8-5" aria-hidden="true"></a></span>
<span id="cb8-6"><a href="#cb8-6" aria-hidden="true"></a><span class="co"># Add meta only to posts without it</span></span>
<span id="cb8-7"><a href="#cb8-7" aria-hidden="true"></a><span class="kw">for</span> <span class="ex">post_id</span> in <span class="va">$(</span><span class="ex">wp</span> post list --format=ids<span class="va">)</span><span class="kw">;</span> <span class="kw">do</span></span>
<span id="cb8-8"><a href="#cb8-8" aria-hidden="true"></a>    <span class="kw">if</span> ! <span class="ex">wp</span> post meta get <span class="va">$post_id</span> custom_field <span class="op">&amp;&gt;</span>/dev/null<span class="kw">;</span> <span class="kw">then</span></span>
<span id="cb8-9"><a href="#cb8-9" aria-hidden="true"></a>        <span class="ex">wp</span> post meta add <span class="va">$post_id</span> custom_field <span class="st">"default_value"</span></span>
<span id="cb8-10"><a href="#cb8-10" aria-hidden="true"></a>    <span class="kw">fi</span></span>
<span id="cb8-11"><a href="#cb8-11" aria-hidden="true"></a><span class="kw">done</span></span></code></pre>
</div>



<h4 class="wp-block-heading" id="update-meta-in-bulk">Update Meta in Bulk</h4>



<div class="sourceCode" id="cb9">
<pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true"></a><span class="co"># Update meta for posts in specific category</span></span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true"></a><span class="va">POSTS=$(</span><span class="ex">wp</span> post list --category_name=<span class="st">"premium"</span> --format=ids<span class="va">)</span></span>
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true"></a></span>
<span id="cb9-4"><a href="#cb9-4" aria-hidden="true"></a><span class="kw">for</span> <span class="ex">post_id</span> in <span class="va">$POSTS</span><span class="kw">;</span> <span class="kw">do</span></span>
<span id="cb9-5"><a href="#cb9-5" aria-hidden="true"></a>    <span class="ex">wp</span> post meta update <span class="va">$post_id</span> access_level <span class="st">"premium"</span></span>
<span id="cb9-6"><a href="#cb9-6" aria-hidden="true"></a>    <span class="ex">wp</span> post meta update <span class="va">$post_id</span> show_ads <span class="st">"false"</span></span>
<span id="cb9-7"><a href="#cb9-7" aria-hidden="true"></a><span class="kw">done</span></span>
<span id="cb9-8"><a href="#cb9-8" aria-hidden="true"></a></span>
<span id="cb9-9"><a href="#cb9-9" aria-hidden="true"></a><span class="co"># Conditional meta update</span></span>
<span id="cb9-10"><a href="#cb9-10" aria-hidden="true"></a><span class="kw">for</span> <span class="ex">post_id</span> in <span class="va">$(</span><span class="ex">wp</span> post list --format=ids<span class="va">)</span><span class="kw">;</span> <span class="kw">do</span></span>
<span id="cb9-11"><a href="#cb9-11" aria-hidden="true"></a>    <span class="va">OLD_VALUE=$(</span><span class="ex">wp</span> post meta get <span class="va">$post_id</span> old_field <span class="op">2&gt;</span>/dev/null<span class="va">)</span></span>
<span id="cb9-12"><a href="#cb9-12" aria-hidden="true"></a></span>
<span id="cb9-13"><a href="#cb9-13" aria-hidden="true"></a>    <span class="kw">if</span><span class="bu"> [</span> <span class="ot">-n</span> <span class="st">"</span><span class="va">$OLD_VALUE</span><span class="st">"</span><span class="bu"> ]</span>; <span class="kw">then</span></span>
<span id="cb9-14"><a href="#cb9-14" aria-hidden="true"></a>        <span class="ex">wp</span> post meta add <span class="va">$post_id</span> new_field <span class="st">"</span><span class="va">$OLD_VALUE</span><span class="st">"</span></span>
<span id="cb9-15"><a href="#cb9-15" aria-hidden="true"></a>        <span class="ex">wp</span> post meta delete <span class="va">$post_id</span> old_field</span>
<span id="cb9-16"><a href="#cb9-16" aria-hidden="true"></a>    <span class="kw">fi</span></span>
<span id="cb9-17"><a href="#cb9-17" aria-hidden="true"></a><span class="kw">done</span></span></code></pre>
</div>



<h4 class="wp-block-heading" id="clean-orphaned-meta">Clean Orphaned Meta</h4>



<div class="sourceCode" id="cb10">
<pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true"></a><span class="co">#!/bin/bash</span></span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true"></a><span class="co"># clean-post-meta.sh - Remove meta from deleted posts</span></span>
<span id="cb10-3"><a href="#cb10-3" aria-hidden="true"></a></span>
<span id="cb10-4"><a href="#cb10-4" aria-hidden="true"></a><span class="bu">echo</span> <span class="st">"Cleaning orphaned post meta..."</span></span>
<span id="cb10-5"><a href="#cb10-5" aria-hidden="true"></a></span>
<span id="cb10-6"><a href="#cb10-6" aria-hidden="true"></a><span class="co"># SQL query to find orphaned meta</span></span>
<span id="cb10-7"><a href="#cb10-7" aria-hidden="true"></a><span class="ex">wp</span> db query <span class="st">"</span></span>
<span id="cb10-8"><a href="#cb10-8" aria-hidden="true"></a><span class="st">DELETE FROM wp_postmeta</span></span>
<span id="cb10-9"><a href="#cb10-9" aria-hidden="true"></a><span class="st">WHERE post_id NOT IN (</span></span>
<span id="cb10-10"><a href="#cb10-10" aria-hidden="true"></a><span class="st">    SELECT ID FROM wp_posts</span></span>
<span id="cb10-11"><a href="#cb10-11" aria-hidden="true"></a><span class="st">)</span></span>
<span id="cb10-12"><a href="#cb10-12" aria-hidden="true"></a><span class="st">"</span></span>
<span id="cb10-13"><a href="#cb10-13" aria-hidden="true"></a></span>
<span id="cb10-14"><a href="#cb10-14" aria-hidden="true"></a><span class="bu">echo</span> <span class="st">"✓ Orphaned post meta cleaned"</span></span></code></pre>
</div>



<p>Learn about <a href="https://wordpress.org/support/article/custom-fields/">WordPress custom fields</a>.</p>



<h3 class="wp-block-heading" id="transformations">Content Transformation Operations</h3>



<p>Transform post content structure and format.</p>



<h4 class="wp-block-heading" id="bulk-content-search-replace">Bulk Content Search-Replace</h4>



<div class="sourceCode" id="cb11">
<pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true"></a><span class="co"># Replace text in all post content</span></span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true"></a><span class="ex">wp</span> search-replace <span class="st">"old company name"</span> <span class="st">"new company name"</span> wp_posts --dry-run</span>
<span id="cb11-3"><a href="#cb11-3" aria-hidden="true"></a><span class="ex">wp</span> search-replace <span class="st">"old company name"</span> <span class="st">"new company name"</span> wp_posts</span>
<span id="cb11-4"><a href="#cb11-4" aria-hidden="true"></a></span>
<span id="cb11-5"><a href="#cb11-5" aria-hidden="true"></a><span class="co"># Update image URLs</span></span>
<span id="cb11-6"><a href="#cb11-6" aria-hidden="true"></a><span class="ex">wp</span> search-replace <span class="st">"http://oldcdn.com"</span> <span class="st">"https://newcdn.com"</span> wp_posts</span>
<span id="cb11-7"><a href="#cb11-7" aria-hidden="true"></a></span>
<span id="cb11-8"><a href="#cb11-8" aria-hidden="true"></a><span class="co"># Fix broken shortcodes</span></span>
<span id="cb11-9"><a href="#cb11-9" aria-hidden="true"></a><span class="ex">wp</span> search-replace <span class="st">"[old_shortcode"</span> <span class="st">"[new_shortcode"</span> wp_posts</span></code></pre>
</div>



<h4 class="wp-block-heading" id="add-content-prefixsuffix">Add Content Prefix/Suffix</h4>



<div class="sourceCode" id="cb12">
<pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true"></a><span class="co">#!/bin/bash</span></span>
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true"></a><span class="co"># add-content-notice.sh - Add notice to all posts</span></span>
<span id="cb12-3"><a href="#cb12-3" aria-hidden="true"></a></span>
<span id="cb12-4"><a href="#cb12-4" aria-hidden="true"></a><span class="va">NOTICE=</span><span class="st">'&lt;div class="post-notice"&gt;This article was published over a year ago.&lt;/div&gt;'</span></span>
<span id="cb12-5"><a href="#cb12-5" aria-hidden="true"></a></span>
<span id="cb12-6"><a href="#cb12-6" aria-hidden="true"></a><span class="co"># Get posts older than 1 year</span></span>
<span id="cb12-7"><a href="#cb12-7" aria-hidden="true"></a><span class="va">POSTS=$(</span><span class="ex">wp</span> post list --before=<span class="st">"1 year ago"</span> --post_status=publish --format=ids<span class="va">)</span></span>
<span id="cb12-8"><a href="#cb12-8" aria-hidden="true"></a></span>
<span id="cb12-9"><a href="#cb12-9" aria-hidden="true"></a><span class="kw">for</span> <span class="ex">post_id</span> in <span class="va">$POSTS</span><span class="kw">;</span> <span class="kw">do</span></span>
<span id="cb12-10"><a href="#cb12-10" aria-hidden="true"></a>    <span class="va">CONTENT=$(</span><span class="ex">wp</span> post get <span class="va">$post_id</span> --field=post_content<span class="va">)</span></span>
<span id="cb12-11"><a href="#cb12-11" aria-hidden="true"></a></span>
<span id="cb12-12"><a href="#cb12-12" aria-hidden="true"></a>    <span class="co"># Check if notice already exists</span></span>
<span id="cb12-13"><a href="#cb12-13" aria-hidden="true"></a>    <span class="kw">if [[</span> <span class="ot">!</span> <span class="st">"</span><span class="va">$CONTENT</span><span class="st">"</span> =~ <span class="st">"post-notice"</span><span class="kw"> ]]</span>; <span class="kw">then</span></span>
<span id="cb12-14"><a href="#cb12-14" aria-hidden="true"></a>        <span class="va">NEW_CONTENT=</span><span class="st">"</span><span class="va">${NOTICE}${CONTENT}</span><span class="st">"</span></span>
<span id="cb12-15"><a href="#cb12-15" aria-hidden="true"></a></span>
<span id="cb12-16"><a href="#cb12-16" aria-hidden="true"></a>        <span class="ex">wp</span> post update <span class="va">$post_id</span> --post_content=<span class="st">"</span><span class="va">$NEW_CONTENT</span><span class="st">"</span></span>
<span id="cb12-17"><a href="#cb12-17" aria-hidden="true"></a>        <span class="bu">echo</span> <span class="st">"Added notice to post </span><span class="va">$post_id</span><span class="st">"</span></span>
<span id="cb12-18"><a href="#cb12-18" aria-hidden="true"></a>    <span class="kw">fi</span></span>
<span id="cb12-19"><a href="#cb12-19" aria-hidden="true"></a><span class="kw">done</span></span>
<span id="cb12-20"><a href="#cb12-20" aria-hidden="true"></a></span>
<span id="cb12-21"><a href="#cb12-21" aria-hidden="true"></a><span class="bu">echo</span> <span class="st">"✓ Content notices added"</span></span></code></pre>
</div>



<h4 class="wp-block-heading" id="convert-post-types">Convert Post Types</h4>



<div class="sourceCode" id="cb13">
<pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true"></a><span class="co"># Convert posts to pages</span></span>
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true"></a><span class="kw">for</span> <span class="ex">post_id</span> in <span class="va">$(</span><span class="ex">wp</span> post list --post_type=post --format=ids<span class="va">)</span><span class="kw">;</span> <span class="kw">do</span></span>
<span id="cb13-3"><a href="#cb13-3" aria-hidden="true"></a>    <span class="ex">wp</span> post update <span class="va">$post_id</span> --post_type=page</span>
<span id="cb13-4"><a href="#cb13-4" aria-hidden="true"></a><span class="kw">done</span></span>
<span id="cb13-5"><a href="#cb13-5" aria-hidden="true"></a></span>
<span id="cb13-6"><a href="#cb13-6" aria-hidden="true"></a><span class="co"># Convert pages back to posts</span></span>
<span id="cb13-7"><a href="#cb13-7" aria-hidden="true"></a><span class="kw">for</span> <span class="ex">post_id</span> in <span class="va">$(</span><span class="ex">wp</span> post list --post_type=page --format=ids<span class="va">)</span><span class="kw">;</span> <span class="kw">do</span></span>
<span id="cb13-8"><a href="#cb13-8" aria-hidden="true"></a>    <span class="ex">wp</span> post update <span class="va">$post_id</span> --post_type=post --post_category=1</span>
<span id="cb13-9"><a href="#cb13-9" aria-hidden="true"></a><span class="kw">done</span></span></code></pre>
</div>



<h3 class="wp-block-heading" id="cleanup-operations">Bulk Post Cleanup</h3>



<p>Remove unwanted content and maintain database health.</p>



<h4 class="wp-block-heading" id="delete-posts-by-criteria">Delete Posts by Criteria</h4>



<div class="sourceCode" id="cb14">
<pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true"></a><span class="co"># Delete all drafts older than 6 months</span></span>
<span id="cb14-2"><a href="#cb14-2" aria-hidden="true"></a><span class="ex">wp</span> post delete <span class="va">$(</span><span class="ex">wp</span> post list --post_status=draft --before=<span class="st">"6 months ago"</span> --format=ids<span class="va">)</span> --force</span>
<span id="cb14-3"><a href="#cb14-3" aria-hidden="true"></a></span>
<span id="cb14-4"><a href="#cb14-4" aria-hidden="true"></a><span class="co"># Delete empty posts</span></span>
<span id="cb14-5"><a href="#cb14-5" aria-hidden="true"></a><span class="ex">wp</span> post delete <span class="va">$(</span><span class="ex">wp</span> post list --post_content=<span class="st">""</span> --format=ids<span class="va">)</span> --force</span>
<span id="cb14-6"><a href="#cb14-6" aria-hidden="true"></a></span>
<span id="cb14-7"><a href="#cb14-7" aria-hidden="true"></a><span class="co"># Empty trash</span></span>
<span id="cb14-8"><a href="#cb14-8" aria-hidden="true"></a><span class="ex">wp</span> post delete <span class="va">$(</span><span class="ex">wp</span> post list --post_status=trash --format=ids<span class="va">)</span> --force</span>
<span id="cb14-9"><a href="#cb14-9" aria-hidden="true"></a></span>
<span id="cb14-10"><a href="#cb14-10" aria-hidden="true"></a><span class="co"># Delete posts with specific meta</span></span>
<span id="cb14-11"><a href="#cb14-11" aria-hidden="true"></a><span class="kw">for</span> <span class="ex">post_id</span> in <span class="va">$(</span><span class="ex">wp</span> post list --format=ids<span class="va">)</span><span class="kw">;</span> <span class="kw">do</span></span>
<span id="cb14-12"><a href="#cb14-12" aria-hidden="true"></a>    <span class="kw">if</span> <span class="ex">wp</span> post meta get <span class="va">$post_id</span> spam_flag <span class="op">2&gt;</span>/dev/null <span class="kw">|</span> <span class="fu">grep</span> -q <span class="st">"true"</span><span class="kw">;</span> <span class="kw">then</span></span>
<span id="cb14-13"><a href="#cb14-13" aria-hidden="true"></a>        <span class="ex">wp</span> post delete <span class="va">$post_id</span> --force</span>
<span id="cb14-14"><a href="#cb14-14" aria-hidden="true"></a>        <span class="bu">echo</span> <span class="st">"Deleted spam post: </span><span class="va">$post_id</span><span class="st">"</span></span>
<span id="cb14-15"><a href="#cb14-15" aria-hidden="true"></a>    <span class="kw">fi</span></span>
<span id="cb14-16"><a href="#cb14-16" aria-hidden="true"></a><span class="kw">done</span></span></code></pre>
</div>



<h4 class="wp-block-heading" id="clean-revisions">Clean Revisions</h4>



<div class="sourceCode" id="cb15">
<pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb15-1"><a href="#cb15-1" aria-hidden="true"></a><span class="co"># Delete all revisions</span></span>
<span id="cb15-2"><a href="#cb15-2" aria-hidden="true"></a><span class="ex">wp</span> post delete <span class="va">$(</span><span class="ex">wp</span> post list --post_type=revision --format=ids<span class="va">)</span> --force</span>
<span id="cb15-3"><a href="#cb15-3" aria-hidden="true"></a></span>
<span id="cb15-4"><a href="#cb15-4" aria-hidden="true"></a><span class="co"># Keep only last 5 revisions per post (requires custom logic)</span></span>
<span id="cb15-5"><a href="#cb15-5" aria-hidden="true"></a><span class="co">#!/bin/bash</span></span>
<span id="cb15-6"><a href="#cb15-6" aria-hidden="true"></a><span class="kw">for</span> <span class="ex">post_id</span> in <span class="va">$(</span><span class="ex">wp</span> post list --format=ids<span class="va">)</span><span class="kw">;</span> <span class="kw">do</span></span>
<span id="cb15-7"><a href="#cb15-7" aria-hidden="true"></a>    <span class="co"># Get revision IDs</span></span>
<span id="cb15-8"><a href="#cb15-8" aria-hidden="true"></a>    <span class="va">REVISIONS=$(</span><span class="ex">wp</span> post list --post_type=revision --post_parent=<span class="va">$post_id</span> --orderby=date --order=DESC --format=ids<span class="va">)</span></span>
<span id="cb15-9"><a href="#cb15-9" aria-hidden="true"></a></span>
<span id="cb15-10"><a href="#cb15-10" aria-hidden="true"></a>    <span class="co"># Convert to array</span></span>
<span id="cb15-11"><a href="#cb15-11" aria-hidden="true"></a>    <span class="va">REV_ARRAY=($REVISIONS)</span></span>
<span id="cb15-12"><a href="#cb15-12" aria-hidden="true"></a></span>
<span id="cb15-13"><a href="#cb15-13" aria-hidden="true"></a>    <span class="co"># Delete all but first 5</span></span>
<span id="cb15-14"><a href="#cb15-14" aria-hidden="true"></a>    <span class="kw">if</span><span class="bu"> [</span> <span class="va">${#REV_ARRAY[@]}</span> <span class="ot">-gt</span> 5<span class="bu"> ]</span>; <span class="kw">then</span></span>
<span id="cb15-15"><a href="#cb15-15" aria-hidden="true"></a>        <span class="va">REVISIONS_TO_DELETE=</span><span class="st">"</span><span class="va">${REV_ARRAY[@]:5}</span><span class="st">"</span></span>
<span id="cb15-16"><a href="#cb15-16" aria-hidden="true"></a>        <span class="ex">wp</span> post delete <span class="va">$REVISIONS_TO_DELETE</span> --force</span>
<span id="cb15-17"><a href="#cb15-17" aria-hidden="true"></a>    <span class="kw">fi</span></span>
<span id="cb15-18"><a href="#cb15-18" aria-hidden="true"></a><span class="kw">done</span></span></code></pre>
</div>



<h3 class="wp-block-heading" id="scheduled-operations">Scheduled Content Operations</h3>



<p>Automate recurring bulk content tasks.</p>



<h4 class="wp-block-heading" id="auto-publish-scheduled-script">Auto-Publish Scheduled Script</h4>



<div class="sourceCode" id="cb16">
<pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb16-1"><a href="#cb16-1" aria-hidden="true"></a><span class="co">#!/bin/bash</span></span>
<span id="cb16-2"><a href="#cb16-2" aria-hidden="true"></a><span class="co"># auto-publish-oldest-draft.sh - Publish oldest draft daily</span></span>
<span id="cb16-3"><a href="#cb16-3" aria-hidden="true"></a></span>
<span id="cb16-4"><a href="#cb16-4" aria-hidden="true"></a><span class="va">MAX_POSTS=${1:-</span>1<span class="va">}</span></span>
<span id="cb16-5"><a href="#cb16-5" aria-hidden="true"></a></span>
<span id="cb16-6"><a href="#cb16-6" aria-hidden="true"></a><span class="bu">echo</span> <span class="st">"Publishing up to </span><span class="va">$MAX_POSTS</span><span class="st"> draft posts..."</span></span>
<span id="cb16-7"><a href="#cb16-7" aria-hidden="true"></a></span>
<span id="cb16-8"><a href="#cb16-8" aria-hidden="true"></a><span class="va">DRAFTS=$(</span><span class="ex">wp</span> post list <span class="kw">\</span></span>
<span id="cb16-9"><a href="#cb16-9" aria-hidden="true"></a>    <span class="ex">--post_status</span>=draft <span class="kw">\</span></span>
<span id="cb16-10"><a href="#cb16-10" aria-hidden="true"></a>    <span class="ex">--orderby</span>=date <span class="kw">\</span></span>
<span id="cb16-11"><a href="#cb16-11" aria-hidden="true"></a>    <span class="ex">--order</span>=ASC <span class="kw">\</span></span>
<span id="cb16-12"><a href="#cb16-12" aria-hidden="true"></a>    <span class="ex">--posts_per_page</span>=<span class="va">$MAX_POSTS</span> <span class="kw">\</span></span>
<span id="cb16-13"><a href="#cb16-13" aria-hidden="true"></a>    <span class="ex">--format</span>=ids<span class="va">)</span></span>
<span id="cb16-14"><a href="#cb16-14" aria-hidden="true"></a></span>
<span id="cb16-15"><a href="#cb16-15" aria-hidden="true"></a><span class="kw">if</span><span class="bu"> [</span> <span class="ot">-z</span> <span class="st">"</span><span class="va">$DRAFTS</span><span class="st">"</span><span class="bu"> ]</span>; <span class="kw">then</span></span>
<span id="cb16-16"><a href="#cb16-16" aria-hidden="true"></a>    <span class="bu">echo</span> <span class="st">"No drafts available"</span></span>
<span id="cb16-17"><a href="#cb16-17" aria-hidden="true"></a>    <span class="bu">exit</span> 0</span>
<span id="cb16-18"><a href="#cb16-18" aria-hidden="true"></a><span class="kw">fi</span></span>
<span id="cb16-19"><a href="#cb16-19" aria-hidden="true"></a></span>
<span id="cb16-20"><a href="#cb16-20" aria-hidden="true"></a><span class="kw">for</span> <span class="ex">post_id</span> in <span class="va">$DRAFTS</span><span class="kw">;</span> <span class="kw">do</span></span>
<span id="cb16-21"><a href="#cb16-21" aria-hidden="true"></a>    <span class="va">TITLE=$(</span><span class="ex">wp</span> post get <span class="va">$post_id</span> --field=post_title<span class="va">)</span></span>
<span id="cb16-22"><a href="#cb16-22" aria-hidden="true"></a>    <span class="bu">echo</span> <span class="st">"Publishing: </span><span class="va">$TITLE</span><span class="st">"</span></span>
<span id="cb16-23"><a href="#cb16-23" aria-hidden="true"></a></span>
<span id="cb16-24"><a href="#cb16-24" aria-hidden="true"></a>    <span class="ex">wp</span> post update <span class="va">$post_id</span> <span class="kw">\</span></span>
<span id="cb16-25"><a href="#cb16-25" aria-hidden="true"></a>        <span class="ex">--post_status</span>=publish <span class="kw">\</span></span>
<span id="cb16-26"><a href="#cb16-26" aria-hidden="true"></a>        <span class="ex">--post_date</span>=<span class="st">"</span><span class="va">$(</span><span class="fu">date</span> <span class="st">'+%Y-%m-%d %H:%M:%S'</span><span class="va">)</span><span class="st">"</span></span>
<span id="cb16-27"><a href="#cb16-27" aria-hidden="true"></a><span class="kw">done</span></span>
<span id="cb16-28"><a href="#cb16-28" aria-hidden="true"></a></span>
<span id="cb16-29"><a href="#cb16-29" aria-hidden="true"></a><span class="bu">echo</span> <span class="st">"✓ Publishing complete"</span></span></code></pre>
</div>



<p>Schedule with cron:</p>



<div class="sourceCode" id="cb17">
<pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb17-1"><a href="#cb17-1" aria-hidden="true"></a><span class="co"># Publish 1 draft daily at 9 AM</span></span>
<span id="cb17-2"><a href="#cb17-2" aria-hidden="true"></a><span class="ex">0</span> 9 * * * /usr/local/bin/auto-publish-oldest-draft.sh 1</span></code></pre>
</div>



<h4 class="wp-block-heading" id="monthly-content-audit">Monthly Content Audit</h4>



<div class="sourceCode" id="cb18">
<pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb18-1"><a href="#cb18-1" aria-hidden="true"></a><span class="co">#!/bin/bash</span></span>
<span id="cb18-2"><a href="#cb18-2" aria-hidden="true"></a><span class="co"># monthly-content-audit.sh</span></span>
<span id="cb18-3"><a href="#cb18-3" aria-hidden="true"></a></span>
<span id="cb18-4"><a href="#cb18-4" aria-hidden="true"></a><span class="va">REPORT=</span><span class="st">"/tmp/content-audit-</span><span class="va">$(</span><span class="fu">date</span> +%Y%m<span class="va">)</span><span class="st">.txt"</span></span>
<span id="cb18-5"><a href="#cb18-5" aria-hidden="true"></a></span>
<span id="cb18-6"><a href="#cb18-6" aria-hidden="true"></a><span class="kw">{</span></span>
<span id="cb18-7"><a href="#cb18-7" aria-hidden="true"></a>    <span class="bu">echo</span> <span class="st">"WordPress Content Audit Report"</span></span>
<span id="cb18-8"><a href="#cb18-8" aria-hidden="true"></a>    <span class="bu">echo</span> <span class="st">"Generated: </span><span class="va">$(</span><span class="fu">date</span><span class="va">)</span><span class="st">"</span></span>
<span id="cb18-9"><a href="#cb18-9" aria-hidden="true"></a>    <span class="bu">echo</span> <span class="st">"=============================="</span></span>
<span id="cb18-10"><a href="#cb18-10" aria-hidden="true"></a>    <span class="bu">echo</span> <span class="st">""</span></span>
<span id="cb18-11"><a href="#cb18-11" aria-hidden="true"></a></span>
<span id="cb18-12"><a href="#cb18-12" aria-hidden="true"></a>    <span class="bu">echo</span> <span class="st">"Total Posts: </span><span class="va">$(</span><span class="ex">wp</span> post list --post_type=post --format=count<span class="va">)</span><span class="st">"</span></span>
<span id="cb18-13"><a href="#cb18-13" aria-hidden="true"></a>    <span class="bu">echo</span> <span class="st">"Published: </span><span class="va">$(</span><span class="ex">wp</span> post list --post_status=publish --format=count<span class="va">)</span><span class="st">"</span></span>
<span id="cb18-14"><a href="#cb18-14" aria-hidden="true"></a>    <span class="bu">echo</span> <span class="st">"Drafts: </span><span class="va">$(</span><span class="ex">wp</span> post list --post_status=draft --format=count<span class="va">)</span><span class="st">"</span></span>
<span id="cb18-15"><a href="#cb18-15" aria-hidden="true"></a>    <span class="bu">echo</span> <span class="st">"Scheduled: </span><span class="va">$(</span><span class="ex">wp</span> post list --post_status=future --format=count<span class="va">)</span><span class="st">"</span></span>
<span id="cb18-16"><a href="#cb18-16" aria-hidden="true"></a>    <span class="bu">echo</span> <span class="st">""</span></span>
<span id="cb18-17"><a href="#cb18-17" aria-hidden="true"></a></span>
<span id="cb18-18"><a href="#cb18-18" aria-hidden="true"></a>    <span class="bu">echo</span> <span class="st">"Posts by Category:"</span></span>
<span id="cb18-19"><a href="#cb18-19" aria-hidden="true"></a>    <span class="ex">wp</span> term list category --fields=name,count --format=table</span>
<span id="cb18-20"><a href="#cb18-20" aria-hidden="true"></a>    <span class="bu">echo</span> <span class="st">""</span></span>
<span id="cb18-21"><a href="#cb18-21" aria-hidden="true"></a></span>
<span id="cb18-22"><a href="#cb18-22" aria-hidden="true"></a>    <span class="bu">echo</span> <span class="st">"Posts Without Categories:"</span></span>
<span id="cb18-23"><a href="#cb18-23" aria-hidden="true"></a>    <span class="ex">wp</span> post list --category=0 --format=count</span>
<span id="cb18-24"><a href="#cb18-24" aria-hidden="true"></a>    <span class="bu">echo</span> <span class="st">""</span></span>
<span id="cb18-25"><a href="#cb18-25" aria-hidden="true"></a></span>
<span id="cb18-26"><a href="#cb18-26" aria-hidden="true"></a>    <span class="bu">echo</span> <span class="st">"Posts Without Tags:"</span></span>
<span id="cb18-27"><a href="#cb18-27" aria-hidden="true"></a>    <span class="kw">for</span> <span class="ex">post_id</span> in <span class="va">$(</span><span class="ex">wp</span> post list --format=ids <span class="kw">|</span> <span class="fu">head</span> -100<span class="va">)</span><span class="kw">;</span> <span class="kw">do</span></span>
<span id="cb18-28"><a href="#cb18-28" aria-hidden="true"></a>        <span class="va">TAG_COUNT=$(</span><span class="ex">wp</span> post term list <span class="va">$post_id</span> post_tag --format=count<span class="va">)</span></span>
<span id="cb18-29"><a href="#cb18-29" aria-hidden="true"></a>        [ <span class="st">"</span><span class="va">$TAG_COUNT</span><span class="st">"</span> <span class="ex">-eq</span> 0 ] <span class="kw">&amp;&amp;</span> <span class="kw">((</span>NO_TAGS++<span class="kw">))</span></span>
<span id="cb18-30"><a href="#cb18-30" aria-hidden="true"></a>    <span class="kw">done</span></span>
<span id="cb18-31"><a href="#cb18-31" aria-hidden="true"></a>    <span class="bu">echo</span> <span class="st">"</span><span class="va">${NO_TAGS:-</span>0<span class="va">}</span><span class="st"> posts"</span></span>
<span id="cb18-32"><a href="#cb18-32" aria-hidden="true"></a></span>
<span id="cb18-33"><a href="#cb18-33" aria-hidden="true"></a><span class="kw">}</span> <span class="op">&gt;</span> <span class="st">"</span><span class="va">$REPORT</span><span class="st">"</span></span>
<span id="cb18-34"><a href="#cb18-34" aria-hidden="true"></a></span>
<span id="cb18-35"><a href="#cb18-35" aria-hidden="true"></a><span class="co"># Email report</span></span>
<span id="cb18-36"><a href="#cb18-36" aria-hidden="true"></a><span class="ex">mail</span> -s <span class="st">"Monthly Content Audit"</span> admin@example.com <span class="op">&lt;</span> <span class="st">"</span><span class="va">$REPORT</span><span class="st">"</span></span>
<span id="cb18-37"><a href="#cb18-37" aria-hidden="true"></a></span>
<span id="cb18-38"><a href="#cb18-38" aria-hidden="true"></a><span class="bu">echo</span> <span class="st">"✓ Audit report sent"</span></span></code></pre>
</div>



<h3 class="wp-block-heading" id="next-steps">Next Steps</h3>



<p>You now have advanced bulk content operation skills for WordPress at scale.</p>



<h4 class="wp-block-heading" id="recommended-learning-path">Recommended Learning Path</h4>



<p><strong>Week 1</strong>: Basic bulk operations</p>



<ul class="wp-block-list">
<li>Practice post status updates</li>



<li>Master taxonomy assignments</li>



<li>Update post authors</li>
</ul>



<p><strong>Week 2</strong>: Advanced transformations</p>



<ul class="wp-block-list">
<li>Content search-replace</li>



<li>Meta field operations</li>



<li>Post type conversions</li>
</ul>



<p><strong>Week 3</strong>: Cleanup automation</p>



<ul class="wp-block-list">
<li>Delete unwanted content</li>



<li>Manage revisions</li>



<li>Orphaned data cleanup</li>
</ul>



<p><strong>Week 4</strong>: Scheduled workflows</p>



<ul class="wp-block-list">
<li>Auto-publishing scripts</li>



<li>Content audits</li>



<li>Maintenance automation</li>
</ul>



<h4 class="wp-block-heading" id="advanced-topics">Advanced Topics</h4>



<ol class="wp-block-list">
<li><strong><a href="#">Custom Post Type Bulk Operations</a></strong> &#8211; Advanced CPT management</li>



<li><strong><a href="#">Multi-Site Content Sync</a></strong> &#8211; Network-wide operations</li>



<li><strong><a href="#">AI Content Enhancement</a></strong> &#8211; Automated content improvements</li>
</ol>



<h4 class="wp-block-heading" id="get-more-resources">Get More Resources</h4>



<p><strong><a href="#">Download bulk operation scripts</a></strong> including:</p>



<ul class="wp-block-list">
<li>Complete automation toolkit</li>



<li>Content transformation scripts</li>



<li>Cleanup utilities</li>
</ul>



<p><strong><a href="/#get-started">Join our email course</a></strong> for:</p>



<ul class="wp-block-list">
<li>Weekly WP-CLI tutorials</li>



<li>Content management strategies</li>



<li>Automation best practices</li>
</ul>



<h3 class="wp-block-heading" id="conclusion">Conclusion</h3>



<p>WP-CLI bulk content operations transform WordPress content management from manual drudgery into fast, automated workflows that handle any scale.</p>



<p>What we covered:</p>



<p>✅ Bulk post status and publication management <br>✅ Taxonomy assignment and reorganization <br>✅ Author reassignment and distribution <br>✅ Post meta bulk operations <br>✅ Content transformation and cleanup <br>✅ Scheduled and automated workflows</p>



<p>Master these techniques, and you’ll manage thousands of WordPress posts as easily as managing ten—whether publishing content at scale or maintaining large content archives.</p>



<p><strong>Ready for more?</strong> Learn <a href="#">WordPress content migration</a> or <a href="#">automated content workflows</a>.</p>



<p><strong>Questions about bulk content operations in WordPress?</strong> Drop a comment below!</p>



<p><strong>Found this helpful?</strong> Share with other WordPress content managers.</p>
<p>The post <a href="https://wpclimastery.com/blog/bulk-content-operations-in-wordpress-wp-cli-advanced-techniques/">Bulk Content Operations in WordPress: WP-CLI Advanced Techniques</a> appeared first on <a href="https://wpclimastery.com">WP-CLI Mastery</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>WordPress Media Library Automation with WP-CLI: Complete Guide</title>
		<link>https://wpclimastery.com/blog/wordpress-media-library-automation-with-wp-cli-complete-guide/</link>
					<comments>https://wpclimastery.com/blog/wordpress-media-library-automation-with-wp-cli-complete-guide/#respond</comments>
		
		<dc:creator><![CDATA[Krasen]]></dc:creator>
		<pubDate>Mon, 24 Nov 2025 11:16:24 +0000</pubDate>
				<category><![CDATA[Content Management Automation]]></category>
		<category><![CDATA[bulk image upload]]></category>
		<category><![CDATA[wordpress media automation]]></category>
		<category><![CDATA[wordpress media management]]></category>
		<category><![CDATA[wp-cli media library]]></category>
		<category><![CDATA[wpcli media commands]]></category>
		<guid isPermaLink="false">https://wpclimastery.com/?p=218</guid>

					<description><![CDATA[<p>Managing thousands of media files in WordPress becomes tedious through the dashboard. WP-CLI transforms media library management from a manual chore into an automated, scriptable process, saving hours of work...</p>
<p>The post <a href="https://wpclimastery.com/blog/wordpress-media-library-automation-with-wp-cli-complete-guide/">WordPress Media Library Automation with WP-CLI: Complete Guide</a> appeared first on <a href="https://wpclimastery.com">WP-CLI Mastery</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>Managing thousands of media files in WordPress becomes tedious through the dashboard. WP-CLI transforms media library management from a manual chore into an automated, scriptable process, saving hours of work and ensuring consistency across large image collections.</p>



<h2 class="wp-block-heading" id="understanding-wordpress-media-management">Understanding WordPress Media Management</h2>



<p>WordPress stores media files in the uploads directory while maintaining database records for each attachment. These records include metadata like file paths, dimensions, captions, alt text, and custom fields. Effective media automation requires managing both filesystem operations and database records simultaneously.</p>



<p>The media library grows rapidly on content-heavy sites. Manual management becomes impractical when dealing with bulk operations like regenerating thumbnails, updating metadata, or migrating files. WP-CLI provides the tools to automate these tasks efficiently.</p>



<h2 class="wp-block-heading" id="bulk-image-import-and-upload">Bulk Image Import and Upload</h2>



<p>Traditional WordPress uploads through the dashboard are slow for large batches. WP-CLI enables efficient bulk imports from local directories or remote URLs.</p>



<pre class="wp-block-code"><code><em># Import single image</em>
wp media import /path/to/image.jpg --post_id=123 --title="Image Title" --alt="Alt text"

<em># Import all images from a directory</em>
wp media import /path/to/images/*.jpg --porcelain

<em># Import images and assign to specific post</em>
for file in /path/to/images/*.jpg; do
    wp media import "$file" --post_id=456 --featured_image
done

<em># Import from URL</em>
wp media import https://example.com/image.jpg --title="Remote Image"

<em># Bulk import with metadata from CSV</em>
while IFS=',' read -r filepath title alt caption; do
    wp media import "$filepath" --title="$title" --alt="$alt" --caption="$caption"
done &lt; images.csv
</code></pre>



<p>Create a comprehensive bulk import script:</p>



<pre class="wp-block-code"><code>#!/bin/bash
<em># bulk-media-import.sh - Import media with metadata</em>

set -euo pipefail

WP_PATH="/var/www/html"
IMPORT_DIR="/path/to/import"
LOG_FILE="/var/log/media-import-$(date +%Y%m%d).log"

log() {
    echo "&#91;$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
}

<em># Check if import directory exists</em>
if &#91; ! -d "$IMPORT_DIR" ]; then
    log "ERROR: Import directory does not exist: $IMPORT_DIR"
    exit 1
fi

log "Starting bulk media import from $IMPORT_DIR"

<em># Count files to process</em>
TOTAL_FILES=$(find "$IMPORT_DIR" -type f \( -iname "*.jpg" -o -iname "*.jpeg" -o -iname "*.png" -o -iname "*.gif" \) | wc -l)
log "Found $TOTAL_FILES files to import"

IMPORTED=0
FAILED=0

<em># Process each image</em>
find "$IMPORT_DIR" -type f \( -iname "*.jpg" -o -iname "*.jpeg" -o -iname "*.png" -o -iname "*.gif" \) | while read -r file; do
    FILENAME=$(basename "$file")
    log "Processing: $FILENAME"

    <em># Extract metadata from filename (example: product-123-description.jpg)</em>
    if &#91;&#91; "$FILENAME" =~ ^(&#91;^-]+)-(&#91;0-9]+)-(.+)\..+$ ]]; then
        TYPE="${BASH_REMATCH&#91;1]}"
        POST_ID="${BASH_REMATCH&#91;2]}"
        DESCRIPTION="${BASH_REMATCH&#91;3]}"

        <em># Import with metadata</em>
        if ATTACHMENT_ID=$(wp --path="$WP_PATH" media import "$file" \
            --post_id="$POST_ID" \
            --title="$DESCRIPTION" \
            --alt="$DESCRIPTION" \
            --porcelain 2&gt;&amp;1); then

            log "SUCCESS: Imported $FILENAME (ID: $ATTACHMENT_ID)"
            ((IMPORTED++))

            <em># Move processed file to archive</em>
            mkdir -p "$IMPORT_DIR/processed"
            mv "$file" "$IMPORT_DIR/processed/"
        else
            log "ERROR: Failed to import $FILENAME: $ATTACHMENT_ID"
            ((FAILED++))
        fi
    else
        <em># Import without post association</em>
        if ATTACHMENT_ID=$(wp --path="$WP_PATH" media import "$file" --porcelain 2&gt;&amp;1); then
            log "SUCCESS: Imported $FILENAME (ID: $ATTACHMENT_ID)"
            ((IMPORTED++))
            mv "$file" "$IMPORT_DIR/processed/"
        else
            log "ERROR: Failed to import $FILENAME"
            ((FAILED++))
        fi
    fi
done

log "Import completed. Imported: $IMPORTED, Failed: $FAILED"
</code></pre>



<h2 class="wp-block-heading" id="thumbnail-regeneration">Thumbnail Regeneration</h2>



<p>Changing themes or image sizes requires regenerating thumbnails for existing images. WP-CLI makes this process efficient.</p>



<pre class="wp-block-code"><code><em># Regenerate all thumbnails</em>
wp media regenerate --yes

<em># Regenerate only missing thumbnails</em>
wp media regenerate --only-missing --yes

<em># Regenerate for specific image sizes</em>
wp media regenerate --image_size=thumbnail,medium --yes

<em># Regenerate images from specific year</em>
wp media regenerate --yes $(wp post list --post_type=attachment --year=2024 --format=ids)

<em># Regenerate for specific attachment IDs</em>
wp media regenerate 123 456 789 --yes

<em># Skip thumbnail generation (only register sizes)</em>
wp media regenerate --skip-delete --yes
</code></pre>



<p>Automated thumbnail regeneration with progress tracking:</p>



<pre class="wp-block-code"><code>#!/bin/bash
<em># regenerate-thumbnails.sh - Regenerate with progress tracking</em>

WP_PATH="/var/www/html"

<em># Get total attachment count</em>
TOTAL=$(wp --path="$WP_PATH" post list --post_type=attachment --post_mime_type=image --format=count)
echo "Total images to process: $TOTAL"

<em># Process in batches</em>
BATCH_SIZE=50
PROCESSED=0

while &#91; $PROCESSED -lt $TOTAL ]; do
    echo "Processing batch: $PROCESSED to $((PROCESSED + BATCH_SIZE))"

    <em># Get batch of attachment IDs</em>
    IDS=$(wp --path="$WP_PATH" post list \
        --post_type=attachment \
        --post_mime_type=image \
        --posts_per_page=$BATCH_SIZE \
        --offset=$PROCESSED \
        --format=ids)

    if &#91; -n "$IDS" ]; then
        wp --path="$WP_PATH" media regenerate $IDS --yes
    fi

    PROCESSED=$((PROCESSED + BATCH_SIZE))
    echo "Progress: $PROCESSED / $TOTAL ($(( PROCESSED * 100 / TOTAL ))%)"

    <em># Sleep to avoid overloading server</em>
    sleep 2
done

echo "Thumbnail regeneration completed"
</code></pre>



<h2 class="wp-block-heading" id="image-optimization">Image Optimization</h2>



<p>Optimize images to reduce file sizes and improve site performance.</p>



<pre class="wp-block-code"><code><em># Install optimization plugin</em>
wp plugin install ewww-image-optimizer --activate

<em># Configure optimization settings</em>
wp option update ewww_image_optimizer_auto true
wp option update ewww_image_optimizer_jpg_level 30
wp option update ewww_image_optimizer_png_level 10

<em># Optimize all existing images</em>
wp ewwwio optimize all

<em># Optimize specific images</em>
wp media regenerate --yes --image_size=full
</code></pre>



<p>Alternative optimization with ImageMagick:</p>



<pre class="wp-block-code"><code>#!/bin/bash
<em># optimize-images.sh - Optimize images using ImageMagick</em>

WP_PATH="/var/www/html"
UPLOADS_DIR="$WP_PATH/wp-content/uploads"
QUALITY=85

echo "Optimizing images in $UPLOADS_DIR"

<em># Find and optimize JPG files</em>
find "$UPLOADS_DIR" -type f -iname "*.jpg" -o -iname "*.jpeg" | while read -r file; do
    echo "Optimizing: $file"

    <em># Create backup</em>
    cp "$file" "$file.backup"

    <em># Optimize with ImageMagick</em>
    convert "$file" -strip -interlace Plane -quality $QUALITY "$file"

    <em># Check if optimization saved space</em>
    ORIGINAL_SIZE=$(stat -f%z "$file.backup" 2&gt;/dev/null || stat -c%s "$file.backup")
    NEW_SIZE=$(stat -f%z "$file" 2&gt;/dev/null || stat -c%s "$file")

    if &#91; "$NEW_SIZE" -lt "$ORIGINAL_SIZE" ]; then
        SAVED=$((ORIGINAL_SIZE - NEW_SIZE))
        echo "Saved: $SAVED bytes"
        rm "$file.backup"
    else
        <em># Restore if no improvement</em>
        mv "$file.backup" "$file"
    fi
done

<em># Optimize PNG files</em>
find "$UPLOADS_DIR" -type f -iname "*.png" | while read -r file; do
    echo "Optimizing: $file"
    optipng -o2 "$file"
done

echo "Image optimization completed"
</code></pre>



<h2 class="wp-block-heading" id="metadata-management">Metadata Management</h2>



<p>Update alt text, captions, titles, and descriptions programmatically.</p>



<pre class="wp-block-code"><code><em># Update alt text for specific attachment</em>
wp post meta update 123 _wp_attachment_image_alt "New alt text"

<em># Update attachment title</em>
wp post update 123 --post_title="New Title"

<em># Update caption</em>
wp post update 123 --post_excerpt="New caption"

<em># Update description</em>
wp post update 123 --post_content="New description"

<em># Bulk update alt text based on filename</em>
for id in $(wp post list --post_type=attachment --format=ids); do
    FILENAME=$(wp post get $id --field=post_title)
    <em># Generate alt text from filename</em>
    ALT_TEXT=$(echo "$FILENAME" | sed 's/-/ /g' | sed 's/\.&#91;^.]*$//')
    wp post meta update $id _wp_attachment_image_alt "$ALT_TEXT"
    echo "Updated alt text for ID $id: $ALT_TEXT"
done
</code></pre>



<p>Comprehensive metadata update script:</p>



<pre class="wp-block-code"><code>#!/bin/bash
<em># update-media-metadata.sh - Bulk metadata updates</em>

WP_PATH="/var/www/html"
CSV_FILE="media-metadata.csv"

<em># CSV format: attachment_id,title,alt,caption,description</em>

while IFS=',' read -r id title alt caption description; do
    <em># Skip header row</em>
    if &#91; "$id" == "attachment_id" ]; then
        continue
    fi

    echo "Updating attachment ID: $id"

    <em># Update title</em>
    if &#91; -n "$title" ]; then
        wp --path="$WP_PATH" post update "$id" --post_title="$title"
    fi

    <em># Update alt text</em>
    if &#91; -n "$alt" ]; then
        wp --path="$WP_PATH" post meta update "$id" _wp_attachment_image_alt "$alt"
    fi

    <em># Update caption</em>
    if &#91; -n "$caption" ]; then
        wp --path="$WP_PATH" post update "$id" --post_excerpt="$caption"
    fi

    <em># Update description</em>
    if &#91; -n "$description" ]; then
        wp --path="$WP_PATH" post update "$id" --post_content="$description"
    fi

    echo "Metadata updated for attachment $id"
done &lt; "$CSV_FILE"

echo "Bulk metadata update completed"
</code></pre>



<h2 class="wp-block-heading" id="media-library-cleanup">Media Library Cleanup</h2>



<p>Remove unused, broken, or duplicate media files.</p>



<pre class="wp-block-code"><code><em># Find unattached media (not assigned to any post)</em>
wp post list --post_type=attachment --post_parent=0 --format=ids

<em># Delete unattached media</em>
wp post delete $(wp post list --post_type=attachment --post_parent=0 --format=ids) --force

<em># Find and remove broken attachments (missing files)</em>
for id in $(wp post list --post_type=attachment --format=ids); do
    FILE=$(wp post meta get $id _wp_attached_file)
    FULL_PATH="/var/www/html/wp-content/uploads/$FILE"

    if &#91; ! -f "$FULL_PATH" ]; then
        echo "Missing file for attachment $id: $FILE"
        wp post delete $id --force
    fi
done

<em># Find duplicate images by hash</em>
find /var/www/html/wp-content/uploads -type f -exec md5sum {} + | \
    sort | \
    uniq -w32 -D
</code></pre>



<p>Automated cleanup script:</p>



<pre class="wp-block-code"><code>#!/bin/bash
<em># media-cleanup.sh - Clean up media library</em>

set -euo pipefail

WP_PATH="/var/www/html"
DRY_RUN=false

if &#91; "${1:-}" == "--dry-run" ]; then
    DRY_RUN=true
    echo "Running in dry-run mode (no changes will be made)"
fi

echo "=== Media Library Cleanup ==="

<em># Find orphaned attachments (older than 30 days, never used)</em>
echo "Finding orphaned attachments..."
ORPHANED_IDS=$(wp --path="$WP_PATH" post list \
    --post_type=attachment \
    --post_parent=0 \
    --post_status=inherit \
    --format=ids \
    --date_query='&#91;{"before":"30 days ago"}]')

if &#91; -n "$ORPHANED_IDS" ]; then
    ORPHANED_COUNT=$(echo "$ORPHANED_IDS" | wc -w)
    echo "Found $ORPHANED_COUNT orphaned attachments"

    if &#91; "$DRY_RUN" == false ]; then
        echo "Deleting orphaned attachments..."
        wp --path="$WP_PATH" post delete $ORPHANED_IDS --force
    else
        echo "Would delete: $ORPHANED_IDS"
    fi
else
    echo "No orphaned attachments found"
fi

<em># Check for broken file links</em>
echo "Checking for broken file links..."
UPLOADS_DIR="$WP_PATH/wp-content/uploads"
BROKEN_COUNT=0

for id in $(wp --path="$WP_PATH" post list --post_type=attachment --format=ids); do
    FILE=$(wp --path="$WP_PATH" post meta get $id _wp_attached_file)
    FULL_PATH="$UPLOADS_DIR/$FILE"

    if &#91; ! -f "$FULL_PATH" ]; then
        echo "Broken attachment $id: $FILE"
        ((BROKEN_COUNT++))

        if &#91; "$DRY_RUN" == false ]; then
            wp --path="$WP_PATH" post delete $id --force
        fi
    fi
done

echo "Found $BROKEN_COUNT broken attachments"

<em># Remove unused image sizes</em>
echo "Cleaning up unused image sizes..."
find "$UPLOADS_DIR" -type f -regextype posix-extended \
    -regex '.*-&#91;0-9]+x&#91;0-9]+\.(jpg|jpeg|png|gif)$' \
    -mtime +90 | head -10

echo "Media cleanup completed"
</code></pre>



<h2 class="wp-block-heading" id="featured-image-management">Featured Image Management</h2>



<p>Automate featured image assignment across posts.</p>



<pre class="wp-block-code"><code><em># Set featured image for specific post</em>
wp post meta set 123 _thumbnail_id 456

<em># Assign first attached image as featured image</em>
for post_id in $(wp post list --post_type=post --format=ids); do
    <em># Get first attachment</em>
    ATTACHMENT_ID=$(wp post list --post_type=attachment --post_parent=$post_id --posts_per_page=1 --format=ids)

    if &#91; -n "$ATTACHMENT_ID" ]; then
        wp post meta set $post_id _thumbnail_id $ATTACHMENT_ID
        echo "Set featured image for post $post_id"
    fi
done

<em># Download and set featured image from URL</em>
URL="https://example.com/image.jpg"
POST_ID=123

ATTACHMENT_ID=$(wp media import "$URL" --post_id=$POST_ID --porcelain)
wp post meta set $POST_ID _thumbnail_id $ATTACHMENT_ID
</code></pre>



<h2 class="wp-block-heading" id="file-organization-and-migration">File Organization and Migration</h2>



<p>Reorganize uploads directory or migrate media between sites.</p>



<pre class="wp-block-code"><code>#!/bin/bash
<em># organize-uploads.sh - Organize uploads by year/month</em>

WP_PATH="/var/www/html"
UPLOADS_DIR="$WP_PATH/wp-content/uploads"

<em># Enable year/month organization</em>
wp --path="$WP_PATH" option update uploads_use_yearmonth_folders 1

<em># Migrate existing files to year/month structure</em>
for id in $(wp --path="$WP_PATH" post list --post_type=attachment --format=ids); do
    <em># Get attachment date</em>
    DATE=$(wp --path="$WP_PATH" post get $id --field=post_date)
    YEAR=$(date -d "$DATE" +%Y 2&gt;/dev/null || echo "")
    MONTH=$(date -d "$DATE" +%m 2&gt;/dev/null || echo "")

    if &#91; -n "$YEAR" ] &amp;&amp; &#91; -n "$MONTH" ]; then
        <em># Get current file path</em>
        FILE=$(wp --path="$WP_PATH" post meta get $id _wp_attached_file)

        <em># Skip if already organized</em>
        if &#91;&#91; "$FILE" =~ ^&#91;0-9]{4}/&#91;0-9]{2}/ ]]; then
            continue
        fi

        <em># Create target directory</em>
        TARGET_DIR="$UPLOADS_DIR/$YEAR/$MONTH"
        mkdir -p "$TARGET_DIR"

        <em># Move file</em>
        BASENAME=$(basename "$FILE")
        if &#91; -f "$UPLOADS_DIR/$FILE" ]; then
            mv "$UPLOADS_DIR/$FILE" "$TARGET_DIR/$BASENAME"

            <em># Update database</em>
            NEW_PATH="$YEAR/$MONTH/$BASENAME"
            wp --path="$WP_PATH" post meta update $id _wp_attached_file "$NEW_PATH"

            echo "Moved: $FILE -&gt; $NEW_PATH"
        fi
    fi
done

echo "Upload organization completed"
</code></pre>



<h2 class="wp-block-heading" id="media-export-and-backup">Media Export and Backup</h2>



<p>Create backups of media library with metadata.</p>



<pre class="wp-block-code"><code>#!/bin/bash
<em># backup-media.sh - Backup media library</em>

WP_PATH="/var/www/html"
BACKUP_DIR="/backups/media"
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
BACKUP_PATH="$BACKUP_DIR/media-backup-$TIMESTAMP"

mkdir -p "$BACKUP_PATH"

echo "Starting media backup..."

<em># Export attachment metadata</em>
wp --path="$WP_PATH" post list \
    --post_type=attachment \
    --format=json &gt; "$BACKUP_PATH/attachments-metadata.json"

<em># Backup uploads directory</em>
tar -czf "$BACKUP_PATH/uploads.tar.gz" \
    -C "$WP_PATH/wp-content" \
    uploads/

<em># Get backup size</em>
BACKUP_SIZE=$(du -sh "$BACKUP_PATH" | cut -f1)
echo "Backup completed: $BACKUP_SIZE at $BACKUP_PATH"

<em># Clean old backups (keep last 7)</em>
ls -t "$BACKUP_DIR" | tail -n +8 | xargs -I {} rm -rf "$BACKUP_DIR/{}"
</code></pre>



<h2 class="wp-block-heading" id="related-links">Related Links</h2>



<ul class="wp-block-list">
<li><a href="https://developer.wordpress.org/cli/commands/media/">WP-CLI Media Commands</a></li>



<li><a href="https://wordpress.org/support/article/media-library-screen/">WordPress Media Library Guide</a></li>



<li><a href="https://developer.wordpress.org/advanced-administration/performance/optimization/">Image Optimization Best Practices</a></li>



<li><a href="https://developer.wordpress.org/reference/functions/wp_generate_attachment_metadata/">WordPress Attachment Metadata</a></li>



<li><a href="https://docs.ewww.io/">EWWW Image Optimizer Documentation</a></li>
</ul>
<p>The post <a href="https://wpclimastery.com/blog/wordpress-media-library-automation-with-wp-cli-complete-guide/">WordPress Media Library Automation with WP-CLI: Complete Guide</a> appeared first on <a href="https://wpclimastery.com">WP-CLI Mastery</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://wpclimastery.com/blog/wordpress-media-library-automation-with-wp-cli-complete-guide/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
