<?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>Developer Resources Archives - Backup Copilot</title>
	<atom:link href="https://backupcopilotplugin.com/blog/category/developer-resources/feed/" rel="self" type="application/rss+xml" />
	<link>https://backupcopilotplugin.com/blog/category/developer-resources/</link>
	<description>WordPress Backups Done Right</description>
	<lastBuildDate>Mon, 24 Nov 2025 11:17:04 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	

<image>
	<url>https://storage.googleapis.com/backupcopilotplugin/2025/11/favicon-alt-150x150.png</url>
	<title>Developer Resources Archives - Backup Copilot</title>
	<link>https://backupcopilotplugin.com/blog/category/developer-resources/</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Backup Copilot Pro REST API: Automate Backups with External Systems</title>
		<link>https://backupcopilotplugin.com/blog/backup-copilot-pro-rest-api-automate-backups-with-external-systems/</link>
		
		<dc:creator><![CDATA[Krasen Slavov]]></dc:creator>
		<pubDate>Sun, 25 Jan 2026 09:00:00 +0000</pubDate>
				<category><![CDATA[Developer Resources]]></category>
		<category><![CDATA[api integration]]></category>
		<category><![CDATA[automation]]></category>
		<category><![CDATA[external integration]]></category>
		<category><![CDATA[headless wordpress]]></category>
		<category><![CDATA[rest api]]></category>
		<guid isPermaLink="false">https://backupcopilotplugin.com/?p=278</guid>

					<description><![CDATA[<p>Backup Copilot Pro’s REST API enables programmatic control of backups, restores, and schedules from external systems.</p>
<p>The post <a href="https://backupcopilotplugin.com/blog/backup-copilot-pro-rest-api-automate-backups-with-external-systems/">Backup Copilot Pro REST API: Automate Backups with External Systems</a> appeared first on <a href="https://backupcopilotplugin.com">Backup Copilot</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p><!-- @format --></p>
<p>Backup Copilot Pro’s REST API enables programmatic control of backups, restores, and schedules from external systems. Automate backups from CI/CD pipelines, build custom monitoring dashboards, integrate with mobile apps, or create multi-site management tools. This complete API reference shows you how with authentication methods, endpoint documentation, and integration examples.</p>
<h2 id="api-capabilities-overview">API Capabilities Overview</h2>
<p>The Backup Copilot Pro REST API provides:</p>
<p><strong>Backup Operations</strong>: Create, list, download, delete, and restore backups programmatically.</p>
<p><strong>Schedule Management</strong>: Create, update, and delete backup schedules via API.</p>
<p><strong>Real-Time Status</strong>: Monitor backup progress and completion status.</p>
<p><strong>Multi-Site Support</strong>: Manage backups across multiple WordPress installations from central system.</p>
<p><strong>Webhooks</strong>: Receive notifications when backup events occur (completed, failed, restored).</p>
<p><strong>Audit Logging</strong>: Track all API operations for compliance and security.</p>
<h2 id="authentication-methods">Authentication Methods</h2>
<p>Backup Copilot Pro API supports two authentication methods:</p>
<h3 id="application-passwords-recommended">Application Passwords (Recommended)</h3>
<p>WordPress Application Passwords provide secure API access without exposing main account password:</p>
<p><strong>Generate Application Password</strong>: 1. Navigate to Users → Profile in WordPress admin 2. Scroll to “Application Passwords” section 3. Enter name: “Backup Automation System” 4. Click “Add New Application Password” 5. Copy generated password (only shown once)</p>
<p><strong>Using Application Password</strong>:</p>
<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="ex">curl</span> -u username:application_password <span class="kw">\</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true"></a>  <span class="ex">https</span>://yoursite.com/wp-json/bkpc/v1/backup/list</span></code></pre>
</div>
<h3 id="oauth-2.0-enterprise">OAuth 2.0 (Enterprise)</h3>
<p>For enterprise integrations requiring token-based auth:</p>
<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"># Step 1: Get authorization code</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true"></a><span class="ex">https</span>://yoursite.com/oauth/authorize?</span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true"></a>  <span class="va">client_id=</span>YOUR_CLIENT_ID<span class="kw">&amp;</span></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true"></a>  <span class="va">redirect_uri=</span>https://app.example.com/callback<span class="kw">&amp;</span></span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true"></a>  <span class="va">response_type=</span>code<span class="kw">&amp;</span></span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true"></a>  <span class="va">scope=</span>backup:read <span class="ex">backup</span>:write</span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true"></a></span>
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true"></a><span class="co"># Step 2: Exchange code for access token</span></span>
<span id="cb2-9"><a href="#cb2-9" aria-hidden="true"></a><span class="ex">curl</span> -X POST https://yoursite.com/oauth/token <span class="kw">\</span></span>
<span id="cb2-10"><a href="#cb2-10" aria-hidden="true"></a>  <span class="ex">-d</span> <span class="st">&quot;grant_type=authorization_code&quot;</span> <span class="kw">\</span></span>
<span id="cb2-11"><a href="#cb2-11" aria-hidden="true"></a>  <span class="ex">-d</span> <span class="st">&quot;code=AUTHORIZATION_CODE&quot;</span> <span class="kw">\</span></span>
<span id="cb2-12"><a href="#cb2-12" aria-hidden="true"></a>  <span class="ex">-d</span> <span class="st">&quot;client_id=YOUR_CLIENT_ID&quot;</span> <span class="kw">\</span></span>
<span id="cb2-13"><a href="#cb2-13" aria-hidden="true"></a>  <span class="ex">-d</span> <span class="st">&quot;client_secret=YOUR_CLIENT_SECRET&quot;</span> <span class="kw">\</span></span>
<span id="cb2-14"><a href="#cb2-14" aria-hidden="true"></a>  <span class="ex">-d</span> <span class="st">&quot;redirect_uri=https://app.example.com/callback&quot;</span></span>
<span id="cb2-15"><a href="#cb2-15" aria-hidden="true"></a></span>
<span id="cb2-16"><a href="#cb2-16" aria-hidden="true"></a><span class="co"># Step 3: Use access token</span></span>
<span id="cb2-17"><a href="#cb2-17" aria-hidden="true"></a><span class="ex">curl</span> -H <span class="st">&quot;Authorization: Bearer ACCESS_TOKEN&quot;</span> <span class="kw">\</span></span>
<span id="cb2-18"><a href="#cb2-18" aria-hidden="true"></a>  <span class="ex">https</span>://yoursite.com/wp-json/bkpc/v1/backup/list</span></code></pre>
</div>
<h2 id="backup-endpoints">Backup Endpoints</h2>
<h3 id="create-new-backup">Create New Backup</h3>
<pre class="http"><code>POST /wp-json/bkpc/v1/backup/create</code></pre>
<p><strong>Request Body</strong>:</p>
<div class="sourceCode" id="cb4">
<pre class="sourceCode json"><code class="sourceCode json"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true"></a><span class="fu">{</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true"></a>  <span class="dt">&quot;type&quot;</span><span class="fu">:</span> <span class="st">&quot;full&quot;</span><span class="fu">,</span></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true"></a>  <span class="dt">&quot;cloud_upload&quot;</span><span class="fu">:</span> <span class="kw">true</span><span class="fu">,</span></span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true"></a>  <span class="dt">&quot;provider&quot;</span><span class="fu">:</span> <span class="st">&quot;dropbox&quot;</span><span class="fu">,</span></span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true"></a>  <span class="dt">&quot;send_notification&quot;</span><span class="fu">:</span> <span class="kw">true</span><span class="fu">,</span></span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true"></a>  <span class="dt">&quot;metadata&quot;</span><span class="fu">:</span> <span class="fu">{</span></span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true"></a>    <span class="dt">&quot;triggered_by&quot;</span><span class="fu">:</span> <span class="st">&quot;CI/CD Pipeline&quot;</span><span class="fu">,</span></span>
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true"></a>    <span class="dt">&quot;build_number&quot;</span><span class="fu">:</span> <span class="st">&quot;245&quot;</span></span>
<span id="cb4-9"><a href="#cb4-9" aria-hidden="true"></a>  <span class="fu">}</span></span>
<span id="cb4-10"><a href="#cb4-10" aria-hidden="true"></a><span class="fu">}</span></span></code></pre>
</div>
<p><strong>Parameters</strong>: &#8211; <code>type</code> (string): “full”, “database”, or “files”. Default: “full” &#8211; <code>cloud_upload</code> (boolean): Upload to cloud after creation. Default: false &#8211; <code>provider</code> (string): Cloud provider ID if uploading. Default: default provider &#8211; <code>send_notification</code> (boolean): Email notification on completion. Default: true &#8211; <code>metadata</code> (object): Custom metadata attached to backup</p>
<p><strong>Response</strong>:</p>
<div class="sourceCode" id="cb5">
<pre class="sourceCode json"><code class="sourceCode json"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true"></a><span class="fu">{</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true"></a>  <span class="dt">&quot;success&quot;</span><span class="fu">:</span> <span class="kw">true</span><span class="fu">,</span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true"></a>  <span class="dt">&quot;data&quot;</span><span class="fu">:</span> <span class="fu">{</span></span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true"></a>    <span class="dt">&quot;uuid&quot;</span><span class="fu">:</span> <span class="st">&quot;bkpc_20250124_093045_a8f3d2&quot;</span><span class="fu">,</span></span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true"></a>    <span class="dt">&quot;status&quot;</span><span class="fu">:</span> <span class="st">&quot;in_progress&quot;</span><span class="fu">,</span></span>
<span id="cb5-6"><a href="#cb5-6" aria-hidden="true"></a>    <span class="dt">&quot;type&quot;</span><span class="fu">:</span> <span class="st">&quot;full&quot;</span><span class="fu">,</span></span>
<span id="cb5-7"><a href="#cb5-7" aria-hidden="true"></a>    <span class="dt">&quot;created_at&quot;</span><span class="fu">:</span> <span class="st">&quot;2025-01-24T09:30:45Z&quot;</span><span class="fu">,</span></span>
<span id="cb5-8"><a href="#cb5-8" aria-hidden="true"></a>    <span class="dt">&quot;estimated_size&quot;</span><span class="fu">:</span> <span class="dv">1247652864</span><span class="fu">,</span></span>
<span id="cb5-9"><a href="#cb5-9" aria-hidden="true"></a>    <span class="dt">&quot;progress_url&quot;</span><span class="fu">:</span> <span class="st">&quot;/wp-json/bkpc/v1/backup/bkpc_20250124_093045_a8f3d2/status&quot;</span></span>
<span id="cb5-10"><a href="#cb5-10" aria-hidden="true"></a>  <span class="fu">}</span></span>
<span id="cb5-11"><a href="#cb5-11" aria-hidden="true"></a><span class="fu">}</span></span></code></pre>
</div>
<p><strong>cURL Example</strong>:</p>
<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="ex">curl</span> -X POST https://yoursite.com/wp-json/bkpc/v1/backup/create <span class="kw">\</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true"></a>  <span class="ex">-u</span> username:app_password <span class="kw">\</span></span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true"></a>  <span class="ex">-H</span> <span class="st">&quot;Content-Type: application/json&quot;</span> <span class="kw">\</span></span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true"></a>  <span class="ex">-d</span> <span class="st">&#39;{&quot;type&quot;:&quot;full&quot;,&quot;cloud_upload&quot;:true}&#39;</span></span></code></pre>
</div>
<h3 id="list-all-backups">List All Backups</h3>
<pre class="http"><code>GET /wp-json/bkpc/v1/backup/list</code></pre>
<p><strong>Query Parameters</strong>: &#8211; <code>page</code> (int): Page number for pagination. Default: 1 &#8211; <code>per_page</code> (int): Results per page (max 100). Default: 20 &#8211; <code>type</code> (string): Filter by backup type (“full”, “database”, “files”) &#8211; <code>status</code> (string): Filter by status (“completed”, “failed”, “in_progress”) &#8211; <code>order</code> (string): Sort order (“asc”, “desc”). Default: “desc” &#8211; <code>orderby</code> (string): Sort field (“created_at”, “size”). Default: “created_at”</p>
<p><strong>Response</strong>:</p>
<div class="sourceCode" id="cb8">
<pre class="sourceCode json"><code class="sourceCode json"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true"></a><span class="fu">{</span></span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true"></a>  <span class="dt">&quot;success&quot;</span><span class="fu">:</span> <span class="kw">true</span><span class="fu">,</span></span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true"></a>  <span class="dt">&quot;data&quot;</span><span class="fu">:</span> <span class="fu">{</span></span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true"></a>    <span class="dt">&quot;backups&quot;</span><span class="fu">:</span> <span class="ot">[</span></span>
<span id="cb8-5"><a href="#cb8-5" aria-hidden="true"></a>      <span class="fu">{</span></span>
<span id="cb8-6"><a href="#cb8-6" aria-hidden="true"></a>        <span class="dt">&quot;uuid&quot;</span><span class="fu">:</span> <span class="st">&quot;bkpc_20250124_093045_a8f3d2&quot;</span><span class="fu">,</span></span>
<span id="cb8-7"><a href="#cb8-7" aria-hidden="true"></a>        <span class="dt">&quot;type&quot;</span><span class="fu">:</span> <span class="st">&quot;full&quot;</span><span class="fu">,</span></span>
<span id="cb8-8"><a href="#cb8-8" aria-hidden="true"></a>        <span class="dt">&quot;status&quot;</span><span class="fu">:</span> <span class="st">&quot;completed&quot;</span><span class="fu">,</span></span>
<span id="cb8-9"><a href="#cb8-9" aria-hidden="true"></a>        <span class="dt">&quot;created_at&quot;</span><span class="fu">:</span> <span class="st">&quot;2025-01-24T09:30:45Z&quot;</span><span class="fu">,</span></span>
<span id="cb8-10"><a href="#cb8-10" aria-hidden="true"></a>        <span class="dt">&quot;completed_at&quot;</span><span class="fu">:</span> <span class="st">&quot;2025-01-24T09:35:12Z&quot;</span><span class="fu">,</span></span>
<span id="cb8-11"><a href="#cb8-11" aria-hidden="true"></a>        <span class="dt">&quot;size&quot;</span><span class="fu">:</span> <span class="dv">1247652864</span><span class="fu">,</span></span>
<span id="cb8-12"><a href="#cb8-12" aria-hidden="true"></a>        <span class="dt">&quot;cloud_provider&quot;</span><span class="fu">:</span> <span class="st">&quot;dropbox&quot;</span><span class="fu">,</span></span>
<span id="cb8-13"><a href="#cb8-13" aria-hidden="true"></a>        <span class="dt">&quot;cloud_uploaded&quot;</span><span class="fu">:</span> <span class="kw">true</span><span class="fu">,</span></span>
<span id="cb8-14"><a href="#cb8-14" aria-hidden="true"></a>        <span class="dt">&quot;download_url&quot;</span><span class="fu">:</span> <span class="st">&quot;/wp-json/bkpc/v1/backup/bkpc_20250124_093045_a8f3d2/download&quot;</span></span>
<span id="cb8-15"><a href="#cb8-15" aria-hidden="true"></a>      <span class="fu">}</span></span>
<span id="cb8-16"><a href="#cb8-16" aria-hidden="true"></a>    <span class="ot">]</span><span class="fu">,</span></span>
<span id="cb8-17"><a href="#cb8-17" aria-hidden="true"></a>    <span class="dt">&quot;pagination&quot;</span><span class="fu">:</span> <span class="fu">{</span></span>
<span id="cb8-18"><a href="#cb8-18" aria-hidden="true"></a>      <span class="dt">&quot;current_page&quot;</span><span class="fu">:</span> <span class="dv">1</span><span class="fu">,</span></span>
<span id="cb8-19"><a href="#cb8-19" aria-hidden="true"></a>      <span class="dt">&quot;per_page&quot;</span><span class="fu">:</span> <span class="dv">20</span><span class="fu">,</span></span>
<span id="cb8-20"><a href="#cb8-20" aria-hidden="true"></a>      <span class="dt">&quot;total_items&quot;</span><span class="fu">:</span> <span class="dv">87</span><span class="fu">,</span></span>
<span id="cb8-21"><a href="#cb8-21" aria-hidden="true"></a>      <span class="dt">&quot;total_pages&quot;</span><span class="fu">:</span> <span class="dv">5</span></span>
<span id="cb8-22"><a href="#cb8-22" aria-hidden="true"></a>    <span class="fu">}</span></span>
<span id="cb8-23"><a href="#cb8-23" aria-hidden="true"></a>  <span class="fu">}</span></span>
<span id="cb8-24"><a href="#cb8-24" aria-hidden="true"></a><span class="fu">}</span></span></code></pre>
</div>
<h3 id="get-backup-details">Get Backup Details</h3>
<pre class="http"><code>GET /wp-json/bkpc/v1/backup/{uuid}</code></pre>
<p><strong>Response</strong>:</p>
<div class="sourceCode" id="cb10">
<pre class="sourceCode json"><code class="sourceCode json"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true"></a><span class="fu">{</span></span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true"></a>  <span class="dt">&quot;success&quot;</span><span class="fu">:</span> <span class="kw">true</span><span class="fu">,</span></span>
<span id="cb10-3"><a href="#cb10-3" aria-hidden="true"></a>  <span class="dt">&quot;data&quot;</span><span class="fu">:</span> <span class="fu">{</span></span>
<span id="cb10-4"><a href="#cb10-4" aria-hidden="true"></a>    <span class="dt">&quot;uuid&quot;</span><span class="fu">:</span> <span class="st">&quot;bkpc_20250124_093045_a8f3d2&quot;</span><span class="fu">,</span></span>
<span id="cb10-5"><a href="#cb10-5" aria-hidden="true"></a>    <span class="dt">&quot;type&quot;</span><span class="fu">:</span> <span class="st">&quot;full&quot;</span><span class="fu">,</span></span>
<span id="cb10-6"><a href="#cb10-6" aria-hidden="true"></a>    <span class="dt">&quot;status&quot;</span><span class="fu">:</span> <span class="st">&quot;completed&quot;</span><span class="fu">,</span></span>
<span id="cb10-7"><a href="#cb10-7" aria-hidden="true"></a>    <span class="dt">&quot;created_at&quot;</span><span class="fu">:</span> <span class="st">&quot;2025-01-24T09:30:45Z&quot;</span><span class="fu">,</span></span>
<span id="cb10-8"><a href="#cb10-8" aria-hidden="true"></a>    <span class="dt">&quot;completed_at&quot;</span><span class="fu">:</span> <span class="st">&quot;2025-01-24T09:35:12Z&quot;</span><span class="fu">,</span></span>
<span id="cb10-9"><a href="#cb10-9" aria-hidden="true"></a>    <span class="dt">&quot;size&quot;</span><span class="fu">:</span> <span class="dv">1247652864</span><span class="fu">,</span></span>
<span id="cb10-10"><a href="#cb10-10" aria-hidden="true"></a>    <span class="dt">&quot;cloud_provider&quot;</span><span class="fu">:</span> <span class="st">&quot;dropbox&quot;</span><span class="fu">,</span></span>
<span id="cb10-11"><a href="#cb10-11" aria-hidden="true"></a>    <span class="dt">&quot;cloud_uploaded&quot;</span><span class="fu">:</span> <span class="kw">true</span><span class="fu">,</span></span>
<span id="cb10-12"><a href="#cb10-12" aria-hidden="true"></a>    <span class="dt">&quot;cloud_path&quot;</span><span class="fu">:</span> <span class="st">&quot;/backups/bkpc_20250124_093045_a8f3d2.zip&quot;</span><span class="fu">,</span></span>
<span id="cb10-13"><a href="#cb10-13" aria-hidden="true"></a>    <span class="dt">&quot;metadata&quot;</span><span class="fu">:</span> <span class="fu">{</span></span>
<span id="cb10-14"><a href="#cb10-14" aria-hidden="true"></a>      <span class="dt">&quot;wordpress_version&quot;</span><span class="fu">:</span> <span class="st">&quot;6.4.2&quot;</span><span class="fu">,</span></span>
<span id="cb10-15"><a href="#cb10-15" aria-hidden="true"></a>      <span class="dt">&quot;php_version&quot;</span><span class="fu">:</span> <span class="st">&quot;8.2.0&quot;</span><span class="fu">,</span></span>
<span id="cb10-16"><a href="#cb10-16" aria-hidden="true"></a>      <span class="dt">&quot;mysql_version&quot;</span><span class="fu">:</span> <span class="st">&quot;8.0.35&quot;</span><span class="fu">,</span></span>
<span id="cb10-17"><a href="#cb10-17" aria-hidden="true"></a>      <span class="dt">&quot;table_count&quot;</span><span class="fu">:</span> <span class="dv">47</span><span class="fu">,</span></span>
<span id="cb10-18"><a href="#cb10-18" aria-hidden="true"></a>      <span class="dt">&quot;file_count&quot;</span><span class="fu">:</span> <span class="dv">12847</span><span class="fu">,</span></span>
<span id="cb10-19"><a href="#cb10-19" aria-hidden="true"></a>      <span class="dt">&quot;triggered_by&quot;</span><span class="fu">:</span> <span class="st">&quot;CI/CD Pipeline&quot;</span></span>
<span id="cb10-20"><a href="#cb10-20" aria-hidden="true"></a>    <span class="fu">},</span></span>
<span id="cb10-21"><a href="#cb10-21" aria-hidden="true"></a>    <span class="dt">&quot;includes&quot;</span><span class="fu">:</span> <span class="fu">{</span></span>
<span id="cb10-22"><a href="#cb10-22" aria-hidden="true"></a>      <span class="dt">&quot;database&quot;</span><span class="fu">:</span> <span class="kw">true</span><span class="fu">,</span></span>
<span id="cb10-23"><a href="#cb10-23" aria-hidden="true"></a>      <span class="dt">&quot;plugins&quot;</span><span class="fu">:</span> <span class="kw">true</span><span class="fu">,</span></span>
<span id="cb10-24"><a href="#cb10-24" aria-hidden="true"></a>      <span class="dt">&quot;themes&quot;</span><span class="fu">:</span> <span class="kw">true</span><span class="fu">,</span></span>
<span id="cb10-25"><a href="#cb10-25" aria-hidden="true"></a>      <span class="dt">&quot;uploads&quot;</span><span class="fu">:</span> <span class="kw">true</span><span class="fu">,</span></span>
<span id="cb10-26"><a href="#cb10-26" aria-hidden="true"></a>      <span class="dt">&quot;wordpress_core&quot;</span><span class="fu">:</span> <span class="kw">false</span></span>
<span id="cb10-27"><a href="#cb10-27" aria-hidden="true"></a>    <span class="fu">}</span></span>
<span id="cb10-28"><a href="#cb10-28" aria-hidden="true"></a>  <span class="fu">}</span></span>
<span id="cb10-29"><a href="#cb10-29" aria-hidden="true"></a><span class="fu">}</span></span></code></pre>
</div>
<h3 id="download-backup">Download Backup</h3>
<pre class="http"><code>POST /wp-json/bkpc/v1/backup/{uuid}/download</code></pre>
<p><strong>Response</strong>:</p>
<div class="sourceCode" id="cb12">
<pre class="sourceCode json"><code class="sourceCode json"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true"></a><span class="fu">{</span></span>
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true"></a>  <span class="dt">&quot;success&quot;</span><span class="fu">:</span> <span class="kw">true</span><span class="fu">,</span></span>
<span id="cb12-3"><a href="#cb12-3" aria-hidden="true"></a>  <span class="dt">&quot;data&quot;</span><span class="fu">:</span> <span class="fu">{</span></span>
<span id="cb12-4"><a href="#cb12-4" aria-hidden="true"></a>    <span class="dt">&quot;download_url&quot;</span><span class="fu">:</span> <span class="st">&quot;https://yoursite.com/wp-content/backup-copilot-pro/downloads/bkpc_20250124_093045_a8f3d2.zip?token=abc123&quot;</span><span class="fu">,</span></span>
<span id="cb12-5"><a href="#cb12-5" aria-hidden="true"></a>    <span class="dt">&quot;expires_at&quot;</span><span class="fu">:</span> <span class="st">&quot;2025-01-24T10:30:45Z&quot;</span><span class="fu">,</span></span>
<span id="cb12-6"><a href="#cb12-6" aria-hidden="true"></a>    <span class="dt">&quot;size&quot;</span><span class="fu">:</span> <span class="dv">1247652864</span></span>
<span id="cb12-7"><a href="#cb12-7" aria-hidden="true"></a>  <span class="fu">}</span></span>
<span id="cb12-8"><a href="#cb12-8" aria-hidden="true"></a><span class="fu">}</span></span></code></pre>
</div>
<p>Download URL expires after 1 hour for security.</p>
<h3 id="delete-backup">Delete Backup</h3>
<pre class="http"><code>DELETE /wp-json/bkpc/v1/backup/{uuid}</code></pre>
<p><strong>Query Parameters</strong>: &#8211; <code>delete_cloud</code> (boolean): Also delete from cloud storage. Default: false</p>
<p><strong>Response</strong>:</p>
<div class="sourceCode" id="cb14">
<pre class="sourceCode json"><code class="sourceCode json"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true"></a><span class="fu">{</span></span>
<span id="cb14-2"><a href="#cb14-2" aria-hidden="true"></a>  <span class="dt">&quot;success&quot;</span><span class="fu">:</span> <span class="kw">true</span><span class="fu">,</span></span>
<span id="cb14-3"><a href="#cb14-3" aria-hidden="true"></a>  <span class="dt">&quot;message&quot;</span><span class="fu">:</span> <span class="st">&quot;Backup deleted successfully&quot;</span></span>
<span id="cb14-4"><a href="#cb14-4" aria-hidden="true"></a><span class="fu">}</span></span></code></pre>
</div>
<h3 id="restore-from-backup">Restore from Backup</h3>
<pre class="http"><code>POST /wp-json/bkpc/v1/backup/{uuid}/restore</code></pre>
<p><strong>Request Body</strong>:</p>
<div class="sourceCode" id="cb16">
<pre class="sourceCode json"><code class="sourceCode json"><span id="cb16-1"><a href="#cb16-1" aria-hidden="true"></a><span class="fu">{</span></span>
<span id="cb16-2"><a href="#cb16-2" aria-hidden="true"></a>  <span class="dt">&quot;restore_database&quot;</span><span class="fu">:</span> <span class="kw">true</span><span class="fu">,</span></span>
<span id="cb16-3"><a href="#cb16-3" aria-hidden="true"></a>  <span class="dt">&quot;restore_files&quot;</span><span class="fu">:</span> <span class="kw">true</span><span class="fu">,</span></span>
<span id="cb16-4"><a href="#cb16-4" aria-hidden="true"></a>  <span class="dt">&quot;restore_plugins&quot;</span><span class="fu">:</span> <span class="kw">true</span><span class="fu">,</span></span>
<span id="cb16-5"><a href="#cb16-5" aria-hidden="true"></a>  <span class="dt">&quot;restore_themes&quot;</span><span class="fu">:</span> <span class="kw">true</span><span class="fu">,</span></span>
<span id="cb16-6"><a href="#cb16-6" aria-hidden="true"></a>  <span class="dt">&quot;restore_uploads&quot;</span><span class="fu">:</span> <span class="kw">true</span></span>
<span id="cb16-7"><a href="#cb16-7" aria-hidden="true"></a><span class="fu">}</span></span></code></pre>
</div>
<p><strong>Response</strong>:</p>
<div class="sourceCode" id="cb17">
<pre class="sourceCode json"><code class="sourceCode json"><span id="cb17-1"><a href="#cb17-1" aria-hidden="true"></a><span class="fu">{</span></span>
<span id="cb17-2"><a href="#cb17-2" aria-hidden="true"></a>  <span class="dt">&quot;success&quot;</span><span class="fu">:</span> <span class="kw">true</span><span class="fu">,</span></span>
<span id="cb17-3"><a href="#cb17-3" aria-hidden="true"></a>  <span class="dt">&quot;data&quot;</span><span class="fu">:</span> <span class="fu">{</span></span>
<span id="cb17-4"><a href="#cb17-4" aria-hidden="true"></a>    <span class="dt">&quot;restore_id&quot;</span><span class="fu">:</span> <span class="st">&quot;restore_20250124_103045&quot;</span><span class="fu">,</span></span>
<span id="cb17-5"><a href="#cb17-5" aria-hidden="true"></a>    <span class="dt">&quot;status&quot;</span><span class="fu">:</span> <span class="st">&quot;in_progress&quot;</span><span class="fu">,</span></span>
<span id="cb17-6"><a href="#cb17-6" aria-hidden="true"></a>    <span class="dt">&quot;started_at&quot;</span><span class="fu">:</span> <span class="st">&quot;2025-01-24T10:30:45Z&quot;</span><span class="fu">,</span></span>
<span id="cb17-7"><a href="#cb17-7" aria-hidden="true"></a>    <span class="dt">&quot;progress_url&quot;</span><span class="fu">:</span> <span class="st">&quot;/wp-json/bkpc/v1/restore/restore_20250124_103045/status&quot;</span></span>
<span id="cb17-8"><a href="#cb17-8" aria-hidden="true"></a>  <span class="fu">}</span></span>
<span id="cb17-9"><a href="#cb17-9" aria-hidden="true"></a><span class="fu">}</span></span></code></pre>
</div>
<h3 id="monitor-backup-status">Monitor Backup Status</h3>
<pre class="http"><code>GET /wp-json/bkpc/v1/backup/{uuid}/status</code></pre>
<p><strong>Response</strong>:</p>
<div class="sourceCode" id="cb19">
<pre class="sourceCode json"><code class="sourceCode json"><span id="cb19-1"><a href="#cb19-1" aria-hidden="true"></a><span class="fu">{</span></span>
<span id="cb19-2"><a href="#cb19-2" aria-hidden="true"></a>  <span class="dt">&quot;success&quot;</span><span class="fu">:</span> <span class="kw">true</span><span class="fu">,</span></span>
<span id="cb19-3"><a href="#cb19-3" aria-hidden="true"></a>  <span class="dt">&quot;data&quot;</span><span class="fu">:</span> <span class="fu">{</span></span>
<span id="cb19-4"><a href="#cb19-4" aria-hidden="true"></a>    <span class="dt">&quot;status&quot;</span><span class="fu">:</span> <span class="st">&quot;in_progress&quot;</span><span class="fu">,</span></span>
<span id="cb19-5"><a href="#cb19-5" aria-hidden="true"></a>    <span class="dt">&quot;progress&quot;</span><span class="fu">:</span> <span class="fu">{</span></span>
<span id="cb19-6"><a href="#cb19-6" aria-hidden="true"></a>      <span class="dt">&quot;percentage&quot;</span><span class="fu">:</span> <span class="dv">67</span><span class="fu">,</span></span>
<span id="cb19-7"><a href="#cb19-7" aria-hidden="true"></a>      <span class="dt">&quot;current_step&quot;</span><span class="fu">:</span> <span class="st">&quot;Uploading to cloud&quot;</span><span class="fu">,</span></span>
<span id="cb19-8"><a href="#cb19-8" aria-hidden="true"></a>      <span class="dt">&quot;steps_completed&quot;</span><span class="fu">:</span> <span class="dv">4</span><span class="fu">,</span></span>
<span id="cb19-9"><a href="#cb19-9" aria-hidden="true"></a>      <span class="dt">&quot;steps_total&quot;</span><span class="fu">:</span> <span class="dv">6</span><span class="fu">,</span></span>
<span id="cb19-10"><a href="#cb19-10" aria-hidden="true"></a>      <span class="dt">&quot;files_processed&quot;</span><span class="fu">:</span> <span class="dv">8472</span><span class="fu">,</span></span>
<span id="cb19-11"><a href="#cb19-11" aria-hidden="true"></a>      <span class="dt">&quot;files_total&quot;</span><span class="fu">:</span> <span class="dv">12847</span><span class="fu">,</span></span>
<span id="cb19-12"><a href="#cb19-12" aria-hidden="true"></a>      <span class="dt">&quot;bytes_processed&quot;</span><span class="fu">:</span> <span class="dv">835891230</span><span class="fu">,</span></span>
<span id="cb19-13"><a href="#cb19-13" aria-hidden="true"></a>      <span class="dt">&quot;bytes_total&quot;</span><span class="fu">:</span> <span class="dv">1247652864</span></span>
<span id="cb19-14"><a href="#cb19-14" aria-hidden="true"></a>    <span class="fu">},</span></span>
<span id="cb19-15"><a href="#cb19-15" aria-hidden="true"></a>    <span class="dt">&quot;estimated_time_remaining&quot;</span><span class="fu">:</span> <span class="dv">135</span></span>
<span id="cb19-16"><a href="#cb19-16" aria-hidden="true"></a>  <span class="fu">}</span></span>
<span id="cb19-17"><a href="#cb19-17" aria-hidden="true"></a><span class="fu">}</span></span></code></pre>
</div>
<h2 id="schedule-endpoints">Schedule Endpoints</h2>
<h3 id="list-schedules">List Schedules</h3>
<pre class="http"><code>GET /wp-json/bkpc/v1/schedule/list</code></pre>
<p><strong>Response</strong>:</p>
<div class="sourceCode" id="cb21">
<pre class="sourceCode json"><code class="sourceCode json"><span id="cb21-1"><a href="#cb21-1" aria-hidden="true"></a><span class="fu">{</span></span>
<span id="cb21-2"><a href="#cb21-2" aria-hidden="true"></a>  <span class="dt">&quot;success&quot;</span><span class="fu">:</span> <span class="kw">true</span><span class="fu">,</span></span>
<span id="cb21-3"><a href="#cb21-3" aria-hidden="true"></a>  <span class="dt">&quot;data&quot;</span><span class="fu">:</span> <span class="fu">{</span></span>
<span id="cb21-4"><a href="#cb21-4" aria-hidden="true"></a>    <span class="dt">&quot;schedules&quot;</span><span class="fu">:</span> <span class="ot">[</span></span>
<span id="cb21-5"><a href="#cb21-5" aria-hidden="true"></a>      <span class="fu">{</span></span>
<span id="cb21-6"><a href="#cb21-6" aria-hidden="true"></a>        <span class="dt">&quot;id&quot;</span><span class="fu">:</span> <span class="dv">42</span><span class="fu">,</span></span>
<span id="cb21-7"><a href="#cb21-7" aria-hidden="true"></a>        <span class="dt">&quot;name&quot;</span><span class="fu">:</span> <span class="st">&quot;Daily Full Backup&quot;</span><span class="fu">,</span></span>
<span id="cb21-8"><a href="#cb21-8" aria-hidden="true"></a>        <span class="dt">&quot;enabled&quot;</span><span class="fu">:</span> <span class="kw">true</span><span class="fu">,</span></span>
<span id="cb21-9"><a href="#cb21-9" aria-hidden="true"></a>        <span class="dt">&quot;frequency&quot;</span><span class="fu">:</span> <span class="st">&quot;daily&quot;</span><span class="fu">,</span></span>
<span id="cb21-10"><a href="#cb21-10" aria-hidden="true"></a>        <span class="dt">&quot;time&quot;</span><span class="fu">:</span> <span class="st">&quot;02:00:00&quot;</span><span class="fu">,</span></span>
<span id="cb21-11"><a href="#cb21-11" aria-hidden="true"></a>        <span class="dt">&quot;backup_type&quot;</span><span class="fu">:</span> <span class="st">&quot;full&quot;</span><span class="fu">,</span></span>
<span id="cb21-12"><a href="#cb21-12" aria-hidden="true"></a>        <span class="dt">&quot;cloud_upload&quot;</span><span class="fu">:</span> <span class="kw">true</span><span class="fu">,</span></span>
<span id="cb21-13"><a href="#cb21-13" aria-hidden="true"></a>        <span class="dt">&quot;cloud_provider&quot;</span><span class="fu">:</span> <span class="st">&quot;dropbox&quot;</span><span class="fu">,</span></span>
<span id="cb21-14"><a href="#cb21-14" aria-hidden="true"></a>        <span class="dt">&quot;retention_days&quot;</span><span class="fu">:</span> <span class="dv">30</span><span class="fu">,</span></span>
<span id="cb21-15"><a href="#cb21-15" aria-hidden="true"></a>        <span class="dt">&quot;next_run&quot;</span><span class="fu">:</span> <span class="st">&quot;2025-01-25T02:00:00Z&quot;</span><span class="fu">,</span></span>
<span id="cb21-16"><a href="#cb21-16" aria-hidden="true"></a>        <span class="dt">&quot;last_run&quot;</span><span class="fu">:</span> <span class="st">&quot;2025-01-24T02:00:00Z&quot;</span><span class="fu">,</span></span>
<span id="cb21-17"><a href="#cb21-17" aria-hidden="true"></a>        <span class="dt">&quot;last_run_status&quot;</span><span class="fu">:</span> <span class="st">&quot;completed&quot;</span></span>
<span id="cb21-18"><a href="#cb21-18" aria-hidden="true"></a>      <span class="fu">}</span></span>
<span id="cb21-19"><a href="#cb21-19" aria-hidden="true"></a>    <span class="ot">]</span></span>
<span id="cb21-20"><a href="#cb21-20" aria-hidden="true"></a>  <span class="fu">}</span></span>
<span id="cb21-21"><a href="#cb21-21" aria-hidden="true"></a><span class="fu">}</span></span></code></pre>
</div>
<h3 id="create-schedule">Create Schedule</h3>
<pre class="http"><code>POST /wp-json/bkpc/v1/schedule/create</code></pre>
<p><strong>Request Body</strong>:</p>
<div class="sourceCode" id="cb23">
<pre class="sourceCode json"><code class="sourceCode json"><span id="cb23-1"><a href="#cb23-1" aria-hidden="true"></a><span class="fu">{</span></span>
<span id="cb23-2"><a href="#cb23-2" aria-hidden="true"></a>  <span class="dt">&quot;name&quot;</span><span class="fu">:</span> <span class="st">&quot;Hourly Database Backup&quot;</span><span class="fu">,</span></span>
<span id="cb23-3"><a href="#cb23-3" aria-hidden="true"></a>  <span class="dt">&quot;enabled&quot;</span><span class="fu">:</span> <span class="kw">true</span><span class="fu">,</span></span>
<span id="cb23-4"><a href="#cb23-4" aria-hidden="true"></a>  <span class="dt">&quot;frequency&quot;</span><span class="fu">:</span> <span class="st">&quot;hourly&quot;</span><span class="fu">,</span></span>
<span id="cb23-5"><a href="#cb23-5" aria-hidden="true"></a>  <span class="dt">&quot;backup_type&quot;</span><span class="fu">:</span> <span class="st">&quot;database&quot;</span><span class="fu">,</span></span>
<span id="cb23-6"><a href="#cb23-6" aria-hidden="true"></a>  <span class="dt">&quot;cloud_upload&quot;</span><span class="fu">:</span> <span class="kw">true</span><span class="fu">,</span></span>
<span id="cb23-7"><a href="#cb23-7" aria-hidden="true"></a>  <span class="dt">&quot;cloud_provider&quot;</span><span class="fu">:</span> <span class="st">&quot;google_drive&quot;</span><span class="fu">,</span></span>
<span id="cb23-8"><a href="#cb23-8" aria-hidden="true"></a>  <span class="dt">&quot;retention_days&quot;</span><span class="fu">:</span> <span class="dv">7</span><span class="fu">,</span></span>
<span id="cb23-9"><a href="#cb23-9" aria-hidden="true"></a>  <span class="dt">&quot;send_notification&quot;</span><span class="fu">:</span> <span class="kw">false</span></span>
<span id="cb23-10"><a href="#cb23-10" aria-hidden="true"></a><span class="fu">}</span></span></code></pre>
</div>
<p><strong>Response</strong>:</p>
<div class="sourceCode" id="cb24">
<pre class="sourceCode json"><code class="sourceCode json"><span id="cb24-1"><a href="#cb24-1" aria-hidden="true"></a><span class="fu">{</span></span>
<span id="cb24-2"><a href="#cb24-2" aria-hidden="true"></a>  <span class="dt">&quot;success&quot;</span><span class="fu">:</span> <span class="kw">true</span><span class="fu">,</span></span>
<span id="cb24-3"><a href="#cb24-3" aria-hidden="true"></a>  <span class="dt">&quot;data&quot;</span><span class="fu">:</span> <span class="fu">{</span></span>
<span id="cb24-4"><a href="#cb24-4" aria-hidden="true"></a>    <span class="dt">&quot;id&quot;</span><span class="fu">:</span> <span class="dv">43</span><span class="fu">,</span></span>
<span id="cb24-5"><a href="#cb24-5" aria-hidden="true"></a>    <span class="dt">&quot;name&quot;</span><span class="fu">:</span> <span class="st">&quot;Hourly Database Backup&quot;</span><span class="fu">,</span></span>
<span id="cb24-6"><a href="#cb24-6" aria-hidden="true"></a>    <span class="dt">&quot;next_run&quot;</span><span class="fu">:</span> <span class="st">&quot;2025-01-24T11:00:00Z&quot;</span></span>
<span id="cb24-7"><a href="#cb24-7" aria-hidden="true"></a>  <span class="fu">}</span></span>
<span id="cb24-8"><a href="#cb24-8" aria-hidden="true"></a><span class="fu">}</span></span></code></pre>
</div>
<h2 id="webhook-configuration">Webhook Configuration</h2>
<p>Configure webhooks to receive notifications:</p>
<pre class="http"><code>POST /wp-json/bkpc/v1/webhooks/create</code></pre>
<p><strong>Request Body</strong>:</p>
<div class="sourceCode" id="cb26">
<pre class="sourceCode json"><code class="sourceCode json"><span id="cb26-1"><a href="#cb26-1" aria-hidden="true"></a><span class="fu">{</span></span>
<span id="cb26-2"><a href="#cb26-2" aria-hidden="true"></a>  <span class="dt">&quot;url&quot;</span><span class="fu">:</span> <span class="st">&quot;https://monitoring.example.com/webhook/backup-events&quot;</span><span class="fu">,</span></span>
<span id="cb26-3"><a href="#cb26-3" aria-hidden="true"></a>  <span class="dt">&quot;events&quot;</span><span class="fu">:</span> <span class="ot">[</span><span class="st">&quot;backup.completed&quot;</span><span class="ot">,</span> <span class="st">&quot;backup.failed&quot;</span><span class="ot">,</span> <span class="st">&quot;restore.completed&quot;</span><span class="ot">]</span><span class="fu">,</span></span>
<span id="cb26-4"><a href="#cb26-4" aria-hidden="true"></a>  <span class="dt">&quot;secret&quot;</span><span class="fu">:</span> <span class="st">&quot;your_webhook_secret_for_signature_validation&quot;</span></span>
<span id="cb26-5"><a href="#cb26-5" aria-hidden="true"></a><span class="fu">}</span></span></code></pre>
</div>
<p><strong>Webhook Payload Example</strong>:</p>
<div class="sourceCode" id="cb27">
<pre class="sourceCode json"><code class="sourceCode json"><span id="cb27-1"><a href="#cb27-1" aria-hidden="true"></a><span class="fu">{</span></span>
<span id="cb27-2"><a href="#cb27-2" aria-hidden="true"></a>  <span class="dt">&quot;event&quot;</span><span class="fu">:</span> <span class="st">&quot;backup.completed&quot;</span><span class="fu">,</span></span>
<span id="cb27-3"><a href="#cb27-3" aria-hidden="true"></a>  <span class="dt">&quot;timestamp&quot;</span><span class="fu">:</span> <span class="st">&quot;2025-01-24T09:35:12Z&quot;</span><span class="fu">,</span></span>
<span id="cb27-4"><a href="#cb27-4" aria-hidden="true"></a>  <span class="dt">&quot;site_url&quot;</span><span class="fu">:</span> <span class="st">&quot;https://yoursite.com&quot;</span><span class="fu">,</span></span>
<span id="cb27-5"><a href="#cb27-5" aria-hidden="true"></a>  <span class="dt">&quot;data&quot;</span><span class="fu">:</span> <span class="fu">{</span></span>
<span id="cb27-6"><a href="#cb27-6" aria-hidden="true"></a>    <span class="dt">&quot;uuid&quot;</span><span class="fu">:</span> <span class="st">&quot;bkpc_20250124_093045_a8f3d2&quot;</span><span class="fu">,</span></span>
<span id="cb27-7"><a href="#cb27-7" aria-hidden="true"></a>    <span class="dt">&quot;type&quot;</span><span class="fu">:</span> <span class="st">&quot;full&quot;</span><span class="fu">,</span></span>
<span id="cb27-8"><a href="#cb27-8" aria-hidden="true"></a>    <span class="dt">&quot;size&quot;</span><span class="fu">:</span> <span class="dv">1247652864</span><span class="fu">,</span></span>
<span id="cb27-9"><a href="#cb27-9" aria-hidden="true"></a>    <span class="dt">&quot;duration_seconds&quot;</span><span class="fu">:</span> <span class="dv">267</span><span class="fu">,</span></span>
<span id="cb27-10"><a href="#cb27-10" aria-hidden="true"></a>    <span class="dt">&quot;cloud_uploaded&quot;</span><span class="fu">:</span> <span class="kw">true</span><span class="fu">,</span></span>
<span id="cb27-11"><a href="#cb27-11" aria-hidden="true"></a>    <span class="dt">&quot;cloud_provider&quot;</span><span class="fu">:</span> <span class="st">&quot;dropbox&quot;</span></span>
<span id="cb27-12"><a href="#cb27-12" aria-hidden="true"></a>  <span class="fu">}</span></span>
<span id="cb27-13"><a href="#cb27-13" aria-hidden="true"></a><span class="fu">}</span></span></code></pre>
</div>
<h2 id="integration-examples">Integration Examples</h2>
<h3 id="cicd-pipeline-integration">CI/CD Pipeline Integration</h3>
<p>Trigger backup before deployment:</p>
<div class="sourceCode" id="cb28">
<pre class="sourceCode yaml"><code class="sourceCode yaml"><span id="cb28-1"><a href="#cb28-1" aria-hidden="true"></a><span class="co"># GitHub Actions example</span></span>
<span id="cb28-2"><a href="#cb28-2" aria-hidden="true"></a><span class="kw">-</span><span class="at"> </span><span class="fu">name</span><span class="kw">:</span><span class="at"> Create Pre-Deployment Backup</span></span>
<span id="cb28-3"><a href="#cb28-3" aria-hidden="true"></a><span class="fu">  run</span><span class="kw">: </span><span class="ch">|</span></span>
<span id="cb28-4"><a href="#cb28-4" aria-hidden="true"></a>    RESPONSE=$(curl -s -X POST https://yoursite.com/wp-json/bkpc/v1/backup/create \</span>
<span id="cb28-5"><a href="#cb28-5" aria-hidden="true"></a>      -u ${{ secrets.WP_USERNAME }}:${{ secrets.WP_APP_PASSWORD }} \</span>
<span id="cb28-6"><a href="#cb28-6" aria-hidden="true"></a>      -H &quot;Content-Type: application/json&quot; \</span>
<span id="cb28-7"><a href="#cb28-7" aria-hidden="true"></a>      -d &#39;{&quot;type&quot;:&quot;full&quot;,&quot;cloud_upload&quot;:true,&quot;metadata&quot;:{&quot;build&quot;:&quot;${{ github.run_number }}&quot;}}&#39;&#39;)</span>
<span id="cb28-8"><a href="#cb28-8" aria-hidden="true"></a></span>
<span id="cb28-9"><a href="#cb28-9" aria-hidden="true"></a>    BACKUP_UUID=$(echo $RESPONSE | jq -r &#39;.data.uuid&#39;)</span>
<span id="cb28-10"><a href="#cb28-10" aria-hidden="true"></a></span>
<span id="cb28-11"><a href="#cb28-11" aria-hidden="true"></a>    # Wait for backup completion</span>
<span id="cb28-12"><a href="#cb28-12" aria-hidden="true"></a>    while true; do</span>
<span id="cb28-13"><a href="#cb28-13" aria-hidden="true"></a>      STATUS=$(curl -s https://yoursite.com/wp-json/bkpc/v1/backup/$BACKUP_UUID/status \</span>
<span id="cb28-14"><a href="#cb28-14" aria-hidden="true"></a>        -u ${{ secrets.WP_USERNAME }}:${{ secrets.WP_APP_PASSWORD }} | jq -r &#39;.data.status&#39;)</span>
<span id="cb28-15"><a href="#cb28-15" aria-hidden="true"></a></span>
<span id="cb28-16"><a href="#cb28-16" aria-hidden="true"></a>      if [ &quot;$STATUS&quot; = &quot;completed&quot; ]; then</span>
<span id="cb28-17"><a href="#cb28-17" aria-hidden="true"></a>        echo &quot;Backup completed successfully&quot;</span>
<span id="cb28-18"><a href="#cb28-18" aria-hidden="true"></a>        break</span>
<span id="cb28-19"><a href="#cb28-19" aria-hidden="true"></a>      elif [ &quot;$STATUS&quot; = &quot;failed&quot; ]; then</span>
<span id="cb28-20"><a href="#cb28-20" aria-hidden="true"></a>        echo &quot;Backup failed&quot;</span>
<span id="cb28-21"><a href="#cb28-21" aria-hidden="true"></a>        exit 1</span>
<span id="cb28-22"><a href="#cb28-22" aria-hidden="true"></a>      fi</span>
<span id="cb28-23"><a href="#cb28-23" aria-hidden="true"></a></span>
<span id="cb28-24"><a href="#cb28-24" aria-hidden="true"></a>      sleep 10</span>
<span id="cb28-25"><a href="#cb28-25" aria-hidden="true"></a>    done</span></code></pre>
</div>
<h3 id="python-monitoring-script">Python Monitoring Script</h3>
<div class="sourceCode" id="cb29">
<pre class="sourceCode python"><code class="sourceCode python"><span id="cb29-1"><a href="#cb29-1" aria-hidden="true"></a><span class="im">import</span> requests</span>
<span id="cb29-2"><a href="#cb29-2" aria-hidden="true"></a><span class="im">from</span> requests.auth <span class="im">import</span> HTTPBasicAuth</span>
<span id="cb29-3"><a href="#cb29-3" aria-hidden="true"></a></span>
<span id="cb29-4"><a href="#cb29-4" aria-hidden="true"></a><span class="kw">class</span> BackupMonitor:</span>
<span id="cb29-5"><a href="#cb29-5" aria-hidden="true"></a>    <span class="kw">def</span> <span class="fu">__init__</span>(<span class="va">self</span>, site_url, username, app_password):</span>
<span id="cb29-6"><a href="#cb29-6" aria-hidden="true"></a>        <span class="va">self</span>.site_url <span class="op">=</span> site_url</span>
<span id="cb29-7"><a href="#cb29-7" aria-hidden="true"></a>        <span class="va">self</span>.auth <span class="op">=</span> HTTPBasicAuth(username, app_password)</span>
<span id="cb29-8"><a href="#cb29-8" aria-hidden="true"></a>        <span class="va">self</span>.api_base <span class="op">=</span> <span class="ss">f&quot;</span><span class="sc">{</span>site_url<span class="sc">}</span><span class="ss">/wp-json/bkpc/v1&quot;</span></span>
<span id="cb29-9"><a href="#cb29-9" aria-hidden="true"></a></span>
<span id="cb29-10"><a href="#cb29-10" aria-hidden="true"></a>    <span class="kw">def</span> list_backups(<span class="va">self</span>, status<span class="op">=</span><span class="va">None</span>):</span>
<span id="cb29-11"><a href="#cb29-11" aria-hidden="true"></a>        url <span class="op">=</span> <span class="ss">f&quot;</span><span class="sc">{</span><span class="va">self</span><span class="sc">.</span>api_base<span class="sc">}</span><span class="ss">/backup/list&quot;</span></span>
<span id="cb29-12"><a href="#cb29-12" aria-hidden="true"></a>        params <span class="op">=</span> {<span class="st">&#39;status&#39;</span>: status} <span class="cf">if</span> status <span class="cf">else</span> {}</span>
<span id="cb29-13"><a href="#cb29-13" aria-hidden="true"></a></span>
<span id="cb29-14"><a href="#cb29-14" aria-hidden="true"></a>        response <span class="op">=</span> requests.get(url, auth<span class="op">=</span><span class="va">self</span>.auth, params<span class="op">=</span>params)</span>
<span id="cb29-15"><a href="#cb29-15" aria-hidden="true"></a>        response.raise_for_status()</span>
<span id="cb29-16"><a href="#cb29-16" aria-hidden="true"></a>        <span class="cf">return</span> response.json()[<span class="st">&#39;data&#39;</span>][<span class="st">&#39;backups&#39;</span>]</span>
<span id="cb29-17"><a href="#cb29-17" aria-hidden="true"></a></span>
<span id="cb29-18"><a href="#cb29-18" aria-hidden="true"></a>    <span class="kw">def</span> create_backup(<span class="va">self</span>, backup_type<span class="op">=</span><span class="st">&#39;full&#39;</span>, cloud_upload<span class="op">=</span><span class="va">True</span>):</span>
<span id="cb29-19"><a href="#cb29-19" aria-hidden="true"></a>        url <span class="op">=</span> <span class="ss">f&quot;</span><span class="sc">{</span><span class="va">self</span><span class="sc">.</span>api_base<span class="sc">}</span><span class="ss">/backup/create&quot;</span></span>
<span id="cb29-20"><a href="#cb29-20" aria-hidden="true"></a>        data <span class="op">=</span> {</span>
<span id="cb29-21"><a href="#cb29-21" aria-hidden="true"></a>            <span class="st">&#39;type&#39;</span>: backup_type,</span>
<span id="cb29-22"><a href="#cb29-22" aria-hidden="true"></a>            <span class="st">&#39;cloud_upload&#39;</span>: cloud_upload</span>
<span id="cb29-23"><a href="#cb29-23" aria-hidden="true"></a>        }</span>
<span id="cb29-24"><a href="#cb29-24" aria-hidden="true"></a></span>
<span id="cb29-25"><a href="#cb29-25" aria-hidden="true"></a>        response <span class="op">=</span> requests.post(url, auth<span class="op">=</span><span class="va">self</span>.auth, json<span class="op">=</span>data)</span>
<span id="cb29-26"><a href="#cb29-26" aria-hidden="true"></a>        response.raise_for_status()</span>
<span id="cb29-27"><a href="#cb29-27" aria-hidden="true"></a>        <span class="cf">return</span> response.json()[<span class="st">&#39;data&#39;</span>]</span>
<span id="cb29-28"><a href="#cb29-28" aria-hidden="true"></a></span>
<span id="cb29-29"><a href="#cb29-29" aria-hidden="true"></a>    <span class="kw">def</span> monitor_backup(<span class="va">self</span>, uuid):</span>
<span id="cb29-30"><a href="#cb29-30" aria-hidden="true"></a>        url <span class="op">=</span> <span class="ss">f&quot;</span><span class="sc">{</span><span class="va">self</span><span class="sc">.</span>api_base<span class="sc">}</span><span class="ss">/backup/</span><span class="sc">{</span>uuid<span class="sc">}</span><span class="ss">/status&quot;</span></span>
<span id="cb29-31"><a href="#cb29-31" aria-hidden="true"></a></span>
<span id="cb29-32"><a href="#cb29-32" aria-hidden="true"></a>        <span class="cf">while</span> <span class="va">True</span>:</span>
<span id="cb29-33"><a href="#cb29-33" aria-hidden="true"></a>            response <span class="op">=</span> requests.get(url, auth<span class="op">=</span><span class="va">self</span>.auth)</span>
<span id="cb29-34"><a href="#cb29-34" aria-hidden="true"></a>            data <span class="op">=</span> response.json()[<span class="st">&#39;data&#39;</span>]</span>
<span id="cb29-35"><a href="#cb29-35" aria-hidden="true"></a></span>
<span id="cb29-36"><a href="#cb29-36" aria-hidden="true"></a>            status <span class="op">=</span> data[<span class="st">&#39;status&#39;</span>]</span>
<span id="cb29-37"><a href="#cb29-37" aria-hidden="true"></a>            progress <span class="op">=</span> data.get(<span class="st">&#39;progress&#39;</span>, {}).get(<span class="st">&#39;percentage&#39;</span>, <span class="dv">0</span>)</span>
<span id="cb29-38"><a href="#cb29-38" aria-hidden="true"></a></span>
<span id="cb29-39"><a href="#cb29-39" aria-hidden="true"></a>            <span class="bu">print</span>(<span class="ss">f&quot;Status: </span><span class="sc">{</span>status<span class="sc">}</span><span class="ss"> - Progress: </span><span class="sc">{</span>progress<span class="sc">}</span><span class="ss">%&quot;</span>)</span>
<span id="cb29-40"><a href="#cb29-40" aria-hidden="true"></a></span>
<span id="cb29-41"><a href="#cb29-41" aria-hidden="true"></a>            <span class="cf">if</span> status <span class="kw">in</span> [<span class="st">&#39;completed&#39;</span>, <span class="st">&#39;failed&#39;</span>]:</span>
<span id="cb29-42"><a href="#cb29-42" aria-hidden="true"></a>                <span class="cf">return</span> status</span>
<span id="cb29-43"><a href="#cb29-43" aria-hidden="true"></a></span>
<span id="cb29-44"><a href="#cb29-44" aria-hidden="true"></a>            time.sleep(<span class="dv">10</span>)</span>
<span id="cb29-45"><a href="#cb29-45" aria-hidden="true"></a></span>
<span id="cb29-46"><a href="#cb29-46" aria-hidden="true"></a><span class="co"># Usage</span></span>
<span id="cb29-47"><a href="#cb29-47" aria-hidden="true"></a>monitor <span class="op">=</span> BackupMonitor(</span>
<span id="cb29-48"><a href="#cb29-48" aria-hidden="true"></a>    <span class="st">&#39;https://yoursite.com&#39;</span>,</span>
<span id="cb29-49"><a href="#cb29-49" aria-hidden="true"></a>    <span class="st">&#39;admin&#39;</span>,</span>
<span id="cb29-50"><a href="#cb29-50" aria-hidden="true"></a>    <span class="st">&#39;your-application-password&#39;</span></span>
<span id="cb29-51"><a href="#cb29-51" aria-hidden="true"></a>)</span>
<span id="cb29-52"><a href="#cb29-52" aria-hidden="true"></a></span>
<span id="cb29-53"><a href="#cb29-53" aria-hidden="true"></a>backup <span class="op">=</span> monitor.create_backup()</span>
<span id="cb29-54"><a href="#cb29-54" aria-hidden="true"></a>status <span class="op">=</span> monitor.monitor_backup(backup[<span class="st">&#39;uuid&#39;</span>])</span>
<span id="cb29-55"><a href="#cb29-55" aria-hidden="true"></a><span class="bu">print</span>(<span class="ss">f&quot;Final status: </span><span class="sc">{</span>status<span class="sc">}</span><span class="ss">&quot;</span>)</span></code></pre>
</div>
<h3 id="javascript-dashboard">JavaScript Dashboard</h3>
<div class="sourceCode" id="cb30">
<pre class="sourceCode javascript"><code class="sourceCode javascript"><span id="cb30-1"><a href="#cb30-1" aria-hidden="true"></a><span class="kw">class</span> BackupDashboard {</span>
<span id="cb30-2"><a href="#cb30-2" aria-hidden="true"></a>    <span class="fu">constructor</span>(siteUrl<span class="op">,</span> username<span class="op">,</span> appPassword) {</span>
<span id="cb30-3"><a href="#cb30-3" aria-hidden="true"></a>        <span class="kw">this</span><span class="op">.</span><span class="at">apiBase</span> <span class="op">=</span> <span class="vs">`</span><span class="sc">${</span>siteUrl<span class="sc">}</span><span class="vs">/wp-json/bkpc/v1`</span><span class="op">;</span></span>
<span id="cb30-4"><a href="#cb30-4" aria-hidden="true"></a>        <span class="kw">this</span><span class="op">.</span><span class="at">auth</span> <span class="op">=</span> <span class="fu">btoa</span>(<span class="vs">`</span><span class="sc">${</span>username<span class="sc">}</span><span class="vs">:</span><span class="sc">${</span>appPassword<span class="sc">}</span><span class="vs">`</span>)<span class="op">;</span></span>
<span id="cb30-5"><a href="#cb30-5" aria-hidden="true"></a>    }</span>
<span id="cb30-6"><a href="#cb30-6" aria-hidden="true"></a></span>
<span id="cb30-7"><a href="#cb30-7" aria-hidden="true"></a>    <span class="kw">async</span> <span class="fu">listBackups</span>() {</span>
<span id="cb30-8"><a href="#cb30-8" aria-hidden="true"></a>        <span class="kw">const</span> response <span class="op">=</span> <span class="cf">await</span> <span class="fu">fetch</span>(<span class="vs">`</span><span class="sc">${</span><span class="kw">this</span><span class="op">.</span><span class="at">apiBase</span><span class="sc">}</span><span class="vs">/backup/list`</span><span class="op">,</span> {</span>
<span id="cb30-9"><a href="#cb30-9" aria-hidden="true"></a>            <span class="dt">headers</span><span class="op">:</span> {</span>
<span id="cb30-10"><a href="#cb30-10" aria-hidden="true"></a>                <span class="st">&#39;Authorization&#39;</span><span class="op">:</span> <span class="vs">`Basic </span><span class="sc">${</span><span class="kw">this</span><span class="op">.</span><span class="at">auth</span><span class="sc">}</span><span class="vs">`</span></span>
<span id="cb30-11"><a href="#cb30-11" aria-hidden="true"></a>            }</span>
<span id="cb30-12"><a href="#cb30-12" aria-hidden="true"></a>        })<span class="op">;</span></span>
<span id="cb30-13"><a href="#cb30-13" aria-hidden="true"></a></span>
<span id="cb30-14"><a href="#cb30-14" aria-hidden="true"></a>        <span class="cf">return</span> <span class="cf">await</span> response<span class="op">.</span><span class="fu">json</span>()<span class="op">;</span></span>
<span id="cb30-15"><a href="#cb30-15" aria-hidden="true"></a>    }</span>
<span id="cb30-16"><a href="#cb30-16" aria-hidden="true"></a></span>
<span id="cb30-17"><a href="#cb30-17" aria-hidden="true"></a>    <span class="kw">async</span> <span class="fu">createBackup</span>(type <span class="op">=</span> <span class="st">&#39;full&#39;</span>) {</span>
<span id="cb30-18"><a href="#cb30-18" aria-hidden="true"></a>        <span class="kw">const</span> response <span class="op">=</span> <span class="cf">await</span> <span class="fu">fetch</span>(<span class="vs">`</span><span class="sc">${</span><span class="kw">this</span><span class="op">.</span><span class="at">apiBase</span><span class="sc">}</span><span class="vs">/backup/create`</span><span class="op">,</span> {</span>
<span id="cb30-19"><a href="#cb30-19" aria-hidden="true"></a>            <span class="dt">method</span><span class="op">:</span> <span class="st">&#39;POST&#39;</span><span class="op">,</span></span>
<span id="cb30-20"><a href="#cb30-20" aria-hidden="true"></a>            <span class="dt">headers</span><span class="op">:</span> {</span>
<span id="cb30-21"><a href="#cb30-21" aria-hidden="true"></a>                <span class="st">&#39;Authorization&#39;</span><span class="op">:</span> <span class="vs">`Basic </span><span class="sc">${</span><span class="kw">this</span><span class="op">.</span><span class="at">auth</span><span class="sc">}</span><span class="vs">`</span><span class="op">,</span></span>
<span id="cb30-22"><a href="#cb30-22" aria-hidden="true"></a>                <span class="st">&#39;Content-Type&#39;</span><span class="op">:</span> <span class="st">&#39;application/json&#39;</span></span>
<span id="cb30-23"><a href="#cb30-23" aria-hidden="true"></a>            }<span class="op">,</span></span>
<span id="cb30-24"><a href="#cb30-24" aria-hidden="true"></a>            <span class="dt">body</span><span class="op">:</span> <span class="bu">JSON</span><span class="op">.</span><span class="fu">stringify</span>({</span>
<span id="cb30-25"><a href="#cb30-25" aria-hidden="true"></a>                <span class="dt">type</span><span class="op">:</span> type<span class="op">,</span></span>
<span id="cb30-26"><a href="#cb30-26" aria-hidden="true"></a>                <span class="dt">cloud_upload</span><span class="op">:</span> <span class="kw">true</span></span>
<span id="cb30-27"><a href="#cb30-27" aria-hidden="true"></a>            })</span>
<span id="cb30-28"><a href="#cb30-28" aria-hidden="true"></a>        })<span class="op">;</span></span>
<span id="cb30-29"><a href="#cb30-29" aria-hidden="true"></a></span>
<span id="cb30-30"><a href="#cb30-30" aria-hidden="true"></a>        <span class="cf">return</span> <span class="cf">await</span> response<span class="op">.</span><span class="fu">json</span>()<span class="op">;</span></span>
<span id="cb30-31"><a href="#cb30-31" aria-hidden="true"></a>    }</span>
<span id="cb30-32"><a href="#cb30-32" aria-hidden="true"></a></span>
<span id="cb30-33"><a href="#cb30-33" aria-hidden="true"></a>    <span class="kw">async</span> <span class="fu">deleteBackup</span>(uuid) {</span>
<span id="cb30-34"><a href="#cb30-34" aria-hidden="true"></a>        <span class="kw">const</span> response <span class="op">=</span> <span class="cf">await</span> <span class="fu">fetch</span>(<span class="vs">`</span><span class="sc">${</span><span class="kw">this</span><span class="op">.</span><span class="at">apiBase</span><span class="sc">}</span><span class="vs">/backup/</span><span class="sc">${</span>uuid<span class="sc">}</span><span class="vs">`</span><span class="op">,</span> {</span>
<span id="cb30-35"><a href="#cb30-35" aria-hidden="true"></a>            <span class="dt">method</span><span class="op">:</span> <span class="st">&#39;DELETE&#39;</span><span class="op">,</span></span>
<span id="cb30-36"><a href="#cb30-36" aria-hidden="true"></a>            <span class="dt">headers</span><span class="op">:</span> {</span>
<span id="cb30-37"><a href="#cb30-37" aria-hidden="true"></a>                <span class="st">&#39;Authorization&#39;</span><span class="op">:</span> <span class="vs">`Basic </span><span class="sc">${</span><span class="kw">this</span><span class="op">.</span><span class="at">auth</span><span class="sc">}</span><span class="vs">`</span></span>
<span id="cb30-38"><a href="#cb30-38" aria-hidden="true"></a>            }</span>
<span id="cb30-39"><a href="#cb30-39" aria-hidden="true"></a>        })<span class="op">;</span></span>
<span id="cb30-40"><a href="#cb30-40" aria-hidden="true"></a></span>
<span id="cb30-41"><a href="#cb30-41" aria-hidden="true"></a>        <span class="cf">return</span> <span class="cf">await</span> response<span class="op">.</span><span class="fu">json</span>()<span class="op">;</span></span>
<span id="cb30-42"><a href="#cb30-42" aria-hidden="true"></a>    }</span>
<span id="cb30-43"><a href="#cb30-43" aria-hidden="true"></a>}</span>
<span id="cb30-44"><a href="#cb30-44" aria-hidden="true"></a></span>
<span id="cb30-45"><a href="#cb30-45" aria-hidden="true"></a><span class="co">// Usage</span></span>
<span id="cb30-46"><a href="#cb30-46" aria-hidden="true"></a><span class="kw">const</span> dashboard <span class="op">=</span> <span class="kw">new</span> <span class="fu">BackupDashboard</span>(</span>
<span id="cb30-47"><a href="#cb30-47" aria-hidden="true"></a>    <span class="st">&#39;https://yoursite.com&#39;</span><span class="op">,</span></span>
<span id="cb30-48"><a href="#cb30-48" aria-hidden="true"></a>    <span class="st">&#39;admin&#39;</span><span class="op">,</span></span>
<span id="cb30-49"><a href="#cb30-49" aria-hidden="true"></a>    <span class="st">&#39;your-application-password&#39;</span></span>
<span id="cb30-50"><a href="#cb30-50" aria-hidden="true"></a>)<span class="op">;</span></span>
<span id="cb30-51"><a href="#cb30-51" aria-hidden="true"></a></span>
<span id="cb30-52"><a href="#cb30-52" aria-hidden="true"></a><span class="co">// Create backup button handler</span></span>
<span id="cb30-53"><a href="#cb30-53" aria-hidden="true"></a><span class="bu">document</span><span class="op">.</span><span class="fu">getElementById</span>(<span class="st">&#39;create-backup&#39;</span>)<span class="op">.</span><span class="fu">addEventListener</span>(<span class="st">&#39;click&#39;</span><span class="op">,</span> <span class="kw">async</span> () <span class="kw">=&gt;</span> {</span>
<span id="cb30-54"><a href="#cb30-54" aria-hidden="true"></a>    <span class="kw">const</span> result <span class="op">=</span> <span class="cf">await</span> dashboard<span class="op">.</span><span class="fu">createBackup</span>(<span class="st">&#39;full&#39;</span>)<span class="op">;</span></span>
<span id="cb30-55"><a href="#cb30-55" aria-hidden="true"></a>    <span class="bu">console</span><span class="op">.</span><span class="fu">log</span>(<span class="st">&#39;Backup created:&#39;</span><span class="op">,</span> result<span class="op">.</span><span class="at">data</span><span class="op">.</span><span class="at">uuid</span>)<span class="op">;</span></span>
<span id="cb30-56"><a href="#cb30-56" aria-hidden="true"></a>})<span class="op">;</span></span></code></pre>
</div>
<h2 id="error-handling">Error Handling</h2>
<p>API returns standard HTTP status codes:</p>
<p><strong>200 OK</strong>: Request successful <strong>201 Created</strong>: Resource created successfully <strong>400 Bad Request</strong>: Invalid request parameters <strong>401 Unauthorized</strong>: Authentication failed <strong>403 Forbidden</strong>: Insufficient permissions <strong>404 Not Found</strong>: Resource not found <strong>429 Too Many Requests</strong>: Rate limit exceeded <strong>500 Internal Server Error</strong>: Server error</p>
<p><strong>Error Response Format</strong>:</p>
<div class="sourceCode" id="cb31">
<pre class="sourceCode json"><code class="sourceCode json"><span id="cb31-1"><a href="#cb31-1" aria-hidden="true"></a><span class="fu">{</span></span>
<span id="cb31-2"><a href="#cb31-2" aria-hidden="true"></a>  <span class="dt">&quot;success&quot;</span><span class="fu">:</span> <span class="kw">false</span><span class="fu">,</span></span>
<span id="cb31-3"><a href="#cb31-3" aria-hidden="true"></a>  <span class="dt">&quot;error&quot;</span><span class="fu">:</span> <span class="fu">{</span></span>
<span id="cb31-4"><a href="#cb31-4" aria-hidden="true"></a>    <span class="dt">&quot;code&quot;</span><span class="fu">:</span> <span class="st">&quot;invalid_backup_type&quot;</span><span class="fu">,</span></span>
<span id="cb31-5"><a href="#cb31-5" aria-hidden="true"></a>    <span class="dt">&quot;message&quot;</span><span class="fu">:</span> <span class="st">&quot;Backup type must be &#39;full&#39;, &#39;database&#39;, or &#39;files&#39;&quot;</span><span class="fu">,</span></span>
<span id="cb31-6"><a href="#cb31-6" aria-hidden="true"></a>    <span class="dt">&quot;data&quot;</span><span class="fu">:</span> <span class="fu">{</span></span>
<span id="cb31-7"><a href="#cb31-7" aria-hidden="true"></a>      <span class="dt">&quot;provided_value&quot;</span><span class="fu">:</span> <span class="st">&quot;partial&quot;</span></span>
<span id="cb31-8"><a href="#cb31-8" aria-hidden="true"></a>    <span class="fu">}</span></span>
<span id="cb31-9"><a href="#cb31-9" aria-hidden="true"></a>  <span class="fu">}</span></span>
<span id="cb31-10"><a href="#cb31-10" aria-hidden="true"></a><span class="fu">}</span></span></code></pre>
</div>
<h2 id="rate-limiting">Rate Limiting</h2>
<p>API requests are rate limited:</p>
<p><strong>Free Plan</strong>: 100 requests/hour <strong>Pro Plan</strong>: 500 requests/hour <strong>Enterprise Plan</strong>: 5000 requests/hour</p>
<p>Rate limit headers included in responses:</p>
<pre><code>X-RateLimit-Limit: 500
X-RateLimit-Remaining: 487
X-RateLimit-Reset: 1706097600</code></pre>
<h2 id="security-best-practices">Security Best Practices</h2>
<p><strong>Use Application Passwords</strong>: Never use main account password for API authentication.</p>
<p><strong>HTTPS Only</strong>: Always use HTTPS for API requests to encrypt credentials and data.</p>
<p><strong>Rotate Credentials</strong>: Regularly rotate Application Passwords and revoke unused ones.</p>
<p><strong>Validate Webhooks</strong>: Verify webhook signatures using shared secret:</p>
<div class="sourceCode" id="cb33">
<pre class="sourceCode php"><code class="sourceCode php"><span id="cb33-1"><a href="#cb33-1" aria-hidden="true"></a><span class="kw">$payload</span> = <span class="fu">file_get_contents</span><span class="ot">(</span><span class="st">&#39;php://input&#39;</span><span class="ot">);</span></span>
<span id="cb33-2"><a href="#cb33-2" aria-hidden="true"></a><span class="kw">$signature</span> = <span class="fu">hash_hmac</span><span class="ot">(</span><span class="st">&#39;sha256&#39;</span><span class="ot">,</span> <span class="kw">$payload</span><span class="ot">,</span> <span class="st">&#39;your_webhook_secret&#39;</span><span class="ot">);</span></span>
<span id="cb33-3"><a href="#cb33-3" aria-hidden="true"></a></span>
<span id="cb33-4"><a href="#cb33-4" aria-hidden="true"></a><span class="kw">if</span> <span class="ot">(</span>!<span class="fu">hash_equals</span><span class="ot">(</span><span class="kw">$signature</span><span class="ot">,</span> <span class="kw">$_SERVER</span><span class="ot">[</span><span class="st">&#39;HTTP_X_BKPC_SIGNATURE&#39;</span><span class="ot">]))</span> {</span>
<span id="cb33-5"><a href="#cb33-5" aria-hidden="true"></a>    <span class="fu">http_response_code</span><span class="ot">(</span><span class="dv">401</span><span class="ot">);</span></span>
<span id="cb33-6"><a href="#cb33-6" aria-hidden="true"></a>    <span class="kw">exit</span><span class="ot">;</span></span>
<span id="cb33-7"><a href="#cb33-7" aria-hidden="true"></a>}</span></code></pre>
</div>
<p><strong>Minimum Permissions</strong>: Grant API users minimum required permissions (backup operator role rather than administrator).</p>
<h2 id="conclusion">Conclusion</h2>
<p>Backup Copilot Pro’s REST API enables powerful automation and integration possibilities. From CI/CD pipeline integrations ensuring pre-deployment backups to custom monitoring dashboards providing real-time visibility, the API provides complete programmatic control over backup operations.</p>
<p>Authentication via Application Passwords provides secure access, comprehensive endpoints cover all backup operations, real-time status monitoring enables responsive workflows, and webhook notifications enable event-driven architectures. Whether building custom tools or integrating with existing systems, the API provides the foundation for automated, reliable WordPress backup management.</p>
<h2 id="external-links">External Links</h2>
<ol type="1">
<li><a href="https://developer.wordpress.org/rest-api/">WordPress REST API Handbook</a></li>
<li><a href="https://make.wordpress.org/core/2020/11/05/application-passwords-integration-guide/">Application Passwords</a></li>
<li><a href="https://developer.wordpress.org/rest-api/using-the-rest-api/authentication/">REST API Authentication</a></li>
<li><a href="https://www.postman.com/api-platform/api-testing/">Postman API Testing</a></li>
<li><a href="https://oauth.net/2/">OAuth 2.0 for WordPress</a></li>
</ol>
<h2 id="call-to-action">Call to Action</h2>
<p>Build powerful integrations! <a href="https://backupcopilotplugin.com/#pricing">Backup Copilot Pro</a> includes full REST API access with comprehensive documentation. Automate your entire backup workflow—get started today!</p>
<p>The post <a href="https://backupcopilotplugin.com/blog/backup-copilot-pro-rest-api-automate-backups-with-external-systems/">Backup Copilot Pro REST API: Automate Backups with External Systems</a> appeared first on <a href="https://backupcopilotplugin.com">Backup Copilot</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Backup Copilot Pro Developer Guide: Hooks, Filters, and Custom Integrations</title>
		<link>https://backupcopilotplugin.com/blog/backup-copilot-pro-developer-guide-hooks-filters-and-custom-integrations/</link>
		
		<dc:creator><![CDATA[Krasen Slavov]]></dc:creator>
		<pubDate>Mon, 15 Dec 2025 09:00:00 +0000</pubDate>
				<category><![CDATA[Developer Resources]]></category>
		<category><![CDATA[api reference]]></category>
		<category><![CDATA[custom integration]]></category>
		<category><![CDATA[developer guide]]></category>
		<category><![CDATA[plugin development]]></category>
		<category><![CDATA[wordpress hooks]]></category>
		<guid isPermaLink="false">https://backupcopilotplugin.com/?p=271</guid>

					<description><![CDATA[<p>Backup Copilot Pro provides dozens of WordPress hooks and filters enabling developers to customize backup behavior, add integrations, and extend functionality without modifying core code.</p>
<p>The post <a href="https://backupcopilotplugin.com/blog/backup-copilot-pro-developer-guide-hooks-filters-and-custom-integrations/">Backup Copilot Pro Developer Guide: Hooks, Filters, and Custom Integrations</a> appeared first on <a href="https://backupcopilotplugin.com">Backup Copilot</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p><!-- @format --></p>
<p>Backup Copilot Pro provides dozens of WordPress hooks and filters enabling developers to customize backup behavior, add integrations, and extend functionality without modifying core code. This comprehensive developer reference documents all available hooks with practical examples for common customizations from Slack notifications to custom retention policies.</p>
<h2 id="plugin-architecture-overview">Plugin Architecture Overview</h2>
<p>Backup Copilot Pro follows WordPress plugin development standards with clearly defined extension points:</p>
<p><strong>Action Hooks</strong>: Fire at specific points in backup workflow allowing custom code execution (notifications, logging, external integrations).</p>
<p><strong>Filter Hooks</strong>: Modify data or behavior before processing (exclude files, customize metadata, adjust settings).</p>
<p><strong>API Functions</strong>: Helper functions for accessing plugin functionality programmatically.</p>
<p>All hooks follow <code>bkpc_*</code> naming convention for easy identification and avoiding conflicts.</p>
<h2 id="action-hooks-reference">Action Hooks Reference</h2>
<h3 id="bkpc_before_backup_create">bkpc_before_backup_create</h3>
<p>Fires immediately before backup creation starts.</p>
<p><strong>Parameters</strong>: &#8211; <code>$backup_type</code> (string): Type of backup (“full”, “database”, “files”) &#8211; <code>$options</code> (array): Backup options and settings</p>
<p><strong>Example &#8211; Log Backup Start</strong>:</p>
<div class="sourceCode" id="cb1">
<pre class="sourceCode php"><code class="sourceCode php"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true"></a>add_action<span class="ot">(</span><span class="st">&#39;bkpc_before_backup_create&#39;</span><span class="ot">,</span> <span class="st">&#39;log_backup_start&#39;</span><span class="ot">,</span> <span class="dv">10</span><span class="ot">,</span> <span class="dv">2</span><span class="ot">);</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true"></a></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true"></a><span class="kw">function</span> log_backup_start<span class="ot">(</span><span class="kw">$backup_type</span><span class="ot">,</span> <span class="kw">$options</span><span class="ot">)</span> {</span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true"></a>    <span class="fu">error_log</span><span class="ot">(</span><span class="fu">sprintf</span><span class="ot">(</span></span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true"></a>        <span class="st">&#39;[Backup] Starting %s backup at %s&#39;</span><span class="ot">,</span></span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true"></a>        <span class="kw">$backup_type</span><span class="ot">,</span></span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true"></a>        current_time<span class="ot">(</span><span class="st">&#39;mysql&#39;</span><span class="ot">)</span></span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true"></a>    <span class="ot">));</span></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">// Notify monitoring system</span></span>
<span id="cb1-11"><a href="#cb1-11" aria-hidden="true"></a>    wp_remote_post<span class="ot">(</span><span class="st">&#39;https://monitoring.example.com/backup-started&#39;</span><span class="ot">,</span> <span class="ot">[</span></span>
<span id="cb1-12"><a href="#cb1-12" aria-hidden="true"></a>        <span class="st">&#39;body&#39;</span> =&gt; <span class="ot">[</span></span>
<span id="cb1-13"><a href="#cb1-13" aria-hidden="true"></a>            <span class="st">&#39;site&#39;</span> =&gt; get_site_url<span class="ot">(),</span></span>
<span id="cb1-14"><a href="#cb1-14" aria-hidden="true"></a>            <span class="st">&#39;type&#39;</span> =&gt; <span class="kw">$backup_type</span><span class="ot">,</span></span>
<span id="cb1-15"><a href="#cb1-15" aria-hidden="true"></a>            <span class="st">&#39;timestamp&#39;</span> =&gt; <span class="fu">time</span><span class="ot">()</span></span>
<span id="cb1-16"><a href="#cb1-16" aria-hidden="true"></a>        <span class="ot">]</span></span>
<span id="cb1-17"><a href="#cb1-17" aria-hidden="true"></a>    <span class="ot">]);</span></span>
<span id="cb1-18"><a href="#cb1-18" aria-hidden="true"></a>}</span></code></pre>
</div>
<h3 id="bkpc_after_backup_create">bkpc_after_backup_create</h3>
<p>Fires after backup creation completes successfully.</p>
<p><strong>Parameters</strong>: &#8211; <code>$backup_uuid</code> (string): Unique backup identifier &#8211; <code>$backup_data</code> (array): Backup details (size, path, duration, etc.)</p>
<p><strong>Example &#8211; Slack Notification</strong>:</p>
<div class="sourceCode" id="cb2">
<pre class="sourceCode php"><code class="sourceCode php"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true"></a>add_action<span class="ot">(</span><span class="st">&#39;bkpc_after_backup_create&#39;</span><span class="ot">,</span> <span class="st">&#39;notify_slack_backup_complete&#39;</span><span class="ot">,</span> <span class="dv">10</span><span class="ot">,</span> <span class="dv">2</span><span class="ot">);</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true"></a></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true"></a><span class="kw">function</span> notify_slack_backup_complete<span class="ot">(</span><span class="kw">$backup_uuid</span><span class="ot">,</span> <span class="kw">$backup_data</span><span class="ot">)</span> {</span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true"></a>    <span class="kw">$webhook_url</span> = <span class="st">&#39;https://hooks.slack.com/services/YOUR/WEBHOOK/URL&#39;</span><span class="ot">;</span></span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true"></a></span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true"></a>    <span class="kw">$message</span> = <span class="fu">sprintf</span><span class="ot">(</span></span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true"></a>        <span class="st">&#39;:white_check_mark: Backup completed for %s\n&#39;</span> .</span>
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true"></a>        <span class="st">&#39;Type: %s | Size: %s | Duration: %s seconds&#39;</span><span class="ot">,</span></span>
<span id="cb2-9"><a href="#cb2-9" aria-hidden="true"></a>        get_bloginfo<span class="ot">(</span><span class="st">&#39;name&#39;</span><span class="ot">),</span></span>
<span id="cb2-10"><a href="#cb2-10" aria-hidden="true"></a>        <span class="kw">$backup_data</span><span class="ot">[</span><span class="st">&#39;type&#39;</span><span class="ot">],</span></span>
<span id="cb2-11"><a href="#cb2-11" aria-hidden="true"></a>        size_format<span class="ot">(</span><span class="kw">$backup_data</span><span class="ot">[</span><span class="st">&#39;size&#39;</span><span class="ot">]),</span></span>
<span id="cb2-12"><a href="#cb2-12" aria-hidden="true"></a>        <span class="kw">$backup_data</span><span class="ot">[</span><span class="st">&#39;duration&#39;</span><span class="ot">]</span></span>
<span id="cb2-13"><a href="#cb2-13" aria-hidden="true"></a>    <span class="ot">);</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>    wp_remote_post<span class="ot">(</span><span class="kw">$webhook_url</span><span class="ot">,</span> <span class="ot">[</span></span>
<span id="cb2-16"><a href="#cb2-16" aria-hidden="true"></a>        <span class="st">&#39;body&#39;</span> =&gt; <span class="fu">json_encode</span><span class="ot">([</span><span class="st">&#39;text&#39;</span> =&gt; <span class="kw">$message</span><span class="ot">]),</span></span>
<span id="cb2-17"><a href="#cb2-17" aria-hidden="true"></a>        <span class="st">&#39;headers&#39;</span> =&gt; <span class="ot">[</span><span class="st">&#39;Content-Type&#39;</span> =&gt; <span class="st">&#39;application/json&#39;</span><span class="ot">]</span></span>
<span id="cb2-18"><a href="#cb2-18" aria-hidden="true"></a>    <span class="ot">]);</span></span>
<span id="cb2-19"><a href="#cb2-19" aria-hidden="true"></a>}</span></code></pre>
</div>
<h3 id="bkpc_backup_failed">bkpc_backup_failed</h3>
<p>Fires when backup fails for any reason.</p>
<p><strong>Parameters</strong>: &#8211; <code>$backup_uuid</code> (string): Backup identifier &#8211; <code>$error_message</code> (string): Error description &#8211; <code>$error_data</code> (array): Additional error context</p>
<p><strong>Example &#8211; Critical Error Alert</strong>:</p>
<div class="sourceCode" id="cb3">
<pre class="sourceCode php"><code class="sourceCode php"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true"></a>add_action<span class="ot">(</span><span class="st">&#39;bkpc_backup_failed&#39;</span><span class="ot">,</span> <span class="st">&#39;alert_backup_failure&#39;</span><span class="ot">,</span> <span class="dv">10</span><span class="ot">,</span> <span class="dv">3</span><span class="ot">);</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true"></a></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true"></a><span class="kw">function</span> alert_backup_failure<span class="ot">(</span><span class="kw">$backup_uuid</span><span class="ot">,</span> <span class="kw">$error_message</span><span class="ot">,</span> <span class="kw">$error_data</span><span class="ot">)</span> {</span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true"></a>    <span class="co">// Send critical alert to monitoring system</span></span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true"></a>    wp_remote_post<span class="ot">(</span><span class="st">&#39;https://monitoring.example.com/alert&#39;</span><span class="ot">,</span> <span class="ot">[</span></span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true"></a>        <span class="st">&#39;body&#39;</span> =&gt; <span class="fu">json_encode</span><span class="ot">([</span></span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true"></a>            <span class="st">&#39;severity&#39;</span> =&gt; <span class="st">&#39;critical&#39;</span><span class="ot">,</span></span>
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true"></a>            <span class="st">&#39;service&#39;</span> =&gt; <span class="st">&#39;wordpress_backup&#39;</span><span class="ot">,</span></span>
<span id="cb3-9"><a href="#cb3-9" aria-hidden="true"></a>            <span class="st">&#39;message&#39;</span> =&gt; <span class="kw">$error_message</span><span class="ot">,</span></span>
<span id="cb3-10"><a href="#cb3-10" aria-hidden="true"></a>            <span class="st">&#39;site&#39;</span> =&gt; get_site_url<span class="ot">(),</span></span>
<span id="cb3-11"><a href="#cb3-11" aria-hidden="true"></a>            <span class="st">&#39;backup_id&#39;</span> =&gt; <span class="kw">$backup_uuid</span><span class="ot">,</span></span>
<span id="cb3-12"><a href="#cb3-12" aria-hidden="true"></a>            <span class="st">&#39;context&#39;</span> =&gt; <span class="kw">$error_data</span></span>
<span id="cb3-13"><a href="#cb3-13" aria-hidden="true"></a>        <span class="ot">]),</span></span>
<span id="cb3-14"><a href="#cb3-14" aria-hidden="true"></a>        <span class="st">&#39;headers&#39;</span> =&gt; <span class="ot">[</span><span class="st">&#39;Content-Type&#39;</span> =&gt; <span class="st">&#39;application/json&#39;</span><span class="ot">]</span></span>
<span id="cb3-15"><a href="#cb3-15" aria-hidden="true"></a>    <span class="ot">]);</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="co">// Email site administrator</span></span>
<span id="cb3-18"><a href="#cb3-18" aria-hidden="true"></a>    wp_mail<span class="ot">(</span></span>
<span id="cb3-19"><a href="#cb3-19" aria-hidden="true"></a>        get_option<span class="ot">(</span><span class="st">&#39;admin_email&#39;</span><span class="ot">),</span></span>
<span id="cb3-20"><a href="#cb3-20" aria-hidden="true"></a>        <span class="st">&#39;[CRITICAL] Backup Failed: &#39;</span> . get_bloginfo<span class="ot">(</span><span class="st">&#39;name&#39;</span><span class="ot">),</span></span>
<span id="cb3-21"><a href="#cb3-21" aria-hidden="true"></a>        <span class="fu">sprintf</span><span class="ot">(</span></span>
<span id="cb3-22"><a href="#cb3-22" aria-hidden="true"></a>            <span class="st">&quot;Backup %s failed with error:</span><span class="kw">\n\n</span><span class="st">%s</span><span class="kw">\n\n</span><span class="st">Time: %s&quot;</span><span class="ot">,</span></span>
<span id="cb3-23"><a href="#cb3-23" aria-hidden="true"></a>            <span class="kw">$backup_uuid</span><span class="ot">,</span></span>
<span id="cb3-24"><a href="#cb3-24" aria-hidden="true"></a>            <span class="kw">$error_message</span><span class="ot">,</span></span>
<span id="cb3-25"><a href="#cb3-25" aria-hidden="true"></a>            current_time<span class="ot">(</span><span class="st">&#39;mysql&#39;</span><span class="ot">)</span></span>
<span id="cb3-26"><a href="#cb3-26" aria-hidden="true"></a>        <span class="ot">)</span></span>
<span id="cb3-27"><a href="#cb3-27" aria-hidden="true"></a>    <span class="ot">);</span></span>
<span id="cb3-28"><a href="#cb3-28" aria-hidden="true"></a>}</span></code></pre>
</div>
<h3 id="bkpc_before_restore">bkpc_before_restore</h3>
<p>Fires before restore operation begins.</p>
<p><strong>Parameters</strong>: &#8211; <code>$backup_uuid</code> (string): Backup being restored &#8211; <code>$restore_options</code> (array): Restore settings (what to restore, overwrite options)</p>
<p><strong>Example &#8211; Pre-Restore Backup</strong>:</p>
<div class="sourceCode" id="cb4">
<pre class="sourceCode php"><code class="sourceCode php"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true"></a>add_action<span class="ot">(</span><span class="st">&#39;bkpc_before_restore&#39;</span><span class="ot">,</span> <span class="st">&#39;create_pre_restore_backup&#39;</span><span class="ot">,</span> <span class="dv">10</span><span class="ot">,</span> <span class="dv">2</span><span class="ot">);</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true"></a></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true"></a><span class="kw">function</span> create_pre_restore_backup<span class="ot">(</span><span class="kw">$backup_uuid</span><span class="ot">,</span> <span class="kw">$restore_options</span><span class="ot">)</span> {</span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true"></a>    <span class="co">// Create safety backup before restore</span></span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true"></a>    <span class="kw">if</span> <span class="ot">(</span><span class="fu">function_exists</span><span class="ot">(</span><span class="st">&#39;bkpc_create_backup&#39;</span><span class="ot">))</span> {</span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true"></a>        <span class="kw">$safety_backup</span> = bkpc_create_backup<span class="ot">([</span></span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true"></a>            <span class="st">&#39;type&#39;</span> =&gt; <span class="st">&#39;full&#39;</span><span class="ot">,</span></span>
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true"></a>            <span class="st">&#39;metadata&#39;</span> =&gt; <span class="ot">[</span></span>
<span id="cb4-9"><a href="#cb4-9" aria-hidden="true"></a>                <span class="st">&#39;purpose&#39;</span> =&gt; <span class="st">&#39;pre_restore_safety&#39;</span><span class="ot">,</span></span>
<span id="cb4-10"><a href="#cb4-10" aria-hidden="true"></a>                <span class="st">&#39;restoring_backup&#39;</span> =&gt; <span class="kw">$backup_uuid</span></span>
<span id="cb4-11"><a href="#cb4-11" aria-hidden="true"></a>            <span class="ot">]</span></span>
<span id="cb4-12"><a href="#cb4-12" aria-hidden="true"></a>        <span class="ot">]);</span></span>
<span id="cb4-13"><a href="#cb4-13" aria-hidden="true"></a></span>
<span id="cb4-14"><a href="#cb4-14" aria-hidden="true"></a>        <span class="fu">error_log</span><span class="ot">(</span><span class="st">&#39;[Backup] Created pre-restore safety backup: &#39;</span> . <span class="kw">$safety_backup</span><span class="ot">[</span><span class="st">&#39;uuid&#39;</span><span class="ot">]);</span></span>
<span id="cb4-15"><a href="#cb4-15" aria-hidden="true"></a>    }</span>
<span id="cb4-16"><a href="#cb4-16" aria-hidden="true"></a>}</span></code></pre>
</div>
<h3 id="bkpc_after_restore">bkpc_after_restore</h3>
<p>Fires after restore operation completes.</p>
<p><strong>Parameters</strong>: &#8211; <code>$backup_uuid</code> (string): Restored backup ID &#8211; <code>$restore_summary</code> (array): What was restored and results</p>
<p><strong>Example &#8211; Clear Caches Post-Restore</strong>:</p>
<div class="sourceCode" id="cb5">
<pre class="sourceCode php"><code class="sourceCode php"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true"></a>add_action<span class="ot">(</span><span class="st">&#39;bkpc_after_restore&#39;</span><span class="ot">,</span> <span class="st">&#39;clear_caches_after_restore&#39;</span><span class="ot">,</span> <span class="dv">10</span><span class="ot">,</span> <span class="dv">2</span><span class="ot">);</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true"></a></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true"></a><span class="kw">function</span> clear_caches_after_restore<span class="ot">(</span><span class="kw">$backup_uuid</span><span class="ot">,</span> <span class="kw">$restore_summary</span><span class="ot">)</span> {</span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true"></a>    <span class="co">// Clear WordPress object cache</span></span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true"></a>    wp_cache_flush<span class="ot">();</span></span>
<span id="cb5-6"><a href="#cb5-6" aria-hidden="true"></a></span>
<span id="cb5-7"><a href="#cb5-7" aria-hidden="true"></a>    <span class="co">// Clear WP Rocket cache if active</span></span>
<span id="cb5-8"><a href="#cb5-8" aria-hidden="true"></a>    <span class="kw">if</span> <span class="ot">(</span><span class="fu">function_exists</span><span class="ot">(</span><span class="st">&#39;rocket_clean_domain&#39;</span><span class="ot">))</span> {</span>
<span id="cb5-9"><a href="#cb5-9" aria-hidden="true"></a>        rocket_clean_domain<span class="ot">();</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">// Clear W3 Total Cache if active</span></span>
<span id="cb5-13"><a href="#cb5-13" aria-hidden="true"></a>    <span class="kw">if</span> <span class="ot">(</span><span class="fu">function_exists</span><span class="ot">(</span><span class="st">&#39;w3tc_flush_all&#39;</span><span class="ot">))</span> {</span>
<span id="cb5-14"><a href="#cb5-14" aria-hidden="true"></a>        w3tc_flush_all<span class="ot">();</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>
<span id="cb5-17"><a href="#cb5-17" aria-hidden="true"></a>    <span class="co">// Clear Cloudflare cache if configured</span></span>
<span id="cb5-18"><a href="#cb5-18" aria-hidden="true"></a>    <span class="kw">$cf_zone_id</span> = get_option<span class="ot">(</span><span class="st">&#39;cloudflare_zone_id&#39;</span><span class="ot">);</span></span>
<span id="cb5-19"><a href="#cb5-19" aria-hidden="true"></a>    <span class="kw">$cf_api_key</span> = get_option<span class="ot">(</span><span class="st">&#39;cloudflare_api_key&#39;</span><span class="ot">);</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">if</span> <span class="ot">(</span><span class="kw">$cf_zone_id</span> &amp;&amp; <span class="kw">$cf_api_key</span><span class="ot">)</span> {</span>
<span id="cb5-22"><a href="#cb5-22" aria-hidden="true"></a>        wp_remote_post<span class="ot">(</span><span class="st">&quot;https://api.cloudflare.com/client/v4/zones/</span><span class="kw">{$cf_zone_id}</span><span class="st">/purge_cache&quot;</span><span class="ot">,</span> <span class="ot">[</span></span>
<span id="cb5-23"><a href="#cb5-23" aria-hidden="true"></a>            <span class="st">&#39;headers&#39;</span> =&gt; <span class="ot">[</span></span>
<span id="cb5-24"><a href="#cb5-24" aria-hidden="true"></a>                <span class="st">&#39;Authorization&#39;</span> =&gt; <span class="st">&#39;Bearer &#39;</span> . <span class="kw">$cf_api_key</span><span class="ot">,</span></span>
<span id="cb5-25"><a href="#cb5-25" aria-hidden="true"></a>                <span class="st">&#39;Content-Type&#39;</span> =&gt; <span class="st">&#39;application/json&#39;</span></span>
<span id="cb5-26"><a href="#cb5-26" aria-hidden="true"></a>            <span class="ot">],</span></span>
<span id="cb5-27"><a href="#cb5-27" aria-hidden="true"></a>            <span class="st">&#39;body&#39;</span> =&gt; <span class="fu">json_encode</span><span class="ot">([</span><span class="st">&#39;purge_everything&#39;</span> =&gt; <span class="kw">true</span><span class="ot">])</span></span>
<span id="cb5-28"><a href="#cb5-28" aria-hidden="true"></a>        <span class="ot">]);</span></span>
<span id="cb5-29"><a href="#cb5-29" aria-hidden="true"></a>    }</span>
<span id="cb5-30"><a href="#cb5-30" aria-hidden="true"></a>}</span></code></pre>
</div>
<h3 id="bkpc_before_cloud_upload">bkpc_before_cloud_upload</h3>
<p>Fires before backup uploads to cloud storage.</p>
<p><strong>Parameters</strong>: &#8211; <code>$backup_uuid</code> (string): Backup being uploaded &#8211; <code>$provider</code> (string): Cloud provider ID &#8211; <code>$local_path</code> (string): Local backup file path</p>
<p><strong>Example &#8211; Virus Scan Before Upload</strong>:</p>
<div class="sourceCode" id="cb6">
<pre class="sourceCode php"><code class="sourceCode php"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true"></a>add_action<span class="ot">(</span><span class="st">&#39;bkpc_before_cloud_upload&#39;</span><span class="ot">,</span> <span class="st">&#39;scan_backup_before_upload&#39;</span><span class="ot">,</span> <span class="dv">10</span><span class="ot">,</span> <span class="dv">3</span><span class="ot">);</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true"></a></span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true"></a><span class="kw">function</span> scan_backup_before_upload<span class="ot">(</span><span class="kw">$backup_uuid</span><span class="ot">,</span> <span class="kw">$provider</span><span class="ot">,</span> <span class="kw">$local_path</span><span class="ot">)</span> {</span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true"></a>    <span class="co">// Scan with ClamAV before uploading</span></span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true"></a>    <span class="kw">$output</span> = <span class="ot">[];</span></span>
<span id="cb6-6"><a href="#cb6-6" aria-hidden="true"></a>    <span class="kw">$return_var</span> = <span class="dv">0</span><span class="ot">;</span></span>
<span id="cb6-7"><a href="#cb6-7" aria-hidden="true"></a></span>
<span id="cb6-8"><a href="#cb6-8" aria-hidden="true"></a>    <span class="fu">exec</span><span class="ot">(</span><span class="st">&quot;clamscan --no-summary </span><span class="kw">{$local_path}</span><span class="st">&quot;</span><span class="ot">,</span> <span class="kw">$output</span><span class="ot">,</span> <span class="kw">$return_var</span><span class="ot">);</span></span>
<span id="cb6-9"><a href="#cb6-9" aria-hidden="true"></a></span>
<span id="cb6-10"><a href="#cb6-10" aria-hidden="true"></a>    <span class="kw">if</span> <span class="ot">(</span><span class="kw">$return_var</span> !== <span class="dv">0</span><span class="ot">)</span> {</span>
<span id="cb6-11"><a href="#cb6-11" aria-hidden="true"></a>        <span class="co">// Virus detected - abort upload</span></span>
<span id="cb6-12"><a href="#cb6-12" aria-hidden="true"></a>        <span class="fu">error_log</span><span class="ot">(</span><span class="st">&#39;[Security] Virus detected in backup &#39;</span> . <span class="kw">$backup_uuid</span><span class="ot">);</span></span>
<span id="cb6-13"><a href="#cb6-13" aria-hidden="true"></a>        <span class="kw">throw</span> <span class="kw">new</span> <span class="kw">Exception</span><span class="ot">(</span><span class="st">&#39;Backup failed virus scan&#39;</span><span class="ot">);</span></span>
<span id="cb6-14"><a href="#cb6-14" aria-hidden="true"></a>    }</span>
<span id="cb6-15"><a href="#cb6-15" aria-hidden="true"></a>}</span></code></pre>
</div>
<h3 id="bkpc_after_cloud_upload">bkpc_after_cloud_upload</h3>
<p>Fires after successful cloud upload.</p>
<p><strong>Parameters</strong>: &#8211; <code>$backup_uuid</code> (string): Uploaded backup ID &#8211; <code>$provider</code> (string): Cloud provider &#8211; <code>$remote_path</code> (string): Cloud storage path &#8211; <code>$upload_duration</code> (int): Upload time in seconds</p>
<p><strong>Example &#8211; Update External Database</strong>:</p>
<div class="sourceCode" id="cb7">
<pre class="sourceCode php"><code class="sourceCode php"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true"></a>add_action<span class="ot">(</span><span class="st">&#39;bkpc_after_cloud_upload&#39;</span><span class="ot">,</span> <span class="st">&#39;log_upload_to_external_db&#39;</span><span class="ot">,</span> <span class="dv">10</span><span class="ot">,</span> <span class="dv">4</span><span class="ot">);</span></span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true"></a></span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true"></a><span class="kw">function</span> log_upload_to_external_db<span class="ot">(</span><span class="kw">$backup_uuid</span><span class="ot">,</span> <span class="kw">$provider</span><span class="ot">,</span> <span class="kw">$remote_path</span><span class="ot">,</span> <span class="kw">$upload_duration</span><span class="ot">)</span> {</span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true"></a>    <span class="kw">global</span> <span class="kw">$wpdb</span><span class="ot">;</span></span>
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true"></a></span>
<span id="cb7-6"><a href="#cb7-6" aria-hidden="true"></a>    <span class="co">// Log to external monitoring database</span></span>
<span id="cb7-7"><a href="#cb7-7" aria-hidden="true"></a>    <span class="kw">$wpdb</span>-&gt;insert<span class="ot">(</span><span class="st">&#39;backup_audit_log&#39;</span><span class="ot">,</span> <span class="ot">[</span></span>
<span id="cb7-8"><a href="#cb7-8" aria-hidden="true"></a>        <span class="st">&#39;site_id&#39;</span> =&gt; get_current_blog_id<span class="ot">(),</span></span>
<span id="cb7-9"><a href="#cb7-9" aria-hidden="true"></a>        <span class="st">&#39;site_url&#39;</span> =&gt; get_site_url<span class="ot">(),</span></span>
<span id="cb7-10"><a href="#cb7-10" aria-hidden="true"></a>        <span class="st">&#39;backup_id&#39;</span> =&gt; <span class="kw">$backup_uuid</span><span class="ot">,</span></span>
<span id="cb7-11"><a href="#cb7-11" aria-hidden="true"></a>        <span class="st">&#39;provider&#39;</span> =&gt; <span class="kw">$provider</span><span class="ot">,</span></span>
<span id="cb7-12"><a href="#cb7-12" aria-hidden="true"></a>        <span class="st">&#39;remote_path&#39;</span> =&gt; <span class="kw">$remote_path</span><span class="ot">,</span></span>
<span id="cb7-13"><a href="#cb7-13" aria-hidden="true"></a>        <span class="st">&#39;upload_duration&#39;</span> =&gt; <span class="kw">$upload_duration</span><span class="ot">,</span></span>
<span id="cb7-14"><a href="#cb7-14" aria-hidden="true"></a>        <span class="st">&#39;timestamp&#39;</span> =&gt; current_time<span class="ot">(</span><span class="st">&#39;mysql&#39;</span><span class="ot">)</span></span>
<span id="cb7-15"><a href="#cb7-15" aria-hidden="true"></a>    <span class="ot">]);</span></span>
<span id="cb7-16"><a href="#cb7-16" aria-hidden="true"></a>}</span></code></pre>
</div>
<h2 id="filter-hooks-reference">Filter Hooks Reference</h2>
<h3 id="bkpc_backup_excluded_files">bkpc_backup_excluded_files</h3>
<p>Filter files and directories excluded from backup.</p>
<p><strong>Parameters</strong>: &#8211; <code>$excluded</code> (array): Default exclusions</p>
<p><strong>Returns</strong>: Modified exclusion array</p>
<p><strong>Example &#8211; Exclude Custom Directories</strong>:</p>
<div class="sourceCode" id="cb8">
<pre class="sourceCode php"><code class="sourceCode php"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true"></a>add_filter<span class="ot">(</span><span class="st">&#39;bkpc_backup_excluded_files&#39;</span><span class="ot">,</span> <span class="st">&#39;exclude_custom_directories&#39;</span><span class="ot">);</span></span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true"></a></span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true"></a><span class="kw">function</span> exclude_custom_directories<span class="ot">(</span><span class="kw">$excluded</span><span class="ot">)</span> {</span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true"></a>    <span class="co">// Add custom exclusions</span></span>
<span id="cb8-5"><a href="#cb8-5" aria-hidden="true"></a>    <span class="kw">$custom_exclusions</span> = <span class="ot">[</span></span>
<span id="cb8-6"><a href="#cb8-6" aria-hidden="true"></a>        <span class="st">&#39;/wp-content/cache&#39;</span><span class="ot">,</span></span>
<span id="cb8-7"><a href="#cb8-7" aria-hidden="true"></a>        <span class="st">&#39;/wp-content/temp&#39;</span><span class="ot">,</span></span>
<span id="cb8-8"><a href="#cb8-8" aria-hidden="true"></a>        <span class="st">&#39;/wp-content/uploads/backups&#39;</span><span class="ot">,</span></span>
<span id="cb8-9"><a href="#cb8-9" aria-hidden="true"></a>        <span class="st">&#39;/wp-content/ai-training-data&#39;</span><span class="ot">,</span>  <span class="co">// Large AI model files</span></span>
<span id="cb8-10"><a href="#cb8-10" aria-hidden="true"></a>        <span class="st">&#39;/node_modules&#39;</span><span class="ot">,</span>  <span class="co">// Development dependencies</span></span>
<span id="cb8-11"><a href="#cb8-11" aria-hidden="true"></a>        <span class="st">&#39;/.git&#39;</span>  <span class="co">// Version control</span></span>
<span id="cb8-12"><a href="#cb8-12" aria-hidden="true"></a>    <span class="ot">];</span></span>
<span id="cb8-13"><a href="#cb8-13" aria-hidden="true"></a></span>
<span id="cb8-14"><a href="#cb8-14" aria-hidden="true"></a>    <span class="kw">return</span> <span class="fu">array_merge</span><span class="ot">(</span><span class="kw">$excluded</span><span class="ot">,</span> <span class="kw">$custom_exclusions</span><span class="ot">);</span></span>
<span id="cb8-15"><a href="#cb8-15" aria-hidden="true"></a>}</span></code></pre>
</div>
<h3 id="bkpc_backup_excluded_tables">bkpc_backup_excluded_tables</h3>
<p>Filter database tables excluded from backup.</p>
<p><strong>Parameters</strong>: &#8211; <code>$excluded_tables</code> (array): Default excluded tables &#8211; <code>$backup_type</code> (string): Backup type</p>
<p><strong>Returns</strong>: Modified table exclusion array</p>
<p><strong>Example &#8211; Exclude Temporary Tables</strong>:</p>
<div class="sourceCode" id="cb9">
<pre class="sourceCode php"><code class="sourceCode php"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true"></a>add_filter<span class="ot">(</span><span class="st">&#39;bkpc_backup_excluded_tables&#39;</span><span class="ot">,</span> <span class="st">&#39;exclude_temp_tables&#39;</span><span class="ot">,</span> <span class="dv">10</span><span class="ot">,</span> <span class="dv">2</span><span class="ot">);</span></span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true"></a></span>
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true"></a><span class="kw">function</span> exclude_temp_tables<span class="ot">(</span><span class="kw">$excluded_tables</span><span class="ot">,</span> <span class="kw">$backup_type</span><span class="ot">)</span> {</span>
<span id="cb9-4"><a href="#cb9-4" aria-hidden="true"></a>    <span class="kw">global</span> <span class="kw">$wpdb</span><span class="ot">;</span></span>
<span id="cb9-5"><a href="#cb9-5" aria-hidden="true"></a></span>
<span id="cb9-6"><a href="#cb9-6" aria-hidden="true"></a>    <span class="co">// Exclude analytics tables (can be regenerated)</span></span>
<span id="cb9-7"><a href="#cb9-7" aria-hidden="true"></a>    <span class="kw">$analytics_tables</span> = <span class="ot">[</span></span>
<span id="cb9-8"><a href="#cb9-8" aria-hidden="true"></a>        <span class="kw">$wpdb</span>-&gt;prefix . <span class="st">&#39;analytics_cache&#39;</span><span class="ot">,</span></span>
<span id="cb9-9"><a href="#cb9-9" aria-hidden="true"></a>        <span class="kw">$wpdb</span>-&gt;prefix . <span class="st">&#39;statistics_temp&#39;</span><span class="ot">,</span></span>
<span id="cb9-10"><a href="#cb9-10" aria-hidden="true"></a>        <span class="kw">$wpdb</span>-&gt;prefix . <span class="st">&#39;search_log&#39;</span></span>
<span id="cb9-11"><a href="#cb9-11" aria-hidden="true"></a>    <span class="ot">];</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">return</span> <span class="fu">array_merge</span><span class="ot">(</span><span class="kw">$excluded_tables</span><span class="ot">,</span> <span class="kw">$analytics_tables</span><span class="ot">);</span></span>
<span id="cb9-14"><a href="#cb9-14" aria-hidden="true"></a>}</span></code></pre>
</div>
<h3 id="bkpc_backup_metadata">bkpc_backup_metadata</h3>
<p>Filter backup metadata before save.</p>
<p><strong>Parameters</strong>: &#8211; <code>$metadata</code> (array): Default metadata</p>
<p><strong>Returns</strong>: Modified metadata array</p>
<p><strong>Example &#8211; Add Custom Metadata</strong>:</p>
<div class="sourceCode" id="cb10">
<pre class="sourceCode php"><code class="sourceCode php"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true"></a>add_filter<span class="ot">(</span><span class="st">&#39;bkpc_backup_metadata&#39;</span><span class="ot">,</span> <span class="st">&#39;add_custom_backup_metadata&#39;</span><span class="ot">);</span></span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true"></a></span>
<span id="cb10-3"><a href="#cb10-3" aria-hidden="true"></a><span class="kw">function</span> add_custom_backup_metadata<span class="ot">(</span><span class="kw">$metadata</span><span class="ot">)</span> {</span>
<span id="cb10-4"><a href="#cb10-4" aria-hidden="true"></a>    <span class="co">// Add environment information</span></span>
<span id="cb10-5"><a href="#cb10-5" aria-hidden="true"></a>    <span class="kw">$metadata</span><span class="ot">[</span><span class="st">&#39;environment&#39;</span><span class="ot">]</span> = wp_get_environment_type<span class="ot">();</span>  <span class="co">// production, staging, development</span></span>
<span id="cb10-6"><a href="#cb10-6" aria-hidden="true"></a></span>
<span id="cb10-7"><a href="#cb10-7" aria-hidden="true"></a>    <span class="co">// Add theme/plugin versions</span></span>
<span id="cb10-8"><a href="#cb10-8" aria-hidden="true"></a>    <span class="kw">$metadata</span><span class="ot">[</span><span class="st">&#39;active_theme&#39;</span><span class="ot">]</span> = wp_get_theme<span class="ot">()</span>-&gt;get<span class="ot">(</span><span class="st">&#39;Name&#39;</span><span class="ot">)</span> . <span class="st">&#39; &#39;</span> . wp_get_theme<span class="ot">()</span>-&gt;get<span class="ot">(</span><span class="st">&#39;Version&#39;</span><span class="ot">);</span></span>
<span id="cb10-9"><a href="#cb10-9" aria-hidden="true"></a></span>
<span id="cb10-10"><a href="#cb10-10" aria-hidden="true"></a>    <span class="kw">$active_plugins</span> = <span class="ot">[];</span></span>
<span id="cb10-11"><a href="#cb10-11" aria-hidden="true"></a>    <span class="kw">foreach</span> <span class="ot">(</span>get_option<span class="ot">(</span><span class="st">&#39;active_plugins&#39;</span><span class="ot">)</span> <span class="kw">as</span> <span class="kw">$plugin</span><span class="ot">)</span> {</span>
<span id="cb10-12"><a href="#cb10-12" aria-hidden="true"></a>        <span class="kw">$plugin_data</span> = get_plugin_data<span class="ot">(</span><span class="kw">WP_PLUGIN_DIR</span> . <span class="st">&#39;/&#39;</span> . <span class="kw">$plugin</span><span class="ot">);</span></span>
<span id="cb10-13"><a href="#cb10-13" aria-hidden="true"></a>        <span class="kw">$active_plugins</span><span class="ot">[]</span> = <span class="kw">$plugin_data</span><span class="ot">[</span><span class="st">&#39;Name&#39;</span><span class="ot">]</span> . <span class="st">&#39; &#39;</span> . <span class="kw">$plugin_data</span><span class="ot">[</span><span class="st">&#39;Version&#39;</span><span class="ot">];</span></span>
<span id="cb10-14"><a href="#cb10-14" aria-hidden="true"></a>    }</span>
<span id="cb10-15"><a href="#cb10-15" aria-hidden="true"></a>    <span class="kw">$metadata</span><span class="ot">[</span><span class="st">&#39;active_plugins&#39;</span><span class="ot">]</span> = <span class="kw">$active_plugins</span><span class="ot">;</span></span>
<span id="cb10-16"><a href="#cb10-16" aria-hidden="true"></a></span>
<span id="cb10-17"><a href="#cb10-17" aria-hidden="true"></a>    <span class="co">// Add WooCommerce order count if active</span></span>
<span id="cb10-18"><a href="#cb10-18" aria-hidden="true"></a>    <span class="kw">if</span> <span class="ot">(</span><span class="fu">class_exists</span><span class="ot">(</span><span class="st">&#39;WooCommerce&#39;</span><span class="ot">))</span> {</span>
<span id="cb10-19"><a href="#cb10-19" aria-hidden="true"></a>        <span class="kw">$order_count</span> = wp_count_posts<span class="ot">(</span><span class="st">&#39;shop_order&#39;</span><span class="ot">);</span></span>
<span id="cb10-20"><a href="#cb10-20" aria-hidden="true"></a>        <span class="kw">$metadata</span><span class="ot">[</span><span class="st">&#39;woocommerce_orders&#39;</span><span class="ot">]</span> = <span class="kw">$order_count</span>-&gt;publish<span class="ot">;</span></span>
<span id="cb10-21"><a href="#cb10-21" aria-hidden="true"></a>    }</span>
<span id="cb10-22"><a href="#cb10-22" aria-hidden="true"></a></span>
<span id="cb10-23"><a href="#cb10-23" aria-hidden="true"></a>    <span class="kw">return</span> <span class="kw">$metadata</span><span class="ot">;</span></span>
<span id="cb10-24"><a href="#cb10-24" aria-hidden="true"></a>}</span></code></pre>
</div>
<h3 id="bkpc_schedule_options">bkpc_schedule_options</h3>
<p>Filter schedule configuration before save.</p>
<p><strong>Parameters</strong>: &#8211; <code>$options</code> (array): Schedule settings &#8211; <code>$schedule_id</code> (int): Schedule ID</p>
<p><strong>Returns</strong>: Modified options array</p>
<p><strong>Example &#8211; Enforce Backup Policies</strong>:</p>
<div class="sourceCode" id="cb11">
<pre class="sourceCode php"><code class="sourceCode php"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true"></a>add_filter<span class="ot">(</span><span class="st">&#39;bkpc_schedule_options&#39;</span><span class="ot">,</span> <span class="st">&#39;enforce_backup_policies&#39;</span><span class="ot">,</span> <span class="dv">10</span><span class="ot">,</span> <span class="dv">2</span><span class="ot">);</span></span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true"></a></span>
<span id="cb11-3"><a href="#cb11-3" aria-hidden="true"></a><span class="kw">function</span> enforce_backup_policies<span class="ot">(</span><span class="kw">$options</span><span class="ot">,</span> <span class="kw">$schedule_id</span><span class="ot">)</span> {</span>
<span id="cb11-4"><a href="#cb11-4" aria-hidden="true"></a>    <span class="co">// Enforce minimum retention for production</span></span>
<span id="cb11-5"><a href="#cb11-5" aria-hidden="true"></a>    <span class="kw">if</span> <span class="ot">(</span>wp_get_environment_type<span class="ot">()</span> === <span class="st">&#39;production&#39;</span><span class="ot">)</span> {</span>
<span id="cb11-6"><a href="#cb11-6" aria-hidden="true"></a>        <span class="kw">if</span> <span class="ot">(</span><span class="kw">$options</span><span class="ot">[</span><span class="st">&#39;retention_days&#39;</span><span class="ot">]</span> &lt; <span class="dv">30</span><span class="ot">)</span> {</span>
<span id="cb11-7"><a href="#cb11-7" aria-hidden="true"></a>            <span class="kw">$options</span><span class="ot">[</span><span class="st">&#39;retention_days&#39;</span><span class="ot">]</span> = <span class="dv">30</span><span class="ot">;</span></span>
<span id="cb11-8"><a href="#cb11-8" aria-hidden="true"></a>            <span class="fu">error_log</span><span class="ot">(</span><span class="st">&#39;[Backup] Enforced minimum 30-day retention for production&#39;</span><span class="ot">);</span></span>
<span id="cb11-9"><a href="#cb11-9" aria-hidden="true"></a>        }</span>
<span id="cb11-10"><a href="#cb11-10" aria-hidden="true"></a></span>
<span id="cb11-11"><a href="#cb11-11" aria-hidden="true"></a>        <span class="co">// Require cloud upload for production</span></span>
<span id="cb11-12"><a href="#cb11-12" aria-hidden="true"></a>        <span class="kw">$options</span><span class="ot">[</span><span class="st">&#39;cloud_upload&#39;</span><span class="ot">]</span> = <span class="kw">true</span><span class="ot">;</span></span>
<span id="cb11-13"><a href="#cb11-13" aria-hidden="true"></a>    }</span>
<span id="cb11-14"><a href="#cb11-14" aria-hidden="true"></a></span>
<span id="cb11-15"><a href="#cb11-15" aria-hidden="true"></a>    <span class="co">// Limit backup frequency to prevent server overload</span></span>
<span id="cb11-16"><a href="#cb11-16" aria-hidden="true"></a>    <span class="kw">if</span> <span class="ot">(</span><span class="kw">$options</span><span class="ot">[</span><span class="st">&#39;frequency&#39;</span><span class="ot">]</span> === <span class="st">&#39;hourly&#39;</span> &amp;&amp; <span class="kw">$options</span><span class="ot">[</span><span class="st">&#39;backup_type&#39;</span><span class="ot">]</span> === <span class="st">&#39;full&#39;</span><span class="ot">)</span> {</span>
<span id="cb11-17"><a href="#cb11-17" aria-hidden="true"></a>        <span class="kw">$options</span><span class="ot">[</span><span class="st">&#39;frequency&#39;</span><span class="ot">]</span> = <span class="st">&#39;every_6_hours&#39;</span><span class="ot">;</span></span>
<span id="cb11-18"><a href="#cb11-18" aria-hidden="true"></a>        <span class="fu">error_log</span><span class="ot">(</span><span class="st">&#39;[Backup] Reduced full backup frequency to prevent overload&#39;</span><span class="ot">);</span></span>
<span id="cb11-19"><a href="#cb11-19" aria-hidden="true"></a>    }</span>
<span id="cb11-20"><a href="#cb11-20" aria-hidden="true"></a></span>
<span id="cb11-21"><a href="#cb11-21" aria-hidden="true"></a>    <span class="kw">return</span> <span class="kw">$options</span><span class="ot">;</span></span>
<span id="cb11-22"><a href="#cb11-22" aria-hidden="true"></a>}</span></code></pre>
</div>
<h3 id="bkpc_notification_email_content">bkpc_notification_email_content</h3>
<p>Customize notification email content.</p>
<p><strong>Parameters</strong>: &#8211; <code>$content</code> (array): Email content (subject, message, headers) &#8211; <code>$backup_data</code> (array): Backup details</p>
<p><strong>Returns</strong>: Modified email content</p>
<p><strong>Example &#8211; Customized Notification</strong>:</p>
<div class="sourceCode" id="cb12">
<pre class="sourceCode php"><code class="sourceCode php"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true"></a>add_filter<span class="ot">(</span><span class="st">&#39;bkpc_notification_email_content&#39;</span><span class="ot">,</span> <span class="st">&#39;customize_backup_email&#39;</span><span class="ot">,</span> <span class="dv">10</span><span class="ot">,</span> <span class="dv">2</span><span class="ot">);</span></span>
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true"></a></span>
<span id="cb12-3"><a href="#cb12-3" aria-hidden="true"></a><span class="kw">function</span> customize_backup_email<span class="ot">(</span><span class="kw">$content</span><span class="ot">,</span> <span class="kw">$backup_data</span><span class="ot">)</span> {</span>
<span id="cb12-4"><a href="#cb12-4" aria-hidden="true"></a>    <span class="kw">$content</span><span class="ot">[</span><span class="st">&#39;subject&#39;</span><span class="ot">]</span> = <span class="fu">sprintf</span><span class="ot">(</span></span>
<span id="cb12-5"><a href="#cb12-5" aria-hidden="true"></a>        <span class="st">&#39;[%s] %s Backup %s&#39;</span><span class="ot">,</span></span>
<span id="cb12-6"><a href="#cb12-6" aria-hidden="true"></a>        get_bloginfo<span class="ot">(</span><span class="st">&#39;name&#39;</span><span class="ot">),</span></span>
<span id="cb12-7"><a href="#cb12-7" aria-hidden="true"></a>        <span class="fu">ucfirst</span><span class="ot">(</span><span class="kw">$backup_data</span><span class="ot">[</span><span class="st">&#39;type&#39;</span><span class="ot">]),</span></span>
<span id="cb12-8"><a href="#cb12-8" aria-hidden="true"></a>        <span class="kw">$backup_data</span><span class="ot">[</span><span class="st">&#39;status&#39;</span><span class="ot">]</span> === <span class="st">&#39;completed&#39;</span> <span class="ot">?</span> <span class="st">&#39;Completed&#39;</span> <span class="ot">:</span> <span class="st">&#39;Failed&#39;</span></span>
<span id="cb12-9"><a href="#cb12-9" aria-hidden="true"></a>    <span class="ot">);</span></span>
<span id="cb12-10"><a href="#cb12-10" aria-hidden="true"></a></span>
<span id="cb12-11"><a href="#cb12-11" aria-hidden="true"></a>    <span class="kw">$content</span><span class="ot">[</span><span class="st">&#39;message&#39;</span><span class="ot">]</span> = <span class="fu">sprintf</span><span class="ot">(</span></span>
<span id="cb12-12"><a href="#cb12-12" aria-hidden="true"></a>        <span class="st">&quot;Backup Report for %s</span><span class="kw">\n</span><span class="st">&quot;</span> .</span>
<span id="cb12-13"><a href="#cb12-13" aria-hidden="true"></a>        <span class="st">&quot;================================</span><span class="kw">\n\n</span><span class="st">&quot;</span> .</span>
<span id="cb12-14"><a href="#cb12-14" aria-hidden="true"></a>        <span class="st">&quot;Status: %s</span><span class="kw">\n</span><span class="st">&quot;</span> .</span>
<span id="cb12-15"><a href="#cb12-15" aria-hidden="true"></a>        <span class="st">&quot;Type: %s</span><span class="kw">\n</span><span class="st">&quot;</span> .</span>
<span id="cb12-16"><a href="#cb12-16" aria-hidden="true"></a>        <span class="st">&quot;Size: %s</span><span class="kw">\n</span><span class="st">&quot;</span> .</span>
<span id="cb12-17"><a href="#cb12-17" aria-hidden="true"></a>        <span class="st">&quot;Duration: %d seconds</span><span class="kw">\n</span><span class="st">&quot;</span> .</span>
<span id="cb12-18"><a href="#cb12-18" aria-hidden="true"></a>        <span class="st">&quot;Cloud Upload: %s</span><span class="kw">\n</span><span class="st">&quot;</span> .</span>
<span id="cb12-19"><a href="#cb12-19" aria-hidden="true"></a>        <span class="st">&quot;Timestamp: %s</span><span class="kw">\n\n</span><span class="st">&quot;</span> .</span>
<span id="cb12-20"><a href="#cb12-20" aria-hidden="true"></a>        <span class="st">&quot;View backup details: %s</span><span class="kw">\n</span><span class="st">&quot;</span><span class="ot">,</span></span>
<span id="cb12-21"><a href="#cb12-21" aria-hidden="true"></a>        get_bloginfo<span class="ot">(</span><span class="st">&#39;name&#39;</span><span class="ot">),</span></span>
<span id="cb12-22"><a href="#cb12-22" aria-hidden="true"></a>        <span class="fu">strtoupper</span><span class="ot">(</span><span class="kw">$backup_data</span><span class="ot">[</span><span class="st">&#39;status&#39;</span><span class="ot">]),</span></span>
<span id="cb12-23"><a href="#cb12-23" aria-hidden="true"></a>        <span class="kw">$backup_data</span><span class="ot">[</span><span class="st">&#39;type&#39;</span><span class="ot">],</span></span>
<span id="cb12-24"><a href="#cb12-24" aria-hidden="true"></a>        size_format<span class="ot">(</span><span class="kw">$backup_data</span><span class="ot">[</span><span class="st">&#39;size&#39;</span><span class="ot">]),</span></span>
<span id="cb12-25"><a href="#cb12-25" aria-hidden="true"></a>        <span class="kw">$backup_data</span><span class="ot">[</span><span class="st">&#39;duration&#39;</span><span class="ot">],</span></span>
<span id="cb12-26"><a href="#cb12-26" aria-hidden="true"></a>        <span class="kw">$backup_data</span><span class="ot">[</span><span class="st">&#39;cloud_uploaded&#39;</span><span class="ot">]</span> <span class="ot">?</span> <span class="st">&#39;Yes&#39;</span> <span class="ot">:</span> <span class="st">&#39;No&#39;</span><span class="ot">,</span></span>
<span id="cb12-27"><a href="#cb12-27" aria-hidden="true"></a>        <span class="kw">$backup_data</span><span class="ot">[</span><span class="st">&#39;completed_at&#39;</span><span class="ot">],</span></span>
<span id="cb12-28"><a href="#cb12-28" aria-hidden="true"></a>        admin_url<span class="ot">(</span><span class="st">&#39;admin.php?page=backup-copilot-pro&amp;backup=&#39;</span> . <span class="kw">$backup_data</span><span class="ot">[</span><span class="st">&#39;uuid&#39;</span><span class="ot">])</span></span>
<span id="cb12-29"><a href="#cb12-29" aria-hidden="true"></a>    <span class="ot">);</span></span>
<span id="cb12-30"><a href="#cb12-30" aria-hidden="true"></a></span>
<span id="cb12-31"><a href="#cb12-31" aria-hidden="true"></a>    <span class="co">// Add HTML version</span></span>
<span id="cb12-32"><a href="#cb12-32" aria-hidden="true"></a>    <span class="kw">$content</span><span class="ot">[</span><span class="st">&#39;headers&#39;</span><span class="ot">][]</span> = <span class="st">&#39;Content-Type: text/html&#39;</span><span class="ot">;</span></span>
<span id="cb12-33"><a href="#cb12-33" aria-hidden="true"></a></span>
<span id="cb12-34"><a href="#cb12-34" aria-hidden="true"></a>    <span class="kw">return</span> <span class="kw">$content</span><span class="ot">;</span></span>
<span id="cb12-35"><a href="#cb12-35" aria-hidden="true"></a>}</span></code></pre>
</div>
<h3 id="bkpc_cloud_upload_chunk_size">bkpc_cloud_upload_chunk_size</h3>
<p>Customize upload chunk size for different providers.</p>
<p><strong>Parameters</strong>: &#8211; <code>$chunk_size</code> (int): Default chunk size in bytes &#8211; <code>$provider</code> (string): Cloud provider ID</p>
<p><strong>Returns</strong>: Modified chunk size</p>
<p><strong>Example &#8211; Optimize Chunk Sizes</strong>:</p>
<div class="sourceCode" id="cb13">
<pre class="sourceCode php"><code class="sourceCode php"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true"></a>add_filter<span class="ot">(</span><span class="st">&#39;bkpc_cloud_upload_chunk_size&#39;</span><span class="ot">,</span> <span class="st">&#39;optimize_chunk_size&#39;</span><span class="ot">,</span> <span class="dv">10</span><span class="ot">,</span> <span class="dv">2</span><span class="ot">);</span></span>
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true"></a></span>
<span id="cb13-3"><a href="#cb13-3" aria-hidden="true"></a><span class="kw">function</span> optimize_chunk_size<span class="ot">(</span><span class="kw">$chunk_size</span><span class="ot">,</span> <span class="kw">$provider</span><span class="ot">)</span> {</span>
<span id="cb13-4"><a href="#cb13-4" aria-hidden="true"></a>    <span class="co">// Different providers have different optimal chunk sizes</span></span>
<span id="cb13-5"><a href="#cb13-5" aria-hidden="true"></a>    <span class="kw">$optimal_sizes</span> = <span class="ot">[</span></span>
<span id="cb13-6"><a href="#cb13-6" aria-hidden="true"></a>        <span class="st">&#39;dropbox&#39;</span> =&gt; <span class="dv">10</span> * <span class="dv">1024</span> * <span class="dv">1024</span><span class="ot">,</span>      <span class="co">// 10MB for Dropbox</span></span>
<span id="cb13-7"><a href="#cb13-7" aria-hidden="true"></a>        <span class="st">&#39;google_drive&#39;</span> =&gt; <span class="dv">5</span> * <span class="dv">1024</span> * <span class="dv">1024</span><span class="ot">,</span>   <span class="co">// 5MB for Google Drive</span></span>
<span id="cb13-8"><a href="#cb13-8" aria-hidden="true"></a>        <span class="st">&#39;amazon_s3&#39;</span> =&gt; <span class="dv">15</span> * <span class="dv">1024</span> * <span class="dv">1024</span><span class="ot">,</span>     <span class="co">// 15MB for S3</span></span>
<span id="cb13-9"><a href="#cb13-9" aria-hidden="true"></a>        <span class="st">&#39;backblaze&#39;</span> =&gt; <span class="dv">100</span> * <span class="dv">1024</span> * <span class="dv">1024</span>     <span class="co">// 100MB for Backblaze B2</span></span>
<span id="cb13-10"><a href="#cb13-10" aria-hidden="true"></a>    <span class="ot">];</span></span>
<span id="cb13-11"><a href="#cb13-11" aria-hidden="true"></a></span>
<span id="cb13-12"><a href="#cb13-12" aria-hidden="true"></a>    <span class="kw">return</span> <span class="kw">isset</span><span class="ot">(</span><span class="kw">$optimal_sizes</span><span class="ot">[</span><span class="kw">$provider</span><span class="ot">])</span> <span class="ot">?</span> <span class="kw">$optimal_sizes</span><span class="ot">[</span><span class="kw">$provider</span><span class="ot">]</span> <span class="ot">:</span> <span class="kw">$chunk_size</span><span class="ot">;</span></span>
<span id="cb13-13"><a href="#cb13-13" aria-hidden="true"></a>}</span></code></pre>
</div>
<h2 id="advanced-integration-examples">Advanced Integration Examples</h2>
<h3 id="custom-retention-logic">Custom Retention Logic</h3>
<p>Implement sophisticated retention policies:</p>
<div class="sourceCode" id="cb14">
<pre class="sourceCode php"><code class="sourceCode php"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true"></a>add_filter<span class="ot">(</span><span class="st">&#39;bkpc_retention_policy&#39;</span><span class="ot">,</span> <span class="st">&#39;custom_retention_logic&#39;</span><span class="ot">,</span> <span class="dv">10</span><span class="ot">,</span> <span class="dv">2</span><span class="ot">);</span></span>
<span id="cb14-2"><a href="#cb14-2" aria-hidden="true"></a></span>
<span id="cb14-3"><a href="#cb14-3" aria-hidden="true"></a><span class="kw">function</span> custom_retention_logic<span class="ot">(</span><span class="kw">$should_delete</span><span class="ot">,</span> <span class="kw">$backup_data</span><span class="ot">)</span> {</span>
<span id="cb14-4"><a href="#cb14-4" aria-hidden="true"></a>    <span class="co">// Keep all backups from the first of each month indefinitely</span></span>
<span id="cb14-5"><a href="#cb14-5" aria-hidden="true"></a>    <span class="kw">$backup_date</span> = <span class="kw">new</span> <span class="kw">DateTime</span><span class="ot">(</span><span class="kw">$backup_data</span><span class="ot">[</span><span class="st">&#39;created_at&#39;</span><span class="ot">]);</span></span>
<span id="cb14-6"><a href="#cb14-6" aria-hidden="true"></a>    <span class="kw">if</span> <span class="ot">(</span><span class="kw">$backup_date</span>-&gt;format<span class="ot">(</span><span class="st">&#39;d&#39;</span><span class="ot">)</span> === <span class="st">&#39;01&#39;</span><span class="ot">)</span> {</span>
<span id="cb14-7"><a href="#cb14-7" aria-hidden="true"></a>        <span class="kw">return</span> <span class="kw">false</span><span class="ot">;</span>  <span class="co">// Don&#39;t delete monthly backups</span></span>
<span id="cb14-8"><a href="#cb14-8" aria-hidden="true"></a>    }</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">// Keep backups tagged as &quot;before_major_update&quot; for 1 year</span></span>
<span id="cb14-11"><a href="#cb14-11" aria-hidden="true"></a>    <span class="kw">if</span> <span class="ot">(</span><span class="kw">isset</span><span class="ot">(</span><span class="kw">$backup_data</span><span class="ot">[</span><span class="st">&#39;metadata&#39;</span><span class="ot">][</span><span class="st">&#39;tag&#39;</span><span class="ot">])</span> &amp;&amp;</span>
<span id="cb14-12"><a href="#cb14-12" aria-hidden="true"></a>        <span class="kw">$backup_data</span><span class="ot">[</span><span class="st">&#39;metadata&#39;</span><span class="ot">][</span><span class="st">&#39;tag&#39;</span><span class="ot">]</span> === <span class="st">&#39;before_major_update&#39;</span><span class="ot">)</span> {</span>
<span id="cb14-13"><a href="#cb14-13" aria-hidden="true"></a>        <span class="kw">$age_days</span> = <span class="ot">(</span><span class="fu">time</span><span class="ot">()</span> - <span class="fu">strtotime</span><span class="ot">(</span><span class="kw">$backup_data</span><span class="ot">[</span><span class="st">&#39;created_at&#39;</span><span class="ot">]))</span> / <span class="kw">DAY_IN_SECONDS</span><span class="ot">;</span></span>
<span id="cb14-14"><a href="#cb14-14" aria-hidden="true"></a>        <span class="kw">return</span> <span class="kw">$age_days</span> &gt; <span class="dv">365</span><span class="ot">;</span>  <span class="co">// Delete after 1 year</span></span>
<span id="cb14-15"><a href="#cb14-15" aria-hidden="true"></a>    }</span>
<span id="cb14-16"><a href="#cb14-16" aria-hidden="true"></a></span>
<span id="cb14-17"><a href="#cb14-17" aria-hidden="true"></a>    <span class="co">// Default retention logic</span></span>
<span id="cb14-18"><a href="#cb14-18" aria-hidden="true"></a>    <span class="kw">return</span> <span class="kw">$should_delete</span><span class="ot">;</span></span>
<span id="cb14-19"><a href="#cb14-19" aria-hidden="true"></a>}</span></code></pre>
</div>
<h3 id="database-query-optimization">Database Query Optimization</h3>
<p>Optimize database export queries:</p>
<div class="sourceCode" id="cb15">
<pre class="sourceCode php"><code class="sourceCode php"><span id="cb15-1"><a href="#cb15-1" aria-hidden="true"></a>add_filter<span class="ot">(</span><span class="st">&#39;bkpc_database_export_query&#39;</span><span class="ot">,</span> <span class="st">&#39;optimize_export_query&#39;</span><span class="ot">,</span> <span class="dv">10</span><span class="ot">,</span> <span class="dv">2</span><span class="ot">);</span></span>
<span id="cb15-2"><a href="#cb15-2" aria-hidden="true"></a></span>
<span id="cb15-3"><a href="#cb15-3" aria-hidden="true"></a><span class="kw">function</span> optimize_export_query<span class="ot">(</span><span class="kw">$query</span><span class="ot">,</span> <span class="kw">$table</span><span class="ot">)</span> {</span>
<span id="cb15-4"><a href="#cb15-4" aria-hidden="true"></a>    <span class="co">// Skip certain columns from large tables</span></span>
<span id="cb15-5"><a href="#cb15-5" aria-hidden="true"></a>    <span class="kw">$optimizations</span> = <span class="ot">[</span></span>
<span id="cb15-6"><a href="#cb15-6" aria-hidden="true"></a>        <span class="st">&#39;wp_posts&#39;</span> =&gt; <span class="st">&#39;SELECT ID, post_author, post_date, post_content, post_title, post_status FROM&#39;</span><span class="ot">,</span></span>
<span id="cb15-7"><a href="#cb15-7" aria-hidden="true"></a>        <span class="st">&#39;wp_comments&#39;</span> =&gt; <span class="st">&#39;SELECT * FROM&#39;</span>  <span class="co">// Exclude spam comments</span></span>
<span id="cb15-8"><a href="#cb15-8" aria-hidden="true"></a>    <span class="ot">];</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="kw">foreach</span> <span class="ot">(</span><span class="kw">$optimizations</span> <span class="kw">as</span> <span class="kw">$table_name</span> =&gt; <span class="kw">$select</span><span class="ot">)</span> {</span>
<span id="cb15-11"><a href="#cb15-11" aria-hidden="true"></a>        <span class="kw">if</span> <span class="ot">(</span><span class="fu">strpos</span><span class="ot">(</span><span class="kw">$table</span><span class="ot">,</span> <span class="kw">$table_name</span><span class="ot">)</span> !== <span class="kw">false</span><span class="ot">)</span> {</span>
<span id="cb15-12"><a href="#cb15-12" aria-hidden="true"></a>            <span class="co">// Modify query for this table</span></span>
<span id="cb15-13"><a href="#cb15-13" aria-hidden="true"></a>            <span class="kw">if</span> <span class="ot">(</span><span class="kw">$table_name</span> === <span class="st">&#39;wp_comments&#39;</span><span class="ot">)</span> {</span>
<span id="cb15-14"><a href="#cb15-14" aria-hidden="true"></a>                <span class="kw">$query</span> .= <span class="st">&quot; WHERE comment_approved != &#39;spam&#39;&quot;</span><span class="ot">;</span></span>
<span id="cb15-15"><a href="#cb15-15" aria-hidden="true"></a>            }</span>
<span id="cb15-16"><a href="#cb15-16" aria-hidden="true"></a>        }</span>
<span id="cb15-17"><a href="#cb15-17" aria-hidden="true"></a>    }</span>
<span id="cb15-18"><a href="#cb15-18" aria-hidden="true"></a></span>
<span id="cb15-19"><a href="#cb15-19" aria-hidden="true"></a>    <span class="kw">return</span> <span class="kw">$query</span><span class="ot">;</span></span>
<span id="cb15-20"><a href="#cb15-20" aria-hidden="true"></a>}</span></code></pre>
</div>
<h3 id="third-party-service-integration">Third-Party Service Integration</h3>
<p>Integrate with external backup verification service:</p>
<div class="sourceCode" id="cb16">
<pre class="sourceCode php"><code class="sourceCode php"><span id="cb16-1"><a href="#cb16-1" aria-hidden="true"></a>add_action<span class="ot">(</span><span class="st">&#39;bkpc_after_cloud_upload&#39;</span><span class="ot">,</span> <span class="st">&#39;verify_backup_externally&#39;</span><span class="ot">,</span> <span class="dv">10</span><span class="ot">,</span> <span class="dv">4</span><span class="ot">);</span></span>
<span id="cb16-2"><a href="#cb16-2" aria-hidden="true"></a></span>
<span id="cb16-3"><a href="#cb16-3" aria-hidden="true"></a><span class="kw">function</span> verify_backup_externally<span class="ot">(</span><span class="kw">$backup_uuid</span><span class="ot">,</span> <span class="kw">$provider</span><span class="ot">,</span> <span class="kw">$remote_path</span><span class="ot">,</span> <span class="kw">$duration</span><span class="ot">)</span> {</span>
<span id="cb16-4"><a href="#cb16-4" aria-hidden="true"></a>    <span class="co">// Send to external backup verification service</span></span>
<span id="cb16-5"><a href="#cb16-5" aria-hidden="true"></a>    <span class="kw">$verification_service</span> = <span class="st">&#39;https://backup-verify.example.com/api/verify&#39;</span><span class="ot">;</span></span>
<span id="cb16-6"><a href="#cb16-6" aria-hidden="true"></a></span>
<span id="cb16-7"><a href="#cb16-7" aria-hidden="true"></a>    <span class="kw">$backup_info</span> = bkpc_get_backup<span class="ot">(</span><span class="kw">$backup_uuid</span><span class="ot">);</span></span>
<span id="cb16-8"><a href="#cb16-8" aria-hidden="true"></a></span>
<span id="cb16-9"><a href="#cb16-9" aria-hidden="true"></a>    wp_remote_post<span class="ot">(</span><span class="kw">$verification_service</span><span class="ot">,</span> <span class="ot">[</span></span>
<span id="cb16-10"><a href="#cb16-10" aria-hidden="true"></a>        <span class="st">&#39;body&#39;</span> =&gt; <span class="fu">json_encode</span><span class="ot">([</span></span>
<span id="cb16-11"><a href="#cb16-11" aria-hidden="true"></a>            <span class="st">&#39;site_id&#39;</span> =&gt; get_option<span class="ot">(</span><span class="st">&#39;site_verification_id&#39;</span><span class="ot">),</span></span>
<span id="cb16-12"><a href="#cb16-12" aria-hidden="true"></a>            <span class="st">&#39;backup_id&#39;</span> =&gt; <span class="kw">$backup_uuid</span><span class="ot">,</span></span>
<span id="cb16-13"><a href="#cb16-13" aria-hidden="true"></a>            <span class="st">&#39;provider&#39;</span> =&gt; <span class="kw">$provider</span><span class="ot">,</span></span>
<span id="cb16-14"><a href="#cb16-14" aria-hidden="true"></a>            <span class="st">&#39;remote_path&#39;</span> =&gt; <span class="kw">$remote_path</span><span class="ot">,</span></span>
<span id="cb16-15"><a href="#cb16-15" aria-hidden="true"></a>            <span class="st">&#39;size&#39;</span> =&gt; <span class="kw">$backup_info</span><span class="ot">[</span><span class="st">&#39;size&#39;</span><span class="ot">],</span></span>
<span id="cb16-16"><a href="#cb16-16" aria-hidden="true"></a>            <span class="st">&#39;checksum&#39;</span> =&gt; <span class="kw">$backup_info</span><span class="ot">[</span><span class="st">&#39;checksum&#39;</span><span class="ot">],</span></span>
<span id="cb16-17"><a href="#cb16-17" aria-hidden="true"></a>            <span class="st">&#39;timestamp&#39;</span> =&gt; <span class="fu">time</span><span class="ot">()</span></span>
<span id="cb16-18"><a href="#cb16-18" aria-hidden="true"></a>        <span class="ot">]),</span></span>
<span id="cb16-19"><a href="#cb16-19" aria-hidden="true"></a>        <span class="st">&#39;headers&#39;</span> =&gt; <span class="ot">[</span></span>
<span id="cb16-20"><a href="#cb16-20" aria-hidden="true"></a>            <span class="st">&#39;Content-Type&#39;</span> =&gt; <span class="st">&#39;application/json&#39;</span><span class="ot">,</span></span>
<span id="cb16-21"><a href="#cb16-21" aria-hidden="true"></a>            <span class="st">&#39;Authorization&#39;</span> =&gt; <span class="st">&#39;Bearer &#39;</span> . get_option<span class="ot">(</span><span class="st">&#39;verification_api_key&#39;</span><span class="ot">)</span></span>
<span id="cb16-22"><a href="#cb16-22" aria-hidden="true"></a>        <span class="ot">]</span></span>
<span id="cb16-23"><a href="#cb16-23" aria-hidden="true"></a>    <span class="ot">]);</span></span>
<span id="cb16-24"><a href="#cb16-24" aria-hidden="true"></a>}</span></code></pre>
</div>
<h2 id="security-considerations">Security Considerations</h2>
<p><strong>Validate All Inputs</strong>: When using filters that accept user input, always validate and sanitize.</p>
<p><strong>Capability Checks</strong>: Ensure custom code respects WordPress capabilities:</p>
<div class="sourceCode" id="cb17">
<pre class="sourceCode php"><code class="sourceCode php"><span id="cb17-1"><a href="#cb17-1" aria-hidden="true"></a>add_action<span class="ot">(</span><span class="st">&#39;bkpc_before_backup_create&#39;</span><span class="ot">,</span> <span class="st">&#39;log_backup_initiator&#39;</span><span class="ot">,</span> <span class="dv">10</span><span class="ot">,</span> <span class="dv">2</span><span class="ot">);</span></span>
<span id="cb17-2"><a href="#cb17-2" aria-hidden="true"></a></span>
<span id="cb17-3"><a href="#cb17-3" aria-hidden="true"></a><span class="kw">function</span> log_backup_initiator<span class="ot">(</span><span class="kw">$backup_type</span><span class="ot">,</span> <span class="kw">$options</span><span class="ot">)</span> {</span>
<span id="cb17-4"><a href="#cb17-4" aria-hidden="true"></a>    <span class="kw">if</span> <span class="ot">(</span>!current_user_can<span class="ot">(</span><span class="st">&#39;manage_options&#39;</span><span class="ot">))</span> {</span>
<span id="cb17-5"><a href="#cb17-5" aria-hidden="true"></a>        <span class="kw">return</span><span class="ot">;</span>  <span class="co">// Only log for administrators</span></span>
<span id="cb17-6"><a href="#cb17-6" aria-hidden="true"></a>    }</span>
<span id="cb17-7"><a href="#cb17-7" aria-hidden="true"></a></span>
<span id="cb17-8"><a href="#cb17-8" aria-hidden="true"></a>    <span class="co">// Log who initiated backup</span></span>
<span id="cb17-9"><a href="#cb17-9" aria-hidden="true"></a>}</span></code></pre>
</div>
<p><strong>Prevent Information Disclosure</strong>: Don’t expose sensitive information in logs or notifications.</p>
<p><strong>Rate Limiting</strong>: External API calls should implement retry limits and exponential backoff.</p>
<h2 id="performance-impact">Performance Impact</h2>
<p><strong>Minimize Hook Execution Time</strong>: Keep hook callbacks fast. Defer long operations:</p>
<div class="sourceCode" id="cb18">
<pre class="sourceCode php"><code class="sourceCode php"><span id="cb18-1"><a href="#cb18-1" aria-hidden="true"></a>add_action<span class="ot">(</span><span class="st">&#39;bkpc_after_backup_create&#39;</span><span class="ot">,</span> <span class="st">&#39;defer_slow_operation&#39;</span><span class="ot">,</span> <span class="dv">10</span><span class="ot">,</span> <span class="dv">2</span><span class="ot">);</span></span>
<span id="cb18-2"><a href="#cb18-2" aria-hidden="true"></a></span>
<span id="cb18-3"><a href="#cb18-3" aria-hidden="true"></a><span class="kw">function</span> defer_slow_operation<span class="ot">(</span><span class="kw">$backup_uuid</span><span class="ot">,</span> <span class="kw">$backup_data</span><span class="ot">)</span> {</span>
<span id="cb18-4"><a href="#cb18-4" aria-hidden="true"></a>    <span class="co">// Schedule slow operation for later rather than blocking</span></span>
<span id="cb18-5"><a href="#cb18-5" aria-hidden="true"></a>    wp_schedule_single_event<span class="ot">(</span><span class="fu">time</span><span class="ot">()</span> + <span class="dv">60</span><span class="ot">,</span> <span class="st">&#39;process_backup_analytics&#39;</span><span class="ot">,</span> <span class="ot">[</span><span class="kw">$backup_uuid</span><span class="ot">]);</span></span>
<span id="cb18-6"><a href="#cb18-6" aria-hidden="true"></a>}</span></code></pre>
</div>
<p><strong>Cache When Possible</strong>: Don’t repeat expensive operations unnecessarily.</p>
<p><strong>Async for External Calls</strong>: Use <code>blocking =&gt; false</code> for non-critical external requests:</p>
<div class="sourceCode" id="cb19">
<pre class="sourceCode php"><code class="sourceCode php"><span id="cb19-1"><a href="#cb19-1" aria-hidden="true"></a>wp_remote_post<span class="ot">(</span><span class="kw">$url</span><span class="ot">,</span> <span class="ot">[</span></span>
<span id="cb19-2"><a href="#cb19-2" aria-hidden="true"></a>    <span class="st">&#39;blocking&#39;</span> =&gt; <span class="kw">false</span><span class="ot">,</span>  <span class="co">// Don&#39;t wait for response</span></span>
<span id="cb19-3"><a href="#cb19-3" aria-hidden="true"></a>    <span class="st">&#39;timeout&#39;</span> =&gt; <span class="dv">5</span><span class="ot">,</span></span>
<span id="cb19-4"><a href="#cb19-4" aria-hidden="true"></a>    <span class="st">&#39;body&#39;</span> =&gt; <span class="kw">$data</span></span>
<span id="cb19-5"><a href="#cb19-5" aria-hidden="true"></a><span class="ot">]);</span></span></code></pre>
</div>
<h2 id="debugging-custom-integrations">Debugging Custom Integrations</h2>
<p>Enable WordPress debugging and use error logging:</p>
<div class="sourceCode" id="cb20">
<pre class="sourceCode php"><code class="sourceCode php"><span id="cb20-1"><a href="#cb20-1" aria-hidden="true"></a>add_action<span class="ot">(</span><span class="st">&#39;bkpc_before_backup_create&#39;</span><span class="ot">,</span> <span class="st">&#39;debug_backup_hooks&#39;</span><span class="ot">,</span> <span class="dv">10</span><span class="ot">,</span> <span class="dv">2</span><span class="ot">);</span></span>
<span id="cb20-2"><a href="#cb20-2" aria-hidden="true"></a></span>
<span id="cb20-3"><a href="#cb20-3" aria-hidden="true"></a><span class="kw">function</span> debug_backup_hooks<span class="ot">(</span><span class="kw">$backup_type</span><span class="ot">,</span> <span class="kw">$options</span><span class="ot">)</span> {</span>
<span id="cb20-4"><a href="#cb20-4" aria-hidden="true"></a>    <span class="kw">if</span> <span class="ot">(</span><span class="fu">defined</span><span class="ot">(</span><span class="st">&#39;WP_DEBUG&#39;</span><span class="ot">)</span> &amp;&amp; <span class="kw">WP_DEBUG</span><span class="ot">)</span> {</span>
<span id="cb20-5"><a href="#cb20-5" aria-hidden="true"></a>        <span class="fu">error_log</span><span class="ot">(</span><span class="st">&#39;=== Backup Hook Debug ===&#39;</span><span class="ot">);</span></span>
<span id="cb20-6"><a href="#cb20-6" aria-hidden="true"></a>        <span class="fu">error_log</span><span class="ot">(</span><span class="st">&#39;Type: &#39;</span> . <span class="kw">$backup_type</span><span class="ot">);</span></span>
<span id="cb20-7"><a href="#cb20-7" aria-hidden="true"></a>        <span class="fu">error_log</span><span class="ot">(</span><span class="st">&#39;Options: &#39;</span> . <span class="fu">print_r</span><span class="ot">(</span><span class="kw">$options</span><span class="ot">,</span> <span class="kw">true</span><span class="ot">));</span></span>
<span id="cb20-8"><a href="#cb20-8" aria-hidden="true"></a>        <span class="fu">error_log</span><span class="ot">(</span><span class="st">&#39;Current user: &#39;</span> . wp_get_current_user<span class="ot">()</span>-&gt;user_login<span class="ot">);</span></span>
<span id="cb20-9"><a href="#cb20-9" aria-hidden="true"></a>        <span class="fu">error_log</span><span class="ot">(</span><span class="st">&#39;Memory usage: &#39;</span> . size_format<span class="ot">(</span><span class="fu">memory_get_usage</span><span class="ot">(</span><span class="kw">true</span><span class="ot">)));</span></span>
<span id="cb20-10"><a href="#cb20-10" aria-hidden="true"></a>        <span class="fu">error_log</span><span class="ot">(</span><span class="st">&#39;========================&#39;</span><span class="ot">);</span></span>
<span id="cb20-11"><a href="#cb20-11" aria-hidden="true"></a>    }</span>
<span id="cb20-12"><a href="#cb20-12" aria-hidden="true"></a>}</span></code></pre>
</div>
<h2 id="best-practices">Best Practices</h2>
<p><strong>Use Priority Wisely</strong>: Default priority is 10. Lower numbers run first, higher run later. Critical operations should run early (priority 5), non-critical later (priority 20).</p>
<p><strong>Check Function Existence</strong>: Always verify functions exist before calling:</p>
<div class="sourceCode" id="cb21">
<pre class="sourceCode php"><code class="sourceCode php"><span id="cb21-1"><a href="#cb21-1" aria-hidden="true"></a><span class="kw">if</span> <span class="ot">(</span><span class="fu">function_exists</span><span class="ot">(</span><span class="st">&#39;bkpc_create_backup&#39;</span><span class="ot">))</span> {</span>
<span id="cb21-2"><a href="#cb21-2" aria-hidden="true"></a>    <span class="co">// Safe to call</span></span>
<span id="cb21-3"><a href="#cb21-3" aria-hidden="true"></a>}</span></code></pre>
</div>
<p><strong>Document Custom Code</strong>: Comment your hooks explaining what they do and why.</p>
<p><strong>Test Thoroughly</strong>: Test custom hooks with various backup types, sizes, and failure scenarios.</p>
<p><strong>Plugin Compatibility</strong>: Check for conflicts with other backup or security plugins.</p>
<h2 id="conclusion">Conclusion</h2>
<p>Backup Copilot Pro’s extensive hook and filter system provides complete customization without touching core code. From simple exclusions to complex integrations with external services, the architecture supports sophisticated workflows while maintaining compatibility and performance.</p>
<p>Action hooks enable event-driven integrations, filter hooks allow data manipulation, proper implementation ensures security and performance, and thorough testing prevents issues in production. Whether adding Slack notifications, implementing custom retention policies, or integrating with enterprise monitoring systems, these hooks provide the foundation for extending Backup Copilot Pro to meet any requirement.</p>
<h2 id="external-links">External Links</h2>
<ol type="1">
<li><a href="https://developer.wordpress.org/plugins/hooks/">WordPress Plugin API</a></li>
<li><a href="https://codex.wordpress.org/Plugin_API/Action_Reference">Action Reference</a></li>
<li><a href="https://codex.wordpress.org/Plugin_API/Filter_Reference">Filter Reference</a></li>
<li><a href="https://developer.wordpress.org/coding-standards/wordpress-coding-standards/">WordPress Coding Standards</a></li>
<li><a href="https://developer.wordpress.org/plugins/">Plugin Development Handbook</a></li>
</ol>
<h2 id="call-to-action">Call to Action</h2>
<p>Ready to extend Backup Copilot Pro? <a href="https://backupcopilotplugin.com/#pricing">Get Pro</a> and access our complete API documentation, developer support, and custom integration assistance. Build exactly what you need!</p>
<p>The post <a href="https://backupcopilotplugin.com/blog/backup-copilot-pro-developer-guide-hooks-filters-and-custom-integrations/">Backup Copilot Pro Developer Guide: Hooks, Filters, and Custom Integrations</a> appeared first on <a href="https://backupcopilotplugin.com">Backup Copilot</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Building Custom Cloud Storage Providers for Backup Copilot Pro</title>
		<link>https://backupcopilotplugin.com/blog/building-custom-cloud-storage-providers-for-backup-copilot-pro/</link>
		
		<dc:creator><![CDATA[Krasen Slavov]]></dc:creator>
		<pubDate>Fri, 05 Dec 2025 09:00:00 +0000</pubDate>
				<category><![CDATA[Developer Resources]]></category>
		<category><![CDATA[plugin-test]]></category>
		<category><![CDATA[rest api]]></category>
		<category><![CDATA[yoast-seo]]></category>
		<guid isPermaLink="false">https://backupcopilotplugin.com/?p=269</guid>

					<description><![CDATA[<p>Backup Copilot Pro supports Dropbox, Google Drive, and Amazon S3 out of the box.</p>
<p>The post <a href="https://backupcopilotplugin.com/blog/building-custom-cloud-storage-providers-for-backup-copilot-pro/">Building Custom Cloud Storage Providers for Backup Copilot Pro</a> appeared first on <a href="https://backupcopilotplugin.com">Backup Copilot</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p><!-- @format --></p>
<p>Backup Copilot Pro supports Dropbox, Google Drive, and Amazon S3 out of the box. But what if you need Wasabi, Backblaze B2, DigitalOcean Spaces, or your own custom storage backend? This developer guide shows you how to build custom cloud storage providers by extending Backup Copilot Pro’s provider architecture with complete code examples and implementation details.</p>
<h2 id="understanding-the-cloud-provider-architecture">Understanding the Cloud Provider Architecture</h2>
<p>Backup Copilot Pro uses an abstract cloud provider interface that all storage backends implement. This architecture enables consistent behavior across different cloud services while allowing provider-specific implementations.</p>
<p><strong>Base Provider Class</strong>: All providers extend <code>BKPC_Cloud_Provider</code> abstract class defining required methods:</p>
<div class="sourceCode" id="cb1">
<pre class="sourceCode php"><code class="sourceCode php"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true"></a><span class="kw">abstract</span> <span class="kw">class</span> BKPC_Cloud_Provider {</span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true"></a>    <span class="kw">abstract</span> <span class="kw">public</span> <span class="kw">function</span> authenticate<span class="ot">(</span><span class="kw">$credentials</span><span class="ot">);</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true"></a>    <span class="kw">abstract</span> <span class="kw">public</span> <span class="kw">function</span> upload<span class="ot">(</span><span class="kw">$local_file</span><span class="ot">,</span> <span class="kw">$remote_path</span><span class="ot">,</span> <span class="kw">$options</span><span class="ot">);</span></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true"></a>    <span class="kw">abstract</span> <span class="kw">public</span> <span class="kw">function</span> download<span class="ot">(</span><span class="kw">$remote_path</span><span class="ot">,</span> <span class="kw">$local_file</span><span class="ot">);</span></span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true"></a>    <span class="kw">abstract</span> <span class="kw">public</span> <span class="kw">function</span> delete<span class="ot">(</span><span class="kw">$remote_path</span><span class="ot">);</span></span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true"></a>    <span class="kw">abstract</span> <span class="kw">public</span> <span class="kw">function</span> list_files<span class="ot">(</span><span class="kw">$remote_dir</span><span class="ot">);</span></span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true"></a>    <span class="kw">abstract</span> <span class="kw">public</span> <span class="kw">function</span> get_storage_info<span class="ot">();</span></span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true"></a>}</span></code></pre>
</div>
<p>Your custom provider implements these methods using your chosen storage service’s API.</p>
<h2 id="required-methods-overview">Required Methods Overview</h2>
<p>Each method serves specific purpose in backup workflow:</p>
<p><strong>authenticate($credentials)</strong>: Validates API credentials, OAuth tokens, or connection parameters. Returns true on success, throws exception on failure.</p>
<p><strong>upload($local_file, $remote_path, $options)</strong>: Uploads backup file to cloud storage. Handles chunked uploads for large files, progress callbacks, and resumable sessions.</p>
<p><strong>download($remote_path, $local_file)</strong>: Downloads backup from cloud to local server for restoration. Must handle partial downloads and resume capability.</p>
<p><strong>delete($remote_path)</strong>: Removes backup file from cloud storage. Called during retention policy enforcement.</p>
<p><strong>list_files($remote_dir)</strong>: Returns array of files in remote directory with metadata (size, modified date, path). Used for backup inventory.</p>
<p><strong>get_storage_info()</strong>: Returns current storage quota usage and available space. Displayed in plugin dashboard.</p>
<h2 id="building-an-s3-compatible-provider">Building an S3-Compatible Provider</h2>
<p>S3-compatible storage (Wasabi, Backblaze B2, DigitalOcean Spaces) shares common API. Here’s complete implementation:</p>
<div class="sourceCode" id="cb2">
<pre class="sourceCode php"><code class="sourceCode php"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true"></a><span class="kw">class</span> BKPC_Cloud_Provider_S3_Compatible <span class="kw">extends</span> BKPC_Cloud_Provider {</span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true"></a></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true"></a>    <span class="kw">private</span> <span class="kw">$endpoint</span><span class="ot">;</span></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true"></a>    <span class="kw">private</span> <span class="kw">$bucket</span><span class="ot">;</span></span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true"></a>    <span class="kw">private</span> <span class="kw">$access_key</span><span class="ot">;</span></span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true"></a>    <span class="kw">private</span> <span class="kw">$secret_key</span><span class="ot">;</span></span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true"></a>    <span class="kw">private</span> <span class="kw">$client</span><span class="ot">;</span></span>
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true"></a></span>
<span id="cb2-9"><a href="#cb2-9" aria-hidden="true"></a>    <span class="kw">public</span> <span class="kw">function</span> <span class="fu">__construct</span><span class="ot">()</span> {</span>
<span id="cb2-10"><a href="#cb2-10" aria-hidden="true"></a>        <span class="kw">$this</span>-&gt;endpoint = get_option<span class="ot">(</span><span class="st">&#39;bkpc_s3_endpoint&#39;</span><span class="ot">);</span></span>
<span id="cb2-11"><a href="#cb2-11" aria-hidden="true"></a>        <span class="kw">$this</span>-&gt;bucket = get_option<span class="ot">(</span><span class="st">&#39;bkpc_s3_bucket&#39;</span><span class="ot">);</span></span>
<span id="cb2-12"><a href="#cb2-12" aria-hidden="true"></a>        <span class="kw">$this</span>-&gt;access_key = get_option<span class="ot">(</span><span class="st">&#39;bkpc_s3_access_key&#39;</span><span class="ot">);</span></span>
<span id="cb2-13"><a href="#cb2-13" aria-hidden="true"></a>        <span class="kw">$this</span>-&gt;secret_key = <span class="kw">$this</span>-&gt;decrypt<span class="ot">(</span>get_option<span class="ot">(</span><span class="st">&#39;bkpc_s3_secret_key&#39;</span><span class="ot">));</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>
<span id="cb2-16"><a href="#cb2-16" aria-hidden="true"></a>    <span class="kw">public</span> <span class="kw">function</span> authenticate<span class="ot">(</span><span class="kw">$credentials</span><span class="ot">)</span> {</span>
<span id="cb2-17"><a href="#cb2-17" aria-hidden="true"></a>        <span class="kw">require_once</span> <span class="st">&#39;aws-sdk/aws-autoloader.php&#39;</span><span class="ot">;</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="kw">try</span> {</span>
<span id="cb2-20"><a href="#cb2-20" aria-hidden="true"></a>            <span class="kw">$this</span>-&gt;client = <span class="kw">new</span> Aws\<span class="kw">S3</span>\S3Client<span class="ot">([</span></span>
<span id="cb2-21"><a href="#cb2-21" aria-hidden="true"></a>                <span class="st">&#39;version&#39;</span> =&gt; <span class="st">&#39;latest&#39;</span><span class="ot">,</span></span>
<span id="cb2-22"><a href="#cb2-22" aria-hidden="true"></a>                <span class="st">&#39;region&#39;</span> =&gt; <span class="st">&#39;us-east-1&#39;</span><span class="ot">,</span></span>
<span id="cb2-23"><a href="#cb2-23" aria-hidden="true"></a>                <span class="st">&#39;endpoint&#39;</span> =&gt; <span class="kw">$credentials</span><span class="ot">[</span><span class="st">&#39;endpoint&#39;</span><span class="ot">],</span></span>
<span id="cb2-24"><a href="#cb2-24" aria-hidden="true"></a>                <span class="st">&#39;credentials&#39;</span> =&gt; <span class="ot">[</span></span>
<span id="cb2-25"><a href="#cb2-25" aria-hidden="true"></a>                    <span class="st">&#39;key&#39;</span> =&gt; <span class="kw">$credentials</span><span class="ot">[</span><span class="st">&#39;access_key&#39;</span><span class="ot">],</span></span>
<span id="cb2-26"><a href="#cb2-26" aria-hidden="true"></a>                    <span class="st">&#39;secret&#39;</span> =&gt; <span class="kw">$credentials</span><span class="ot">[</span><span class="st">&#39;secret_key&#39;</span><span class="ot">]</span></span>
<span id="cb2-27"><a href="#cb2-27" aria-hidden="true"></a>                <span class="ot">],</span></span>
<span id="cb2-28"><a href="#cb2-28" aria-hidden="true"></a>                <span class="st">&#39;use_path_style_endpoint&#39;</span> =&gt; <span class="kw">true</span></span>
<span id="cb2-29"><a href="#cb2-29" aria-hidden="true"></a>            <span class="ot">]);</span></span>
<span id="cb2-30"><a href="#cb2-30" aria-hidden="true"></a></span>
<span id="cb2-31"><a href="#cb2-31" aria-hidden="true"></a>            <span class="co">// Test connection by listing buckets</span></span>
<span id="cb2-32"><a href="#cb2-32" aria-hidden="true"></a>            <span class="kw">$this</span>-&gt;client-&gt;headBucket<span class="ot">([</span><span class="st">&#39;Bucket&#39;</span> =&gt; <span class="kw">$credentials</span><span class="ot">[</span><span class="st">&#39;bucket&#39;</span><span class="ot">]]);</span></span>
<span id="cb2-33"><a href="#cb2-33" aria-hidden="true"></a></span>
<span id="cb2-34"><a href="#cb2-34" aria-hidden="true"></a>            <span class="kw">return</span> <span class="kw">true</span><span class="ot">;</span></span>
<span id="cb2-35"><a href="#cb2-35" aria-hidden="true"></a>        } <span class="kw">catch</span> <span class="ot">(</span><span class="kw">Exception</span> <span class="kw">$e</span><span class="ot">)</span> {</span>
<span id="cb2-36"><a href="#cb2-36" aria-hidden="true"></a>            <span class="kw">throw</span> <span class="kw">new</span> <span class="kw">Exception</span><span class="ot">(</span><span class="st">&#39;S3 Authentication failed: &#39;</span> . <span class="kw">$e</span>-&gt;getMessage<span class="ot">());</span></span>
<span id="cb2-37"><a href="#cb2-37" aria-hidden="true"></a>        }</span>
<span id="cb2-38"><a href="#cb2-38" aria-hidden="true"></a>    }</span>
<span id="cb2-39"><a href="#cb2-39" aria-hidden="true"></a></span>
<span id="cb2-40"><a href="#cb2-40" aria-hidden="true"></a>    <span class="kw">public</span> <span class="kw">function</span> upload<span class="ot">(</span><span class="kw">$local_file</span><span class="ot">,</span> <span class="kw">$remote_path</span><span class="ot">,</span> <span class="kw">$options</span> = <span class="ot">[])</span> {</span>
<span id="cb2-41"><a href="#cb2-41" aria-hidden="true"></a>        <span class="kw">$file_size</span> = <span class="fu">filesize</span><span class="ot">(</span><span class="kw">$local_file</span><span class="ot">);</span></span>
<span id="cb2-42"><a href="#cb2-42" aria-hidden="true"></a></span>
<span id="cb2-43"><a href="#cb2-43" aria-hidden="true"></a>        <span class="co">// Use multipart upload for files &gt; 100MB</span></span>
<span id="cb2-44"><a href="#cb2-44" aria-hidden="true"></a>        <span class="kw">if</span> <span class="ot">(</span><span class="kw">$file_size</span> &gt; <span class="dv">100</span> * <span class="dv">1024</span> * <span class="dv">1024</span><span class="ot">)</span> {</span>
<span id="cb2-45"><a href="#cb2-45" aria-hidden="true"></a>            <span class="kw">return</span> <span class="kw">$this</span>-&gt;multipart_upload<span class="ot">(</span><span class="kw">$local_file</span><span class="ot">,</span> <span class="kw">$remote_path</span><span class="ot">,</span> <span class="kw">$options</span><span class="ot">);</span></span>
<span id="cb2-46"><a href="#cb2-46" aria-hidden="true"></a>        }</span>
<span id="cb2-47"><a href="#cb2-47" aria-hidden="true"></a></span>
<span id="cb2-48"><a href="#cb2-48" aria-hidden="true"></a>        <span class="kw">try</span> {</span>
<span id="cb2-49"><a href="#cb2-49" aria-hidden="true"></a>            <span class="kw">$result</span> = <span class="kw">$this</span>-&gt;client-&gt;putObject<span class="ot">([</span></span>
<span id="cb2-50"><a href="#cb2-50" aria-hidden="true"></a>                <span class="st">&#39;Bucket&#39;</span> =&gt; <span class="kw">$this</span>-&gt;bucket<span class="ot">,</span></span>
<span id="cb2-51"><a href="#cb2-51" aria-hidden="true"></a>                <span class="st">&#39;Key&#39;</span> =&gt; <span class="kw">$remote_path</span><span class="ot">,</span></span>
<span id="cb2-52"><a href="#cb2-52" aria-hidden="true"></a>                <span class="st">&#39;SourceFile&#39;</span> =&gt; <span class="kw">$local_file</span><span class="ot">,</span></span>
<span id="cb2-53"><a href="#cb2-53" aria-hidden="true"></a>                <span class="st">&#39;ServerSideEncryption&#39;</span> =&gt; <span class="st">&#39;AES256&#39;</span></span>
<span id="cb2-54"><a href="#cb2-54" aria-hidden="true"></a>            <span class="ot">]);</span></span>
<span id="cb2-55"><a href="#cb2-55" aria-hidden="true"></a></span>
<span id="cb2-56"><a href="#cb2-56" aria-hidden="true"></a>            <span class="kw">if</span> <span class="ot">(</span><span class="kw">isset</span><span class="ot">(</span><span class="kw">$options</span><span class="ot">[</span><span class="st">&#39;progress_callback&#39;</span><span class="ot">]))</span> {</span>
<span id="cb2-57"><a href="#cb2-57" aria-hidden="true"></a>                <span class="fu">call_user_func</span><span class="ot">(</span><span class="kw">$options</span><span class="ot">[</span><span class="st">&#39;progress_callback&#39;</span><span class="ot">],</span> <span class="kw">$file_size</span><span class="ot">,</span> <span class="kw">$file_size</span><span class="ot">);</span></span>
<span id="cb2-58"><a href="#cb2-58" aria-hidden="true"></a>            }</span>
<span id="cb2-59"><a href="#cb2-59" aria-hidden="true"></a></span>
<span id="cb2-60"><a href="#cb2-60" aria-hidden="true"></a>            <span class="kw">return</span> <span class="kw">$result</span><span class="ot">[</span><span class="st">&#39;ObjectURL&#39;</span><span class="ot">];</span></span>
<span id="cb2-61"><a href="#cb2-61" aria-hidden="true"></a>        } <span class="kw">catch</span> <span class="ot">(</span><span class="kw">Exception</span> <span class="kw">$e</span><span class="ot">)</span> {</span>
<span id="cb2-62"><a href="#cb2-62" aria-hidden="true"></a>            <span class="kw">throw</span> <span class="kw">new</span> <span class="kw">Exception</span><span class="ot">(</span><span class="st">&#39;Upload failed: &#39;</span> . <span class="kw">$e</span>-&gt;getMessage<span class="ot">());</span></span>
<span id="cb2-63"><a href="#cb2-63" aria-hidden="true"></a>        }</span>
<span id="cb2-64"><a href="#cb2-64" aria-hidden="true"></a>    }</span>
<span id="cb2-65"><a href="#cb2-65" aria-hidden="true"></a></span>
<span id="cb2-66"><a href="#cb2-66" aria-hidden="true"></a>    <span class="kw">private</span> <span class="kw">function</span> multipart_upload<span class="ot">(</span><span class="kw">$local_file</span><span class="ot">,</span> <span class="kw">$remote_path</span><span class="ot">,</span> <span class="kw">$options</span><span class="ot">)</span> {</span>
<span id="cb2-67"><a href="#cb2-67" aria-hidden="true"></a>        <span class="kw">$uploader</span> = <span class="kw">new</span> Aws\<span class="kw">S3</span>\MultipartUploader<span class="ot">(</span><span class="kw">$this</span>-&gt;client<span class="ot">,</span> <span class="kw">$local_file</span><span class="ot">,</span> <span class="ot">[</span></span>
<span id="cb2-68"><a href="#cb2-68" aria-hidden="true"></a>            <span class="st">&#39;bucket&#39;</span> =&gt; <span class="kw">$this</span>-&gt;bucket<span class="ot">,</span></span>
<span id="cb2-69"><a href="#cb2-69" aria-hidden="true"></a>            <span class="st">&#39;key&#39;</span> =&gt; <span class="kw">$remote_path</span><span class="ot">,</span></span>
<span id="cb2-70"><a href="#cb2-70" aria-hidden="true"></a>            <span class="st">&#39;before_initiate&#39;</span> =&gt; <span class="kw">function</span> <span class="ot">()</span> <span class="kw">use</span> <span class="ot">(</span><span class="kw">$options</span><span class="ot">)</span> {</span>
<span id="cb2-71"><a href="#cb2-71" aria-hidden="true"></a>                <span class="co">// Store upload ID for resume capability</span></span>
<span id="cb2-72"><a href="#cb2-72" aria-hidden="true"></a>            }<span class="ot">,</span></span>
<span id="cb2-73"><a href="#cb2-73" aria-hidden="true"></a>            <span class="st">&#39;before_upload&#39;</span> =&gt; <span class="kw">function</span> <span class="ot">(</span><span class="kw">$command</span><span class="ot">)</span> <span class="kw">use</span> <span class="ot">(</span><span class="kw">$options</span><span class="ot">)</span> {</span>
<span id="cb2-74"><a href="#cb2-74" aria-hidden="true"></a>                <span class="kw">if</span> <span class="ot">(</span><span class="kw">isset</span><span class="ot">(</span><span class="kw">$options</span><span class="ot">[</span><span class="st">&#39;progress_callback&#39;</span><span class="ot">]))</span> {</span>
<span id="cb2-75"><a href="#cb2-75" aria-hidden="true"></a>                    <span class="co">// Update progress</span></span>
<span id="cb2-76"><a href="#cb2-76" aria-hidden="true"></a>                }</span>
<span id="cb2-77"><a href="#cb2-77" aria-hidden="true"></a>            }</span>
<span id="cb2-78"><a href="#cb2-78" aria-hidden="true"></a>        <span class="ot">]);</span></span>
<span id="cb2-79"><a href="#cb2-79" aria-hidden="true"></a></span>
<span id="cb2-80"><a href="#cb2-80" aria-hidden="true"></a>        <span class="kw">try</span> {</span>
<span id="cb2-81"><a href="#cb2-81" aria-hidden="true"></a>            <span class="kw">$result</span> = <span class="kw">$uploader</span>-&gt;upload<span class="ot">();</span></span>
<span id="cb2-82"><a href="#cb2-82" aria-hidden="true"></a>            <span class="kw">return</span> <span class="kw">$result</span><span class="ot">[</span><span class="st">&#39;ObjectURL&#39;</span><span class="ot">];</span></span>
<span id="cb2-83"><a href="#cb2-83" aria-hidden="true"></a>        } <span class="kw">catch</span> <span class="ot">(</span>Aws\<span class="kw">S3</span>\<span class="kw">Exception</span>\S3MultipartUploadException <span class="kw">$e</span><span class="ot">)</span> {</span>
<span id="cb2-84"><a href="#cb2-84" aria-hidden="true"></a>            <span class="co">// Resume failed upload</span></span>
<span id="cb2-85"><a href="#cb2-85" aria-hidden="true"></a>            <span class="kw">$uploader</span> = <span class="kw">new</span> Aws\<span class="kw">S3</span>\MultipartUploader<span class="ot">(</span><span class="kw">$this</span>-&gt;client<span class="ot">,</span> <span class="kw">$local_file</span><span class="ot">,</span> <span class="ot">[</span></span>
<span id="cb2-86"><a href="#cb2-86" aria-hidden="true"></a>                <span class="st">&#39;bucket&#39;</span> =&gt; <span class="kw">$this</span>-&gt;bucket<span class="ot">,</span></span>
<span id="cb2-87"><a href="#cb2-87" aria-hidden="true"></a>                <span class="st">&#39;key&#39;</span> =&gt; <span class="kw">$remote_path</span><span class="ot">,</span></span>
<span id="cb2-88"><a href="#cb2-88" aria-hidden="true"></a>                <span class="st">&#39;state&#39;</span> =&gt; <span class="kw">$e</span>-&gt;getState<span class="ot">()</span></span>
<span id="cb2-89"><a href="#cb2-89" aria-hidden="true"></a>            <span class="ot">]);</span></span>
<span id="cb2-90"><a href="#cb2-90" aria-hidden="true"></a>            <span class="kw">$result</span> = <span class="kw">$uploader</span>-&gt;upload<span class="ot">();</span></span>
<span id="cb2-91"><a href="#cb2-91" aria-hidden="true"></a>            <span class="kw">return</span> <span class="kw">$result</span><span class="ot">[</span><span class="st">&#39;ObjectURL&#39;</span><span class="ot">];</span></span>
<span id="cb2-92"><a href="#cb2-92" aria-hidden="true"></a>        }</span>
<span id="cb2-93"><a href="#cb2-93" aria-hidden="true"></a>    }</span>
<span id="cb2-94"><a href="#cb2-94" aria-hidden="true"></a></span>
<span id="cb2-95"><a href="#cb2-95" aria-hidden="true"></a>    <span class="kw">public</span> <span class="kw">function</span> download<span class="ot">(</span><span class="kw">$remote_path</span><span class="ot">,</span> <span class="kw">$local_file</span><span class="ot">)</span> {</span>
<span id="cb2-96"><a href="#cb2-96" aria-hidden="true"></a>        <span class="kw">try</span> {</span>
<span id="cb2-97"><a href="#cb2-97" aria-hidden="true"></a>            <span class="kw">$this</span>-&gt;client-&gt;getObject<span class="ot">([</span></span>
<span id="cb2-98"><a href="#cb2-98" aria-hidden="true"></a>                <span class="st">&#39;Bucket&#39;</span> =&gt; <span class="kw">$this</span>-&gt;bucket<span class="ot">,</span></span>
<span id="cb2-99"><a href="#cb2-99" aria-hidden="true"></a>                <span class="st">&#39;Key&#39;</span> =&gt; <span class="kw">$remote_path</span><span class="ot">,</span></span>
<span id="cb2-100"><a href="#cb2-100" aria-hidden="true"></a>                <span class="st">&#39;SaveAs&#39;</span> =&gt; <span class="kw">$local_file</span></span>
<span id="cb2-101"><a href="#cb2-101" aria-hidden="true"></a>            <span class="ot">]);</span></span>
<span id="cb2-102"><a href="#cb2-102" aria-hidden="true"></a>            <span class="kw">return</span> <span class="kw">true</span><span class="ot">;</span></span>
<span id="cb2-103"><a href="#cb2-103" aria-hidden="true"></a>        } <span class="kw">catch</span> <span class="ot">(</span><span class="kw">Exception</span> <span class="kw">$e</span><span class="ot">)</span> {</span>
<span id="cb2-104"><a href="#cb2-104" aria-hidden="true"></a>            <span class="kw">throw</span> <span class="kw">new</span> <span class="kw">Exception</span><span class="ot">(</span><span class="st">&#39;Download failed: &#39;</span> . <span class="kw">$e</span>-&gt;getMessage<span class="ot">());</span></span>
<span id="cb2-105"><a href="#cb2-105" aria-hidden="true"></a>        }</span>
<span id="cb2-106"><a href="#cb2-106" aria-hidden="true"></a>    }</span>
<span id="cb2-107"><a href="#cb2-107" aria-hidden="true"></a></span>
<span id="cb2-108"><a href="#cb2-108" aria-hidden="true"></a>    <span class="kw">public</span> <span class="kw">function</span> delete<span class="ot">(</span><span class="kw">$remote_path</span><span class="ot">)</span> {</span>
<span id="cb2-109"><a href="#cb2-109" aria-hidden="true"></a>        <span class="kw">try</span> {</span>
<span id="cb2-110"><a href="#cb2-110" aria-hidden="true"></a>            <span class="kw">$this</span>-&gt;client-&gt;deleteObject<span class="ot">([</span></span>
<span id="cb2-111"><a href="#cb2-111" aria-hidden="true"></a>                <span class="st">&#39;Bucket&#39;</span> =&gt; <span class="kw">$this</span>-&gt;bucket<span class="ot">,</span></span>
<span id="cb2-112"><a href="#cb2-112" aria-hidden="true"></a>                <span class="st">&#39;Key&#39;</span> =&gt; <span class="kw">$remote_path</span></span>
<span id="cb2-113"><a href="#cb2-113" aria-hidden="true"></a>            <span class="ot">]);</span></span>
<span id="cb2-114"><a href="#cb2-114" aria-hidden="true"></a>            <span class="kw">return</span> <span class="kw">true</span><span class="ot">;</span></span>
<span id="cb2-115"><a href="#cb2-115" aria-hidden="true"></a>        } <span class="kw">catch</span> <span class="ot">(</span><span class="kw">Exception</span> <span class="kw">$e</span><span class="ot">)</span> {</span>
<span id="cb2-116"><a href="#cb2-116" aria-hidden="true"></a>            <span class="kw">throw</span> <span class="kw">new</span> <span class="kw">Exception</span><span class="ot">(</span><span class="st">&#39;Delete failed: &#39;</span> . <span class="kw">$e</span>-&gt;getMessage<span class="ot">());</span></span>
<span id="cb2-117"><a href="#cb2-117" aria-hidden="true"></a>        }</span>
<span id="cb2-118"><a href="#cb2-118" aria-hidden="true"></a>    }</span>
<span id="cb2-119"><a href="#cb2-119" aria-hidden="true"></a></span>
<span id="cb2-120"><a href="#cb2-120" aria-hidden="true"></a>    <span class="kw">public</span> <span class="kw">function</span> list_files<span class="ot">(</span><span class="kw">$remote_dir</span><span class="ot">)</span> {</span>
<span id="cb2-121"><a href="#cb2-121" aria-hidden="true"></a>        <span class="kw">try</span> {</span>
<span id="cb2-122"><a href="#cb2-122" aria-hidden="true"></a>            <span class="kw">$results</span> = <span class="kw">$this</span>-&gt;client-&gt;listObjects<span class="ot">([</span></span>
<span id="cb2-123"><a href="#cb2-123" aria-hidden="true"></a>                <span class="st">&#39;Bucket&#39;</span> =&gt; <span class="kw">$this</span>-&gt;bucket<span class="ot">,</span></span>
<span id="cb2-124"><a href="#cb2-124" aria-hidden="true"></a>                <span class="st">&#39;Prefix&#39;</span> =&gt; <span class="kw">$remote_dir</span></span>
<span id="cb2-125"><a href="#cb2-125" aria-hidden="true"></a>            <span class="ot">]);</span></span>
<span id="cb2-126"><a href="#cb2-126" aria-hidden="true"></a></span>
<span id="cb2-127"><a href="#cb2-127" aria-hidden="true"></a>            <span class="kw">$files</span> = <span class="ot">[];</span></span>
<span id="cb2-128"><a href="#cb2-128" aria-hidden="true"></a>            <span class="kw">foreach</span> <span class="ot">(</span><span class="kw">$results</span><span class="ot">[</span><span class="st">&#39;Contents&#39;</span><span class="ot">]</span> <span class="kw">as</span> <span class="kw">$object</span><span class="ot">)</span> {</span>
<span id="cb2-129"><a href="#cb2-129" aria-hidden="true"></a>                <span class="kw">$files</span><span class="ot">[]</span> = <span class="ot">[</span></span>
<span id="cb2-130"><a href="#cb2-130" aria-hidden="true"></a>                    <span class="st">&#39;path&#39;</span> =&gt; <span class="kw">$object</span><span class="ot">[</span><span class="st">&#39;Key&#39;</span><span class="ot">],</span></span>
<span id="cb2-131"><a href="#cb2-131" aria-hidden="true"></a>                    <span class="st">&#39;size&#39;</span> =&gt; <span class="kw">$object</span><span class="ot">[</span><span class="st">&#39;Size&#39;</span><span class="ot">],</span></span>
<span id="cb2-132"><a href="#cb2-132" aria-hidden="true"></a>                    <span class="st">&#39;modified&#39;</span> =&gt; <span class="kw">$object</span><span class="ot">[</span><span class="st">&#39;LastModified&#39;</span><span class="ot">]</span></span>
<span id="cb2-133"><a href="#cb2-133" aria-hidden="true"></a>                <span class="ot">];</span></span>
<span id="cb2-134"><a href="#cb2-134" aria-hidden="true"></a>            }</span>
<span id="cb2-135"><a href="#cb2-135" aria-hidden="true"></a>            <span class="kw">return</span> <span class="kw">$files</span><span class="ot">;</span></span>
<span id="cb2-136"><a href="#cb2-136" aria-hidden="true"></a>        } <span class="kw">catch</span> <span class="ot">(</span><span class="kw">Exception</span> <span class="kw">$e</span><span class="ot">)</span> {</span>
<span id="cb2-137"><a href="#cb2-137" aria-hidden="true"></a>            <span class="kw">throw</span> <span class="kw">new</span> <span class="kw">Exception</span><span class="ot">(</span><span class="st">&#39;List files failed: &#39;</span> . <span class="kw">$e</span>-&gt;getMessage<span class="ot">());</span></span>
<span id="cb2-138"><a href="#cb2-138" aria-hidden="true"></a>        }</span>
<span id="cb2-139"><a href="#cb2-139" aria-hidden="true"></a>    }</span>
<span id="cb2-140"><a href="#cb2-140" aria-hidden="true"></a></span>
<span id="cb2-141"><a href="#cb2-141" aria-hidden="true"></a>    <span class="kw">public</span> <span class="kw">function</span> get_storage_info<span class="ot">()</span> {</span>
<span id="cb2-142"><a href="#cb2-142" aria-hidden="true"></a>        <span class="co">// S3 doesn&#39;t provide quota info via API</span></span>
<span id="cb2-143"><a href="#cb2-143" aria-hidden="true"></a>        <span class="kw">return</span> <span class="ot">[</span></span>
<span id="cb2-144"><a href="#cb2-144" aria-hidden="true"></a>            <span class="st">&#39;used&#39;</span> =&gt; <span class="dv">0</span><span class="ot">,</span></span>
<span id="cb2-145"><a href="#cb2-145" aria-hidden="true"></a>            <span class="st">&#39;total&#39;</span> =&gt; <span class="dv">-1</span><span class="ot">,</span> <span class="co">// Unlimited</span></span>
<span id="cb2-146"><a href="#cb2-146" aria-hidden="true"></a>            <span class="st">&#39;available&#39;</span> =&gt; <span class="dv">-1</span></span>
<span id="cb2-147"><a href="#cb2-147" aria-hidden="true"></a>        <span class="ot">];</span></span>
<span id="cb2-148"><a href="#cb2-148" aria-hidden="true"></a>    }</span>
<span id="cb2-149"><a href="#cb2-149" aria-hidden="true"></a>}</span></code></pre>
</div>
<h2 id="implementing-ftpsftp-provider">Implementing FTP/SFTP Provider</h2>
<p>For legacy systems or custom infrastructure, FTP/SFTP support may be needed:</p>
<div class="sourceCode" id="cb3">
<pre class="sourceCode php"><code class="sourceCode php"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true"></a><span class="kw">class</span> BKPC_Cloud_Provider_SFTP <span class="kw">extends</span> BKPC_Cloud_Provider {</span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true"></a></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true"></a>    <span class="kw">private</span> <span class="kw">$connection</span><span class="ot">;</span></span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true"></a>    <span class="kw">private</span> <span class="kw">$sftp</span><span class="ot">;</span></span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true"></a></span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true"></a>    <span class="kw">public</span> <span class="kw">function</span> authenticate<span class="ot">(</span><span class="kw">$credentials</span><span class="ot">)</span> {</span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true"></a>        <span class="kw">if</span> <span class="ot">(</span>!<span class="fu">function_exists</span><span class="ot">(</span><span class="st">&#39;ssh2_connect&#39;</span><span class="ot">))</span> {</span>
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true"></a>            <span class="kw">throw</span> <span class="kw">new</span> <span class="kw">Exception</span><span class="ot">(</span><span class="st">&#39;PHP SSH2 extension required&#39;</span><span class="ot">);</span></span>
<span id="cb3-9"><a href="#cb3-9" aria-hidden="true"></a>        }</span>
<span id="cb3-10"><a href="#cb3-10" aria-hidden="true"></a></span>
<span id="cb3-11"><a href="#cb3-11" aria-hidden="true"></a>        <span class="kw">$this</span>-&gt;connection = <span class="fu">ssh2_connect</span><span class="ot">(</span></span>
<span id="cb3-12"><a href="#cb3-12" aria-hidden="true"></a>            <span class="kw">$credentials</span><span class="ot">[</span><span class="st">&#39;host&#39;</span><span class="ot">],</span></span>
<span id="cb3-13"><a href="#cb3-13" aria-hidden="true"></a>            <span class="kw">$credentials</span><span class="ot">[</span><span class="st">&#39;port&#39;</span><span class="ot">]</span> <span class="ot">??</span> <span class="dv">22</span></span>
<span id="cb3-14"><a href="#cb3-14" aria-hidden="true"></a>        <span class="ot">);</span></span>
<span id="cb3-15"><a href="#cb3-15" aria-hidden="true"></a></span>
<span id="cb3-16"><a href="#cb3-16" aria-hidden="true"></a>        <span class="kw">if</span> <span class="ot">(</span>!<span class="kw">$this</span>-&gt;connection<span class="ot">)</span> {</span>
<span id="cb3-17"><a href="#cb3-17" aria-hidden="true"></a>            <span class="kw">throw</span> <span class="kw">new</span> <span class="kw">Exception</span><span class="ot">(</span><span class="st">&#39;Cannot connect to SFTP server&#39;</span><span class="ot">);</span></span>
<span id="cb3-18"><a href="#cb3-18" aria-hidden="true"></a>        }</span>
<span id="cb3-19"><a href="#cb3-19" aria-hidden="true"></a></span>
<span id="cb3-20"><a href="#cb3-20" aria-hidden="true"></a>        <span class="kw">if</span> <span class="ot">(</span><span class="kw">$credentials</span><span class="ot">[</span><span class="st">&#39;auth_type&#39;</span><span class="ot">]</span> === <span class="st">&#39;password&#39;</span><span class="ot">)</span> {</span>
<span id="cb3-21"><a href="#cb3-21" aria-hidden="true"></a>            <span class="kw">$auth</span> = <span class="fu">ssh2_auth_password</span><span class="ot">(</span></span>
<span id="cb3-22"><a href="#cb3-22" aria-hidden="true"></a>                <span class="kw">$this</span>-&gt;connection<span class="ot">,</span></span>
<span id="cb3-23"><a href="#cb3-23" aria-hidden="true"></a>                <span class="kw">$credentials</span><span class="ot">[</span><span class="st">&#39;username&#39;</span><span class="ot">],</span></span>
<span id="cb3-24"><a href="#cb3-24" aria-hidden="true"></a>                <span class="kw">$credentials</span><span class="ot">[</span><span class="st">&#39;password&#39;</span><span class="ot">]</span></span>
<span id="cb3-25"><a href="#cb3-25" aria-hidden="true"></a>            <span class="ot">);</span></span>
<span id="cb3-26"><a href="#cb3-26" aria-hidden="true"></a>        } <span class="kw">else</span> {</span>
<span id="cb3-27"><a href="#cb3-27" aria-hidden="true"></a>            <span class="kw">$auth</span> = <span class="fu">ssh2_auth_pubkey_file</span><span class="ot">(</span></span>
<span id="cb3-28"><a href="#cb3-28" aria-hidden="true"></a>                <span class="kw">$this</span>-&gt;connection<span class="ot">,</span></span>
<span id="cb3-29"><a href="#cb3-29" aria-hidden="true"></a>                <span class="kw">$credentials</span><span class="ot">[</span><span class="st">&#39;username&#39;</span><span class="ot">],</span></span>
<span id="cb3-30"><a href="#cb3-30" aria-hidden="true"></a>                <span class="kw">$credentials</span><span class="ot">[</span><span class="st">&#39;public_key&#39;</span><span class="ot">],</span></span>
<span id="cb3-31"><a href="#cb3-31" aria-hidden="true"></a>                <span class="kw">$credentials</span><span class="ot">[</span><span class="st">&#39;private_key&#39;</span><span class="ot">],</span></span>
<span id="cb3-32"><a href="#cb3-32" aria-hidden="true"></a>                <span class="kw">$credentials</span><span class="ot">[</span><span class="st">&#39;passphrase&#39;</span><span class="ot">]</span></span>
<span id="cb3-33"><a href="#cb3-33" aria-hidden="true"></a>            <span class="ot">);</span></span>
<span id="cb3-34"><a href="#cb3-34" aria-hidden="true"></a>        }</span>
<span id="cb3-35"><a href="#cb3-35" aria-hidden="true"></a></span>
<span id="cb3-36"><a href="#cb3-36" aria-hidden="true"></a>        <span class="kw">if</span> <span class="ot">(</span>!<span class="kw">$auth</span><span class="ot">)</span> {</span>
<span id="cb3-37"><a href="#cb3-37" aria-hidden="true"></a>            <span class="kw">throw</span> <span class="kw">new</span> <span class="kw">Exception</span><span class="ot">(</span><span class="st">&#39;SFTP authentication failed&#39;</span><span class="ot">);</span></span>
<span id="cb3-38"><a href="#cb3-38" aria-hidden="true"></a>        }</span>
<span id="cb3-39"><a href="#cb3-39" aria-hidden="true"></a></span>
<span id="cb3-40"><a href="#cb3-40" aria-hidden="true"></a>        <span class="kw">$this</span>-&gt;sftp = <span class="fu">ssh2_sftp</span><span class="ot">(</span><span class="kw">$this</span>-&gt;connection<span class="ot">);</span></span>
<span id="cb3-41"><a href="#cb3-41" aria-hidden="true"></a>        <span class="kw">return</span> <span class="kw">true</span><span class="ot">;</span></span>
<span id="cb3-42"><a href="#cb3-42" aria-hidden="true"></a>    }</span>
<span id="cb3-43"><a href="#cb3-43" aria-hidden="true"></a></span>
<span id="cb3-44"><a href="#cb3-44" aria-hidden="true"></a>    <span class="kw">public</span> <span class="kw">function</span> upload<span class="ot">(</span><span class="kw">$local_file</span><span class="ot">,</span> <span class="kw">$remote_path</span><span class="ot">,</span> <span class="kw">$options</span> = <span class="ot">[])</span> {</span>
<span id="cb3-45"><a href="#cb3-45" aria-hidden="true"></a>        <span class="kw">$remote_stream</span> = <span class="fu">fopen</span><span class="ot">(</span><span class="st">&quot;ssh2.sftp://</span><span class="kw">{$this-&gt;sftp}{$remote_path}</span><span class="st">&quot;</span><span class="ot">,</span> <span class="st">&#39;w&#39;</span><span class="ot">);</span></span>
<span id="cb3-46"><a href="#cb3-46" aria-hidden="true"></a>        <span class="kw">$local_stream</span> = <span class="fu">fopen</span><span class="ot">(</span><span class="kw">$local_file</span><span class="ot">,</span> <span class="st">&#39;r&#39;</span><span class="ot">);</span></span>
<span id="cb3-47"><a href="#cb3-47" aria-hidden="true"></a></span>
<span id="cb3-48"><a href="#cb3-48" aria-hidden="true"></a>        <span class="kw">$file_size</span> = <span class="fu">filesize</span><span class="ot">(</span><span class="kw">$local_file</span><span class="ot">);</span></span>
<span id="cb3-49"><a href="#cb3-49" aria-hidden="true"></a>        <span class="kw">$uploaded</span> = <span class="dv">0</span><span class="ot">;</span></span>
<span id="cb3-50"><a href="#cb3-50" aria-hidden="true"></a></span>
<span id="cb3-51"><a href="#cb3-51" aria-hidden="true"></a>        <span class="kw">while</span> <span class="ot">(</span>!<span class="fu">feof</span><span class="ot">(</span><span class="kw">$local_stream</span><span class="ot">))</span> {</span>
<span id="cb3-52"><a href="#cb3-52" aria-hidden="true"></a>            <span class="kw">$buffer</span> = <span class="fu">fread</span><span class="ot">(</span><span class="kw">$local_stream</span><span class="ot">,</span> <span class="dv">8192</span><span class="ot">);</span></span>
<span id="cb3-53"><a href="#cb3-53" aria-hidden="true"></a>            <span class="fu">fwrite</span><span class="ot">(</span><span class="kw">$remote_stream</span><span class="ot">,</span> <span class="kw">$buffer</span><span class="ot">);</span></span>
<span id="cb3-54"><a href="#cb3-54" aria-hidden="true"></a>            <span class="kw">$uploaded</span> += <span class="fu">strlen</span><span class="ot">(</span><span class="kw">$buffer</span><span class="ot">);</span></span>
<span id="cb3-55"><a href="#cb3-55" aria-hidden="true"></a></span>
<span id="cb3-56"><a href="#cb3-56" aria-hidden="true"></a>            <span class="kw">if</span> <span class="ot">(</span><span class="kw">isset</span><span class="ot">(</span><span class="kw">$options</span><span class="ot">[</span><span class="st">&#39;progress_callback&#39;</span><span class="ot">]))</span> {</span>
<span id="cb3-57"><a href="#cb3-57" aria-hidden="true"></a>                <span class="fu">call_user_func</span><span class="ot">(</span><span class="kw">$options</span><span class="ot">[</span><span class="st">&#39;progress_callback&#39;</span><span class="ot">],</span> <span class="kw">$uploaded</span><span class="ot">,</span> <span class="kw">$file_size</span><span class="ot">);</span></span>
<span id="cb3-58"><a href="#cb3-58" aria-hidden="true"></a>            }</span>
<span id="cb3-59"><a href="#cb3-59" aria-hidden="true"></a>        }</span>
<span id="cb3-60"><a href="#cb3-60" aria-hidden="true"></a></span>
<span id="cb3-61"><a href="#cb3-61" aria-hidden="true"></a>        <span class="fu">fclose</span><span class="ot">(</span><span class="kw">$local_stream</span><span class="ot">);</span></span>
<span id="cb3-62"><a href="#cb3-62" aria-hidden="true"></a>        <span class="fu">fclose</span><span class="ot">(</span><span class="kw">$remote_stream</span><span class="ot">);</span></span>
<span id="cb3-63"><a href="#cb3-63" aria-hidden="true"></a></span>
<span id="cb3-64"><a href="#cb3-64" aria-hidden="true"></a>        <span class="kw">return</span> <span class="st">&quot;sftp://</span><span class="kw">{$credentials[&#39;host&#39;]}{$remote_path}</span><span class="st">&quot;</span><span class="ot">;</span></span>
<span id="cb3-65"><a href="#cb3-65" aria-hidden="true"></a>    }</span>
<span id="cb3-66"><a href="#cb3-66" aria-hidden="true"></a></span>
<span id="cb3-67"><a href="#cb3-67" aria-hidden="true"></a>    <span class="kw">public</span> <span class="kw">function</span> download<span class="ot">(</span><span class="kw">$remote_path</span><span class="ot">,</span> <span class="kw">$local_file</span><span class="ot">)</span> {</span>
<span id="cb3-68"><a href="#cb3-68" aria-hidden="true"></a>        <span class="kw">return</span> <span class="fu">ssh2_scp_recv</span><span class="ot">(</span><span class="kw">$this</span>-&gt;connection<span class="ot">,</span> <span class="kw">$remote_path</span><span class="ot">,</span> <span class="kw">$local_file</span><span class="ot">);</span></span>
<span id="cb3-69"><a href="#cb3-69" aria-hidden="true"></a>    }</span>
<span id="cb3-70"><a href="#cb3-70" aria-hidden="true"></a></span>
<span id="cb3-71"><a href="#cb3-71" aria-hidden="true"></a>    <span class="kw">public</span> <span class="kw">function</span> delete<span class="ot">(</span><span class="kw">$remote_path</span><span class="ot">)</span> {</span>
<span id="cb3-72"><a href="#cb3-72" aria-hidden="true"></a>        <span class="kw">return</span> <span class="fu">ssh2_sftp_unlink</span><span class="ot">(</span><span class="kw">$this</span>-&gt;sftp<span class="ot">,</span> <span class="kw">$remote_path</span><span class="ot">);</span></span>
<span id="cb3-73"><a href="#cb3-73" aria-hidden="true"></a>    }</span>
<span id="cb3-74"><a href="#cb3-74" aria-hidden="true"></a></span>
<span id="cb3-75"><a href="#cb3-75" aria-hidden="true"></a>    <span class="kw">public</span> <span class="kw">function</span> list_files<span class="ot">(</span><span class="kw">$remote_dir</span><span class="ot">)</span> {</span>
<span id="cb3-76"><a href="#cb3-76" aria-hidden="true"></a>        <span class="kw">$handle</span> = <span class="fu">opendir</span><span class="ot">(</span><span class="st">&quot;ssh2.sftp://</span><span class="kw">{$this-&gt;sftp}{$remote_dir}</span><span class="st">&quot;</span><span class="ot">);</span></span>
<span id="cb3-77"><a href="#cb3-77" aria-hidden="true"></a>        <span class="kw">$files</span> = <span class="ot">[];</span></span>
<span id="cb3-78"><a href="#cb3-78" aria-hidden="true"></a></span>
<span id="cb3-79"><a href="#cb3-79" aria-hidden="true"></a>        <span class="kw">while</span> <span class="ot">(</span><span class="kw">false</span> !== <span class="ot">(</span><span class="kw">$file</span> = <span class="fu">readdir</span><span class="ot">(</span><span class="kw">$handle</span><span class="ot">)))</span> {</span>
<span id="cb3-80"><a href="#cb3-80" aria-hidden="true"></a>            <span class="kw">if</span> <span class="ot">(</span><span class="kw">$file</span> !== <span class="st">&#39;.&#39;</span> &amp;&amp; <span class="kw">$file</span> !== <span class="st">&#39;..&#39;</span><span class="ot">)</span> {</span>
<span id="cb3-81"><a href="#cb3-81" aria-hidden="true"></a>                <span class="kw">$path</span> = <span class="kw">$remote_dir</span> . <span class="st">&#39;/&#39;</span> . <span class="kw">$file</span><span class="ot">;</span></span>
<span id="cb3-82"><a href="#cb3-82" aria-hidden="true"></a>                <span class="kw">$stat</span> = <span class="fu">ssh2_sftp_stat</span><span class="ot">(</span><span class="kw">$this</span>-&gt;sftp<span class="ot">,</span> <span class="kw">$path</span><span class="ot">);</span></span>
<span id="cb3-83"><a href="#cb3-83" aria-hidden="true"></a>                <span class="kw">$files</span><span class="ot">[]</span> = <span class="ot">[</span></span>
<span id="cb3-84"><a href="#cb3-84" aria-hidden="true"></a>                    <span class="st">&#39;path&#39;</span> =&gt; <span class="kw">$path</span><span class="ot">,</span></span>
<span id="cb3-85"><a href="#cb3-85" aria-hidden="true"></a>                    <span class="st">&#39;size&#39;</span> =&gt; <span class="kw">$stat</span><span class="ot">[</span><span class="st">&#39;size&#39;</span><span class="ot">],</span></span>
<span id="cb3-86"><a href="#cb3-86" aria-hidden="true"></a>                    <span class="st">&#39;modified&#39;</span> =&gt; <span class="kw">$stat</span><span class="ot">[</span><span class="st">&#39;mtime&#39;</span><span class="ot">]</span></span>
<span id="cb3-87"><a href="#cb3-87" aria-hidden="true"></a>                <span class="ot">];</span></span>
<span id="cb3-88"><a href="#cb3-88" aria-hidden="true"></a>            }</span>
<span id="cb3-89"><a href="#cb3-89" aria-hidden="true"></a>        }</span>
<span id="cb3-90"><a href="#cb3-90" aria-hidden="true"></a></span>
<span id="cb3-91"><a href="#cb3-91" aria-hidden="true"></a>        <span class="fu">closedir</span><span class="ot">(</span><span class="kw">$handle</span><span class="ot">);</span></span>
<span id="cb3-92"><a href="#cb3-92" aria-hidden="true"></a>        <span class="kw">return</span> <span class="kw">$files</span><span class="ot">;</span></span>
<span id="cb3-93"><a href="#cb3-93" aria-hidden="true"></a>    }</span>
<span id="cb3-94"><a href="#cb3-94" aria-hidden="true"></a></span>
<span id="cb3-95"><a href="#cb3-95" aria-hidden="true"></a>    <span class="kw">public</span> <span class="kw">function</span> get_storage_info<span class="ot">()</span> {</span>
<span id="cb3-96"><a href="#cb3-96" aria-hidden="true"></a>        <span class="co">// Execute df command via SSH</span></span>
<span id="cb3-97"><a href="#cb3-97" aria-hidden="true"></a>        <span class="kw">$stream</span> = <span class="fu">ssh2_exec</span><span class="ot">(</span><span class="kw">$this</span>-&gt;connection<span class="ot">,</span> <span class="st">&#39;df -k .&#39;</span><span class="ot">);</span></span>
<span id="cb3-98"><a href="#cb3-98" aria-hidden="true"></a>        <span class="fu">stream_set_blocking</span><span class="ot">(</span><span class="kw">$stream</span><span class="ot">,</span> <span class="kw">true</span><span class="ot">);</span></span>
<span id="cb3-99"><a href="#cb3-99" aria-hidden="true"></a>        <span class="kw">$output</span> = <span class="fu">stream_get_contents</span><span class="ot">(</span><span class="kw">$stream</span><span class="ot">);</span></span>
<span id="cb3-100"><a href="#cb3-100" aria-hidden="true"></a></span>
<span id="cb3-101"><a href="#cb3-101" aria-hidden="true"></a>        <span class="co">// Parse df output to get storage info</span></span>
<span id="cb3-102"><a href="#cb3-102" aria-hidden="true"></a>        <span class="co">// Implementation depends on server OS</span></span>
<span id="cb3-103"><a href="#cb3-103" aria-hidden="true"></a></span>
<span id="cb3-104"><a href="#cb3-104" aria-hidden="true"></a>        <span class="kw">return</span> <span class="ot">[</span><span class="st">&#39;used&#39;</span> =&gt; <span class="dv">0</span><span class="ot">,</span> <span class="st">&#39;total&#39;</span> =&gt; <span class="dv">0</span><span class="ot">,</span> <span class="st">&#39;available&#39;</span> =&gt; <span class="dv">0</span><span class="ot">];</span></span>
<span id="cb3-105"><a href="#cb3-105" aria-hidden="true"></a>    }</span>
<span id="cb3-106"><a href="#cb3-106" aria-hidden="true"></a>}</span></code></pre>
</div>
<h2 id="registering-custom-providers">Registering Custom Providers</h2>
<p>Make your provider available in Backup Copilot Pro:</p>
<div class="sourceCode" id="cb4">
<pre class="sourceCode php"><code class="sourceCode php"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true"></a>add_filter<span class="ot">(</span><span class="st">&#39;bkpc_cloud_providers&#39;</span><span class="ot">,</span> <span class="st">&#39;register_custom_providers&#39;</span><span class="ot">);</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true"></a></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true"></a><span class="kw">function</span> register_custom_providers<span class="ot">(</span><span class="kw">$providers</span><span class="ot">)</span> {</span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true"></a>    <span class="kw">$providers</span><span class="ot">[</span><span class="st">&#39;s3_compatible&#39;</span><span class="ot">]</span> = <span class="ot">[</span></span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true"></a>        <span class="st">&#39;name&#39;</span> =&gt; <span class="st">&#39;S3-Compatible Storage&#39;</span><span class="ot">,</span></span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true"></a>        <span class="st">&#39;class&#39;</span> =&gt; <span class="st">&#39;BKPC_Cloud_Provider_S3_Compatible&#39;</span><span class="ot">,</span></span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true"></a>        <span class="st">&#39;icon&#39;</span> =&gt; <span class="st">&#39;dashicons-cloud&#39;</span><span class="ot">,</span></span>
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true"></a>        <span class="st">&#39;settings_fields&#39;</span> =&gt; <span class="ot">[</span></span>
<span id="cb4-9"><a href="#cb4-9" aria-hidden="true"></a>            <span class="st">&#39;endpoint&#39;</span> =&gt; <span class="ot">[</span><span class="st">&#39;type&#39;</span> =&gt; <span class="st">&#39;text&#39;</span><span class="ot">,</span> <span class="st">&#39;label&#39;</span> =&gt; <span class="st">&#39;Endpoint URL&#39;</span><span class="ot">],</span></span>
<span id="cb4-10"><a href="#cb4-10" aria-hidden="true"></a>            <span class="st">&#39;bucket&#39;</span> =&gt; <span class="ot">[</span><span class="st">&#39;type&#39;</span> =&gt; <span class="st">&#39;text&#39;</span><span class="ot">,</span> <span class="st">&#39;label&#39;</span> =&gt; <span class="st">&#39;Bucket Name&#39;</span><span class="ot">],</span></span>
<span id="cb4-11"><a href="#cb4-11" aria-hidden="true"></a>            <span class="st">&#39;access_key&#39;</span> =&gt; <span class="ot">[</span><span class="st">&#39;type&#39;</span> =&gt; <span class="st">&#39;text&#39;</span><span class="ot">,</span> <span class="st">&#39;label&#39;</span> =&gt; <span class="st">&#39;Access Key&#39;</span><span class="ot">],</span></span>
<span id="cb4-12"><a href="#cb4-12" aria-hidden="true"></a>            <span class="st">&#39;secret_key&#39;</span> =&gt; <span class="ot">[</span><span class="st">&#39;type&#39;</span> =&gt; <span class="st">&#39;password&#39;</span><span class="ot">,</span> <span class="st">&#39;label&#39;</span> =&gt; <span class="st">&#39;Secret Key&#39;</span><span class="ot">]</span></span>
<span id="cb4-13"><a href="#cb4-13" aria-hidden="true"></a>        <span class="ot">]</span></span>
<span id="cb4-14"><a href="#cb4-14" aria-hidden="true"></a>    <span class="ot">];</span></span>
<span id="cb4-15"><a href="#cb4-15" aria-hidden="true"></a></span>
<span id="cb4-16"><a href="#cb4-16" aria-hidden="true"></a>    <span class="kw">$providers</span><span class="ot">[</span><span class="st">&#39;sftp&#39;</span><span class="ot">]</span> = <span class="ot">[</span></span>
<span id="cb4-17"><a href="#cb4-17" aria-hidden="true"></a>        <span class="st">&#39;name&#39;</span> =&gt; <span class="st">&#39;SFTP&#39;</span><span class="ot">,</span></span>
<span id="cb4-18"><a href="#cb4-18" aria-hidden="true"></a>        <span class="st">&#39;class&#39;</span> =&gt; <span class="st">&#39;BKPC_Cloud_Provider_SFTP&#39;</span><span class="ot">,</span></span>
<span id="cb4-19"><a href="#cb4-19" aria-hidden="true"></a>        <span class="st">&#39;icon&#39;</span> =&gt; <span class="st">&#39;dashicons-admin-site&#39;</span><span class="ot">,</span></span>
<span id="cb4-20"><a href="#cb4-20" aria-hidden="true"></a>        <span class="st">&#39;settings_fields&#39;</span> =&gt; <span class="ot">[</span></span>
<span id="cb4-21"><a href="#cb4-21" aria-hidden="true"></a>            <span class="st">&#39;host&#39;</span> =&gt; <span class="ot">[</span><span class="st">&#39;type&#39;</span> =&gt; <span class="st">&#39;text&#39;</span><span class="ot">,</span> <span class="st">&#39;label&#39;</span> =&gt; <span class="st">&#39;Host&#39;</span><span class="ot">],</span></span>
<span id="cb4-22"><a href="#cb4-22" aria-hidden="true"></a>            <span class="st">&#39;port&#39;</span> =&gt; <span class="ot">[</span><span class="st">&#39;type&#39;</span> =&gt; <span class="st">&#39;number&#39;</span><span class="ot">,</span> <span class="st">&#39;label&#39;</span> =&gt; <span class="st">&#39;Port&#39;</span><span class="ot">,</span> <span class="st">&#39;default&#39;</span> =&gt; <span class="dv">22</span><span class="ot">],</span></span>
<span id="cb4-23"><a href="#cb4-23" aria-hidden="true"></a>            <span class="st">&#39;username&#39;</span> =&gt; <span class="ot">[</span><span class="st">&#39;type&#39;</span> =&gt; <span class="st">&#39;text&#39;</span><span class="ot">,</span> <span class="st">&#39;label&#39;</span> =&gt; <span class="st">&#39;Username&#39;</span><span class="ot">],</span></span>
<span id="cb4-24"><a href="#cb4-24" aria-hidden="true"></a>            <span class="st">&#39;password&#39;</span> =&gt; <span class="ot">[</span><span class="st">&#39;type&#39;</span> =&gt; <span class="st">&#39;password&#39;</span><span class="ot">,</span> <span class="st">&#39;label&#39;</span> =&gt; <span class="st">&#39;Password&#39;</span><span class="ot">]</span></span>
<span id="cb4-25"><a href="#cb4-25" aria-hidden="true"></a>        <span class="ot">]</span></span>
<span id="cb4-26"><a href="#cb4-26" aria-hidden="true"></a>    <span class="ot">];</span></span>
<span id="cb4-27"><a href="#cb4-27" aria-hidden="true"></a></span>
<span id="cb4-28"><a href="#cb4-28" aria-hidden="true"></a>    <span class="kw">return</span> <span class="kw">$providers</span><span class="ot">;</span></span>
<span id="cb4-29"><a href="#cb4-29" aria-hidden="true"></a>}</span></code></pre>
</div>
<h2 id="implementing-oauth-2.0-authentication">Implementing OAuth 2.0 Authentication</h2>
<p>For providers requiring OAuth (Google Drive, Dropbox):</p>
<div class="sourceCode" id="cb5">
<pre class="sourceCode php"><code class="sourceCode php"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true"></a><span class="kw">public</span> <span class="kw">function</span> authenticate<span class="ot">(</span><span class="kw">$credentials</span><span class="ot">)</span> {</span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true"></a>    <span class="co">// Step 1: Redirect to OAuth consent screen</span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true"></a>    <span class="kw">if</span> <span class="ot">(</span>!<span class="kw">isset</span><span class="ot">(</span><span class="kw">$credentials</span><span class="ot">[</span><span class="st">&#39;code&#39;</span><span class="ot">]))</span> {</span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true"></a>        <span class="kw">$auth_url</span> = <span class="st">&#39;https://provider.com/oauth/authorize?&#39;</span> . <span class="fu">http_build_query</span><span class="ot">([</span></span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true"></a>            <span class="st">&#39;client_id&#39;</span> =&gt; <span class="kw">$credentials</span><span class="ot">[</span><span class="st">&#39;client_id&#39;</span><span class="ot">],</span></span>
<span id="cb5-6"><a href="#cb5-6" aria-hidden="true"></a>            <span class="st">&#39;redirect_uri&#39;</span> =&gt; admin_url<span class="ot">(</span><span class="st">&#39;admin.php?page=bkpc-oauth-callback&#39;</span><span class="ot">),</span></span>
<span id="cb5-7"><a href="#cb5-7" aria-hidden="true"></a>            <span class="st">&#39;response_type&#39;</span> =&gt; <span class="st">&#39;code&#39;</span><span class="ot">,</span></span>
<span id="cb5-8"><a href="#cb5-8" aria-hidden="true"></a>            <span class="st">&#39;scope&#39;</span> =&gt; <span class="st">&#39;file.read file.write&#39;</span></span>
<span id="cb5-9"><a href="#cb5-9" aria-hidden="true"></a>        <span class="ot">]);</span></span>
<span id="cb5-10"><a href="#cb5-10" aria-hidden="true"></a>        wp_redirect<span class="ot">(</span><span class="kw">$auth_url</span><span class="ot">);</span></span>
<span id="cb5-11"><a href="#cb5-11" aria-hidden="true"></a>        <span class="kw">exit</span><span class="ot">;</span></span>
<span id="cb5-12"><a href="#cb5-12" aria-hidden="true"></a>    }</span>
<span id="cb5-13"><a href="#cb5-13" aria-hidden="true"></a></span>
<span id="cb5-14"><a href="#cb5-14" aria-hidden="true"></a>    <span class="co">// Step 2: Exchange code for access token</span></span>
<span id="cb5-15"><a href="#cb5-15" aria-hidden="true"></a>    <span class="kw">$response</span> = wp_remote_post<span class="ot">(</span><span class="st">&#39;https://provider.com/oauth/token&#39;</span><span class="ot">,</span> <span class="ot">[</span></span>
<span id="cb5-16"><a href="#cb5-16" aria-hidden="true"></a>        <span class="st">&#39;body&#39;</span> =&gt; <span class="ot">[</span></span>
<span id="cb5-17"><a href="#cb5-17" aria-hidden="true"></a>            <span class="st">&#39;code&#39;</span> =&gt; <span class="kw">$credentials</span><span class="ot">[</span><span class="st">&#39;code&#39;</span><span class="ot">],</span></span>
<span id="cb5-18"><a href="#cb5-18" aria-hidden="true"></a>            <span class="st">&#39;client_id&#39;</span> =&gt; <span class="kw">$credentials</span><span class="ot">[</span><span class="st">&#39;client_id&#39;</span><span class="ot">],</span></span>
<span id="cb5-19"><a href="#cb5-19" aria-hidden="true"></a>            <span class="st">&#39;client_secret&#39;</span> =&gt; <span class="kw">$credentials</span><span class="ot">[</span><span class="st">&#39;client_secret&#39;</span><span class="ot">],</span></span>
<span id="cb5-20"><a href="#cb5-20" aria-hidden="true"></a>            <span class="st">&#39;redirect_uri&#39;</span> =&gt; admin_url<span class="ot">(</span><span class="st">&#39;admin.php?page=bkpc-oauth-callback&#39;</span><span class="ot">),</span></span>
<span id="cb5-21"><a href="#cb5-21" aria-hidden="true"></a>            <span class="st">&#39;grant_type&#39;</span> =&gt; <span class="st">&#39;authorization_code&#39;</span></span>
<span id="cb5-22"><a href="#cb5-22" aria-hidden="true"></a>        <span class="ot">]</span></span>
<span id="cb5-23"><a href="#cb5-23" aria-hidden="true"></a>    <span class="ot">]);</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">$body</span> = <span class="fu">json_decode</span><span class="ot">(</span>wp_remote_retrieve_body<span class="ot">(</span><span class="kw">$response</span><span class="ot">),</span> <span class="kw">true</span><span class="ot">);</span></span>
<span id="cb5-26"><a href="#cb5-26" aria-hidden="true"></a></span>
<span id="cb5-27"><a href="#cb5-27" aria-hidden="true"></a>    <span class="co">// Store tokens securely</span></span>
<span id="cb5-28"><a href="#cb5-28" aria-hidden="true"></a>    update_option<span class="ot">(</span><span class="st">&#39;bkpc_provider_access_token&#39;</span><span class="ot">,</span> <span class="kw">$this</span>-&gt;encrypt<span class="ot">(</span><span class="kw">$body</span><span class="ot">[</span><span class="st">&#39;access_token&#39;</span><span class="ot">]));</span></span>
<span id="cb5-29"><a href="#cb5-29" aria-hidden="true"></a>    update_option<span class="ot">(</span><span class="st">&#39;bkpc_provider_refresh_token&#39;</span><span class="ot">,</span> <span class="kw">$this</span>-&gt;encrypt<span class="ot">(</span><span class="kw">$body</span><span class="ot">[</span><span class="st">&#39;refresh_token&#39;</span><span class="ot">]));</span></span>
<span id="cb5-30"><a href="#cb5-30" aria-hidden="true"></a>    update_option<span class="ot">(</span><span class="st">&#39;bkpc_provider_token_expires&#39;</span><span class="ot">,</span> <span class="fu">time</span><span class="ot">()</span> + <span class="kw">$body</span><span class="ot">[</span><span class="st">&#39;expires_in&#39;</span><span class="ot">]);</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="kw">return</span> <span class="kw">true</span><span class="ot">;</span></span>
<span id="cb5-33"><a href="#cb5-33" aria-hidden="true"></a>}</span>
<span id="cb5-34"><a href="#cb5-34" aria-hidden="true"></a></span>
<span id="cb5-35"><a href="#cb5-35" aria-hidden="true"></a><span class="kw">private</span> <span class="kw">function</span> get_access_token<span class="ot">()</span> {</span>
<span id="cb5-36"><a href="#cb5-36" aria-hidden="true"></a>    <span class="kw">$expires</span> = get_option<span class="ot">(</span><span class="st">&#39;bkpc_provider_token_expires&#39;</span><span class="ot">);</span></span>
<span id="cb5-37"><a href="#cb5-37" aria-hidden="true"></a></span>
<span id="cb5-38"><a href="#cb5-38" aria-hidden="true"></a>    <span class="co">// Refresh token if expired</span></span>
<span id="cb5-39"><a href="#cb5-39" aria-hidden="true"></a>    <span class="kw">if</span> <span class="ot">(</span><span class="fu">time</span><span class="ot">()</span> &gt;= <span class="kw">$expires</span><span class="ot">)</span> {</span>
<span id="cb5-40"><a href="#cb5-40" aria-hidden="true"></a>        <span class="kw">$this</span>-&gt;refresh_access_token<span class="ot">();</span></span>
<span id="cb5-41"><a href="#cb5-41" aria-hidden="true"></a>    }</span>
<span id="cb5-42"><a href="#cb5-42" aria-hidden="true"></a></span>
<span id="cb5-43"><a href="#cb5-43" aria-hidden="true"></a>    <span class="kw">return</span> <span class="kw">$this</span>-&gt;decrypt<span class="ot">(</span>get_option<span class="ot">(</span><span class="st">&#39;bkpc_provider_access_token&#39;</span><span class="ot">));</span></span>
<span id="cb5-44"><a href="#cb5-44" aria-hidden="true"></a>}</span>
<span id="cb5-45"><a href="#cb5-45" aria-hidden="true"></a></span>
<span id="cb5-46"><a href="#cb5-46" aria-hidden="true"></a><span class="kw">private</span> <span class="kw">function</span> refresh_access_token<span class="ot">()</span> {</span>
<span id="cb5-47"><a href="#cb5-47" aria-hidden="true"></a>    <span class="kw">$refresh_token</span> = <span class="kw">$this</span>-&gt;decrypt<span class="ot">(</span>get_option<span class="ot">(</span><span class="st">&#39;bkpc_provider_refresh_token&#39;</span><span class="ot">));</span></span>
<span id="cb5-48"><a href="#cb5-48" aria-hidden="true"></a></span>
<span id="cb5-49"><a href="#cb5-49" aria-hidden="true"></a>    <span class="kw">$response</span> = wp_remote_post<span class="ot">(</span><span class="st">&#39;https://provider.com/oauth/token&#39;</span><span class="ot">,</span> <span class="ot">[</span></span>
<span id="cb5-50"><a href="#cb5-50" aria-hidden="true"></a>        <span class="st">&#39;body&#39;</span> =&gt; <span class="ot">[</span></span>
<span id="cb5-51"><a href="#cb5-51" aria-hidden="true"></a>            <span class="st">&#39;refresh_token&#39;</span> =&gt; <span class="kw">$refresh_token</span><span class="ot">,</span></span>
<span id="cb5-52"><a href="#cb5-52" aria-hidden="true"></a>            <span class="st">&#39;client_id&#39;</span> =&gt; get_option<span class="ot">(</span><span class="st">&#39;bkpc_provider_client_id&#39;</span><span class="ot">),</span></span>
<span id="cb5-53"><a href="#cb5-53" aria-hidden="true"></a>            <span class="st">&#39;client_secret&#39;</span> =&gt; <span class="kw">$this</span>-&gt;decrypt<span class="ot">(</span>get_option<span class="ot">(</span><span class="st">&#39;bkpc_provider_client_secret&#39;</span><span class="ot">)),</span></span>
<span id="cb5-54"><a href="#cb5-54" aria-hidden="true"></a>            <span class="st">&#39;grant_type&#39;</span> =&gt; <span class="st">&#39;refresh_token&#39;</span></span>
<span id="cb5-55"><a href="#cb5-55" aria-hidden="true"></a>        <span class="ot">]</span></span>
<span id="cb5-56"><a href="#cb5-56" aria-hidden="true"></a>    <span class="ot">]);</span></span>
<span id="cb5-57"><a href="#cb5-57" aria-hidden="true"></a></span>
<span id="cb5-58"><a href="#cb5-58" aria-hidden="true"></a>    <span class="kw">$body</span> = <span class="fu">json_decode</span><span class="ot">(</span>wp_remote_retrieve_body<span class="ot">(</span><span class="kw">$response</span><span class="ot">),</span> <span class="kw">true</span><span class="ot">);</span></span>
<span id="cb5-59"><a href="#cb5-59" aria-hidden="true"></a>    update_option<span class="ot">(</span><span class="st">&#39;bkpc_provider_access_token&#39;</span><span class="ot">,</span> <span class="kw">$this</span>-&gt;encrypt<span class="ot">(</span><span class="kw">$body</span><span class="ot">[</span><span class="st">&#39;access_token&#39;</span><span class="ot">]));</span></span>
<span id="cb5-60"><a href="#cb5-60" aria-hidden="true"></a>    update_option<span class="ot">(</span><span class="st">&#39;bkpc_provider_token_expires&#39;</span><span class="ot">,</span> <span class="fu">time</span><span class="ot">()</span> + <span class="kw">$body</span><span class="ot">[</span><span class="st">&#39;expires_in&#39;</span><span class="ot">]);</span></span>
<span id="cb5-61"><a href="#cb5-61" aria-hidden="true"></a>}</span></code></pre>
</div>
<h2 id="error-handling-and-retry-logic">Error Handling and Retry Logic</h2>
<p>Robust providers handle transient failures:</p>
<div class="sourceCode" id="cb6">
<pre class="sourceCode php"><code class="sourceCode php"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true"></a><span class="kw">public</span> <span class="kw">function</span> upload_with_retry<span class="ot">(</span><span class="kw">$local_file</span><span class="ot">,</span> <span class="kw">$remote_path</span><span class="ot">,</span> <span class="kw">$options</span> = <span class="ot">[])</span> {</span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true"></a>    <span class="kw">$max_retries</span> = <span class="dv">3</span><span class="ot">;</span></span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true"></a>    <span class="kw">$retry_delay</span> = <span class="dv">5</span><span class="ot">;</span> <span class="co">// seconds</span></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="kw">for</span> <span class="ot">(</span><span class="kw">$attempt</span> = <span class="dv">1</span><span class="ot">;</span> <span class="kw">$attempt</span> &lt;= <span class="kw">$max_retries</span><span class="ot">;</span> <span class="kw">$attempt</span>++<span class="ot">)</span> {</span>
<span id="cb6-6"><a href="#cb6-6" aria-hidden="true"></a>        <span class="kw">try</span> {</span>
<span id="cb6-7"><a href="#cb6-7" aria-hidden="true"></a>            <span class="kw">return</span> <span class="kw">$this</span>-&gt;upload<span class="ot">(</span><span class="kw">$local_file</span><span class="ot">,</span> <span class="kw">$remote_path</span><span class="ot">,</span> <span class="kw">$options</span><span class="ot">);</span></span>
<span id="cb6-8"><a href="#cb6-8" aria-hidden="true"></a>        } <span class="kw">catch</span> <span class="ot">(</span><span class="kw">Exception</span> <span class="kw">$e</span><span class="ot">)</span> {</span>
<span id="cb6-9"><a href="#cb6-9" aria-hidden="true"></a>            <span class="kw">if</span> <span class="ot">(</span><span class="kw">$attempt</span> === <span class="kw">$max_retries</span><span class="ot">)</span> {</span>
<span id="cb6-10"><a href="#cb6-10" aria-hidden="true"></a>                <span class="kw">throw</span> <span class="kw">$e</span><span class="ot">;</span></span>
<span id="cb6-11"><a href="#cb6-11" aria-hidden="true"></a>            }</span>
<span id="cb6-12"><a href="#cb6-12" aria-hidden="true"></a></span>
<span id="cb6-13"><a href="#cb6-13" aria-hidden="true"></a>            <span class="co">// Log retry attempt</span></span>
<span id="cb6-14"><a href="#cb6-14" aria-hidden="true"></a>            <span class="fu">error_log</span><span class="ot">(</span><span class="st">&quot;Upload attempt </span><span class="kw">{$attempt}</span><span class="st"> failed: {</span><span class="kw">$e</span><span class="st">-&gt;getMessage()}. Retrying in </span><span class="kw">{$retry_delay}</span><span class="st">s&quot;</span><span class="ot">);</span></span>
<span id="cb6-15"><a href="#cb6-15" aria-hidden="true"></a></span>
<span id="cb6-16"><a href="#cb6-16" aria-hidden="true"></a>            <span class="fu">sleep</span><span class="ot">(</span><span class="kw">$retry_delay</span><span class="ot">);</span></span>
<span id="cb6-17"><a href="#cb6-17" aria-hidden="true"></a>            <span class="kw">$retry_delay</span> *= <span class="dv">2</span><span class="ot">;</span> <span class="co">// Exponential backoff</span></span>
<span id="cb6-18"><a href="#cb6-18" aria-hidden="true"></a>        }</span>
<span id="cb6-19"><a href="#cb6-19" aria-hidden="true"></a>    }</span>
<span id="cb6-20"><a href="#cb6-20" aria-hidden="true"></a>}</span></code></pre>
</div>
<h2 id="security-best-practices">Security Best Practices</h2>
<p>Protect credentials and user data:</p>
<p><strong>Encrypt Sensitive Data</strong>:</p>
<div class="sourceCode" id="cb7">
<pre class="sourceCode php"><code class="sourceCode php"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true"></a><span class="kw">private</span> <span class="kw">function</span> encrypt<span class="ot">(</span><span class="kw">$value</span><span class="ot">)</span> {</span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true"></a>    <span class="kw">if</span> <span class="ot">(</span>!<span class="fu">defined</span><span class="ot">(</span><span class="st">&#39;BKPC_ENCRYPTION_KEY&#39;</span><span class="ot">))</span> {</span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true"></a>        <span class="kw">throw</span> <span class="kw">new</span> <span class="kw">Exception</span><span class="ot">(</span><span class="st">&#39;Encryption key not defined&#39;</span><span class="ot">);</span></span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true"></a>    }</span>
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true"></a>    <span class="kw">return</span> <span class="fu">openssl_encrypt</span><span class="ot">(</span><span class="kw">$value</span><span class="ot">,</span> <span class="st">&#39;AES-256-CBC&#39;</span><span class="ot">,</span> <span class="kw">BKPC_ENCRYPTION_KEY</span><span class="ot">,</span> <span class="dv">0</span><span class="ot">,</span> <span class="fu">substr</span><span class="ot">(</span><span class="kw">BKPC_ENCRYPTION_KEY</span><span class="ot">,</span> <span class="dv">0</span><span class="ot">,</span> <span class="dv">16</span><span class="ot">));</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>
<span id="cb7-8"><a href="#cb7-8" aria-hidden="true"></a><span class="kw">private</span> <span class="kw">function</span> decrypt<span class="ot">(</span><span class="kw">$value</span><span class="ot">)</span> {</span>
<span id="cb7-9"><a href="#cb7-9" aria-hidden="true"></a>    <span class="kw">if</span> <span class="ot">(</span>!<span class="fu">defined</span><span class="ot">(</span><span class="st">&#39;BKPC_ENCRYPTION_KEY&#39;</span><span class="ot">))</span> {</span>
<span id="cb7-10"><a href="#cb7-10" aria-hidden="true"></a>        <span class="kw">throw</span> <span class="kw">new</span> <span class="kw">Exception</span><span class="ot">(</span><span class="st">&#39;Encryption key not defined&#39;</span><span class="ot">);</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="kw">return</span> <span class="fu">openssl_decrypt</span><span class="ot">(</span><span class="kw">$value</span><span class="ot">,</span> <span class="st">&#39;AES-256-CBC&#39;</span><span class="ot">,</span> <span class="kw">BKPC_ENCRYPTION_KEY</span><span class="ot">,</span> <span class="dv">0</span><span class="ot">,</span> <span class="fu">substr</span><span class="ot">(</span><span class="kw">BKPC_ENCRYPTION_KEY</span><span class="ot">,</span> <span class="dv">0</span><span class="ot">,</span> <span class="dv">16</span><span class="ot">));</span></span>
<span id="cb7-13"><a href="#cb7-13" aria-hidden="true"></a>}</span></code></pre>
</div>
<p><strong>Validate Inputs</strong>:</p>
<div class="sourceCode" id="cb8">
<pre class="sourceCode php"><code class="sourceCode php"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true"></a><span class="kw">public</span> <span class="kw">function</span> authenticate<span class="ot">(</span><span class="kw">$credentials</span><span class="ot">)</span> {</span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true"></a>    <span class="kw">$required</span> = <span class="ot">[</span><span class="st">&#39;endpoint&#39;</span><span class="ot">,</span> <span class="st">&#39;bucket&#39;</span><span class="ot">,</span> <span class="st">&#39;access_key&#39;</span><span class="ot">,</span> <span class="st">&#39;secret_key&#39;</span><span class="ot">];</span></span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true"></a>    <span class="kw">foreach</span> <span class="ot">(</span><span class="kw">$required</span> <span class="kw">as</span> <span class="kw">$field</span><span class="ot">)</span> {</span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true"></a>        <span class="kw">if</span> <span class="ot">(</span><span class="kw">empty</span><span class="ot">(</span><span class="kw">$credentials</span><span class="ot">[</span><span class="kw">$field</span><span class="ot">]))</span> {</span>
<span id="cb8-5"><a href="#cb8-5" aria-hidden="true"></a>            <span class="kw">throw</span> <span class="kw">new</span> <span class="kw">Exception</span><span class="ot">(</span><span class="st">&quot;Missing required field: </span><span class="kw">{$field}</span><span class="st">&quot;</span><span class="ot">);</span></span>
<span id="cb8-6"><a href="#cb8-6" aria-hidden="true"></a>        }</span>
<span id="cb8-7"><a href="#cb8-7" aria-hidden="true"></a>    }</span>
<span id="cb8-8"><a href="#cb8-8" aria-hidden="true"></a></span>
<span id="cb8-9"><a href="#cb8-9" aria-hidden="true"></a>    <span class="co">// Validate endpoint is proper URL</span></span>
<span id="cb8-10"><a href="#cb8-10" aria-hidden="true"></a>    <span class="kw">if</span> <span class="ot">(</span>!<span class="fu">filter_var</span><span class="ot">(</span><span class="kw">$credentials</span><span class="ot">[</span><span class="st">&#39;endpoint&#39;</span><span class="ot">],</span> <span class="kw">FILTER_VALIDATE_URL</span><span class="ot">))</span> {</span>
<span id="cb8-11"><a href="#cb8-11" aria-hidden="true"></a>        <span class="kw">throw</span> <span class="kw">new</span> <span class="kw">Exception</span><span class="ot">(</span><span class="st">&#39;Invalid endpoint URL&#39;</span><span class="ot">);</span></span>
<span id="cb8-12"><a href="#cb8-12" aria-hidden="true"></a>    }</span>
<span id="cb8-13"><a href="#cb8-13" aria-hidden="true"></a></span>
<span id="cb8-14"><a href="#cb8-14" aria-hidden="true"></a>    <span class="co">// Continue authentication...</span></span>
<span id="cb8-15"><a href="#cb8-15" aria-hidden="true"></a>}</span></code></pre>
</div>
<h2 id="testing-custom-providers">Testing Custom Providers</h2>
<p>Thorough testing ensures reliability:</p>
<div class="sourceCode" id="cb9">
<pre class="sourceCode php"><code class="sourceCode php"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true"></a><span class="kw">class</span> BKPC_Cloud_Provider_Tests {</span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true"></a></span>
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true"></a>    <span class="kw">public</span> <span class="kw">static</span> <span class="kw">function</span> test_provider<span class="ot">(</span><span class="kw">$provider_class</span><span class="ot">,</span> <span class="kw">$credentials</span><span class="ot">)</span> {</span>
<span id="cb9-4"><a href="#cb9-4" aria-hidden="true"></a>        <span class="kw">$provider</span> = <span class="kw">new</span> <span class="kw">$provider_class</span><span class="ot">();</span></span>
<span id="cb9-5"><a href="#cb9-5" aria-hidden="true"></a>        <span class="kw">$results</span> = <span class="ot">[];</span></span>
<span id="cb9-6"><a href="#cb9-6" aria-hidden="true"></a></span>
<span id="cb9-7"><a href="#cb9-7" aria-hidden="true"></a>        <span class="co">// Test authentication</span></span>
<span id="cb9-8"><a href="#cb9-8" aria-hidden="true"></a>        <span class="kw">try</span> {</span>
<span id="cb9-9"><a href="#cb9-9" aria-hidden="true"></a>            <span class="kw">$provider</span>-&gt;authenticate<span class="ot">(</span><span class="kw">$credentials</span><span class="ot">);</span></span>
<span id="cb9-10"><a href="#cb9-10" aria-hidden="true"></a>            <span class="kw">$results</span><span class="ot">[</span><span class="st">&#39;auth&#39;</span><span class="ot">]</span> = <span class="st">&#39;PASS&#39;</span><span class="ot">;</span></span>
<span id="cb9-11"><a href="#cb9-11" aria-hidden="true"></a>        } <span class="kw">catch</span> <span class="ot">(</span><span class="kw">Exception</span> <span class="kw">$e</span><span class="ot">)</span> {</span>
<span id="cb9-12"><a href="#cb9-12" aria-hidden="true"></a>            <span class="kw">$results</span><span class="ot">[</span><span class="st">&#39;auth&#39;</span><span class="ot">]</span> = <span class="st">&#39;FAIL: &#39;</span> . <span class="kw">$e</span>-&gt;getMessage<span class="ot">();</span></span>
<span id="cb9-13"><a href="#cb9-13" aria-hidden="true"></a>            <span class="kw">return</span> <span class="kw">$results</span><span class="ot">;</span> <span class="co">// Can&#39;t continue without auth</span></span>
<span id="cb9-14"><a href="#cb9-14" aria-hidden="true"></a>        }</span>
<span id="cb9-15"><a href="#cb9-15" aria-hidden="true"></a></span>
<span id="cb9-16"><a href="#cb9-16" aria-hidden="true"></a>        <span class="co">// Test upload</span></span>
<span id="cb9-17"><a href="#cb9-17" aria-hidden="true"></a>        <span class="kw">$test_file</span> = <span class="fu">tempnam</span><span class="ot">(</span><span class="fu">sys_get_temp_dir</span><span class="ot">(),</span> <span class="st">&#39;bkpc_test_&#39;</span><span class="ot">);</span></span>
<span id="cb9-18"><a href="#cb9-18" aria-hidden="true"></a>        <span class="fu">file_put_contents</span><span class="ot">(</span><span class="kw">$test_file</span><span class="ot">,</span> <span class="st">&#39;Test backup content&#39;</span><span class="ot">);</span></span>
<span id="cb9-19"><a href="#cb9-19" aria-hidden="true"></a></span>
<span id="cb9-20"><a href="#cb9-20" aria-hidden="true"></a>        <span class="kw">try</span> {</span>
<span id="cb9-21"><a href="#cb9-21" aria-hidden="true"></a>            <span class="kw">$provider</span>-&gt;upload<span class="ot">(</span><span class="kw">$test_file</span><span class="ot">,</span> <span class="st">&#39;/test-backup.txt&#39;</span><span class="ot">);</span></span>
<span id="cb9-22"><a href="#cb9-22" aria-hidden="true"></a>            <span class="kw">$results</span><span class="ot">[</span><span class="st">&#39;upload&#39;</span><span class="ot">]</span> = <span class="st">&#39;PASS&#39;</span><span class="ot">;</span></span>
<span id="cb9-23"><a href="#cb9-23" aria-hidden="true"></a>        } <span class="kw">catch</span> <span class="ot">(</span><span class="kw">Exception</span> <span class="kw">$e</span><span class="ot">)</span> {</span>
<span id="cb9-24"><a href="#cb9-24" aria-hidden="true"></a>            <span class="kw">$results</span><span class="ot">[</span><span class="st">&#39;upload&#39;</span><span class="ot">]</span> = <span class="st">&#39;FAIL: &#39;</span> . <span class="kw">$e</span>-&gt;getMessage<span class="ot">();</span></span>
<span id="cb9-25"><a href="#cb9-25" aria-hidden="true"></a>        }</span>
<span id="cb9-26"><a href="#cb9-26" aria-hidden="true"></a></span>
<span id="cb9-27"><a href="#cb9-27" aria-hidden="true"></a>        <span class="co">// Test list files</span></span>
<span id="cb9-28"><a href="#cb9-28" aria-hidden="true"></a>        <span class="kw">try</span> {</span>
<span id="cb9-29"><a href="#cb9-29" aria-hidden="true"></a>            <span class="kw">$files</span> = <span class="kw">$provider</span>-&gt;list_files<span class="ot">(</span><span class="st">&#39;/&#39;</span><span class="ot">);</span></span>
<span id="cb9-30"><a href="#cb9-30" aria-hidden="true"></a>            <span class="kw">$results</span><span class="ot">[</span><span class="st">&#39;list&#39;</span><span class="ot">]</span> = <span class="fu">count</span><span class="ot">(</span><span class="kw">$files</span><span class="ot">)</span> &gt; <span class="dv">0</span> <span class="ot">?</span> <span class="st">&#39;PASS&#39;</span> <span class="ot">:</span> <span class="st">&#39;FAIL: No files found&#39;</span><span class="ot">;</span></span>
<span id="cb9-31"><a href="#cb9-31" aria-hidden="true"></a>        } <span class="kw">catch</span> <span class="ot">(</span><span class="kw">Exception</span> <span class="kw">$e</span><span class="ot">)</span> {</span>
<span id="cb9-32"><a href="#cb9-32" aria-hidden="true"></a>            <span class="kw">$results</span><span class="ot">[</span><span class="st">&#39;list&#39;</span><span class="ot">]</span> = <span class="st">&#39;FAIL: &#39;</span> . <span class="kw">$e</span>-&gt;getMessage<span class="ot">();</span></span>
<span id="cb9-33"><a href="#cb9-33" aria-hidden="true"></a>        }</span>
<span id="cb9-34"><a href="#cb9-34" aria-hidden="true"></a></span>
<span id="cb9-35"><a href="#cb9-35" aria-hidden="true"></a>        <span class="co">// Test download</span></span>
<span id="cb9-36"><a href="#cb9-36" aria-hidden="true"></a>        <span class="kw">$download_file</span> = <span class="fu">tempnam</span><span class="ot">(</span><span class="fu">sys_get_temp_dir</span><span class="ot">(),</span> <span class="st">&#39;bkpc_download_&#39;</span><span class="ot">);</span></span>
<span id="cb9-37"><a href="#cb9-37" aria-hidden="true"></a>        <span class="kw">try</span> {</span>
<span id="cb9-38"><a href="#cb9-38" aria-hidden="true"></a>            <span class="kw">$provider</span>-&gt;download<span class="ot">(</span><span class="st">&#39;/test-backup.txt&#39;</span><span class="ot">,</span> <span class="kw">$download_file</span><span class="ot">);</span></span>
<span id="cb9-39"><a href="#cb9-39" aria-hidden="true"></a>            <span class="kw">$results</span><span class="ot">[</span><span class="st">&#39;download&#39;</span><span class="ot">]</span> = <span class="fu">file_get_contents</span><span class="ot">(</span><span class="kw">$download_file</span><span class="ot">)</span> === <span class="st">&#39;Test backup content&#39;</span> <span class="ot">?</span> <span class="st">&#39;PASS&#39;</span> <span class="ot">:</span> <span class="st">&#39;FAIL: Content mismatch&#39;</span><span class="ot">;</span></span>
<span id="cb9-40"><a href="#cb9-40" aria-hidden="true"></a>        } <span class="kw">catch</span> <span class="ot">(</span><span class="kw">Exception</span> <span class="kw">$e</span><span class="ot">)</span> {</span>
<span id="cb9-41"><a href="#cb9-41" aria-hidden="true"></a>            <span class="kw">$results</span><span class="ot">[</span><span class="st">&#39;download&#39;</span><span class="ot">]</span> = <span class="st">&#39;FAIL: &#39;</span> . <span class="kw">$e</span>-&gt;getMessage<span class="ot">();</span></span>
<span id="cb9-42"><a href="#cb9-42" aria-hidden="true"></a>        }</span>
<span id="cb9-43"><a href="#cb9-43" aria-hidden="true"></a></span>
<span id="cb9-44"><a href="#cb9-44" aria-hidden="true"></a>        <span class="co">// Test delete</span></span>
<span id="cb9-45"><a href="#cb9-45" aria-hidden="true"></a>        <span class="kw">try</span> {</span>
<span id="cb9-46"><a href="#cb9-46" aria-hidden="true"></a>            <span class="kw">$provider</span>-&gt;delete<span class="ot">(</span><span class="st">&#39;/test-backup.txt&#39;</span><span class="ot">);</span></span>
<span id="cb9-47"><a href="#cb9-47" aria-hidden="true"></a>            <span class="kw">$results</span><span class="ot">[</span><span class="st">&#39;delete&#39;</span><span class="ot">]</span> = <span class="st">&#39;PASS&#39;</span><span class="ot">;</span></span>
<span id="cb9-48"><a href="#cb9-48" aria-hidden="true"></a>        } <span class="kw">catch</span> <span class="ot">(</span><span class="kw">Exception</span> <span class="kw">$e</span><span class="ot">)</span> {</span>
<span id="cb9-49"><a href="#cb9-49" aria-hidden="true"></a>            <span class="kw">$results</span><span class="ot">[</span><span class="st">&#39;delete&#39;</span><span class="ot">]</span> = <span class="st">&#39;FAIL: &#39;</span> . <span class="kw">$e</span>-&gt;getMessage<span class="ot">();</span></span>
<span id="cb9-50"><a href="#cb9-50" aria-hidden="true"></a>        }</span>
<span id="cb9-51"><a href="#cb9-51" aria-hidden="true"></a></span>
<span id="cb9-52"><a href="#cb9-52" aria-hidden="true"></a>        <span class="co">// Cleanup</span></span>
<span id="cb9-53"><a href="#cb9-53" aria-hidden="true"></a>        <span class="fu">unlink</span><span class="ot">(</span><span class="kw">$test_file</span><span class="ot">);</span></span>
<span id="cb9-54"><a href="#cb9-54" aria-hidden="true"></a>        <span class="fu">unlink</span><span class="ot">(</span><span class="kw">$download_file</span><span class="ot">);</span></span>
<span id="cb9-55"><a href="#cb9-55" aria-hidden="true"></a></span>
<span id="cb9-56"><a href="#cb9-56" aria-hidden="true"></a>        <span class="kw">return</span> <span class="kw">$results</span><span class="ot">;</span></span>
<span id="cb9-57"><a href="#cb9-57" aria-hidden="true"></a>    }</span>
<span id="cb9-58"><a href="#cb9-58" aria-hidden="true"></a>}</span></code></pre>
</div>
<h2 id="performance-optimization">Performance Optimization</h2>
<p>Optimize for large backups:</p>
<p><strong>Chunked Uploads</strong>: Upload large files in chunks (5-10MB) to handle network interruptions and show progress.</p>
<p><strong>Concurrent Connections</strong>: Use multiple connections for faster transfers when API supports it.</p>
<p><strong>Compression</strong>: Compress before upload to reduce bandwidth:</p>
<div class="sourceCode" id="cb10">
<pre class="sourceCode php"><code class="sourceCode php"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true"></a><span class="kw">public</span> <span class="kw">function</span> upload<span class="ot">(</span><span class="kw">$local_file</span><span class="ot">,</span> <span class="kw">$remote_path</span><span class="ot">,</span> <span class="kw">$options</span> = <span class="ot">[])</span> {</span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true"></a>    <span class="co">// Compress if not already compressed</span></span>
<span id="cb10-3"><a href="#cb10-3" aria-hidden="true"></a>    <span class="kw">if</span> <span class="ot">(</span>!<span class="fu">preg_match</span><span class="ot">(</span><span class="st">&#39;/\.(zip|gz|bz2)$/i&#39;</span><span class="ot">,</span> <span class="kw">$local_file</span><span class="ot">))</span> {</span>
<span id="cb10-4"><a href="#cb10-4" aria-hidden="true"></a>        <span class="kw">$compressed</span> = <span class="kw">$local_file</span> . <span class="st">&#39;.gz&#39;</span><span class="ot">;</span></span>
<span id="cb10-5"><a href="#cb10-5" aria-hidden="true"></a>        <span class="kw">$this</span>-&gt;compress_file<span class="ot">(</span><span class="kw">$local_file</span><span class="ot">,</span> <span class="kw">$compressed</span><span class="ot">);</span></span>
<span id="cb10-6"><a href="#cb10-6" aria-hidden="true"></a>        <span class="kw">$local_file</span> = <span class="kw">$compressed</span><span class="ot">;</span></span>
<span id="cb10-7"><a href="#cb10-7" aria-hidden="true"></a>        <span class="kw">$remote_path</span> .= <span class="st">&#39;.gz&#39;</span><span class="ot">;</span></span>
<span id="cb10-8"><a href="#cb10-8" aria-hidden="true"></a>    }</span>
<span id="cb10-9"><a href="#cb10-9" aria-hidden="true"></a></span>
<span id="cb10-10"><a href="#cb10-10" aria-hidden="true"></a>    <span class="co">// Upload compressed file</span></span>
<span id="cb10-11"><a href="#cb10-11" aria-hidden="true"></a>    <span class="kw">return</span> <span class="kw">$this</span>-&gt;do_upload<span class="ot">(</span><span class="kw">$local_file</span><span class="ot">,</span> <span class="kw">$remote_path</span><span class="ot">,</span> <span class="kw">$options</span><span class="ot">);</span></span>
<span id="cb10-12"><a href="#cb10-12" aria-hidden="true"></a>}</span></code></pre>
</div>
<h2 id="publishing-your-provider">Publishing Your Provider</h2>
<p>Share with community:</p>
<ol type="1">
<li><strong>Package as WordPress Plugin</strong>: Create standalone plugin users can install</li>
<li><strong>Documentation</strong>: Provide setup instructions and API credentials guidance</li>
<li><strong>WordPress.org Repository</strong>: Submit to official repository for distribution</li>
<li><strong>GitHub</strong>: Open source on GitHub for community contributions</li>
<li><strong>Support</strong>: Provide support channels for users</li>
</ol>
<h2 id="conclusion">Conclusion</h2>
<p>Custom cloud storage providers extend Backup Copilot Pro to any storage backend. Whether integrating S3-compatible services, legacy FTP/SFTP systems, or proprietary storage APIs, the provider architecture enables consistent functionality while accommodating provider-specific implementations.</p>
<p>Key implementation requirements: authentication, upload/download with chunking and progress tracking, error handling with retries, security through credential encryption, and thorough testing. Follow these patterns and your custom provider will integrate seamlessly with Backup Copilot Pro’s backup workflows.</p>
<h2 id="external-links">External Links</h2>
<ol type="1">
<li><a href="https://docs.aws.amazon.com/s3/">AWS S3 API Documentation</a></li>
<li><a href="https://www.backblaze.com/b2/docs/s3_compatible_api.html">S3-Compatible Storage Guide</a></li>
<li><a href="https://oauth.net/2/">OAuth 2.0 Specification</a></li>
<li><a href="https://www.php.net/manual/en/book.ftp.php">PHP FTP Functions</a></li>
<li><a href="https://developer.wordpress.org/plugins/">WordPress Plugin Development</a></li>
</ol>
<h2 id="call-to-action">Call to Action</h2>
<p>Need a custom storage solution? <a href="https://backupcopilot.com/contact">Contact our team</a> for custom development services or <a href="https://backupcopilotplugin.com/#pricing">get Pro</a> to build your own provider using our SDK!</p>
<p>The post <a href="https://backupcopilotplugin.com/blog/building-custom-cloud-storage-providers-for-backup-copilot-pro/">Building Custom Cloud Storage Providers for Backup Copilot Pro</a> appeared first on <a href="https://backupcopilotplugin.com">Backup Copilot</a>.</p>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
