PluginProbe
The Innovative Form Builder – IvyForms / 1.5
The Innovative Form Builder – IvyForms v1.5
1.5.1 1.5 1.4.1 1.4 trunk 0.1.2 0.2 0.2.1 0.3 0.3.1 0.4 0.5 0.6 0.6.1 0.6.1-backup 0.6.1.1 0.7 0.8 0.8.1 0.8.2 0.9 0.9.1 1.0 1.1 1.1.1 All 27 releases
← All changes | backend/src/Plugin/Plugin.php +138 -149 0.4 → 1.5 View file →
@@ -3,34 +3,32 @@
3 3 /**
4 4 * Plugin Loader.
5 5 *
6 6 * @package IvyForms
7 - * @since 0.0.1
7 + * @since 0.1.0
8 8 */
9 9
10 10 namespace IvyForms\Plugin;
11 11
12 -// phpcs:disable PSR1.Files.SideEffects
13 -if (!defined('ABSPATH')) {
14 - exit; // Exit if accessed directly
15 -}
16 -
17 -use IvyForms\Vendor\DI\Container;
18 -use IvyForms\Vendor\DI\DependencyException;
19 -use IvyForms\Vendor\DI\NotFoundException;
20 12 use Exception;
21 13 use IvyForms\Common\Exceptions\InvalidArgumentException;
14 +use IvyForms\Common\Exceptions\ValidationException;
22 15 use IvyForms\Routes\Routes;
23 16 use IvyForms\Services\InstallActions\ActivationDatabaseHook;
24 -use IvyForms\Services\InstallActions\ActivationMultisite;
25 -use IvyForms\Services\InstallActions\ActivationNewSiteMultisite;
26 -use IvyForms\Services\InstallActions\ActivationSettingsHook;
27 -use IvyForms\Services\InstallActions\DeleteDatabaseHook;
28 -use IvyForms\Services\InstallActions\DeletionMultisite;
17 +use IvyForms\Services\Integrations\Elementor\IvyFormsElementorLoader;
18 +use IvyForms\Services\Integrations\Gutenberg\Blocks\GutenbergBlock;
19 +use IvyForms\Services\Integrations\IntegrationService;
29 20 use IvyForms\Services\Menu\MenuManager;
21 +use IvyForms\Services\Payment\PaymentCspHeaders;
30 22 use IvyForms\Services\Preview\PreviewService;
31 23 use IvyForms\Services\Settings\SettingsService;
24 +use IvyForms\Services\Shortcode\Helpers\ShortcodeHelper;
32 25 use IvyForms\Services\Shortcode\ShortcodeService;
26 +use IvyForms\Services\Usage\UsageTrackingService;
27 +use IvyForms\Vendor\DI\Container;
28 +use IvyForms\Vendor\DI\ContainerBuilder;
29 +use IvyForms\Vendor\DI\DependencyException;
30 +use IvyForms\Vendor\DI\NotFoundException;
33 31
34 32 /**
35 33 * Plugin
36 34 */
@@ -40,8 +38,9 @@
40 38 * Instance
41 39 */
42 40 private static ?object $instance = null;
43 41
42 + private ContainerBuilder $builder;
44 43 /**
45 44 * Container
46 45 */
47 46 public ?Container $container = null;
@@ -56,12 +55,12 @@
56 55 *
57 56 * @return object initialized object of class.
58 57 * @throws Exception
59 58 */
60 - public static function getInstance(Container $container): ?object
59 + public static function getInstance(): ?object
61 60 {
62 61 if (null === self::$instance) {
63 - self::$instance = new self($container);
62 + self::$instance = new self();
64 63 }
65 64 return self::$instance;
66 65 }
67 66
@@ -68,13 +67,27 @@
68 67 /**
69 68 * Constructor
70 69 *
71 70 * @throws Exception
72 - * @since 0.0.1
71 + * @since 0.1.0
73 72 */
74 - public function __construct(Container $container)
73 + public function __construct()
75 74 {
76 - $this->container = $container;
75 + $this->builder = new ContainerBuilder();
76 + $this->builder->addDefinitions(IVYFORMS_PATH . '/backend/src/Config/repository.php');
77 + $this->builder->addDefinitions(IVYFORMS_PATH . '/backend/src/Config/services.php');
78 +
79 + /**
80 + * Allow to hook into container before build
81 + * @since 0.1.0
82 + *
83 + * Arguments:
84 + * - ContainerBuilder $builder The IvyForms DI container builder (base)
85 + */
86 + do_action('ivyforms/boot/extend_container_builder', $this->builder);
87 +
88 + $this->container = $this->builder->build();
89 +
77 90 $this->settingsService = $this->container->get(SettingsService::class);
78 91
79 92 /**
80 93 * The code that runs during plugin activation
@@ -80,26 +93,39 @@
80 93 * The code that runs during plugin activation
81 94 */
82 95 register_activation_hook(
83 96 IVYFORMS_FILE,
84 - [ self::class, 'activation' ]
97 + [ PluginInstallLifecycle::class, 'activation' ]
85 98 );
86 99 register_activation_hook(
87 100 IVYFORMS_FILE,
88 - [ self::class, 'activationSettings' ]
101 + [ PluginInstallLifecycle::class, 'activationSettings' ]
89 102 );
90 103
91 104 /**
92 105 * The code that runs during plugin deactivation
93 106 */
107 + register_deactivation_hook(
108 + IVYFORMS_FILE,
109 + [ PluginInstallLifecycle::class, 'deactivation' ]
110 + );
111 +
112 + /**
113 + * The code that runs when plugin is deleted
114 + */
94 115 register_uninstall_hook(
95 116 IVYFORMS_FILE,
96 - [ self::class, 'deletion']
117 + [ PluginInstallLifecycle::class, 'deletion']
97 118 );
98 119
99 120 /** Init load */
100 121 add_action('plugins_loaded', [ $this, 'init' ]);
101 122
123 + add_action('init', [PluginInstallLifecycle::class, 'maybeEnsureAdministratorCapabilities'], 0);
124 +
125 + /** Load translations at init action (WordPress 6.7+ requirement) */
126 + add_action('init', [ $this, 'loadTranslations' ]);
127 +
102 128 /** Register API calls */
103 129 add_action('rest_api_init', [$this, 'registerRoutes']);
104 130
105 131 /** Isolate API calls */
@@ -106,54 +132,18 @@
106 132 add_action('wp_ajax_ivyforms_api', [ $this, 'registerRoutes' ]);
107 133 add_action('wp_ajax_nopriv_ivyforms_api', [ $this, 'registerRoutes' ]);
108 134
109 135 /** Activation hook for new site on multisite setup */
110 - add_action('wpmu_new_blog', [ $this, 'initNewSite' ]);
136 + add_action('wpmu_new_blog', [ PluginInstallLifecycle::class, 'initNewSite' ]);
111 137
112 138 add_filter('wp_script_attributes', ['IvyForms\Services\Shortcode\ShortcodeService', 'addScriptAttribute']);
113 139
114 - add_action('admin_init', [$this, 'adminInit']);
115 - add_filter('admin_body_class', [$this, 'addAdminBodyClass']);
140 + // Register admin hooks via AdminHooks class
141 + $adminHooks = new AdminHooks($this->settingsService);
142 + $adminHooks->register();
116 143 }
117 144
118 145 /**
119 - * Handle admin initialization tasks
120 - *
121 - * @return void
122 - */
123 - public function adminInit(): void
124 - {
125 - $this->checkVersionAndHandleActivation();
126 -
127 - $this->removeAdminNotices();
128 - }
129 -
130 - /**
131 - * Check a plugin version and handle activation/deactivation if needed
132 - *
133 - * @return void
134 - */
135 - private function checkVersionAndHandleActivation(): void
136 - {
137 - if (!function_exists('activate_plugin')) {
138 - // @phpstan-ignore requireOnce.fileNotFound
139 - require_once ABSPATH . 'wp-admin/includes/plugin.php';
140 - }
141 -
142 - $settingsService = new SettingsService();
143 -
144 - $currentVersion = IVYFORMS_VERSION;
145 - $savedVersion = $settingsService->getSetting('general', 'version');
146 -
147 - if ($savedVersion !== $currentVersion) {
148 - deactivate_plugins(IVYFORMS_PLUGIN_SLUG); // @phpstan-ignore argument.type
149 - activate_plugin(IVYFORMS_PLUGIN_SLUG); // @phpstan-ignore argument.type
150 -
151 - $settingsService->setSetting('general', 'version', $currentVersion);
152 - }
153 - }
154 -
155 - /**
156 146 * @throws DependencyException
157 147 * @throws NotFoundException
158 148 */
159 149 public function registerRoutes(): void
@@ -162,137 +152,136 @@
162 152 Routes::registerRoutes($this->container);
163 153 }
164 154
165 155 /**
166 - * Remove admin notices on IvyForms admin pages
156 + * Init
157 + * @return void
158 + * @throws ValidationException|InvalidArgumentException
167 159 */
168 - public function removeAdminNotices(): void
160 + public function init(): void
169 161 {
170 - // Check if we're on an IvyForms admin page
171 - if ($this->isIvyFormsAdminPage()) {
172 - // Remove all admin notices
173 - remove_all_actions('admin_notices');
174 - remove_all_actions('all_admin_notices');
175 - // For plugins using user_admin_notices or network_admin_notices
176 - remove_all_actions('user_admin_notices');
177 - remove_all_actions('network_admin_notices');
178 - wp_register_style(
179 - 'ivyforms_admin_global',
180 - IVYFORMS_URL . 'frontend/css/global-admin.css',
181 - array(),
182 - IVYFORMS_VERSION
183 - );
184 - wp_enqueue_style('ivyforms_admin_global');
185 - }
162 + new PreviewService();
163 + $this->initIntegrationService();
164 + $this->initMenuManager();
165 + $this->registerShortcode();
166 + PaymentCspHeaders::register();
167 + $this->registerGutenbergBlock();
168 + $this->registerElementorWidget();
169 + $this->initUsageTrackingService();
186 170 }
187 171
188 172 /**
189 - * Check if current page is an IvyForms admin page
173 + * Initialize integration service
190 174 *
191 - * @SuppressWarnings(PHPMD)
192 - *
193 - * @return bool
175 + * @return void
194 176 */
195 - private function isIvyFormsAdminPage(): bool
177 + private function initIntegrationService(): void
196 178 {
197 - if (!is_admin()) {
198 - return false;
179 + try {
180 + /** @var IntegrationService $integrationService */
181 + $integrationService = $this->container->get(IntegrationService::class);
182 + $integrationService->init();
183 + } catch (DependencyException | NotFoundException $e) {
184 + if (defined('WP_DEBUG') && WP_DEBUG) {
185 + error_log('Integration service error: ' . $e->getMessage());
186 + }
199 187 }
200 - // Adjust this based on your page's actual slug/identifier
201 - return (isset($_GET['page']) && strpos($_GET['page'], 'ivyforms') !== false);
202 188 }
203 189
204 190 /**
205 - * @param bool $networkWide
191 + * Initialize usage tracking service
192 + *
193 + * @return void
206 194 */
207 - public static function activation(bool $networkWide): void
195 + private function initUsageTrackingService(): void
208 196 {
209 - //Network activation
210 - if ($networkWide && function_exists('is_multisite') && is_multisite()) {
211 - ActivationMultisite::init();
197 + try {
198 + /** @var UsageTrackingService $usageTrackingService */
199 + $usageTrackingService = $this->container->get(UsageTrackingService::class);
200 + $usageTrackingService->init();
201 + } catch (DependencyException | NotFoundException $e) {
202 + if (defined('WP_DEBUG') && WP_DEBUG) {
203 + error_log('Usage tracking service error: ' . $e->getMessage());
204 + }
212 205 }
213 -
214 - ActivationDatabaseHook::init();
215 206 }
216 207
217 208 /**
218 - * @param int $siteId
209 + * Initialize menu manager
210 + *
211 + * @return void
219 212 */
220 - public static function initNewSite(int $siteId): void
213 + private function initMenuManager(): void
221 214 {
222 - ActivationNewSiteMultisite::init($siteId);
215 + try {
216 + /** @var MenuManager $menuManager*/
217 + $menuManager = $this->container->get(MenuManager::class);
218 + // Register the admin menus and submenus using the 'admin_menu' hook
219 + $menuManager->registerMenus();
220 + } catch (DependencyException | NotFoundException $e) {
221 + if (defined('WP_DEBUG') && WP_DEBUG) {
222 + error_log('Menu error: ' . $e->getMessage());
223 + }
224 + }
223 225 }
224 226
225 227 /**
226 - * @throws Exception
228 + * Register shortcode
229 + *
230 + * @return void
227 231 */
228 - public static function activationSettings(): void
232 + private function registerShortcode(): void
229 233 {
230 - ActivationSettingsHook::init();
234 + if (is_admin()) {
235 + return;
236 + }
237 +
238 + add_action('wp_enqueue_scripts', [ShortcodeHelper::class, 'registerFrontendStyleHandles'], 1);
239 +
240 + add_shortcode('ivyforms', function ($atts = []) {
241 + return ShortcodeService::shortcodeHandler($atts);
242 + });
231 243 }
232 244
233 245 /**
234 - * Uninstall function when plugin is deleted
235 - * @throws InvalidArgumentException
246 + * Register Gutenberg block
247 + *
248 + * @return void
236 249 */
237 - public static function deletion(): void
250 + private function registerGutenbergBlock(): void
238 251 {
239 - $settingsService = new SettingsService();
252 + if (!function_exists('register_block_type')) {
253 + return;
254 + }
240 255
241 - if ($settingsService->getSetting('activation', 'deleteTables')) {
242 - //Network deletion
243 - if (
244 - function_exists('is_multisite') &&
245 - is_multisite()
246 - ) {
247 - DeletionMultisite::delete();
248 - }
249 -
250 - DeleteDatabaseHook::delete();
251 - }
256 + add_action('init', [GutenbergBlock::class, 'register']);
252 257 }
253 258
254 259 /**
255 - * Init
260 + * Register Elementor widget
261 + *
256 262 * @return void
257 263 */
258 - public function init(): void
264 + private function registerElementorWidget(): void
259 265 {
260 -
261 - new PreviewService();
262 -
263 - try {
264 - /** @var MenuManager $menuManager*/
265 - $menuManager = $this->container->get(MenuManager::class);
266 - // Register the admin menus and submenus using the 'admin_menu' hook
267 - $menuManager->registerMenus();
268 - } catch (DependencyException | NotFoundException $e) {
269 - if (defined('WP_DEBUG') && WP_DEBUG) {
270 - error_log('Menu error: ' . $e->getMessage());
271 - }
266 + if (!defined('ELEMENTOR_VERSION')) {
267 + return;
272 268 }
273 269
274 - if (!is_admin()) {
275 - add_shortcode('ivyforms', function ($atts = []) {
276 - return ShortcodeService::shortcodeHandler($atts);
277 - });
278 - }
270 + IvyFormsElementorLoader::instance();
279 271 }
272 +
280 273 /**
281 - * Add admin body class
274 + * Load plugin translations
275 + * Called on 'init' action to comply with WordPress 6.7+ requirements
282 276 *
283 - * @param string $classes
284 - * @return string
277 + * @return void
285 278 */
286 - public function addAdminBodyClass(string $classes): string
279 + public function loadTranslations(): void
287 280 {
288 - if ($this->settingsService === null) {
289 - return $classes;
290 - }
291 -
292 - if ($this->settingsService->getSetting('general', 'fullscreen')) {
293 - $classes .= ' ivyforms-fullscreen-mode ';
294 - }
295 -
296 - return $classes;
281 + load_plugin_textdomain(
282 + 'ivyforms',
283 + false,
284 + dirname(plugin_basename(IVYFORMS_FILE)) . '/languages/' . get_locale() . '/'
285 + );
297 286 }
298 287 }