=Some more tweaks. Mostly on the MenuBlock and adding the Meta.php to WooCommerce Products
| | |
| | | error_log('Tables created!'); |
| | | |
| | | // Store schema version |
| | | update_option('jvb_db_version', '1.0.0'); |
| | | update_option(BASE.'db_version', '1.0.0'); |
| | | error_log('Starting schedules...'); |
| | | jvbSchedules(); |
| | | error_log('Schedules done!'); |
| | |
| | | // Optional: Add upgrade routine |
| | | function jvbMaybeUpgrade():void |
| | | { |
| | | $current_version = get_option('jvb_db_version', '0'); |
| | | $current_version = get_option(BASE.'db_version', '0'); |
| | | if (version_compare($current_version, '1.0.0', '<')) { |
| | | jvbActivatePlugin(); |
| | | } |
| | |
| | | use JVBase\base\Site; |
| | | use JVBase\managers\Cache; |
| | | use JVBase\meta\Meta; |
| | | use JVBase\registrar\Registrar; |
| | | use WP_Block; |
| | | use WP_Post; |
| | | use WP_Query; |
| | | |
| | | if (!defined('ABSPATH')) { |
| | |
| | | public function __construct() |
| | | { |
| | | $this->cache = Cache::for('menu', 'post', WEEK_IN_SECONDS); |
| | | $this->cache->flush(); |
| | | if (Site::hasIntegration('square')) { |
| | | $this->base = '_square_'; |
| | | } else if (Site::hasIntegration('helcim')) { |
| | | $this->base = '_helcim_'; |
| | | } |
| | | add_action('init', [ $this, 'registerBlock' ]); |
| | | add_action('save_post', [$this, 'flushCache'], 10, 2); |
| | | } |
| | | |
| | | public function flushCache(int $postID, WP_Post $post):void |
| | | { |
| | | if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) return; |
| | | if (wp_is_post_revision($postID) || wp_is_post_autosave($postID)) return; |
| | | |
| | | $postType = $post->post_type; |
| | | if ($postType !== 'product' && !in_array($postType, Registrar::getFoodMenuTypes())) { |
| | | return; |
| | | } |
| | | error_log('Flushing food menu block cache'); |
| | | $this->cache->flush(); |
| | | } |
| | | public function registerBlock():void |
| | | { |
| | | register_block_type($this->path, [ |
| | |
| | | return ''; |
| | | } |
| | | jvbInlineStyles('forms'); |
| | | $this->cache->flush(); |
| | | return $this->cache->remember( |
| | | $this->params, |
| | | function() { |
| | |
| | | $this->renderOnThisPage(); |
| | | } |
| | | |
| | | protected function termHasPosts(int $termID):bool |
| | | { |
| | | $query = new WP_Query([ |
| | | 'post_type' => 'product', |
| | | 'post_status' => 'publish', |
| | | 'posts_per_page' => 1, |
| | | 'fields' => 'ids', |
| | | 'tax_query' => [ |
| | | [ |
| | | 'taxonomy' => 'product_cat', |
| | | 'terms' => $termID |
| | | ] |
| | | ] |
| | | ]); |
| | | return $query->have_posts(); |
| | | } |
| | | |
| | | protected function renderHeader():void |
| | | { |
| | | $title = 'Our Menu'; |
| | |
| | | $sections = $this->getSections(); |
| | | foreach ($sections as $section) { |
| | | // if (!jvbTermHasPosts($section['id'], BASE.'section')) { |
| | | if (!jvbTermHasPosts($section['id'], 'product_cat')) { |
| | | if (!$this->termHasPosts($section['id'])) { |
| | | continue; |
| | | } |
| | | ?> |
| | |
| | | |
| | | $fields = $meta->getAll(); |
| | | |
| | | // jvbDump($fields, 'Fields'); |
| | | |
| | | |
| | | $excerpt = get_the_excerpt($ID); |
| | | $isVariable = !empty($fields['variations']??[]); |
| | | $variations = $isVariable ? array_map('floatval', array_column($fields['variations'], 'price')) : []; |
| | | $priceRange = $isVariable ? |
| | | (min($variations).' - '.max($variations)) : |
| | | $fields['_price']??''; |
| | | (jvbCurrency(min($variations)).' - '.jvbCurrency(max($variations))) : |
| | | jvbCurrency($fields['_price']??''); |
| | | // if (!$isVariable) { |
| | | // jvbDump($fields, 'Fields'); |
| | | // } |
| | | |
| | | $out = sprintf( |
| | | '<div class="menu-item%s" data-section="%s" data-label="%s" data-id="%s"> |
| | | '<div id="%s" class="menu-item%s" data-section="%s" data-label="%s" data-id="%s"> |
| | | <div class="header row x-btw"> |
| | | <h3>%s</h3> |
| | | <p class="price">$%s</p> |
| | | <p class="price">%s</p> |
| | | </div> |
| | | <div class="description">%s</div> |
| | | <div class="info col right">', |
| | | sanitize_title($fields['post_title']), |
| | | $isVariable ? ' variable' : '', |
| | | $slug, |
| | | $fields['post_title'], |
| | |
| | | public function handleSavePost(int $postID, WP_Post $post, bool $update):void |
| | | { |
| | | if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) return; |
| | | if (wp_is_post_revision($postID)) return; |
| | | if (wp_is_post_revision($postID) || wp_is_post_autosave($postID)) return; |
| | | |
| | | error_log('=== ['.$this->service_name.']::handleSavePost called'); |
| | | |
| | |
| | | private static ?wpdb $wpdb = null; |
| | | private static string $prefix; |
| | | protected string $tableName; |
| | | protected bool $table_exists = false; |
| | | protected string $definition; |
| | | protected string $fullTableName; |
| | | protected bool $useTransactions; |
| | |
| | | { |
| | | if (!isset(self::$instances[$tableName])) { |
| | | self::$instances[$tableName] = new self($tableName, $user, $auth, $useTransactions); |
| | | self::$instances[$tableName]->setFlags(); |
| | | } |
| | | |
| | | |
| | | return self::$instances[$tableName]; |
| | | } |
| | | protected function setFlags():void |
| | | { |
| | | $this->table_exists = !is_null(self::$wpdb->get_var("SHOW TABLES LIKE '{$this->fullTableName}'")); |
| | | } |
| | | |
| | | public static function destroyInstance(string $tableName):void |
| | | { |
| | |
| | | require_once(ABSPATH . 'wp-admin/includes/upgrade.php'); |
| | | |
| | | foreach (self::$instances as $instance) { |
| | | if (!$instance->wpdb->get_var("SHOW TABLES LIKE '{$instance->fullTableName}'")) { |
| | | if (!$instance->table_exists) { |
| | | $instance->createTable(); |
| | | } |
| | | } |
| | |
| | | error_log('[CustomTable]No definition set for '.$this->tableName); |
| | | return; |
| | | } |
| | | if (self::$wpdb->get_var("SHOW TABLES LIKE '{$this->fullTableName}'")) { |
| | | if ($this->table_exists) { |
| | | return; |
| | | } |
| | | require_once(ABSPATH . 'wp-admin/includes/upgrade.php'); |
| | |
| | | $error_msg = "SQL Error creating table {$this->tableName}: " . self::$wpdb->last_error; |
| | | error_log($error_msg); |
| | | error_log("Failed SQL Query: " . $schema); |
| | | } elseif (self::$wpdb->get_var("SHOW TABLES LIKE '{$this->fullTableName}'")) { |
| | | } else { |
| | | error_log("Successfully created table: {$this->fullTableName}"); |
| | | } |
| | | } |
| | |
| | | foreach ($this->icons as $style => $names) { |
| | | $styleClass = ($style !== $this->style) ? '-'.substr($style, 0, 2) : ''; |
| | | foreach ($names as $icon) { |
| | | $svg = $this->getEncodedSVG($icon, $style); |
| | | if ($svg !== '') { |
| | | if ($icon === 'caret-down') { |
| | | $css .= 'details summary::after,'; |
| | | } elseif ($icon === 'faders-horizontal') { |
| | | $css .= 'details.all-filters summary::after,'; |
| | | } elseif ($icon === 'link') { |
| | | $css .= 'input[type=url],'; |
| | | } elseif ($icon === apply_filters('jvbSeparatorLogo', 'logo')) { |
| | | $css .= 'hr.logo::before,'; |
| | | } |
| | | $css .= ".icon-{$icon}{$styleClass}{"; |
| | | $css .= "--icon:url('data:image/svg+xml;base64,{$svg}');"; |
| | | $css .= "}"; |
| | | } |
| | | $css .= $this->generateSingleIconCss($icon, $style, $styleClass); |
| | | } |
| | | } |
| | | update_option($this->timestampKey, time()); |
| | | return $this->minifyCss($css); |
| | | } |
| | | |
| | | public function generateSingleIconCss(string $icon, ?string $style = null, ?string $styleClass = null):string |
| | | { |
| | | $style = $style??$this->style; |
| | | $styleClass = $styleClass??($style !== $this->style) ? '-'.substr($style, 0, 2) : ''; |
| | | $css = ''; |
| | | $svg = $this->getEncodedSVG($icon, $style); |
| | | if ($svg !== '') { |
| | | if ($icon === 'caret-down') { |
| | | $css .= 'details summary::after,'; |
| | | } elseif ($icon === 'faders-horizontal') { |
| | | $css .= 'details.all-filters summary::after,'; |
| | | } elseif ($icon === 'link') { |
| | | $css .= 'input[type=url],'; |
| | | } elseif ($icon === apply_filters('jvbSeparatorLogo', 'logo')) { |
| | | $css .= 'hr.logo::before,'; |
| | | } |
| | | $css .= ".icon-{$icon}{$styleClass}{"; |
| | | $css .= "--icon:url('data:image/svg+xml;base64,{$svg}');"; |
| | | $css .= "}"; |
| | | } |
| | | return $css; |
| | | } |
| | | |
| | | protected function minifyCSS(string $css): string |
| | | { |
| | | // Remove comments |
| | |
| | | /** |
| | | * Get a specific value from an operation - backwards compatibility |
| | | */ |
| | | public function getOperationValue(string $id, string $column, bool $decodeJson = true): \static|string|int|array|null |
| | | public function getOperationValue(string $id, string $column, bool $decodeJson = true): static|string|int|array|null |
| | | { |
| | | $op = $this->get($id); |
| | | if (!$op) { |
| | |
| | | 'type' => 'text', |
| | | 'label' => 'Short Description', |
| | | ]; |
| | | $fields['post_id'] = [ |
| | | $fields['ID'] = [ |
| | | 'type' => 'text', |
| | | 'label' => 'ID', |
| | | ]; |
| | |
| | | |
| | | |
| | | $product = wc_get_product($id); |
| | | |
| | | $fields['sku'] = [ |
| | | 'type' => 'text', |
| | | 'label' => 'SKU', |
| | |
| | | $value = ''; |
| | | if ($this->type === 'option') { |
| | | $value = get_option(BASE . $fieldName, $config['default'] ?? ''); |
| | | } else if ($this->wpObject && $this->wpObject->post_type === 'product') { |
| | | if (property_exists($this->wpObject, $fieldName)) { |
| | | $value = $this->wpObject->$fieldName; |
| | | } else { |
| | | $product = wc_get_product($this->wpObject->ID); |
| | | $value = match ($fieldName) { |
| | | 'sku' => $product->get_sku(), |
| | | '_price' => $product->get_price(), |
| | | 'description'=> $product->get_short_description(), |
| | | 'sale' => $product->get_sale_price(), |
| | | 'img' => $product->get_image_id(), |
| | | '_stock' => $product->get_stock_quantity(), |
| | | '_stock_status' => $product->get_stock_status(), |
| | | default => '', |
| | | }; |
| | | } |
| | | |
| | | } else if ( |
| | | ($this->wpObject && property_exists($this->wpObject, $fieldName)) |
| | | || ($type === 'user' && $this->wpObject && property_exists($this->wpObject->data, $fieldName))) { |
| | |
| | | //Shared Flags |
| | | 'favouritable', 'karma', 'show_feed', 'show_directory', 'approve_new', 'has_responses', 'invitable', |
| | | //Post Flags |
| | | 'hide_single', 'redirect_to_author', 'is_calendar', 'single_image', 'is_timeline', 'is_gallery', 'is_faq', 'is_glossary', 'rewrite_taxonomy', 'add_image_column', 'is_profile', |
| | | 'hide_single', 'redirect_to_author', 'is_calendar', 'single_image', 'is_timeline', 'is_gallery', 'is_faq', 'is_glossary', 'rewrite_taxonomy', 'add_image_column', 'is_profile', 'is_food_menu', |
| | | //Taxonomy Flags |
| | | 'is_content', 'is_ownable', 'verify_entry', 'track_changes', 'associate_user_content', 'prefix_post_type', |
| | | //User Flags |
| | |
| | | */ |
| | | public bool $profile_link; |
| | | public bool $is_profile = false; |
| | | public bool $is_food_menu = false; |
| | | /** |
| | | * @var array |
| | | */ |
| | |
| | | }, $hasProfiles)); |
| | | } |
| | | |
| | | public function setAsFoodMenu():void |
| | | { |
| | | $this->is_food_menu = true; |
| | | } |
| | | public static function getFoodMenuTypes():array |
| | | { |
| | | return array_map('jvbCheckBase', self::withFeature('is_food_menu')); |
| | | } |
| | | |
| | | public function setUserSubtype(string $type):self |
| | | { |
| | | $this->user_subtype = sanitize_text_field($type); |