| @@ -174,15 +174,14 @@ | ||
| 174 | 174 | /** |
| 175 | 175 | * Define constant if not already set. |
| 176 | 176 | * |
| 177 | 177 | * @since 1.0.0 |
| 178 | - * @param string $timetics_constant_name Constant name. | |
| 178 | + * @param string $name Constant name. | |
| 179 | 179 | * @param string|bool $value Constant value. |
| 180 | 180 | */ |
| 181 | - private function define( $timetics_constant_name, $value ) { | |
| 182 | - if ( ! defined( $timetics_constant_name ) ) { | |
| 183 | - // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.VariableConstantNameFound -- Constant name is dynamic but prefixed by caller | |
| 184 | - define( $timetics_constant_name, $value ); | |
| 181 | + private function define( $name, $value ) { | |
| 182 | + if ( ! defined( $name ) ) { | |
| 183 | + define( $name, $value ); | |
| 185 | 184 | } |
| 186 | 185 | } |
| 187 | 186 | |
| 188 | 187 | /** |
| @@ -228,15 +227,13 @@ | ||
| 228 | 227 | |
| 229 | 228 | // Register scripts and styles first |
| 230 | 229 | if ( $this->is_request( 'admin' ) ) { |
| 231 | 230 | add_action( 'admin_enqueue_scripts', [ $this, 'admin_scripts' ] ); |
| 232 | - add_action( 'admin_enqueue_scripts', [ $this, 'preload_js_translations' ], 5 ); | |
| 233 | 231 | add_action( 'admin_footer', [ $this, 'admin_helpscout_beacon' ] ); |
| 234 | 232 | } |
| 235 | 233 | |
| 236 | 234 | if ( $this->is_request( 'frontend' ) ) { |
| 237 | 235 | add_action( 'wp_enqueue_scripts', array( $this, 'frontend_scripts' ) ); |
| 238 | - add_action( 'wp_enqueue_scripts', [ $this, 'preload_js_translations' ], 5 ); | |
| 239 | 236 | } |
| 240 | 237 | |
| 241 | 238 | // Register admin menu |
| 242 | 239 | Core\Admin\Menu::instance()->init(); |
| @@ -263,109 +260,8 @@ | ||
| 263 | 260 | return "https://arraytics.com/timetics/"; |
| 264 | 261 | } |
| 265 | 262 | |
| 266 | 263 | /** |
| 267 | - * Preload PHP-loaded translations into wp.i18n before any bundle runs. | |
| 268 | - * | |
| 269 | - * Why: webpack bundles collapse many source files into one. wp_set_script_translations() | |
| 270 | - * looks up a JSON file hashed from the registered bundle URL, but Loco and wp i18n make-json | |
| 271 | - * shard JSON by source-file path. The hashes never match, so per-script JSON loading silently | |
| 272 | - * fails. Reading the textdomain that load_text_domain() already populated and injecting it via | |
| 273 | - * setLocaleData() bypasses the hash mismatch entirely — every __() call across every bundle | |
| 274 | - * resolves from in-memory data set before any React component renders. | |
| 275 | - */ | |
| 276 | - public function preload_js_translations() { | |
| 277 | - $locale = determine_locale(); | |
| 278 | - $plural_forms = 'nplurals=2; plural=(n != 1);'; | |
| 279 | - | |
| 280 | - // Read .mo first — canonical, always-fresh source that Loco rewrites on every save. | |
| 281 | - // .l10n.php cache often lags behind .mo because Loco does not regenerate it. | |
| 282 | - $messages = $this->extract_mo_messages( $locale, $plural_forms ); | |
| 283 | - | |
| 284 | - // Merge .l10n.php on top (covers WP 6.5+ system-translated plugins where only .l10n.php exists). | |
| 285 | - foreach ( [ | |
| 286 | - WP_LANG_DIR . '/loco/plugins/timetics-' . $locale . '.l10n.php', | |
| 287 | - TIMETICS_PLUGIN_DIR . 'languages/timetics-' . $locale . '.l10n.php', | |
| 288 | - WP_LANG_DIR . '/plugins/timetics-' . $locale . '.l10n.php', | |
| 289 | - ] as $file ) { | |
| 290 | - if ( ! is_readable( $file ) ) { | |
| 291 | - continue; | |
| 292 | - } | |
| 293 | - $data = include $file; | |
| 294 | - if ( ! is_array( $data ) || empty( $data['messages'] ) ) { | |
| 295 | - continue; | |
| 296 | - } | |
| 297 | - $messages = array_merge( $messages, $data['messages'] ); | |
| 298 | - if ( ! empty( $data['plural-forms'] ) ) { | |
| 299 | - $plural_forms = $data['plural-forms']; | |
| 300 | - } | |
| 301 | - } | |
| 302 | - | |
| 303 | - if ( empty( $messages ) ) { | |
| 304 | - return; | |
| 305 | - } | |
| 306 | - | |
| 307 | - $locale_data = [ | |
| 308 | - '' => [ | |
| 309 | - 'domain' => 'timetics', | |
| 310 | - 'lang' => $locale, | |
| 311 | - 'plural-forms' => $plural_forms, | |
| 312 | - ], | |
| 313 | - ]; | |
| 314 | - | |
| 315 | - foreach ( $messages as $msgid => $msgstr ) { | |
| 316 | - if ( is_string( $msgid ) && $msgid !== '' && is_string( $msgstr ) && $msgstr !== '' ) { | |
| 317 | - $locale_data[ $msgid ] = [ $msgstr ]; | |
| 318 | - } | |
| 319 | - } | |
| 320 | - | |
| 321 | - wp_add_inline_script( | |
| 322 | - 'wp-i18n', | |
| 323 | - sprintf( | |
| 324 | - 'wp.i18n.setLocaleData( %s, "timetics" );', | |
| 325 | - wp_json_encode( $locale_data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES ) | |
| 326 | - ), | |
| 327 | - 'after' | |
| 328 | - ); | |
| 329 | - } | |
| 330 | - | |
| 331 | - /** | |
| 332 | - * Fallback: parse .mo file to extract all translations. | |
| 333 | - */ | |
| 334 | - private function extract_mo_messages( $locale, &$plural_forms ) { | |
| 335 | - $candidates = [ | |
| 336 | - WP_LANG_DIR . '/loco/plugins/timetics-' . $locale . '.mo', | |
| 337 | - TIMETICS_PLUGIN_DIR . 'languages/timetics-' . $locale . '.mo', | |
| 338 | - WP_LANG_DIR . '/plugins/timetics-' . $locale . '.mo', | |
| 339 | - ]; | |
| 340 | - | |
| 341 | - $messages = []; | |
| 342 | - | |
| 343 | - foreach ( $candidates as $mofile ) { | |
| 344 | - if ( ! is_readable( $mofile ) ) { | |
| 345 | - continue; | |
| 346 | - } | |
| 347 | - if ( ! class_exists( 'MO' ) ) { | |
| 348 | - require_once ABSPATH . WPINC . '/pomo/mo.php'; | |
| 349 | - } | |
| 350 | - $mo = new \MO(); | |
| 351 | - if ( ! $mo->import_from_file( $mofile ) ) { | |
| 352 | - continue; | |
| 353 | - } | |
| 354 | - if ( ! empty( $mo->headers['Plural-Forms'] ) ) { | |
| 355 | - $plural_forms = $mo->headers['Plural-Forms']; | |
| 356 | - } | |
| 357 | - foreach ( $mo->entries as $msgid => $entry ) { | |
| 358 | - if ( ! empty( $entry->translations[0] ) ) { | |
| 359 | - $messages[ $msgid ] = $entry->translations[0]; | |
| 360 | - } | |
| 361 | - } | |
| 362 | - } | |
| 363 | - | |
| 364 | - return $messages; | |
| 365 | - } | |
| 366 | - | |
| 367 | - /** | |
| 368 | 264 | * Register scripts and styles for admin |
| 369 | 265 | * |
| 370 | 266 | * @return void |
| 371 | 267 | */ |
| @@ -405,9 +301,8 @@ | ||
| 405 | 301 | } |
| 406 | 302 | |
| 407 | 303 | wp_enqueue_script( 'timetics-dashboard-scripts', TIMETICS_ASSETS_URL . 'js/dashboard.js', [ 'wp-plugins', 'wp-i18n', 'wp-element', 'wp-dom', 'wp-data', 'wp-color-picker' ], TIMETICS_VERSION, true ); |
| 408 | 304 | |
| 409 | - wp_set_script_translations( 'timetics-dashboard-scripts', 'timetics', TIMETICS_PLUGIN_DIR . 'languages/' ); | |
| 410 | 305 | |
| 411 | 306 | $localize_obj = array( |
| 412 | 307 | 'site_url' => site_url(), |
| 413 | 308 | 'admin_url' => admin_url(), |
| @@ -442,25 +337,8 @@ | ||
| 442 | 337 | |
| 443 | 338 | wp_register_style( 'timetics-vendor', TIMETICS_ASSETS_URL . 'css/vendor.css', [], TIMETICS_VERSION, 'all' ); |
| 444 | 339 | wp_register_style( 'timetics-frontend', TIMETICS_ASSETS_URL . 'css/frontend.css', [], TIMETICS_VERSION, 'all' ); |
| 445 | 340 | |
| 446 | - global $post; | |
| 447 | - if ( $post ) { | |
| 448 | - $is_timetics_cpt = ( 'timetics-appointment' === get_post_type( $post ) ); | |
| 449 | - $timetics_shortcodes = [ 'timetics-booking-form', 'timetics-meeting-list', 'timetics-user-dashboard', 'timetics-category' ]; | |
| 450 | - $has_timetics_shortcode = false; | |
| 451 | - foreach ( $timetics_shortcodes as $shortcode ) { | |
| 452 | - if ( has_shortcode( $post->post_content, $shortcode ) ) { | |
| 453 | - $has_timetics_shortcode = true; | |
| 454 | - break; | |
| 455 | - } | |
| 456 | - } | |
| 457 | - if ( $is_timetics_cpt || $has_timetics_shortcode ) { | |
| 458 | - wp_enqueue_style( 'timetics-vendor' ); | |
| 459 | - wp_enqueue_style( 'timetics-frontend' ); | |
| 460 | - } | |
| 461 | - } | |
| 462 | - | |
| 463 | 341 | wp_register_script( 'timetics-flatpickr-scripts', TIMETICS_ASSETS_URL . 'js/vendors/flatpickr.js', [ 'wp-plugins', 'wp-i18n', 'wp-element', 'wp-dom', 'wp-data' ], TIMETICS_VERSION, true ); |
| 464 | 342 | wp_enqueue_script( 'timetics-packages', TIMETICS_ASSETS_URL . 'js/packages.js', [ 'timetics-flatpickr-scripts' ], TIMETICS_VERSION, true ); |
| 465 | 343 | |
| 466 | 344 | wp_register_script( 'timetics-frontend-scripts', TIMETICS_ASSETS_URL . 'js/frontend.js', [ 'jquery', 'wp-plugins', 'wp-i18n', 'wp-element', 'wp-dom', 'wp-data' ], TIMETICS_VERSION, true ); |
| @@ -542,10 +420,9 @@ | ||
| 542 | 420 | * |
| 543 | 421 | * @return void |
| 544 | 422 | */ |
| 545 | 423 | public function handle_buy_pro_module() { |
| 546 | - // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only page parameter check, no form processing | |
| 547 | - $page = isset( $_GET['page'] ) ? sanitize_text_field( wp_unslash( $_GET['page'] ) ) : ''; | |
| 424 | + $page = isset( $_GET['page'] ) ? sanitize_text_field( $_GET['page'] ) : ''; | |
| 548 | 425 | |
| 549 | 426 | |
| 550 | 427 | if ( 'timetics' !== $page ) { |
| 551 | 428 | return; |
| @@ -607,9 +484,9 @@ | ||
| 607 | 484 | color: "#0060e5", |
| 608 | 485 | }); |
| 609 | 486 | window.Beacon('init', '4be24aa2-ee50-483c-a90c-db4216664d65'); |
| 610 | 487 | window.Beacon('on', 'ready', function(){ |
| 611 | - window.Beacon('close'); | |
| 488 | + window.Beacon('show'); | |
| 612 | 489 | }); |
| 613 | 490 | |
| 614 | 491 | </script> |
| 615 | 492 | <?php |