<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
<channel><title>نوشته‌های کیان باباآبادی</title><link>https://kianbabaabady.ir/posts/</link><description>نوشته‌های کیان باباآبادی دربارهٔ PHP، وردپرس و کار بک‌اند.</description><language>fa-IR</language><lastBuildDate>Mon, 19 Oct 2026 09:00:00 +0330</lastBuildDate><atom:link href="https://kianbabaabady.ir/posts/feed.xml" rel="self" type="application/rss+xml"/>
<item><title>Safesprite Icons؛ چرا یک افزونهٔ آیکون SVG دیگر نوشتم</title><link>https://kianbabaabady.ir/posts/safesprite-icons/</link><guid isPermaLink="true">https://kianbabaabady.ir/posts/safesprite-icons/</guid><pubDate>Mon, 19 Oct 2026 09:00:00 +0330</pubDate><description>افزونه‌ای برای آیکون‌های SVG در وردپرس که آپلود SVG را در کتابخانهٔ رسانه باز نمی‌کند و آیکون‌های هر صفحه را در یک اسپرایت‌شیت در فوتر خروجی می‌دهد. چرا ساختمش و چطور کار می‌کند.</description><content:encoded><![CDATA[<p>تقریباً در هر پروژهٔ وردپرسی به آیکون اختصاصی می‌رسیم: آیکون‌های برند، آیکون آیتم‌های منو، آیکون کارت‌ها. معمولاً دو راه جلوی آدم است. یکی فعال‌کردن آپلود SVG در کتابخانهٔ رسانه با یک افزونه، دیگری چسباندن کد خام SVG در قالب یا صفحه‌ساز.</p>
<p>راه اول یعنی باز کردن دری که وردپرس عمداً بسته نگه داشته. فایل SVG در واقع XML است و می‌تواند اسکریپت، استایل یا ارجاع به منابع بیرونی داشته باشد. راه دوم یعنی تکرار همان کد SVG هر جایی که آیکون استفاده شده؛ یک آیکون که در منو و حلقهٔ کارت‌ها می‌آید، ممکن است ده‌ها بار در HTML صفحه تکرار شود.</p>
<p><a href="https://wordpress.org/plugins/safesprite-icons/">Safesprite Icons</a> را برای همین مشکل نوشتم. نسخهٔ ۱.۰.۰ آن شهریور ۱۴۰۵ در مخزن افزونه‌های وردپرس منتشر شد و کدش در <a href="https://github.com/kianbabai/Safesprite-Icons">گیت‌هاب</a> هست. هنوز افزونهٔ تازه‌ای است و کاربران زیادی ندارد؛ این نوشته بیشتر توضیح می‌دهد چرا و چطور ساخته شده.</p>
<h2 id="چه-کاری-میکند">چه کاری می‌کند<a class="headerlink" href="https://kianbabaabady.ir/posts/safesprite-icons/#چه-کاری-میکند">#</a></h2>
<ul>
<li>یک <strong>کتابخانهٔ آیکون جدا</strong> در پیشخوان می‌سازد که آیکون‌ها را در مجموعه‌ها (پوشه‌ها) نگه می‌دارد. آپلود SVG فقط از همین‌جا ممکن است.</li>
<li>آپلود SVG را در <strong>کتابخانهٔ رسانه فعال نمی‌کند</strong>. یعنی از نوع افزونه‌هایی مثل Safe SVG یا SVG Support نیست.</li>
<li>یک <strong>انتخابگر آیکون مشترک</strong> دارد که در بلاک گوتنبرگ، ویجت المنتور، ویرایشگر کلاسیک (TinyMCE) و آیتم‌های منو کار می‌کند.</li>
<li>برای توسعه‌دهنده‌ها شورت‌کد <code>[sfsi_icon slug="my-icon"]</code> و تابع PHP <code>sfsi_icon()</code> دارد.</li>
<li>اسم آیکون و مجموعه را می‌شود عوض کرد بدون اینکه اسلاگ تغییر کند، پس شورت‌کدها و بلاک‌های قبلی خراب نمی‌شوند. حذف هم اول به زباله‌دان می‌رود.</li>
</ul>
<h2 id="چطور-کار-میکند">چطور کار می‌کند<a class="headerlink" href="https://kianbabaabady.ir/posts/safesprite-icons/#چطور-کار-میکند">#</a></h2>
<h3 id="h-۱-پاکسازی-هنگام-آپلود">۱. پاک‌سازی هنگام آپلود<a class="headerlink" href="https://kianbabaabady.ir/posts/safesprite-icons/#h-۱-پاکسازی-هنگام-آپلود">#</a></h3>
<p>هر فایل اول از نظر حجم بررسی می‌شود؛ سقف حجم در تنظیمات افزونه قابل تغییر است. بعد با کتابخانهٔ <code>enshrined/svg-sanitize</code> پاک‌سازی می‌شود که داخل خود افزونه قرار دارد.</p>
<p>بعد از آن یک مرحلهٔ دیگر هم اضافه کردم: تگ‌های <code>&lt;style&gt;</code>، ویژگی‌های <code>style</code> و هر <code>href</code> که به یک شناسهٔ داخلی (<code>#...</code>) اشاره نکند حذف می‌شوند. در آخر یک بررسی نهایی انجام می‌شود که اگر هنوز چیزی مثل استایل یا لینکی به <code>http:</code>، <code>data:</code> یا <code>javascript:</code> در فایل مانده باشد، فایل را کلاً رد می‌کند. ترجیح دادم در موارد مشکوک فایل رد شود تا اینکه چیزی از زیر دست در برود.</p>
<p>فایل‌های پاک‌شده در زیرپوشه‌هایی با نام تصادفی داخل <code>wp-content/uploads/safesprite-icons/</code> ذخیره می‌شوند و اطلاعاتشان در جدول‌های اختصاصی افزونه است، نه در قالب پست‌تایپ.</p>
<h3 id="h-۲-خروجی-سبک-با-use">۲. خروجی سبک با <code>&lt;use&gt;</code><a class="headerlink" href="https://kianbabaabady.ir/posts/safesprite-icons/#h-۲-خروجی-سبک-با-use">#</a></h3>
<p>وقتی آیکونی در صفحه استفاده می‌شود (از بلاک، شورت‌کد یا کد PHP)، خروجی آن فقط یک SVG کوچک است که به یک <code>symbol</code> ارجاع می‌دهد:</p>
<div class="hl" dir="ltr"><pre><span></span><code><span class="cp">&lt;?php</span> <span class="k">echo</span> <span class="nx">sfsi_icon</span><span class="p">(</span> <span class="s1">'my-icon'</span><span class="p">,</span> <span class="k">array</span><span class="p">(</span> <span class="s1">'size'</span> <span class="o">=&gt;</span> <span class="mi">24</span> <span class="p">)</span> <span class="p">);</span> <span class="cp">?&gt;</span>
</code></pre></div>

<p>خروجی این کد تقریباً این است:</p>
<div class="hl" dir="ltr"><pre><span></span><code><span class="p">&lt;</span><span class="nt">svg</span> <span class="na">class</span><span class="o">=</span><span class="s">"sfsi-icon"</span> <span class="na">viewBox</span><span class="o">=</span><span class="s">"0 0 24 24"</span> <span class="na">aria-hidden</span><span class="o">=</span><span class="s">"true"</span> <span class="na">focusable</span><span class="o">=</span><span class="s">"false"</span> <span class="na">style</span><span class="o">=</span><span class="s">"width:24px;height:24px"</span><span class="p">&gt;</span>
  <span class="p">&lt;</span><span class="nt">use</span> <span class="na">href</span><span class="o">=</span><span class="s">"#sfsi-icon-my-icon"</span> <span class="na">xlink:href</span><span class="o">=</span><span class="s">"#sfsi-icon-my-icon"</span><span class="p">&gt;&lt;/</span><span class="nt">use</span><span class="p">&gt;</span>
<span class="p">&lt;/</span><span class="nt">svg</span><span class="p">&gt;</span>
</code></pre></div>

<p>اندازهٔ عددی بین ۱۶ تا ۲۵۶ پیکسل محدود می‌شود و رنگ یا از متن اطراف به ارث می‌رسد یا یک رنگ دلخواهِ پاک‌سازی‌شده است. هم‌زمان اسلاگ آیکون در یک فهرست داخلی برای همان درخواست ثبت می‌شود.</p>
<h3 id="h-۳-ساخت-اسپرایتشیت-در-فوتر">۳. ساخت اسپرایت‌شیت در فوتر<a class="headerlink" href="https://kianbabaabady.ir/posts/safesprite-icons/#h-۳-ساخت-اسپرایتشیت-در-فوتر">#</a></h3>
<p>در هوک <code>wp_footer</code>، افزونه فقط آیکون‌هایی را که در همان صفحه ثبت شده‌اند برمی‌دارد و برای هر کدام یک <code>&lt;symbol&gt;</code> داخل یک SVG مخفی چاپ می‌کند. پس هر آیکون فقط یک بار در صفحه می‌آید، هر چند بار هم که استفاده شده باشد.</p>
<p>قبل از چاپ، هش SHA-256 فایل با هشی که موقع آپلود ذخیره شده مقایسه می‌شود. اگر فایل روی دیسک تغییر کرده باشد، آن آیکون چاپ نمی‌شود.</p>
<h2 id="چیزهایی-که-در-مسیر-پیش-آمد">چیزهایی که در مسیر پیش آمد<a class="headerlink" href="https://kianbabaabady.ir/posts/safesprite-icons/#چیزهایی-که-در-مسیر-پیش-آمد">#</a></h2>
<p>بیشتر کار وقتی شروع شد که خواستم انتخابگر در ویرایشگرها درست کار کند. مثلاً بوم ویرایشگر المنتور اسپرایت‌شیت فوتر را ندارد، پس آنجا باید پیش‌نمایش آیکون به‌صورت درون‌خطی نشان داده شود. یک باگ هم داشتم که با ذخیره‌کردن منو، آیکون‌های آیتم‌ها پاک می‌شدند؛ این‌ها در <a href="https://wordpress.org/plugins/safesprite-icons/#developers">تغییرات نسخه‌ها</a> ثبت شده‌اند.</p>
<h2 id="محدودیتها">محدودیت‌ها<a class="headerlink" href="https://kianbabaabady.ir/posts/safesprite-icons/#محدودیتها">#</a></h2>
<ul>
<li>در نسخهٔ فعلی فقط آیکون‌های خود سایت پشتیبانی می‌شود و از CDN یا کتابخانه‌های آیکون آماده خبری نیست.</li>
<li>به PHP 7.4 به بالا با افزونه‌های <code>dom</code> و <code>libxml</code> و وردپرس ۶.۰ به بالا نیاز دارد.</li>
<li>با حذف افزونه، داده‌ها به‌طور پیش‌فرض باقی می‌مانند. اگر بخواهید جدول‌ها و فایل‌ها هم پاک شوند، باید گزینه‌اش را در تنظیمات روشن کنید.</li>
</ul>
<p>اگر امتحانش کردید و مشکلی دیدید یا پیشنهادی داشتید، در <a href="https://github.com/kianbabai/Safesprite-Icons">گیت‌هاب</a> یا <a href="https://wordpress.org/support/plugin/safesprite-icons/">انجمن پشتیبانی وردپرس</a> بنویسید، یا مستقیم <a href="mailto:kian.babai.09@gmail.com">ایمیل بزنید</a>.</p>]]></content:encoded></item>
</channel>
</rss>
