{"id":11083,"date":"2026-05-26T02:30:04","date_gmt":"2026-05-25T18:30:04","guid":{"rendered":"https:\/\/aeosub.com\/rafaelmarreca-push-dispatch\/"},"modified":"2026-05-26T02:30:04","modified_gmt":"2026-05-25T18:30:04","slug":"rafaelmarreca-push-dispatch","status":"publish","type":"post","link":"https:\/\/aeosub.com\/zh\/rafaelmarreca-push-dispatch\/","title":{"rendered":"RafaelMarreca Push Dispatch for Firebase Cloud Messaging"},"content":{"rendered":"<div class=\"plugin-info-card\" style=\"border: 1px solid #e2e8f0;border-radius: 10px;overflow: hidden;margin-bottom: 30px;font-family: -apple-system, system-ui, sans-serif;background: #fff\">\n<table style=\"width: 100%;border-collapse: collapse;font-size: 14px\">\n<tr style=\"border-bottom: 1px solid #edf2f7\">\n<th style=\"padding: 15px 20px;text-align: left;width: 35%;color: #4a5568;background: #fcfcfc\"><img decoding=\"async\" src=\"https:\/\/s.w.org\/plugins\/geopattern-icon\/rafaelmarreca-push-dispatch.svg\" style=\"width: 40px;height: 40px;border-radius: 6px;margin-right: 12px;vertical-align: middle\"> Developer<\/th>\n<td style=\"padding: 15px 20px;font-weight: 500\"><a href=\"https:\/\/profiles.wordpress.org\/rafael145a\/\" target=\"_blank\" rel=\"noopener\">rafael145a<\/a><\/td>\n<\/tr>\n<tr style=\"border-bottom: 1px solid #edf2f7\">\n<th style=\"padding: 12px 20px;text-align: left;color: #4a5568;background: #fcfcfc\">Version<\/th>\n<td style=\"padding: 12px 20px\">v1.0.1<\/td>\n<\/tr>\n<tr style=\"border-bottom: 1px solid #edf2f7\">\n<th style=\"padding: 12px 20px;text-align: left;color: #4a5568;background: #fcfcfc\">Active Installs<\/th>\n<td style=\"padding: 12px 20px\">0 +<\/td>\n<\/tr>\n<tr style=\"border-bottom: 1px solid #edf2f7\">\n<th style=\"padding: 12px 20px;text-align: left;color: #4a5568;background: #fcfcfc\">Requires \/ Tested<\/th>\n<td style=\"padding: 12px 20px\">5.8 \/ 7.0<\/td>\n<\/tr>\n<tr style=\"border-bottom: 1px solid #edf2f7\">\n<th style=\"padding: 12px 20px;text-align: left;color: #4a5568;background: #fcfcfc\">Last Updated<\/th>\n<td style=\"padding: 12px 20px\">2026-05-25 5:56pm GMT<\/td>\n<\/tr>\n<tr>\n<th style=\"padding: 12px 20px;text-align: left;color: #4a5568;background: #fcfcfc\">Official Link<\/th>\n<td style=\"padding: 12px 20px\"><a href=\"https:\/\/wordpress.org\/plugins\/rafaelmarreca-push-dispatch\/\" target=\"_blank\" style=\"text-decoration: none;color: #4a3bca;font-weight: bold\" rel=\"noopener\">View Details \u2192<\/a><\/td>\n<\/tr>\n<\/table><\/div>\n<div class=\"plugin-short-desc\" style=\"margin: 20px 0;padding: 12px 15px;background: #f9fafb;border-left: 4px solid #4a3bca;border-radius: 6px;font-style: italic;color: #4a5568\">Send push notifications to mobile apps via Google&#039;s Firebase Cloud Messaging \u2014 on post publish or via a notification composer.<\/div>\n<p><strong>RafaelMarreca Push Dispatch<\/strong> connects your WordPress site to your mobile app by sending notifications through Google&#8217;s Firebase Cloud Messaging (FCM HTTP v1) service. No PHP SDK, no Guzzle, no external PHP dependencies \u2014 just the WordPress HTTP API and the OpenSSL extension.<\/p>\n<h4>How it works<\/h4>\n<ul>\n<li>Uses <strong>topic subscriptions<\/strong> \u2014 your mobile app calls <code>subscribeToTopic()<\/code> for each topic it wants to receive. No device tokens are stored, no PII is collected, no extra database tables are created.<\/li>\n<li>When a post is published, the <strong>primary category<\/strong> determines the topic name (configurable via Settings <span aria-hidden=\"true\" class=\"wp-exclude-emoji\">\u2192<\/span> RafaelMarreca Push Dispatch).<\/li>\n<li>A dedicated <strong>notification composer<\/strong> (custom post type) lets you send manual push notifications with a custom title, body, topic, and optional deep link \u2014 without creating a real post.<\/li>\n<\/ul>\n<h4>Features<\/h4>\n<ul>\n<li>OAuth2 JWT authentication (RS256) for FCM HTTP v1<\/li>\n<li>Automatic push on post publish, mapped by category<\/li>\n<li>Manual notification composer with live phone preview and character counters<\/li>\n<li>Deep link support (any custom URL scheme)<\/li>\n<li>OAuth2 access token cached for 55 minutes to minimise round-trips<\/li>\n<li>Service account JSON stored outside the database with <code>.htaccess<\/code> deny + chmod 600<\/li>\n<li>Idempotent dispatch \u2014 republishing never resends<\/li>\n<\/ul>\n<h4>Requirements<\/h4>\n<ul>\n<li>A Firebase project with Cloud Messaging enabled<\/li>\n<li>A Firebase service account JSON (downloaded from the Firebase Console)<\/li>\n<li>PHP <code>openssl<\/code> extension (bundled with most hosts)<\/li>\n<li>Your mobile app must call <code>subscribeToTopic()<\/code> for each topic<\/li>\n<\/ul>\n<h3>Disclaimer<\/h3>\n<p>Firebase, Firebase Cloud Messaging and Google are trademarks of Google LLC. This plugin is an independent, third-party integration and is not affiliated with, endorsed by, or sponsored by Google LLC.<\/p>\n<h3>Service Account Setup<\/h3>\n<p>In the Firebase Console: \u2699 <strong>Project settings<\/strong> <span aria-hidden=\"true\" class=\"wp-exclude-emoji\">\u2192<\/span> <strong>Service accounts<\/strong> <span aria-hidden=\"true\" class=\"wp-exclude-emoji\">\u2192<\/span> <strong>Generate new private key<\/strong> <span aria-hidden=\"true\" class=\"wp-exclude-emoji\">\u2192<\/span> download the JSON <span aria-hidden=\"true\" class=\"wp-exclude-emoji\">\u2192<\/span> upload it in the plugin settings.<\/p>\n<p>The file is stored in <code>wp-content\/uploads\/rafaelmarreca-push-private\/<\/code> with <code>.htaccess<\/code> deny rules and chmod 600. It is never stored in the database.<\/p>\n<h3>Mobile App Setup<\/h3>\n<p>Your app needs to call <code>subscribeToTopic(getMessaging(), '&lt;topic-name&gt;')<\/code> to receive notifications for a given topic. The Firebase Cloud Messaging v1 API delivers to zero devices if no device is subscribed.<\/p>\n<p>Example (React Native \/ Firebase JS SDK):<br \/>\n    await messaging().subscribeToTopic(&#8216;all&#8217;);<\/p>\n<h3>External services<\/h3>\n<p>This plugin relies on two external services operated by Google LLC in order to deliver push notifications. Both are part of the <strong>Google Cloud \/ Firebase<\/strong> platform. The plugin will not send any data to them until you configure it with a Firebase service account JSON and either publish a post (with auto-send enabled), publish a notification via the composer, or click &#8220;Send test&#8221; on the settings page.<\/p>\n<h4>1. Google OAuth2 (oauth2.googleapis.com)<\/h4>\n<ul>\n<li><strong>What it is and what it is used for:<\/strong> Google&#8217;s OAuth2 token service. The plugin needs a short-lived access token to authenticate against Firebase Cloud Messaging. To obtain it, the plugin signs a JWT locally with the private key from your service account JSON and exchanges it for an access token.<\/li>\n<li><strong>When data is sent:<\/strong> Once when the cached access token expires (every 55 minutes) and on the first send action.<\/li>\n<li><strong>What data is sent:<\/strong> A POST request to <code>https:\/\/oauth2.googleapis.com\/token<\/code> containing the OAuth2 <code>urn:ietf:params:oauth:grant-type:jwt-bearer<\/code> grant and a signed JWT. The JWT contains your service account&#8217;s <code>client_email<\/code>, the scope <code>https:\/\/www.googleapis.com\/auth\/firebase.messaging<\/code>, the audience URL, and issued-at\/expiration timestamps. <strong>No WordPress user data, no post content, and no visitor data is sent.<\/strong><\/li>\n<li><strong>Provider:<\/strong> Google LLC<\/li>\n<li><strong>Terms of service:<\/strong> https:\/\/policies.google.com\/terms<\/li>\n<li><strong>Privacy policy:<\/strong> https:\/\/policies.google.com\/privacy<\/li>\n<\/ul>\n<h4>2. Firebase Cloud Messaging (fcm.googleapis.com)<\/h4>\n<ul>\n<li><strong>What it is and what it is used for:<\/strong> Google&#8217;s push notification delivery service. The plugin uses the FCM HTTP v1 API to publish a notification to a topic that your mobile app has subscribed to.<\/li>\n<li><strong>When data is sent:<\/strong> Every time a notification is dispatched \u2014 that is, when a post is published (with the auto-send option enabled), when a notification is published via the &#8220;Notifications&#8221; composer, or when the administrator clicks &#8220;Send test&#8221; on the settings page.<\/li>\n<li><strong>What data is sent:<\/strong> A POST request to <code>https:\/\/fcm.googleapis.com\/v1\/projects\/{your_project_id}\/messages:send<\/code> containing: the destination topic name (e.g. &#8220;news&#8221;), the notification title (max 65 chars) and body (max 140 chars) you typed or that were extracted from your post, an optional deep link URL (when set in the composer), and the post ID \/ slug \/ category ID as plain identifiers in the data payload. <strong>No WordPress user data, no IP addresses, and no device identifiers are sent.<\/strong><\/li>\n<li><strong>Provider:<\/strong> Google LLC<\/li>\n<li><strong>Terms of service:<\/strong> https:\/\/policies.google.com\/terms<\/li>\n<li><strong>Firebase-specific terms:<\/strong> https:\/\/firebase.google.com\/terms<\/li>\n<li><strong>Privacy policy:<\/strong> https:\/\/policies.google.com\/privacy<\/li>\n<\/ul>\n<p>By configuring the plugin with your Firebase service account JSON and publishing posts or notifications, you agree to the Google Terms of Service, the Firebase Terms of Service, and the Google Privacy Policy linked above.<\/p>","protected":false},"excerpt":{"rendered":"<p>Send push notifications to mobile apps via Google&#039;s Firebase Cloud Messaging \u2014 on post publish or via a notification composer.<\/p>","protected":false},"author":1,"featured_media":9317,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"inline_featured_image":false,"footnotes":""},"categories":[252],"tags":[2070,2071,1020,1906,2072,555],"class_list":["post-11083","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-trends","tag-cloud-messaging","tag-firebase","tag-mobile","tag-push-notifications","tag-topic","tag-wordpress-plugin"],"_links":{"self":[{"href":"https:\/\/aeosub.com\/zh\/wp-json\/wp\/v2\/posts\/11083","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/aeosub.com\/zh\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/aeosub.com\/zh\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/aeosub.com\/zh\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/aeosub.com\/zh\/wp-json\/wp\/v2\/comments?post=11083"}],"version-history":[{"count":0,"href":"https:\/\/aeosub.com\/zh\/wp-json\/wp\/v2\/posts\/11083\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/aeosub.com\/zh\/wp-json\/wp\/v2\/media\/9317"}],"wp:attachment":[{"href":"https:\/\/aeosub.com\/zh\/wp-json\/wp\/v2\/media?parent=11083"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/aeosub.com\/zh\/wp-json\/wp\/v2\/categories?post=11083"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/aeosub.com\/zh\/wp-json\/wp\/v2\/tags?post=11083"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}