PluginProbe ʕ •ᴥ•ʔ
ShopEngine Elementor WooCommerce Builder Addon – All in One WooCommerce Solution / 4.7.7
ShopEngine Elementor WooCommerce Builder Addon – All in One WooCommerce Solution v4.7.7
4.9.1 4.9.0 2.0.0 2.1.0 2.2.0 2.2.1 2.2.2 2.3.0 2.4.0 2.5.0 2.5.1 3.0.0 3.1.0 3.1.1 4.0.0 4.0.1 4.1.0 4.1.1 4.2.0 4.2.1 4.3.0 4.3.1 4.4.0 4.5.0 4.5.1 4.6.0 4.6.1 4.6.2 4.6.3 4.6.4 4.6.5 4.6.6 4.6.7 4.6.8 4.6.9 4.7.0 4.7.1 4.7.2 4.7.3 4.7.4 4.7.5 4.7.6 4.7.7 4.7.8 4.7.9 4.8.0 4.8.1 4.8.2 4.8.3 4.8.4 4.8.5 4.8.6 4.8.7 4.8.8 4.8.9 trunk 0.1.2-beta 0.1.3-beta 0.1.4-beta 1.0.0 1.1.0 1.1.1 1.1.2 1.1.3 1.2.0 1.2.1 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 1.4.0 1.4.1 1.5.0 1.5.1 1.6.0 1.6.1 1.7.0 1.8.0 1.8.1 1.9.0
shopengine / plugin.php
shopengine Last commit date
assets 1 year ago base 3 years ago compatibility 1 year ago core 1 year ago languages 1 year ago libs 1 year ago modules 1 year ago traits 3 years ago utils 1 year ago widgets 1 year ago woocommerce 1 year ago autoloader.php 4 years ago phpcs.xml 3 years ago plugin.php 1 year ago readme.txt 1 year ago shopengine.php 1 year ago
plugin.php
583 lines
1 <?php
2
3 namespace ShopEngine;
4
5 defined('ABSPATH') || exit;
6
7 use ShopEngine\Compatibility\Conflicts\Manifest as Conflict_Manifest;
8 use ShopEngine\Core\Builders\Base;
9 use ShopEngine\Compatibility\Migrations\LangMigration;
10 use ShopEngine\Core\Query_Modifier;
11 use ShopEngine\Core\Wc_Customizer\Register_Settings;
12 use ShopEngine\Core\Template_Cpt;
13 use ShopEngine\Libs\License\License_Route;
14 use ShopEngine\Libs\Rating\Rating;
15 use ShopEngine\Libs\Updater\Init as Updater;
16 use ShopEngine\Modules\Manifest as Module_Manifest;
17 use ShopEngine\Widgets\Manifest;
18
19
20 /**
21 * Plugin final Class.
22 * Handles dynamically loading classes only when needed. Check Elementor Plugin, Woocomerce Plugin Loaded or Install.
23 *
24 * @since 1.0.0
25 */
26 final class Plugin {
27
28 private static $instance;
29
30 /**
31 * __construct function
32 * @since 1.0.0
33 */
34 public function __construct() {
35 // load autoload method
36 Autoloader::run();
37 add_action( 'wp_ajax_shopengine_admin_action', [\ShopEngine\Utils\Util::class, 'shopengine_admin_action'] );
38 }
39
40 public function utils_url()
41 {
42 return $this->plugin_url() . 'utils/';
43 }
44 /**
45 * Public function init.
46 * call function for all
47 *
48 * @since 1.0.0
49 */
50 public function init() {
51
52 $error = false;
53
54 // init notice class
55 \Oxaim\Libs\Notice::init();
56
57 // check woocommerce plugin
58 if(!did_action('woocommerce_loaded')) {
59 add_action('admin_notices', [$this, 'missing_woocommerce']);
60
61 $error = true;
62 }
63
64 $check_elementor_version = false;
65
66 // Check if Elementor installed and activated.
67 if(!did_action('elementor/loaded')) {
68
69 if(!did_action('shopengine-gutenberg-addon/before_loaded')) {
70
71 add_action('admin_notices', [$this, 'missing_elementor']);
72
73 $error = true;
74 }
75 }
76
77 // Check for required Elementor version.
78 if(did_action('elementor/loaded') && defined('ELEMENTOR_VERSION') && !version_compare(ELEMENTOR_VERSION, '3.0.0', '>=')) {
79
80 add_action('admin_notices', [$this, 'failed_elementor_version']);
81
82 $error = true;
83 }
84
85 if($error) {
86 return;
87 }
88
89 add_filter("plugin_action_links_shopengine/shopengine.php", function ($links) {
90 $free = esc_html__("Go To Shopengine","shopengine");
91 $pro = esc_html__("Go To ShopenginePro","shopengine");
92
93 $custom_links[] = '<a title="' . $free . '" href="'.admin_url('edit.php?post_type=shopengine-template#getting-started').'" target="_blank">' . esc_html__('Settings', 'shopengine') . '</a>';
94
95 foreach ($custom_links as $custom_link):
96 array_unshift($links, $custom_link);
97 endforeach;
98
99 if (!is_plugin_active('shopengine-pro/shopengine-pro.php')) {
100 $links[] = '<a title="' . $pro . '" href="https://wpmet.com/plugin/shopengine/pricing/" style="color:#FCB214;font-weight:700" target="_blank" rel="noopener">' . esc_html__('Go Pro', 'shopengine') . '</a>';
101 }
102 return $links;
103 });
104
105 if(\ShopEngine\Utils\Util::get_settings( 'shopengine_user_consent_for_banner', 'true' ) == 'true'){
106
107 /**
108 * EmailKit Global Class initialization
109 *
110 */
111 if( !class_exists('EmailKit') && !did_action('edit_with_emailkit_loaded') && class_exists('\Wpmet\Libs\Emailkit') ) {
112
113 new \Wpmet\Libs\Emailkit();
114 }
115
116 /**
117 * MetForm get free templates promotional class initialization
118 *
119 */
120 if( !did_action('metform/after_load') && did_action('elementor/loaded') && class_exists('\Wpmet\Libs\Metform_Promo_Banner') ) {
121
122 new \Wpmet\Libs\Metform_Promo_Banner();
123 }
124 }
125
126
127 /**
128 * Routes initialization
129 *
130 */
131 new License_Route();
132
133 /**
134 * Run pro plugin updater here....
135 *
136 */
137 add_action('admin_init', function () {
138 if(class_exists('ShopEngine_Pro')) {
139 new Updater();
140 }
141 new \ShopEngine\Compatibility\Migrations\Direct_Checkout;
142 });
143
144
145 add_action('wp_loaded', function () {
146 /**
147 * migrate data
148 */
149 LangMigration::instance()->init();
150 });
151
152 // avoid themes for loading woocommerce functions
153 $avoid_themes = ['avada', 'woodmart', 'Avada', 'Woodmart'];
154
155 if( !in_array(get_template(), $avoid_themes) ) {
156 /**
157 * Ensuring woocommerce functions are loaded before theme is modifying those
158 *
159 */
160 require_once WC_ABSPATH . '/includes/wc-template-functions.php';
161 }
162
163
164 if(did_action('elementor/loaded')) {
165 // Load custom elementor controls
166 new \ShopEngine\Core\Elementor_Controls\Init();
167
168 //Loading the scripts and styles
169 add_action('elementor/editor/after_enqueue_styles', [$this, 'js_css_elementor']);
170 }
171
172
173 //Loading public scripts and styles
174 add_action('wp_enqueue_scripts', [$this, 'js_css_public']);
175
176 //woocommece theme support
177 if(!current_theme_supports('woocommerce')) {
178 add_theme_support('woocommerce');
179 add_theme_support('wc-product-gallery-zoom');
180 add_theme_support('wc-product-gallery-lightbox');
181 add_theme_support('wc-product-gallery-slider');
182 }
183
184
185 $filter_string = ''; // elementskit,metform-pro
186 $filter_string .= ((!in_array('elementskit/elementskit.php', apply_filters('active_plugins', get_option('active_plugins')))) ? '' : ',elementskit');
187 $filter_string .= (!class_exists('\MetForm\Plugin') ? '' : ',metform');
188 $filter_string .= (!class_exists('\MetForm_Pro\Plugin') ? '' : ',metform-pro');
189
190 #Registering new post-type & etc
191 Base::instance()->init();
192
193
194 Rating::instance('shopengine')
195 ->set_plugin( 'ShopEngine', 'https://wpmet.com/wordpress.org/rating/shopengine' )
196 ->set_rating_url( 'https://wordpress.org/support/plugin/shopengine/reviews/#new-post' )
197 ->set_plugin_logo( 'https://ps.w.org/shopengine/assets/icon-256x256.gif?rev=2505061', 'width:150px !important' )
198 ->set_priority( 11 )
199 ->set_first_appear_day( 7 )
200 ->set_condition( true )
201 ->call();
202
203 if ( is_admin() && \ShopEngine\Utils\Util::get_settings( 'shopengine_user_consent_for_banner', 'true' ) == 'true' ) {
204
205 /**
206 * Show WPMET stories widget in dashboard
207 */
208
209 \Wpmet\Libs\Stories::instance('shopengine')
210
211 ->set_filter($filter_string)
212 ->set_plugin('ShopEngine', 'https://wpmet.com/plugin/shopengine/')
213 ->set_api_url('https://api.wpmet.com/public/stories/')
214 ->call();
215
216 // banner
217 \Wpmet\Libs\Banner::instance('shopengine')
218 ->set_filter(ltrim($filter_string, ','))
219 ->set_api_url('https://api.wpmet.com/public/jhanda')
220 ->set_plugin_screens('edit-shopengine-template')
221 ->set_plugin_screens('edit-shopengine-template')
222 ->call();
223 }
224
225 $apps_img_path = \ShopEngine::plugin_url() . 'assets/images/apps-page/';
226 /**
227 * Show our plugins menu for others wpmet plugins
228 */
229 \ShopEngine\Wpmet\Libs\Plugins::instance()->init('shopengine')
230 ->set_parent_menu_slug('shopengine-settings')
231 ->set_submenu_name('Our Plugins')
232 ->set_section_title('Get More out of Your WooCommerce Website!')
233 ->set_section_description('Install other plugins from us and take your WooCommerce site to the next level for absolutely free!')
234 ->set_items_per_row(4)
235 ->set_plugins(
236 [
237 'elementskit-lite/elementskit-lite.php' => [
238 'name' => esc_html__('ElementsKit', 'shopengine'),
239 'url' => 'https://wordpress.org/plugins/elementskit-lite/',
240 'icon' => $apps_img_path. 'elementskit.gif',
241 'desc' => esc_html__('All-in-one Elementor addon trusted by 1 Million+ users, makes your website builder process easier with ultimate freedom.', 'shopengine'),
242 'docs' => 'https://wpmet.com/doc/elementskit/',
243 ],
244 'getgenie/getgenie.php' => [
245 'name' => esc_html__('GetGenie', 'shopengine'),
246 'url' => 'https://wordpress.org/plugins/getgenie/',
247 'icon' => $apps_img_path.'getgenie.gif',
248 'desc' => esc_html__('Your personal AI assistant for content and SEO. Write content that ranks on Google with NLP keywords and SERP analysis data.', 'shopengine'),
249 'docs' => 'https://getgenie.ai/docs/',
250 ],
251 'gutenkit-blocks-addon/gutenkit-blocks-addon.php' => [
252 'name' => esc_html__('GutenKit', 'shopengine'),
253 'url' => 'https://wordpress.org/plugins/gutenkit-blocks-addon/',
254 'icon' => $apps_img_path. 'guten-kit.png',
255 'desc' => esc_html__('Gutenberg blocks, patterns, and templates that extend the page-building experience using the WordPress block editor.', 'shopengine'),
256 'docs' => 'https://wpmet.com/doc/gutenkit/',
257 ],
258 'metform/metform.php' => [
259 'name' => esc_html__('MetForm', 'shopengine'),
260 'url' => 'https://wordpress.org/plugins/metform/',
261 'icon' => $apps_img_path. 'metform.png',
262 'desc' => esc_html__('Drag & drop form builder for Elementor to create contact forms, multi-step forms, and more — smoother, faster, and better!', 'shopengine'),
263 'docs' => 'https://wpmet.com/doc/metform/',
264 ],
265 'emailkit/EmailKit.php' => [
266 'name' => esc_html__('EmailKit', 'shopengine'),
267 'url' => 'https://wordpress.org/plugins/emailkit/',
268 'icon' => $apps_img_path . 'emailkit.png',
269 'desc' => esc_html__('Advanced email customizer for WooCommerce and WordPress. Build, customize, and send emails from WordPress to boost your sales!', 'shopengine'),
270 'docs' => 'https://wpmet.com/doc/emailkit/',
271 ],
272 'wp-social/wp-social.php' => [
273 'name' => esc_html__('WP Social', 'shopengine'),
274 'url' => 'https://wordpress.org/plugins/wp-social/',
275 'icon' => $apps_img_path . 'wp-social.png',
276 'desc' => esc_html__('Add social share, login, and engagement counter — unified solution for all social media with tons of different styles for your website.', 'shopengine'),
277 'docs' => 'https://wpmet.com/doc/wp-social/',
278 ],
279 'wp-ultimate-review/wp-ultimate-review.php' => [
280 'name' => esc_html__('WP Ultimate Review', 'shopengine'),
281 'url' => 'https://wordpress.org/plugins/wp-ultimate-review/',
282 'icon' => $apps_img_path . 'ultimate-review.png',
283 'desc' => esc_html__('Collect and showcase reviews on your website to build brand credibility and social proof with the easiest solution.','shopengine'),
284 'docs' => 'https://wpmet.com/doc/wp-ultimate-review/',
285 ],
286 'wp-fundraising-donation/wp-fundraising.php' => [
287 'name' => esc_html__('FundEngine', 'shopengine'),
288 'url' => 'https://wordpress.org/plugins/wp-fundraising-donation/',
289 'icon' => $apps_img_path . 'fundengine.png',
290 'desc' => esc_html__('Create fundraising, crowdfunding, and donation websites with PayPal and Stripe payment gateway integration.', 'shopengine'),
291 'docs' => 'https://wpmet.com/doc/fundengine/',
292 ],
293 'blocks-for-shopengine/shopengine-gutenberg-addon.php' => [
294 'name' => esc_html__('Blocks for ShopEngine', 'shopengine'),
295 'url' => 'https://wordpress.org/plugins/blocks-for-shopengine/',
296 'icon' => $apps_img_path. 'shopengine.gif',
297 'desc' => esc_html__('All in one WooCommerce solution for Gutenberg! Build your WooCommerce pages in a block editor with full customization.', 'shopengine'),
298 'docs' => 'https://wpmet.com/doc/shopengine/shopengine-gutenberg/',
299 ],
300 'genie-image-ai/genie-image-ai.php' => [
301 'name' => esc_html__('Genie Image', 'shopengine'),
302 'url' => 'https://wordpress.org/plugins/genie-image-ai/',
303 'icon' => $apps_img_path . 'genie-image.png',
304 'desc' => esc_html__('AI-powered text-to-image generator for WordPress with OpenAI’s DALL-E 2 technology to generate high-quality images in one click.
305 ', 'shopengine'),
306 'docs' => 'https://getgenie.ai/docs/',
307 ],
308 ]
309 )
310 ->call();
311
312
313
314 \ShopEngine\Core\MultiLanguage\Language::instance()->init();
315
316 \ShopEngine\Core\Settings\Base::instance()->init();
317
318
319 new Libs\Select_Api\Base();
320
321 (new Module_Manifest())->init();
322
323 // working get instance of elementor widget
324 (new Manifest())->init();
325
326 Query_Modifier::instance()->init();
327
328 (new Conflict_Manifest())->init();
329
330 // view count
331 add_action('get_header', [$this, 'shopengine_track_product_views']);
332
333 // database migrations
334 // (new \ShopEngine\Compatibility\Migrations\Migration())->init();
335 // (new \ShopEngine\Compatibility\Migrations\Temp_Migration())->init();
336
337
338 // call service providers
339
340 $service_providers = include \ShopEngine::plugin_dir().'core/service-provider-manager.php';
341 $method = 'init';
342 foreach( $service_providers as $service_provider ){
343
344 if(class_exists($service_provider) && method_exists($service_provider, $method)) {
345 $instance = new $service_provider();
346 $instance->$method();
347 }
348
349 }
350
351 add_filter('script_loader_tag', [$this, 'filter_load_type'], 99, 3);
352
353 //it will register an option in customizer for woocommerce products catelog. It's related with our Arcive Products widget.
354 Register_Settings::instance()->init();
355 }
356
357
358 // add async and defer attributes to enqueued scripts
359 public function filter_load_type($tag, $handle, $src) {
360
361 if(strpos($handle, '-async') !== false) {
362 $tag = str_replace(' src', ' async="async" src', $tag);
363 }
364
365 if(strpos($handle, '-defer') !== false) {
366 $tag = str_replace('<script ', '<script defer ', $tag);
367 }
368
369 return $tag;
370 }
371
372 /**
373 * Public function shopengine_track_product_views
374 * Adding Product Views Count Meta
375 */
376 public function shopengine_track_product_views() {
377
378 if(class_exists('WooCommerce') && !is_product()) {
379 return;
380 }
381
382 $product_id = get_the_id();
383
384 $cookie_name = "shopengine_recent_viewed_product";
385
386 if(isset($_COOKIE[$cookie_name])) {
387
388 $cookie_ids = sanitize_text_field(wp_unslash($_COOKIE[$cookie_name]));
389 $product_ids = explode(',', $cookie_ids);
390
391 if(!is_array($product_ids)) {
392 $product_ids = [$product_ids];
393 }
394
395 $product_ids = array_combine($product_ids, $product_ids);
396 unset($product_ids[$product_id]);
397 $product_ids[] = $product_id;
398
399 $cookie_value = implode(',', $product_ids);
400
401 } else {
402 $cookie_value = $product_id;
403 }
404
405 setcookie($cookie_name, $cookie_value, strtotime('+30 days'), '/' );
406
407 $count_key = 'shopengine_product_views_count';
408 $count = get_post_meta($product_id, $count_key, true);
409
410 if($count == '') {
411 $count = 1;
412 delete_post_meta($product_id, $count_key);
413 add_post_meta($product_id, $count_key, '1');
414 } else {
415 $count++;
416 update_post_meta($product_id, $count_key, $count);
417 }
418 }
419
420 /**
421 * Public function js_css_public .
422 * Include public function
423 *
424 * @since 1.0.0
425 */
426 public function js_css_public() {
427 wp_register_style('shopengine-public', \ShopEngine::plugin_url() . 'assets/css/shopengine-public.css', false, \ShopEngine::version());
428
429 // Modal Stylesheet
430 wp_register_style('shopengine-modal-styles', \ShopEngine::plugin_url() . 'assets/css/shopengine-modal.css', false, \ShopEngine::version());
431
432 // Modal Script
433 wp_register_script('shopengine-modal-script', \ShopEngine::plugin_url() . 'assets/js/shopengine-modal.js', ['jquery'], \ShopEngine::version(), true);
434
435 wp_enqueue_script('shopengine-simple-scrollbar.js-js', \ShopEngine::plugin_url() . 'assets/js/simple-scrollbar.js', [], \ShopEngine::version(), true);
436 wp_enqueue_script('shopengine-filter-js', \ShopEngine::plugin_url() . 'assets/js/filter.js', [], \ShopEngine::version(), true);
437 wp_enqueue_script('shopengine-js', \ShopEngine::plugin_url() . 'assets/js/public.js', [], \ShopEngine::version(), true);
438
439
440 wp_localize_script('shopengine-js', 'shopEngineApiSettings', [
441 'resturl' => get_rest_url(),
442 'rest_nonce' => wp_create_nonce('wp_rest'),
443 ]);
444
445
446 /**
447 * Registering libs css/js
448 *
449 */
450
451 wp_register_style(
452 'lib-sqv-css',
453 \ShopEngine::plugin_url() . '/assets/sqv/smart-quick-view.css',
454 [],
455 \ShopEngine::version()
456 );
457
458 wp_register_script(
459 'lib-sqv-js',
460 \ShopEngine::plugin_url() . 'assets/sqv/smart-quick-view.js',
461 ['jquery', 'wc-single-product'],
462 \ShopEngine::version(),
463 true
464 );
465 }
466
467 public function js_css_elementor() {
468 wp_enqueue_style('shopnegine-panel-icon', \ShopEngine::plugin_url() . 'assets/css/shopengine-icon.css', false, \ShopEngine::version());
469
470 if('shopengine-template' === get_post_type()):
471 wp_enqueue_style('shopnegine-editor-css', \ShopEngine::plugin_url() . 'assets/css/editor.css', false, \ShopEngine::version());
472 endif;
473 }
474
475
476 public function missing_woocommerce() {
477
478 if(!current_user_can('manage_options')) {
479 return;
480 }
481
482 if(file_exists(WP_PLUGIN_DIR . '/woocommerce/woocommerce.php')) {
483
484 $btn['label'] = esc_html__('Activate WooCommerce', 'shopengine');
485 $btn['url'] = wp_nonce_url('plugins.php?action=activate&plugin=woocommerce/woocommerce.php&plugin_status=all&paged=1', 'activate-plugin_woocommerce/woocommerce.php');
486
487 } else {
488
489 $btn['label'] = esc_html__('Install WooCommerce', 'shopengine');
490 $btn['url'] = wp_nonce_url(self_admin_url('update.php?action=install-plugin&plugin=woocommerce'), 'install-plugin_woocommerce');
491 }
492
493 Utils\Notice::push(
494 [
495 'id' => 'missing-woo',
496 'type' => 'error',
497 'dismissible' => true,
498 'is_required' => true,
499 'btn' => $btn,
500 'message' => sprintf(esc_html__('ShopEngine requires woocommerce Plugin, which is currently NOT RUNNING.', 'shopengine'), '4.1.0'),
501 ]
502 );
503 }
504
505
506 public function missing_elementor() {
507
508 if(!current_user_can('manage_options')) {
509 return;
510 }
511
512 if(file_exists(WP_PLUGIN_DIR . '/elementor/elementor.php')) {
513
514 $btn['label'] = esc_html__('Activate Elementor', 'shopengine');
515 $btn['url'] = wp_nonce_url('plugins.php?action=activate&plugin=elementor/elementor.php&plugin_status=all&paged=1', 'activate-plugin_elementor/elementor.php');
516
517 } else {
518
519 $btn['label'] = esc_html__('Install Elementor', 'shopengine');
520 $btn['url'] = wp_nonce_url(self_admin_url('update.php?action=install-plugin&plugin=elementor'), 'install-plugin_elementor');
521 }
522
523 if(file_exists(WP_PLUGIN_DIR . '/blocks-for-shopengine/shopengine-gutenberg-addon.php')) {
524
525 $btn2['label'] = esc_html__('Activate Blocks for ShopEngine', 'shopengine');
526 $btn2['url'] = wp_nonce_url('plugins.php?action=activate&plugin=blocks-for-shopengine/shopengine-gutenberg-addon.php&plugin_status=all&paged=1', 'activate-plugin_blocks-for-shopengine/shopengine-gutenberg-addon.php');
527
528 } else {
529
530 $btn2['label'] = esc_html__('Install Blocks for ShopEngine', 'shopengine');
531 $btn2['url'] = wp_nonce_url(self_admin_url('update.php?action=install-plugin&plugin=blocks-for-shopengine'), 'install-plugin_blocks-for-shopengine');
532 }
533
534 Utils\Notice::push(
535 [
536 'id' => 'missing-elementor',
537 'type' => 'error',
538 'is_required' => true,
539 'dismissible' => true,
540 'btn' => $btn,
541 'btn2' => $btn2,
542 'message' => esc_html__('To use ShopEngine, install Elementor (For the Elementor Builder) OR Blocks for ShopEngine (For Gutenberg Builder).', 'shopengine'),
543 ]
544 );
545 }
546
547
548 public function failed_elementor_version() {
549
550 if(!current_user_can('manage_options')) {
551 return;
552 }
553
554 $btn['label'] = esc_html__('Update Elementor', 'shopengine');
555 $btn['url'] = wp_nonce_url(self_admin_url('update.php?action=upgrade-plugin&plugin=elementor'), 'upgrade-plugin_elementor');
556
557 Utils\Notice::push(
558 [
559 'id' => 'unsupported-elementor-version',
560 'type' => 'error',
561 'dismissible' => true,
562 'btn' => $btn,
563 'message' => sprintf(esc_html__('ShopEngine requires Elementor version %1$s+, which is currently NOT RUNNING.', 'shopengine'), '3.0.0'),
564 ]
565 );
566 }
567
568
569 public function flush_rewrites() {
570 $form_cpt = new Core\Builders\Cpt();
571 $form_cpt->flush_rewrites();
572 }
573
574
575 public static function instance() {
576 if(!self::$instance) {
577 self::$instance = new self();
578 }
579
580 return self::$instance;
581 }
582 }
583