PluginProbe
Buttonizer – Floating Menus, Sticky Buttons, & Popup Builder / 3.6.0
Buttonizer – Floating Menus, Sticky Buttons, & Popup Builder v3.6.0
3.6.0 3.5.0 trunk 1.0.10 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.0.6.1 1.0.7 1.0.8 1.0.9 1.1 1.1.1 1.2 1.3 1.4 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.5 1.5.1 All 110 releases
buttonizer-multifunctional-button / app / Migration / Adapters / ChatButton.php

ChatButton.php in Buttonizer – Floating Menus, Sticky Buttons, & Popup Builder 3.6.0, at app/Migration/Adapters/ChatButton.php

215 lines 7.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /*
3 * SOFTWARE LICENSE INFORMATION
4 *
5 * Copyright (c) 2017 Buttonizer, all rights reserved.
6 *
7 * This file is part of Buttonizer
8 *
9 * For detailed information regarding to the licensing of
10 * this software, please review the license.txt or visit:
11 * https://buttonizer.pro/license/
12 */
13
14 namespace Buttonizer\Migration\Adapters;
15
16 use Buttonizer\Core\PluginConfig;
17 use Buttonizer\Migration\ConnectionAdopter;
18 use Buttonizer\Migration\ModuleLoader;
19
20 # No script kiddies
21 defined('ABSPATH') or die('No script kiddies please!');
22
23 /**
24 * Fits the Chat Button module into Buttonizer without editing it.
25 *
26 * The module under modules/chat-button/ is a byte-for-byte copy of the plugin
27 * it came from, so it still registers a top-level menu and still links to that
28 * plugin's own pages. Everything that has to bend lives here instead, using the
29 * hooks the module already provides.
30 *
31 * Keeping the copy untouched is what makes it re-copyable: when the acquired
32 * plugin ships a new version, the folder is replaced wholesale and only this
33 * file may need attention.
34 */
35 class ChatButton
36 {
37 /**
38 * Called right after the module is loaded, before any hook has fired.
39 */
40 public static function attach(): void
41 {
42 // The module's own bridge to the "new version" points at the acquired
43 // plugin's dashboard, which is deactivated by the time we serve this,
44 // and on the way there it turns the module off — taking the user's
45 // buttons off the site with no way back. Same button, our handler.
46 remove_action('admin_init', 'try_new_version');
47 add_action('admin_init', [self::class, 'handleTryNewVersion']);
48
49 add_action('admin_menu', [self::class, 'arrangeMenu'], 999);
50
51 // The plugin this user came from had no admin bar entry, and the one
52 // Buttonizer adds only leads to a dashboard they cannot see. Checked
53 // by connection and not by hostMenuHidden(), which is admin-only
54 // while the bar also renders on the site.
55 add_action('admin_bar_menu', [self::class, 'removeAdminBar'], 101);
56
57 if (ModuleLoader::hostMenuHidden()) {
58 add_filter('plugin_action_links_' . PluginConfig::baseName(), [self::class, 'pluginActionLinks'], 999);
59 }
60 }
61
62 /**
63 * Drop Buttonizer's admin bar node; its children go with it.
64 */
65 public static function removeAdminBar(\WP_Admin_Bar $bar): void
66 {
67 if (ConnectionAdopter::isTargetConnected()) {
68 return;
69 }
70
71 $bar->remove_node(PluginConfig::name());
72 }
73
74 /**
75 * Replace the dashboard links on the plugins screen with the one the
76 * acquired plugin used to show. The originals all point at Buttonizer's
77 * own page, which redirects to the module anyway, losing the route.
78 *
79 * @param string[] $actions
80 * @return string[]
81 */
82 public static function pluginActionLinks(array $actions): array
83 {
84 $own = admin_url('admin.php?page=' . PluginConfig::pageSlug() . '#/');
85
86 $actions = array_filter($actions, function ($link) use ($own) {
87 return strpos($link, $own) === false;
88 });
89
90 $actions[] = '<a href="' . admin_url('admin.php?page=contact_vr') . '">' . esc_html__('Settings', 'buttonizer-multifunctional-button') . '</a>';
91
92 return $actions;
93 }
94
95 /**
96 * Send "Try now" to Buttonizer instead of to a plugin that is gone.
97 *
98 * Nothing is switched off on the way: the old buttons keep rendering until
99 * the user actually sets Buttonizer up.
100 */
101 public static function handleTryNewVersion(): void
102 {
103 if (
104 !current_user_can(is_multisite() ? 'manage_options' : 'activate_plugins') ||
105 !isset($_GET['page'], $_GET['try_new_version']) ||
106 $_GET['page'] !== 'contact_vr_setting' ||
107 $_GET['try_new_version'] !== 'yes'
108 ) {
109 return;
110 }
111
112 wp_safe_redirect(add_query_arg(
113 ModuleLoader::OWN_DASHBOARD_PARAM,
114 1,
115 admin_url('admin.php?page=' . PluginConfig::pageSlug())
116 ));
117 exit;
118 }
119
120 /**
121 * Decide which of the two menus the user sees.
122 *
123 * Runs late, after the module registered its own top-level entry:
124 *
125 * - Buttonizer has nothing of its own to show → it steps out of the
126 * sidebar and hands its name over to the module's menu, which keeps
127 * every screen underneath exactly where it was.
128 * - Buttonizer is in use → its menu stays and the module's screens move
129 * under it, so there is one entry instead of two.
130 */
131 public static function arrangeMenu(): void
132 {
133 if (ModuleLoader::hostMenuHidden()) {
134 self::adoptMenu(remove_menu_page(PluginConfig::pageSlug()));
135
136 return;
137 }
138
139 // Re-parent: the page stays registered, so its URL and the tabs the
140 // screens navigate with keep working.
141 remove_menu_page('contact_vr');
142
143 add_submenu_page(
144 PluginConfig::pageSlug(),
145 'Button contact VR',
146 'Button contact',
147 'administrator',
148 'contact_vr',
149 'pzf_settings_page'
150 );
151 }
152
153 /**
154 * Put Buttonizer's name on the menu the module registered.
155 *
156 * The user was asked to move to Buttonizer and said yes, so a sidebar
157 * still headed "Button contact" reads as if nothing happened. The browser
158 * tab goes with it, for the same reason.
159 *
160 * Only the top-level entry changes: WordPress copied the submenu off it
161 * back when the module registered its first child, long before this runs,
162 * so the links underneath stay worded exactly as the plugin worded them.
163 *
164 * @param array|false $own Buttonizer's own menu entry, as removed.
165 */
166 private static function adoptMenu($own): void
167 {
168 // Nothing was taken away, so there is nothing to take the name from
169 if (!is_array($own)) {
170 return;
171 }
172
173 foreach ($GLOBALS['menu'] as $position => $item) {
174 if (($item[2] ?? null) !== 'contact_vr') {
175 continue;
176 }
177
178 // Sidebar label, page title, icon
179 $GLOBALS['menu'][$position][0] = $own[0];
180 $GLOBALS['menu'][$position][3] = $own[0];
181 $GLOBALS['menu'][$position][6] = $own[6] ?? '';
182
183 break;
184 }
185
186 self::adoptPageTitle($own[0]);
187 }
188
189 /**
190 * Rename the entry the browser tab actually reads.
191 *
192 * WordPress treats a top-level page that has children as one of its own
193 * children, and takes the title from the copy it made of the parent — not
194 * from the parent itself. Renaming the menu alone leaves the old product
195 * name in the tab.
196 *
197 * The label in that same copy is what the sidebar shows underneath, and it
198 * stays as the plugin wrote it.
199 *
200 * @param string $title Name to show in the browser tab.
201 */
202 private static function adoptPageTitle(string $title): void
203 {
204 foreach ($GLOBALS['submenu']['contact_vr'] ?? [] as $position => $item) {
205 if (($item[2] ?? null) !== 'contact_vr') {
206 continue;
207 }
208
209 $GLOBALS['submenu']['contact_vr'][$position][3] = $title;
210
211 return;
212 }
213 }
214 }
215