MyPWA — плагин для WordPress
PWA-плагин для WordPress — шпаргалка
Что это: плагин, который превращает WordPress-сайт в PWA (Progressive Web App). После установки сайт можно «установить» на телефон как приложение — с иконкой на рабочем столе, офлайн-режимом и без адресной строки браузера.
Куда класть: wp-content/plugins/mypwa.php — один файл, без папки.
Установка: Плагины → активировать → меню MyPWA слева → заполнить иконку и цвета.
Код плагина
<?php
/**
* Plugin Name: MyPWA
* Description: PWA для WordPress: манифест, service worker, офлайн-страница, кнопка установки.
* Version: 2.0
* Author: Вы
*/
if ( ! defined( 'ABSPATH' ) ) exit;
/* ---------- ХЕЛПЕРЫ ---------- */
function mypwa_defaults() {
return [
'name' => get_bloginfo( 'name' ),
'short_name' => get_bloginfo( 'name' ),
'theme_color' => '#000000',
'background_color' => '#ffffff',
'icon' => '',
'screenshot' => '',
];
}
function mypwa_get( $key ) {
$d = mypwa_defaults();
return get_option( 'mypwa_' . $key, $d[ $key ] ?? '' );
}
/* ---------- МЕТА-ТЕГИ ---------- */
add_action( 'wp_head', function () {
$theme = mypwa_get( 'theme_color' );
$icon = mypwa_get( 'icon' ) ?: 'https://www.gravatar.com/avatar/?s=512&d=mp';
?>
<link rel="manifest" href="<?php echo esc_url( home_url( '/?mypwa_manifest=1' ) ); ?>">
<meta name="theme-color" content="<?php echo esc_attr( $theme ); ?>">
<link rel="apple-touch-icon" href="<?php echo esc_url( $icon ); ?>">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="<?php echo esc_attr( mypwa_get( 'short_name' ) ); ?>">
<?php
} );
/* ---------- MANIFEST ---------- */
add_action( 'init', function () {
if ( ! isset( $_GET['mypwa_manifest'] ) ) return;
header( 'Content-Type: application/manifest+json' );
$icon = mypwa_get( 'icon' ) ?: 'https://www.gravatar.com/avatar/?s=512&d=mp';
$shot = mypwa_get( 'screenshot' );
$manifest = [
'name' => mypwa_get( 'name' ),
'short_name' => mypwa_get( 'short_name' ),
'start_url' => home_url( '/' ),
'scope' => '/',
'display' => 'standalone',
'orientation' => 'portrait',
'background_color' => mypwa_get( 'background_color' ),
'theme_color' => mypwa_get( 'theme_color' ),
'description' => get_bloginfo( 'description' ),
'icons' => [
[ 'src' => $icon, 'sizes' => '192x192', 'type' => 'image/png', 'purpose' => 'any' ],
[ 'src' => $icon, 'sizes' => '512x512', 'type' => 'image/png', 'purpose' => 'any' ],
[ 'src' => $icon, 'sizes' => '512x512', 'type' => 'image/png', 'purpose' => 'maskable' ],
],
'shortcuts' => [
[ 'name' => 'Главная', 'url' => '/?utm_source=pwa' ],
],
];
if ( $shot ) {
$manifest['screenshots'] = [
[ 'src' => $shot, 'sizes' => '1080x1920', 'type' => 'image/png', 'form_factor' => 'narrow' ],
];
}
echo json_encode( $manifest, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE );
exit;
} );
/* ---------- SERVICE WORKER ---------- */
add_action( 'init', function () {
if ( ! isset( $_GET['mypwa_sw'] ) ) return;
header( 'Content-Type: application/javascript; charset=utf-8' );
header( 'Service-Worker-Allowed: /' );
header( 'Cache-Control: no-cache' );
$offline = '<!DOCTYPE html><html lang="ru"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Нет соединения</title><style>body{font-family:system-ui,sans-serif;display:flex;align-items:center;justify-content:center;min-height:100vh;margin:0;background:#111;color:#fff;text-align:center;padding:20px}h1{font-size:64px;margin:0 0 10px}p{opacity:.7;max-width:400px}button{margin-top:20px;padding:12px 24px;border:none;border-radius:30px;background:#fff;color:#111;font-size:16px;cursor:pointer}</style></head><body><div><h1>📡</h1><h2>Нет соединения</h2><p>Проверьте интернет и попробуйте снова.</p><button onclick="location.reload()">Обновить</button></div></body></html>';
?>
const CACHE = 'mypwa-v1';
const OFFLINE_HTML = <?php echo json_encode( $offline ); ?>;
self.addEventListener('install', (e) => {
e.waitUntil(caches.open(CACHE).then((c) => c.addAll(['/'])).catch(() => {}));
self.skipWaiting();
});
self.addEventListener('activate', (e) => {
e.waitUntil(
caches.keys().then((keys) =>
Promise.all(keys.filter((k) => k !== CACHE).map((k) => caches.delete(k)))
)
);
self.clients.claim();
});
self.addEventListener('fetch', (e) => {
if (e.request.method !== 'GET') return;
if (e.request.mode === 'navigate') {
e.respondWith(
fetch(e.request)
.then((res) => {
const copy = res.clone();
caches.open(CACHE).then((c) => c.put(e.request, copy));
return res;
})
.catch(() =>
caches.match(e.request).then((r) =>
r || new Response(OFFLINE_HTML, { headers: { 'Content-Type': 'text/html' } })
)
)
);
return;
}
e.respondWith(
fetch(e.request)
.then((res) => {
const copy = res.clone();
caches.open(CACHE).then((c) => c.put(e.request, copy));
return res;
})
.catch(() => caches.match(e.request))
);
});
<?php
exit;
} );
/* ---------- JS: SW + кнопка установки ---------- */
add_action( 'wp_footer', function () {
$sw_url = home_url( '/?mypwa_sw=1' );
?>
<script>
(function () {
if (!('serviceWorker' in navigator)) return;
window.addEventListener('load', function () {
navigator.serviceWorker.register(<?php echo json_encode( $sw_url ); ?>, { scope: '/' })
.then(function (reg) { console.log('SW ok:', reg.scope); })
.catch(function (err) { console.warn('SW fail:', err); });
});
var deferredPrompt = null;
var installBtn = null;
window.addEventListener('beforeinstallprompt', function (e) {
e.preventDefault();
deferredPrompt = e;
if (installBtn) return;
installBtn = document.createElement('button');
installBtn.textContent = '📱 Установить приложение';
installBtn.id = 'mypwa-install-btn';
installBtn.style.cssText = 'position:fixed;bottom:20px;right:20px;padding:12px 18px;border-radius:30px;background:#000;color:#fff;border:none;cursor:pointer;z-index:9999;box-shadow:0 4px 12px rgba(0,0,0,.2);font-size:14px;font-family:inherit;';
installBtn.addEventListener('click', function () {
if (!deferredPrompt) return;
deferredPrompt.prompt();
deferredPrompt.userChoice.finally(function () {
deferredPrompt = null;
if (installBtn) { installBtn.remove(); installBtn = null; }
});
});
document.body.appendChild(installBtn);
});
window.addEventListener('appinstalled', function () {
if (installBtn) { installBtn.remove(); installBtn = null; }
});
})();
</script>
<?php
} );
/* ---------- АДМИНКА ---------- */
add_action( 'admin_menu', function () {
add_menu_page( 'MyPWA', 'MyPWA', 'manage_options', 'mypwa', 'mypwa_admin_page', 'dashicons-smartphone', 80 );
} );
add_action( 'admin_init', function () {
foreach ( [ 'name', 'short_name', 'theme_color', 'background_color', 'icon', 'screenshot' ] as $f ) {
register_setting( 'mypwa_group', 'mypwa_' . $f );
}
} );
function mypwa_admin_page() {
?>
<div class="wrap">
<h1>MyPWA — настройки</h1>
<form method="post" action="options.php">
<?php settings_fields( 'mypwa_group' ); ?>
<table class="form-table">
<tr><th>Название приложения</th><td><input type="text" name="mypwa_name" class="regular-text" value="<?php echo esc_attr( get_option( 'mypwa_name', get_bloginfo( 'name' ) ) ); ?>"></td></tr>
<tr><th>Короткое имя</th><td><input type="text" name="mypwa_short_name" class="regular-text" value="<?php echo esc_attr( get_option( 'mypwa_short_name', get_bloginfo( 'name' ) ) ); ?>"></td></tr>
<tr><th>URL иконки (512×512)</th><td><input type="text" name="mypwa_icon" class="regular-text" value="<?php echo esc_attr( get_option( 'mypwa_icon', '' ) ); ?>"></td></tr>
<tr><th>URL скриншота (1080×1920)</th><td><input type="text" name="mypwa_screenshot" class="regular-text" value="<?php echo esc_attr( get_option( 'mypwa_screenshot', '' ) ); ?>"></td></tr>
<tr><th>Theme color</th><td><input type="color" name="mypwa_theme_color" value="<?php echo esc_attr( get_option( 'mypwa_theme_color', '#000000' ) ); ?>"></td></tr>
<tr><th>Background color</th><td><input type="color" name="mypwa_background_color" value="<?php echo esc_attr( get_option( 'mypwa_background_color', '#ffffff' ) ); ?>"></td></tr>
</table>
<?php submit_button(); ?>
</form>
<hr>
<p><strong>Проверка:</strong>
<a href="https://web.dev/measure/" target="_blank">web.dev/measure</a> ·
<a href="<?php echo esc_url( home_url( '/?mypwa_manifest=1' ) ); ?>" target="_blank">manifest.json</a> ·
<a href="<?php echo esc_url( home_url( '/?mypwa_sw=1' ) ); ?>" target="_blank">sw.js</a>
</p>
</div>
<?php
}
Шпаргалка: что проверять, если не работает
Симптом Причина
Кнопка установки не появляется в Chrome Нужен HTTPS + взаимодействие с сайтом (клик) + ожидание ~30 сек
Яндекс открывает с адресной строкой Ограничение Яндекса, не баг. PWA работает только в Chrome / Safari / Firefox
Manifest не грузится Проверить ?mypwa_manifest=1 напрямую
SW не регистрируется Проверить ?mypwa_sw=1 и заголовок Service-Worker-Allowed: /
iOS не показывает баннер установки Это норма. На iPhone — «Поделиться» → «На экран Домой»
Где что лежит
Файл: wp-content/plugins/mypwa.php
Настройки в БД: mypwa_name, mypwa_icon, mypwa_theme_color и т.д.
Чтобы полностью удалить
Деактивировать и удалить плагин в админке
Опционально: удалить опции из БД
Service Worker в браузерах пользователей отключится сам через ~24 часа
sql
DELETE FROM wp_options WHERE option_name LIKE 'mypwa_%';