PluginProbe ʕ •ᴥ•ʔ
ShopEngine Elementor WooCommerce Builder Addon – All in One WooCommerce Solution / 4.7.8
ShopEngine Elementor WooCommerce Builder Addon – All in One WooCommerce Solution v4.7.8
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
586 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 add_action('init', function () {
226 $apps_img_path = \ShopEngine::plugin_url() . 'assets/images/apps-page/';
227 /**
228 * Show our plugins menu for others wpmet plugins
229 */
230 \ShopEngine\Wpmet\Libs\Plugins::instance()->init('shopengine')
231 ->set_parent_menu_slug('shopengine-settings')
232 ->set_submenu_name('Our Plugins')
233 ->set_section_title('Get More out of Your WooCommerce Website!')
234 ->set_section_description('Install other plugins from us and take your WooCommerce site to the next level for absolutely free!')
235 ->set_items_per_row(4)
236 ->set_plugins(
237 [
238 'elementskit-lite/elementskit-lite.php' => [
239 'name' => esc_html__('ElementsKit', 'shopengine'),
240 'url' => 'https://wordpress.org/plugins/elementskit-lite/',
241 'icon' => $apps_img_path. 'elementskit.gif',
242 'desc' => esc_html__('All-in-one Elementor addon trusted by 1 Million+ users, makes your website builder process easier with ultimate freedom.', 'shopengine'),
243 'docs' => 'https://wpmet.com/doc/elementskit/',
244 ],
245 'getgenie/getgenie.php' => [
246 'name' => esc_html__('GetGenie', 'shopengine'),
247 'url' => 'https://wordpress.org/plugins/getgenie/',
248 'icon' => $apps_img_path.'getgenie.gif',
249 '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'),
250 'docs' => 'https://getgenie.ai/docs/',
251 ],
252 'gutenkit-blocks-addon/gutenkit-blocks-addon.php' => [
253 'name' => esc_html__('GutenKit', 'shopengine'),
254 'url' => 'https://wordpress.org/plugins/gutenkit-blocks-addon/',
255 'icon' => $apps_img_path. 'guten-kit.png',
256 'desc' => esc_html__('Gutenberg blocks, patterns, and templates that extend the page-building experience using the WordPress block editor.', 'shopengine'),
257 'docs' => 'https://wpmet.com/doc/gutenkit/',
258 ],
259 'metform/metform.php' => [
260 'name' => esc_html__('MetForm', 'shopengine'),
261 'url' => 'https://wordpress.org/plugins/metform/',
262 'icon' => $apps_img_path. 'metform.png',
263 'desc' => esc_html__('Drag & drop form builder for Elementor to create contact forms, multi-step forms, and more — smoother, faster, and better!', 'shopengine'),
264 'docs' => 'https://wpmet.com/doc/metform/',
265 ],
266 'emailkit/EmailKit.php' => [
267 'name' => esc_html__('EmailKit', 'shopengine'),
268 'url' => 'https://wordpress.org/plugins/emailkit/',
269 'icon' => $apps_img_path . 'emailkit.png',
270 'desc' => esc_html__('Advanced email customizer for WooCommerce and WordPress. Build, customize, and send emails from WordPress to boost your sales!', 'shopengine'),
271 'docs' => 'https://wpmet.com/doc/emailkit/',
272 ],
273 'wp-social/wp-social.php' => [
274 'name' => esc_html__('WP Social', 'shopengine'),
275 'url' => 'https://wordpress.org/plugins/wp-social/',
276 'icon' => $apps_img_path . 'wp-social.png',
277 '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'),
278 'docs' => 'https://wpmet.com/doc/wp-social/',
279 ],
280 'wp-ultimate-review/wp-ultimate-review.php' => [
281 'name' => esc_html__('WP Ultimate Review', 'shopengine'),
282 'url' => 'https://wordpress.org/plugins/wp-ultimate-review/',
283 'icon' => $apps_img_path . 'ultimate-review.png',
284 'desc' => esc_html__('Collect and showcase reviews on your website to build brand credibility and social proof with the easiest solution.','shopengine'),
285 'docs' => 'https://wpmet.com/doc/wp-ultimate-review/',
286 ],
287 'wp-fundraising-donation/wp-fundraising.php' => [
288 'name' => esc_html__('FundEngine', 'shopengine'),
289 'url' => 'https://wordpress.org/plugins/wp-fundraising-donation/',
290 'icon' => $apps_img_path . 'fundengine.png',
291 'desc' => esc_html__('Create fundraising, crowdfunding, and donation websites with PayPal and Stripe payment gateway integration.', 'shopengine'),
292 'docs' => 'https://wpmet.com/doc/fundengine/',
293 ],
294 'blocks-for-shopengine/shopengine-gutenberg-addon.php' => [
295 'name' => esc_html__('Blocks for ShopEngine', 'shopengine'),
296 'url' => 'https://wordpress.org/plugins/blocks-for-shopengine/',
297 'icon' => $apps_img_path. 'shopengine.gif',
298 'desc' => esc_html__('All in one WooCommerce solution for Gutenberg! Build your WooCommerce pages in a block editor with full customization.', 'shopengine'),
299 'docs' => 'https://wpmet.com/doc/shopengine/shopengine-gutenberg/',
300 ],
301 'genie-image-ai/genie-image-ai.php' => [
302 'name' => esc_html__('Genie Image', 'shopengine'),
303 'url' => 'https://wordpress.org/plugins/genie-image-ai/',
304 'icon' => $apps_img_path . 'genie-image.png',
305 '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.
306 ', 'shopengine'),
307 'docs' => 'https://getgenie.ai/docs/',
308 ],
309 ]
310 )
311 ->call();
312
313 // working get instance of elementor widget
314 (new Manifest())->init();
315 } );
316
317
318
319 \ShopEngine\Core\MultiLanguage\Language::instance()->init();
320
321 \ShopEngine\Core\Settings\Base::instance()->init();
322
323
324 new Libs\Select_Api\Base();
325
326 (new Module_Manifest())->init();
327
328
329 Query_Modifier::instance()->init();
330
331 (new Conflict_Manifest())->init();
332
333 // view count
334 add_action('get_header', [$this, 'shopengine_track_product_views']);
335
336 // database migrations
337 // (new \ShopEngine\Compatibility\Migrations\Migration())->init();
338 // (new \ShopEngine\Compatibility\Migrations\Temp_Migration())->init();
339
340
341 // call service providers
342
343 $service_providers = include \ShopEngine::plugin_dir().'core/service-provider-manager.php';
344 $method = 'init';
345 foreach( $service_providers as $service_provider ){
346
347 if(class_exists($service_provider) && method_exists($service_provider, $method)) {
348 $instance = new $service_provider();
349 $instance->$method();
350 }
351
352 }
353
354 add_filter('script_loader_tag', [$this, 'filter_load_type'], 99, 3);
355
356 //it will register an option in customizer for woocommerce products catelog. It's related with our Arcive Products widget.
357 Register_Settings::instance()->init();
358 }
359
360
361 // add async and defer attributes to enqueued scripts
362 public function filter_load_type($tag, $handle, $src) {
363
364 if(strpos($handle, '-async') !== false) {
365 $tag = str_replace(' src', ' async="async" src', $tag);
366 }
367
368 if(strpos($handle, '-defer') !== false) {
369 $tag = str_replace('<script ', '<script defer ', $tag);
370 }
371
372 return $tag;
373 }
374
375 /**
376 * Public function shopengine_track_product_views
377 * Adding Product Views Count Meta
378 */
379 public function shopengine_track_product_views() {
380
381 if(class_exists('WooCommerce') && !is_product()) {
382 return;
383 }
384
385 $product_id = get_the_id();
386
387 $cookie_name = "shopengine_recent_viewed_product";
388
389 if(isset($_COOKIE[$cookie_name])) {
390
391 $cookie_ids = sanitize_text_field(wp_unslash($_COOKIE[$cookie_name]));
392 $product_ids = explode(',', $cookie_ids);
393
394 if(!is_array($product_ids)) {
395 $product_ids = [$product_ids];
396 }
397
398 $product_ids = array_combine($product_ids, $product_ids);
399 unset($product_ids[$product_id]);
400 $product_ids[] = $product_id;
401
402 $cookie_value = implode(',', $product_ids);
403
404 } else {
405 $cookie_value = $product_id;
406 }
407
408 setcookie($cookie_name, $cookie_value, strtotime('+30 days'), '/' );
409
410 $count_key = 'shopengine_product_views_count';
411 $count = get_post_meta($product_id, $count_key, true);
412
413 if($count == '') {
414 $count = 1;
415 delete_post_meta($product_id, $count_key);
416 add_post_meta($product_id, $count_key, '1');
417 } else {
418 $count++;
419 update_post_meta($product_id, $count_key, $count);
420 }
421 }
422
423 /**
424 * Public function js_css_public .
425 * Include public function
426 *
427 * @since 1.0.0
428 */
429 public function js_css_public() {
430 wp_register_style('shopengine-public', \ShopEngine::plugin_url() . 'assets/css/shopengine-public.css', false, \ShopEngine::version());
431
432 // Modal Stylesheet
433 wp_register_style('shopengine-modal-styles', \ShopEngine::plugin_url() . 'assets/css/shopengine-modal.css', false, \ShopEngine::version());
434
435 // Modal Script
436 wp_register_script('shopengine-modal-script', \ShopEngine::plugin_url() . 'assets/js/shopengine-modal.js', ['jquery'], \ShopEngine::version(), true);
437
438 wp_enqueue_script('shopengine-simple-scrollbar.js-js', \ShopEngine::plugin_url() . 'assets/js/simple-scrollbar.js', [], \ShopEngine::version(), true);
439 wp_enqueue_script('shopengine-filter-js', \ShopEngine::plugin_url() . 'assets/js/filter.js', [], \ShopEngine::version(), true);
440 wp_enqueue_script('shopengine-js', \ShopEngine::plugin_url() . 'assets/js/public.js', [], \ShopEngine::version(), true);
441
442
443 wp_localize_script('shopengine-js', 'shopEngineApiSettings', [
444 'resturl' => get_rest_url(),
445 'rest_nonce' => wp_create_nonce('wp_rest'),
446 ]);
447
448
449 /**
450 * Registering libs css/js
451 *
452 */
453
454 wp_register_style(
455 'lib-sqv-css',
456 \ShopEngine::plugin_url() . '/assets/sqv/smart-quick-view.css',
457 [],
458 \ShopEngine::version()
459 );
460
461 wp_register_script(
462 'lib-sqv-js',
463 \ShopEngine::plugin_url() . 'assets/sqv/smart-quick-view.js',
464 ['jquery', 'wc-single-product'],
465 \ShopEngine::version(),
466 true
467 );
468 }
469
470 public function js_css_elementor() {
471 wp_enqueue_style('shopnegine-panel-icon', \ShopEngine::plugin_url() . 'assets/css/shopengine-icon.css', false, \ShopEngine::version());
472
473 if('shopengine-template' === get_post_type()):
474 wp_enqueue_style('shopnegine-editor-css', \ShopEngine::plugin_url() . 'assets/css/editor.css', false, \ShopEngine::version());
475 endif;
476 }
477
478
479 public function missing_woocommerce() {
480
481 if(!current_user_can('manage_options')) {
482 return;
483 }
484
485 if(file_exists(WP_PLUGIN_DIR . '/woocommerce/woocommerce.php')) {
486
487 $btn['label'] = esc_html__('Activate WooCommerce', 'shopengine');
488 $btn['url'] = wp_nonce_url('plugins.php?action=activate&plugin=woocommerce/woocommerce.php&plugin_status=all&paged=1', 'activate-plugin_woocommerce/woocommerce.php');
489
490 } else {
491
492 $btn['label'] = esc_html__('Install WooCommerce', 'shopengine');
493 $btn['url'] = wp_nonce_url(self_admin_url('update.php?action=install-plugin&plugin=woocommerce'), 'install-plugin_woocommerce');
494 }
495
496 Utils\Notice::push(
497 [
498 'id' => 'missing-woo',
499 'type' => 'error',
500 'dismissible' => true,
501 'is_required' => true,
502 'btn' => $btn,
503 'message' => sprintf(esc_html__('ShopEngine requires woocommerce Plugin, which is currently NOT RUNNING.', 'shopengine'), '4.1.0'),
504 ]
505 );
506 }
507
508
509 public function missing_elementor() {
510
511 if(!current_user_can('manage_options')) {
512 return;
513 }
514
515 if(file_exists(WP_PLUGIN_DIR . '/elementor/elementor.php')) {
516
517 $btn['label'] = esc_html__('Activate Elementor', 'shopengine');
518 $btn['url'] = wp_nonce_url('plugins.php?action=activate&plugin=elementor/elementor.php&plugin_status=all&paged=1', 'activate-plugin_elementor/elementor.php');
519
520 } else {
521
522 $btn['label'] = esc_html__('Install Elementor', 'shopengine');
523 $btn['url'] = wp_nonce_url(self_admin_url('update.php?action=install-plugin&plugin=elementor'), 'install-plugin_elementor');
524 }
525
526 if(file_exists(WP_PLUGIN_DIR . '/blocks-for-shopengine/shopengine-gutenberg-addon.php')) {
527
528 $btn2['label'] = esc_html__('Activate Blocks for ShopEngine', 'shopengine');
529 $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');
530
531 } else {
532
533 $btn2['label'] = esc_html__('Install Blocks for ShopEngine', 'shopengine');
534 $btn2['url'] = wp_nonce_url(self_admin_url('update.php?action=install-plugin&plugin=blocks-for-shopengine'), 'install-plugin_blocks-for-shopengine');
535 }
536
537 Utils\Notice::push(
538 [
539 'id' => 'missing-elementor',
540 'type' => 'error',
541 'is_required' => true,
542 'dismissible' => true,
543 'btn' => $btn,
544 'btn2' => $btn2,
545 'message' => esc_html__('To use ShopEngine, install Elementor (For the Elementor Builder) OR Blocks for ShopEngine (For Gutenberg Builder).', 'shopengine'),
546 ]
547 );
548 }
549
550
551 public function failed_elementor_version() {
552
553 if(!current_user_can('manage_options')) {
554 return;
555 }
556
557 $btn['label'] = esc_html__('Update Elementor', 'shopengine');
558 $btn['url'] = wp_nonce_url(self_admin_url('update.php?action=upgrade-plugin&plugin=elementor'), 'upgrade-plugin_elementor');
559
560 Utils\Notice::push(
561 [
562 'id' => 'unsupported-elementor-version',
563 'type' => 'error',
564 'dismissible' => true,
565 'btn' => $btn,
566 'message' => sprintf(esc_html__('ShopEngine requires Elementor version %1$s+, which is currently NOT RUNNING.', 'shopengine'), '3.0.0'),
567 ]
568 );
569 }
570
571
572 public function flush_rewrites() {
573 $form_cpt = new Core\Builders\Cpt();
574 $form_cpt->flush_rewrites();
575 }
576
577
578 public static function instance() {
579 if(!self::$instance) {
580 self::$instance = new self();
581 }
582
583 return self::$instance;
584 }
585 }
586