5 * 60, 'display' => __('Every 5 minutes', 'jvb') ]; $schedules[ 'every-minute' ] = [ 'interval' => 60, 'display' => __('Every minute', 'jvb') ]; $schedules[ 'monthly' ] = [ 'interval' => 604800 * 4, 'display' => __('Once Monthly', 'jvb') ]; return $schedules; } register_activation_hook(JVB_DIR.'/jvb.php', 'jvbActivatePlugin'); register_deactivation_hook(JVB_DIR.'/jvb.php', 'jvbDeactivatePlugin'); add_action('init', 'jvbUserCheck'); function jvbUserCheck():void { if (is_admin() && isOurPeople()) { wp_redirect(get_home_url(2, '/dash')); exit; } } require(JVB_DIR . '/inc/users/UserSettings.php'); require(JVB_DIR . '/inc/templates.php'); /** * Utilities */ require(JVB_DIR . '/cleanup.php'); require(JVB_DIR . '/inc/admin/_setup.php'); require(JVB_DIR . '/JVBase.php'); add_action('init', 'jvbLoadBase', 1); function jvbLoadBase():void { JVB::getInstance(); } function JVB(): JVB { return JVB::getInstance(); } function checkIf(): Checker { return JVBase\utility\Checker::getInstance(); } require(JVB_DIR . '/inc/blocks/_setup.php'); add_filter('upload_mimes', function ($mimes) { $mimes['webp'] = 'image/webp'; $mimes['avif'] = 'image/avif'; return $mimes; }); // And this to ensure WebP is treated as an image add_filter('file_is_displayable_image', function ($result, $path) { if (preg_match('/\.webp$/i', $path)) { return true; } return $result; }, 10, 2); function jvbDump(mixed $array, string $name = 'var'):void { highlight_string(""); } /** * Scripts */ add_action('wp_enqueue_scripts', 'jvbScripts', 999); function jvbScripts():void { /** * Register Scripts */ //Helper functions used by other classes wp_register_script( 'jvb-utility', JVB_URL.'assets/js/min/utility.min.js', [], '1.0.0', [ 'strategy' => 'defer', 'in_footer' => true, ] ); wp_register_script( 'jvb-favourites', JVB_URL.'assets/js/min/favourites.min.js', [ 'jvb-queue', 'jvb-data-store' ], '1.0.0', [ 'strategy' => 'defer', 'in_footer' => true, ] ); wp_register_script( 'jvb-votes', JVB_URL.'assets/js/min/votes.min.js', [ 'jvb-queue', 'jvb-data-store' ], '1.0.0', [ 'strategy' => 'defer', 'in_footer' => true, ] ); //Main js image resizing, and gallery //TODO: lots of overlap between modals and this, utilize a11y for trapFocus, wp_register_script( 'jvb-media', JVB_URL.'assets/js/min/media.min.js', [], '1.0.0', [ 'strategy' => 'defer', 'in_footer' => true, ] ); wp_register_script( 'jvb-copy-hours', JVB_URL.'assets/js/min/hours.min.js', [ 'jvb-form', 'jvb-utility', 'jvb-modal', 'jvb-a11y' ], '1.0.0', [ 'strategy' => 'defer', 'in_footer' => true, ] ); //Includes the escape and outside click listeners and intersection observers //TODO: make the Modals class use this? // wp_register_script( // 'jvb-ui', // JVB_URL.'assets/js/min/ui.min.js', // [], // '1.0.0', // [ // 'strategy' => 'defer', // 'in_footer' => true, // ] // ); wp_register_script( 'jvb-gallery', JVB_URL.'assets/js/min/gallery.min.js', [ 'jvb-utility', 'jvb-queue' ], '1.0.0', [ 'strategy' => 'defer', 'in_footer' => true, ] ); wp_register_script( 'jvb-integrations', JVB_URL.'assets/js/min/integrations.min.js', [], '1.0.0', [ 'strategy' => 'defer', 'in_footer' => true ] ); $integration_nonces = [ 'jvb_square_sync' => wp_create_nonce('jvb_square_sync'), 'jvb_gmb_sync_reviews' => wp_create_nonce('jvb_gmb_sync'), 'jvb_gmb_test_api' => wp_create_nonce('jvb_gmb_test'), 'jvb_bluesky_test_post' => wp_create_nonce('jvb_bluesky_test'), 'jvb_facebook_test_post' => wp_create_nonce('jvb_facebook_test'), 'jvb_instagram_test_post' => wp_create_nonce('jvb_instagram_test'), 'jvb_instagram_sync_media' => wp_create_nonce('jvb_instagram_sync'), 'jvb_umami_refresh_data' => wp_create_nonce('jvb_umami_refresh'), 'jvb_export_integration_settings' => wp_create_nonce('jvb_integration_export'), ]; $data = [ 'ajaxUrl' => admin_url('admin-ajax.php'), 'nonce' => wp_create_nonce('jvb_integrations'), 'nonces' => $integration_nonces, // 'services' => array_keys(jvbConnect()->getAvailableServices()), 'userId' => get_current_user_id(), 'baseUrl' => admin_url('admin.php?page=' . BASE) ]; wp_localize_script( 'jvb-integrations', 'jvbIntegrationsConfig', $data ); //The On-This-Page menu. TODO: just include in ui? wp_register_script( 'jvb-page-nav', JVB_URL.'assets/js/min/page-nav.min.js', [], '1.0.0', [ 'strategy' => 'defer', 'in_footer' => true, ] ); //A11y accessibility wp_register_script( 'jvb-a11y', JVB_URL.'assets/js/min/a11y.min.js', [], '1.0.0', [ 'strategy' => 'defer', 'in_footer' => true, ] ); //Central Error Management wp_register_script( 'jvb-error', JVB_URL.'assets/js/min/error.min.js', [ ], '1.0.0', [ 'strategy' => 'defer', 'in_footer' => true, ] ); //Cache Management wp_register_script( 'jvb-cache', JVB_URL.'assets/js/min/cache.min.js', [], '1.0.0', [ 'strategy' => 'defer', 'in_footer' => true, ] ); wp_register_Script( 'jvb-data-store', JVB_URL.'assets/js/min/dataStore.min.js', [], '1.0.0', [ 'strategy' => 'defer', 'in_footer' => true, ] ); //Tabs functionality wp_register_script( 'jvb-tabs', JVB_URL.'assets/js/min/tabs.min.js', [ 'jvb-a11y' ], '1.0.0', [ 'strategy' => 'defer', 'in_footer' => true, ] ); //Modal functionality wp_register_script( 'jvb-modal', JVB_URL.'assets/js/min/modal.min.js', [ 'jvb-a11y' ], '1.0.0', [ 'strategy' => 'defer', 'in_footer' => true, ] ); //Central Queue Management wp_register_script( 'jvb-queue', JVB_URL.'assets/js/min/queue.min.js', [ 'jvb-a11y', 'jvb-error', 'jvb-data-store', 'jvb-utility', ], '1.0.0', [ 'strategy' => 'defer', 'in_footer' => true, ] ); //TaxonomySelector.js wp_register_script( 'jvb-selector', JVB_URL.'assets/js/min/selector.min.js', [ 'jvb-utility', 'jvb-a11y', 'jvb-error', 'jvb-data-store', 'jvb-modal', // 'jvb-loading' ], '1.0.0', [ 'strategy' => 'defer', 'in_footer' => true, ] ); wp_register_script( 'jvb-creator', JVB_URL.'assets/js/min/creator.min.js', ['jvb-selector'], '1.0.0', [ 'strategy' => 'defer', 'in_footer' => true ] ); //PostSelector.js wp_register_script( 'jvb-post-selector', JVB_URL.'assets/js/min/postSelector.min.js', [ 'jvb-selector' ], '1.0.0', [ 'strategy' => 'defer', 'in_footer' => true, ] ); // //Central Loading Manager // wp_register_script( // 'jvb-loading', // JVB_URL.'assets/js/min/loading.min.js', // [], // '1.0.0', // [ // 'strategy' => 'defer', // 'in_footer' => true, // ] // ); // wp_localize_script( // 'jvb-loading', // 'loadingQuips', // [ // 'quips' => json_encode(apply_filters( // 'jvbLoadingQuips', // [] // )) // ] // ); //Upload Manager wp_register_script( 'jvb-uploader', JVB_URL.'assets/js/min/uploader.min.js', [ 'jvb-cache', 'jvb-a11y', 'jvb-utility', // 'jvb-loading', 'jvb-queue', 'jvb-notifications' ], '1.0.0', [ 'strategy' => 'defer', 'in_footer' => true, ] ); wp_register_script( 'quill-js', 'https://cdn.jsdelivr.net/npm/quill@2.0.3/dist/quill.js', [], null, true ); wp_register_script( 'sortable-js', 'https://cdn.jsdelivr.net/npm/sortablejs@latest/Sortable.min.js', array(), null, true ); //Custom Dashboard Navigator // wp_register_script( // 'jvb-dashboard-navigator', // JVB_URL.'assets/js/min/DashboardNavigator.min.js', // [ // 'jvb-a11y', // 'jvb-loading', // 'jvb-content', // 'jvb-crud', // 'jvb-tabs' // ], // '1.0.0', // [ // 'strategy' => 'defer', // 'in_footer' => true, // ] // ); //Notifications wp_register_script( 'jvb-notifications', JVB_URL.'assets/js/min/notifications.min.js', [ 'jvb-utility', ], '1.0.0', [ 'strategy' => 'defer', 'in_footer' => true, ] ); //Base Form Handler wp_register_script( 'jvb-form', JVB_URL.'assets/js/min/form.min.js', [ 'jvb-utility', 'jvb-selector', 'jvb-uploader', 'sortable-js' ], '1.0.0', [ 'strategy' => 'defer', 'in_footer' => true, ] ); wp_register_script( 'jvb-populate-form', JVB_URL.'assets/js/min/populate.min.js', [], '1.0.0', [ 'strategy' => 'defer', 'in_footer' => true, ] ); wp_register_script( 'jvb-quill', JVB_URL.'assets/js/min/quill.min.js', [ 'quill-js' ], '1.0.0', [ 'strategy' => 'defer', 'in_footer' => true, ] ); //CRUD Base Manager wp_register_script( 'jvb-crud', JVB_URL.'assets/js/min/crud.min.js', [ 'jvb-selector', 'jvb-a11y', 'jvb-error', 'jvb-data-store', 'jvb-populate-form', 'jvb-queue', 'jvb-utility', 'jvb-quill', 'jvb-form', 'jvb-view', 'jvb-modal' ], '1.0.0', [ 'strategy' => 'defer', 'in_footer' => true, ] ); wp_register_script( 'jvb-view', JVB_URL.'assets/js/min/view.min.js', [ 'jvb-a11y', 'jvb-utility', 'jvb-data-store', 'jvb-error' ], '1.0.0', [ 'strategy' => 'defer', 'in_footer' => true, ] ); //Bio Manager TODO: Replace with Form Handler wp_register_script( 'jvb-bio', JVB_URL.'assets/js/min/bioManager.min.js', [ 'jvb-tabs', 'jvb-form', 'jvb-queue' ], '1.0.0', [ 'strategy' => 'defer', 'in_footer' => true, ] ); //Shop Manager TODO: Replace with Form Handler wp_register_script( 'jvb-shop', JVB_URL.'assets/js/min/shopManager.min.js', [ 'jvb-tabs', 'jvb-form', 'jvb-queue' ], '1.0.0', [ 'strategy' => 'defer', 'in_footer' => true, ] ); //Content Manager TODO: Replace with CRUD.js wp_register_script( 'jvb-content', JVB_URL.'assets/js/min/ContentManager.min.js', [ 'jvb-queue', 'jvb-cache', 'jvb-error', 'jvb-uploader', 'jvb-utility', 'jvb-modal', 'jvb-selector', 'jvb-post-selector', ], '1.0.0', [ 'strategy' => 'defer', 'in_footer' => true, ] ); //Favourites Manager TODO: Replace with CRUD.js wp_register_script( 'jvb-favourites', JVB_URL.'assets/js/min/favouritesManager.min.js', [ 'jvb-a11y', 'jvb-queue', 'jvb-cache', 'jvb-error', 'jvb-utility', 'jvb-tabs', 'jvb-selector', 'jvb-notifications', ], '1.0.0', [ 'strategy' => 'defer', 'in_footer' => true, ] ); //News Manager TODO: Replace with CRUD.js wp_register_script( 'jvb-news', JVB_URL.'assets/js/min/news.min.js', [ 'jvb-a11y', 'jvb-queue', 'jvb-cache', 'jvb-error', 'jvb-utility', 'jvb-modal', 'jvb-selector', 'jvb-tabs', ], '1.0.0', [ 'strategy' => 'defer', 'in_footer' => true, ] ); //Notification Manager TODO: Replace with CRUD? Not quite... wp_register_script( 'jvb-notification-manager', JVB_URL.'assets/js/min/notificationManager.min.js', [ 'jvb-a11y', 'jvb-tabs', ] ); wp_register_script( 'jvb-navigation', JVB_URL.'assets/js/min/navigation.min.js', ); add_action('wp_head', 'jvbInlineNavStyles'); wp_enqueue_script('jvb-queue'); wp_enqueue_script('jvb-navigation'); // wp_enqueue_script('jvb-ui'); wp_enqueue_script('jvb-media'); wp_enqueue_script('jvb-cache'); wp_localize_script( 'jvb-cache', 'cacheJVB', [ 'cache' => json_encode(jvbGetCache()) ] ); $userID = get_current_user_id(); $icons = new \JVBase\JVBIcons(); $queue = (is_user_logged_in()) ? [ 'api' => rest_url('jvb/v1/'), 'currentUser' => $userID, 'nonce' => wp_create_nonce('wp_rest'), 'dash' => wp_create_nonce('dash-'.$userID), 'favourites' => wp_create_nonce('favourites-'.$userID), 'notifications' => wp_create_nonce('notifications-'.$userID), 'icons' => $icons->localizeIcons(), 'labels' => jvbGetLabels(), ] : [ 'api' => rest_url('jvb/v1/'), 'nonce' => wp_create_nonce('wp_rest'), 'currentUser' => false, 'redirect' => wp_login_url(home_url(add_query_arg(null, null))), // Current URL as redirect 'icons' => $icons->localizeIcons(), 'labels' => jvbGetLabels(), ]; wp_localize_script('jvb-queue', 'jvbSettings', $queue); $initUserSettings = 'async function initUserItems() { if (!jvbSettings.currentUser) return; window.userFavourites = {}; window.userVotes = {}; '; if (Features::forSite()->has('favourites')) { wp_enqueue_script('jvb-favourites'); $initUserSettings .= ' //Fetch user favourites try { const result = await window.jvbCache.fetchWithCache( `${jvbSettings.api}favourites?all=true`, { method: \'GET\', headers: {\'X-WP-Nonce\': jvbSettings.nonce} } ); if (result && result.favourites) { for (const key in result.favourites) { window.userFavourites[key] = new Set(); result.favourites[key].forEach(id => { window.userFavourites[key].add(parseInt(id)); }); } } } catch (error) { console.error(\'Failed to fetch user favourites:\', error); }'; } if (Features::anyContentHas('karma') || Features::anyTaxonomyHas('karma') || Features::anyUserHas('karma')) { wp_enqueue_script('jvb-votes'); $initUserSettings .= '// Fetch user votes try { const result = await window.jvbCache.fetchWithCache( `${jvbSettings.api}vote?user=${jvbSettings.currentUser}`, { method: \'GET\', headers: {\'X-WP-Nonce\': jvbSettings.nonce} }, {forceRefresh: true} ); window.userVotes = {}; if (result) { for (const key in result) { window.userVotes[key] = new Map(); for (const [id, vote] of Object.entries(result[key])) { window.userVotes[key].set(parseInt(id), vote); } } } } catch (error) { console.error(\'Failed to fetch user votes:\', error); }'; } $initUserSettings .= '} initUserItems();'; // wp_add_inline_script('jvb-queue', $initUserSettings, 'after'); if (is_search() || is_tax(BASE.'shop') || is_singular(BASE.'artist') || jvbIsDirectory() ) { wp_enqueue_script('jvb-page-nav'); } // Only load on single shop pages or other relevant pages if (is_tax(BASE.'shop') || is_singular(BASE.'partner')) { $ID = get_queried_object_id(); if (is_tax()) { $check = get_term_meta($ID, BASE.'has_map', true); } else { $check = get_post_meta($ID, BASE.'has_map', true); } // if ($check && $check !== '') { //// wp_enqueue_script( //// 'google-maps-frontend', //// 'https://maps.googleapis.com/maps/api/js?key=' . GOOGLE_API . '&callback=googleMapsLoaded', //// [], //// null, //// ['strategy' => 'async', //// 'in_footer' => true] //// ); // // // Add the callback function // wp_add_inline_script('google-maps-frontend', ' // function googleMapsLoaded() { // if (window.googleMapsCallbacks && window.googleMapsCallbacks.length) { // window.googleMapsCallbacks.forEach(callback => callback()); // } // } // '); // } } if (is_user_logged_in()) { wp_enqueue_script('jvb-notifications'); wp_localize_script('jvb-notifications', 'notificationSettings', array( 'homeUrl' => home_url(), 'strings' => array( 'loading' => 'Loading...', 'error' => 'Failed to load notifications', 'noNotifications' => 'No new notifications', 'viewAll' => 'View All Notifications', 'markRead' => 'Mark as read', 'review' => 'Review' ) )); } jvbAddScriptDependency('jvb-feed-view-script', 'jvb-queue'); jvbAddScriptDependency('jvb-feed-view-script', 'jvb-selector'); jvbAddScriptDependency('jvb-feed-view-script', 'jvb-gallery'); // jvbAddScriptDependency('jvb-feed-view-script', 'jvb-loading'); jvbAddScriptDependency('jvb-forms-view-script', 'jvb-queue'); jvbAddScriptDependency('jvb-forms-view-script', 'jvb-quill'); jvbAddScriptDependency('jvb-forms-view-script', 'jvb-form'); jvbAddScriptDependency('jvb-forms-view-script', 'jvb-tabs'); } function jvbAdminMap():void { // wp_enqueue_script( // 'google-maps', // 'https://maps.googleapis.com/maps/api/js?key=' . GOOGLE_API . '&libraries=places&callback=googleMapsLoaded', // [], // null, // [ // 'strategy' => 'async', // 'in_footer' => true // ] // ); // // // Add the callback function // wp_add_inline_script('google-maps', ' // function googleMapsLoaded() { // if (window.googleMapsCallbacks && window.googleMapsCallbacks.length) { // window.googleMapsCallbacks.forEach(callback => callback()); // } // } // '); } function jvbAddScriptDependency(string $handle, string $dep):bool { global $wp_scripts; $script = $wp_scripts->query($handle); if (!$script) { return false; } if (!in_array($dep, $script->deps)) { $script->deps[] = $dep; } return true; } add_action('wp_body_open', 'jvbAccessibility'); function jvbAccessibility():void { echo '
'; } //add_action('wp_head', 'jvbDumpIt'); function jvbDumpIt() { } //add_filter('map_meta_cap', function($caps, $cap, $user_id, $args) { // error_log('Caps: '.print_r($caps, true)); // error_log('Cap: '.print_r($cap, true)); // error_log('User ID: '.print_r($user_id, true)); // error_log('Args: '.print_r($args, true)); // return $caps; //}, 10, 4); add_action( 'doing_it_wrong_run', function( $function, $message, $version ) { if ( 'map_meta_cap' === $function ) { error_log( "Map Meta Cap Wrong: $message" ); error_log( print_r( wp_debug_backtrace_summary( null, 0, false ), true ) ); } }, 10, 3 );