| | |
| | | use DateTime; |
| | | use DOMDocument; |
| | | use JVBase\managers\Cache; |
| | | use JVBase\managers\LoginManager; |
| | | use JVBase\managers\SEO\BreadcrumbManager; |
| | | use JVBase\utility\Image; |
| | | use WP_Block; |
| | | use WP_Query; |
| | | |
| | |
| | | class CustomBlocks |
| | | { |
| | | protected Cache $cache; |
| | | |
| | | protected static ?WP_Query $currentLoop = null; |
| | | protected static ?int $currentQueryId = null; |
| | | protected static array $counters = []; |
| | | protected static ?WP_Query $originalQuery = null; |
| | | protected array $ignore = ['align','alt','area','backgroundColor','borderColor','buttonText','buttonPosition','buttonUseIcon','categories','className','columns','contentPosition','customOverlayColor','dimRatio','displayAsDropdown','displayAuthor','displayFeaturedImage','displayPostContent','displayPostContentRadio','displayPostDate','excerptLength','featuredImageAlign','fontSize','gradient','height','iconColor','iconColorValue','iconColorValue','iconBackgroundColor','iconBackgroundColorValue','id','imageFill','isDark','isLink','isSearchFieldHidden','isStackedOnMobile','isUserOverlayColor','kind','label','largestFontSize','layout','level','mediaId','mediaLink','mediaSizeSlug','mediaType','metadata','minHeight','minHeightUnit','opacity','opensInNewTab','order','orderBy','ordered','overlayMenu','placeholder','postLayout','postsToShow','query', 'queryId','ref','rel','shouldSyncIcon','showEmpty','showHierarchy','showLabel','showLabels','showOnlyTopLevel','showPostCounts','showTagCounts','size','sizeSlug','slug','smallestFontSize','tagName','taxonomy','term','textAlign','textColor','theme','title','type','url','useFeaturedImage','width','widthUnit',]; |
| | | |
| | | //For custom style output for nested links, etc |
| | | protected static array $pendingStyles = []; |
| | | protected static array $pendingClass = []; |
| | | public function __construct() |
| | | { |
| | | $this->cache = Cache::for('blocks', WEEK_IN_SECONDS); |
| | | $this->cache->connect('post')->connect('taxonomy'); |
| | | add_filter('render_block', [$this, 'render'], 900, 3); |
| | | $this->cache->flush(); |
| | | add_filter('pre_render_block', [$this, 'prerender'], 10, 3); |
| | | add_filter('render_block', [$this, 'render'], 10, 2); |
| | | |
| | | add_action('init', [$this, 'registerBlockStyles']); |
| | | } |
| | |
| | | 'label' => __('Callout Alt', 'jvb') |
| | | ] |
| | | ); |
| | | register_block_style( |
| | | 'core/separator', |
| | | [ |
| | | 'name' =>'logo', |
| | | 'label' => __('With Logo', 'jvb') |
| | | ] |
| | | ); |
| | | } |
| | | |
| | | public function render(string $content, array $block, WP_Block $instance) |
| | | { |
| | | protected function checkMethods(?string $content, array $block, ?WP_Block $parent = null, bool $isPrerender = false):?string |
| | | { |
| | | $blockName = $this->sanitizeBlockName($block); |
| | | $method = 'render_'.$blockName; |
| | | |
| | | $base = ($isPrerender) ? 'prerender_' : 'render_'; |
| | | $method = $base.$blockName; |
| | | $function = BASE.$method; |
| | | |
| | | if (function_exists($function)) { |
| | | return $function($block, $content); |
| | | // return $this->cache->remember( |
| | | // get_the_ID(), |
| | | // function () use ($function, $block, $content) { |
| | | // return $function($block, $content); |
| | | // } |
| | | // ); |
| | | return $function($block, $content, $parent); |
| | | } else if (method_exists($this, $method)) { |
| | | return $this->$method($block, $content); |
| | | // |
| | | // return $this->cache->remember( |
| | | // get_the_ID(), |
| | | // function () use ($method, $block, $content) { |
| | | // return $this->$method($block, $content); |
| | | // } |
| | | // ); |
| | | } else if (!empty($block['blockName'])){ |
| | | //TESTING |
| | | $ignore = [ |
| | | 'core/null', |
| | | 'core/post-title', |
| | | 'core/list-item', |
| | | 'core/site-title', |
| | | 'jvb/forms' |
| | | ]; |
| | | // if (!in_array($block['blockName'], $ignore)) { |
| | | // jvbDump('No method found for '.print_r($block['blockName'], true)); |
| | | // } |
| | | $content = $this->$method($block, $content, $parent); |
| | | return $isPrerender ? $this->maybeOutputCustomStyles().$content : $content; |
| | | } elseif (!empty($blockName) && JVB_TESTING) { |
| | | if (!in_array($block['blockName'], $this->getIgnore($isPrerender))) { |
| | | jvbDump('No method found for '.print_r($block['blockName'], true)); |
| | | } |
| | | } |
| | | if ($block['blockName'] === 'jvb/feed') { |
| | | // Enqueue the feed block script (it will automatically load dependencies) |
| | | $this->localize_feedblock(); |
| | | } |
| | | return $content; |
| | | } |
| | | protected function getIgnore(bool $isPrerender):array |
| | | { |
| | | //Ignore for both |
| | | $base = [ |
| | | 'core/null' |
| | | ]; |
| | | if ($isPrerender) { |
| | | $base = array_merge($base, [ |
| | | 'core/query-pagination', |
| | | 'core/query-pagination-previous', |
| | | 'core/query-pagination-next', |
| | | 'core/query-pagination-numbers', |
| | | 'core/query', |
| | | 'core/calendar', |
| | | 'core/archives', |
| | | ]); |
| | | } else { |
| | | $base = array_merge($base, [ |
| | | |
| | | ]); |
| | | } |
| | | return $base; |
| | | } |
| | | public function prerender(?string $content, array $block, ?WP_Block $parent = null):?string |
| | | { |
| | | $result = $this->checkMethods($content, $block, $parent, true); |
| | | return $result; |
| | | } |
| | | |
| | | public function render(string $content, array $block):string |
| | | { |
| | | if ($block['blockName'] === 'jvb/feed') { |
| | | // Enqueue the feed block script (it will automatically load dependencies) |
| | | $this->localize_feedblock(); |
| | | } |
| | | if ($block['blockName'] === 'jvb/forms') { |
| | | wp_enqueue_style('jvb-form'); |
| | | } |
| | | return $content; |
| | | |
| | | return $this->checkMethods($content, $block); |
| | | } |
| | | |
| | | /*********************************** |
| | |
| | | */ |
| | | |
| | | |
| | | public function render_core_button(array $block):string |
| | | public function prerender_core_button(array $block, ?string $content, ?WP_Block $parent):?string |
| | | { |
| | | // jvbDump($block, 'Button'); |
| | | // jvbDump($parent, 'Parent'); |
| | | preg_match('/href="([^"]*)"/', $block['innerHTML'], $url); |
| | | preg_match('/>([^<]*)<\/a>/', $block['innerHTML'], $label); |
| | | |
| | |
| | | } |
| | | $icon = ''; |
| | | if (str_contains($url[1], 'google.com/maps')) { |
| | | $icon = 'google-logo'; |
| | | $icon = jvbIcon('google-logo'); |
| | | } |
| | | if (str_contains($url[1], 'maps.apple.com')) { |
| | | $icon = 'apple-logo'; |
| | | $icon = jvbIcon('apple-logo'); |
| | | } |
| | | |
| | | if ($icon !== '') { |
| | | return sprintf( |
| | | '<li%s><a href="%s" title="Find Us On %s">%s Maps</a></li>', |
| | | $this->getClassesAndStyles($block['attrs']), |
| | | $this->getClassesAndStyles($block['attrs']??[]), |
| | | esc_url($url[1]), |
| | | esc_html($label[1]), |
| | | jvbIcon($icon) |
| | | $icon |
| | | ); |
| | | } |
| | | |
| | | return sprintf( |
| | | '<li%s><a href="%s">%s</a></li>', |
| | | $this->getClassesAndStyles($block['attrs']), |
| | | $this->getClassesAndStyles($block['attrs']??[]), |
| | | esc_url($url[1]), |
| | | esc_html($label[1]) |
| | | ); |
| | | } |
| | | |
| | | public function render_core_buttons(array $block):string |
| | | public function prerender_core_buttons(array $block, ?string $content, ?WP_Block $parent):?string |
| | | { |
| | | return '<ul'.$this->getClassesAndStyles($block['attrs'], ['buttons','row']).'>'. |
| | | // jvbDump($block, 'buttons'); |
| | | // jvbDump($parent, 'Parent'); |
| | | return '<ul'.$this->getClassesAndStyles($block['attrs']??[], ['buttons','row']).'>'. |
| | | $this->innerBlocks($block).'</ul>'; |
| | | } |
| | | |
| | | public function render_core_column(array $block):string |
| | | public function prerender_core_column(array $block, ?string $content, ?WP_Block $parent):?string |
| | | { |
| | | // jvbDump($block, 'column'); |
| | | // jvbDump($parent, 'Parent'); |
| | | $styles = (array_key_exists('attrs', $block) && |
| | | array_key_exists('width', $block['attrs'])) ? |
| | | ['flex-basis:'.$block['attrs']['width']] |
| | | : []; |
| | | return '<div'. |
| | | $this->getClassesAndStyles($block['attrs'], ['col'], $styles).'>'. |
| | | $this->getClassesAndStyles($block['attrs']??[], ['col'], $styles).'>'. |
| | | $this->innerBlocks($block).'</div>'; |
| | | } |
| | | |
| | | public function render_core_columns(array $block):string |
| | | public function prerender_core_columns(array $block, ?string $content, ?WP_Block $parent):?string |
| | | { |
| | | return '<section'. |
| | | $this->getClassesAndStyles($block['attrs'], ['columns']).'>'. |
| | | $this->innerBlocks($block).'</section>'; |
| | | jvbDump($block, 'columns'); |
| | | $attrs = $block['attrs']??[]; |
| | | $tagName = array_key_exists('tagName', $attrs) ? $attrs['tagName'] : 'section'; |
| | | |
| | | $classes = ['row', 'nowrap']; |
| | | if (!array_key_exists('isStackedOnMobile', $attrs) || $attrs['isStackedOnMobile'] === true){ |
| | | $classes[] = 'stack-small'; |
| | | } |
| | | return sprintf( |
| | | '<%s%s>%s</%s>', |
| | | $tagName, |
| | | $this->getClassesAndStyles($attrs, $classes), |
| | | $this->innerBlocks($block).'</section>', |
| | | $tagName |
| | | ); |
| | | } |
| | | //core_comment_template |
| | | |
| | | public function render_core_group(array $block):string |
| | | public function prerender_core_group(array $block, ?string $content, ?WP_Block $parent):?string |
| | | { |
| | | $tag = (array_key_exists('tagName', $block['attrs'])) ? $block['attrs']['tagName'] : 'div'; |
| | | // jvbDump($block, 'group'); |
| | | // jvbDump($parent, 'Parent'); |
| | | $tag = (array_key_exists('tagName', $block['attrs']??[])) ? $block['attrs']['tagName'] : 'div'; |
| | | |
| | | $classes = ($tag === 'main') ? |
| | | '' : |
| | | $this->getClassesAndStyles($block['attrs'], ['group']); |
| | | return '<'.$tag.$classes.'>'.$this->innerBlocks($block).'</'.$tag.'>'; |
| | | |
| | | return sprintf( |
| | | '<%s%s>%s</%s>', |
| | | $tag, |
| | | $tag === 'main' ? '' : $this->getClassesAndStyles($block['attrs']??[], ['group']), |
| | | $this->innerBlocks($block), |
| | | $tag |
| | | ); |
| | | } |
| | | //core_home_link |
| | | //core_more |
| | | //core_nextpage |
| | | public function prerender_core_nextpage(array $block, ?string $content, ?WP_Block $parent):?string |
| | | { |
| | | |
| | | public function render_core_separator(array $block):string |
| | | return str_replace('</a>', '</a></li>',str_replace('<a', '<li><a', wp_link_pages([ |
| | | 'before' => '<nav class="pagination x-btw"><ul>', |
| | | 'after' => '</ul></nav>', |
| | | 'nextpagelink' => __('<span>Next </span>'.jvbIcon('caret-circle-right'), 'jvb'), |
| | | 'previouspagelink' => __(jvbIcon('caret-circle-left').'<span> Previous</span>', 'jvb'), |
| | | 'next_or_number'=> 'next', |
| | | 'echo' => false |
| | | ]))); |
| | | } |
| | | |
| | | public function prerender_core_separator(array $block, ?string $content, ?WP_Block $parent):?string |
| | | { |
| | | return '<hr'.$this->getClassesAndStyles($block['attrs']).'>'; |
| | | // jvbDump($block, 'separator'); |
| | | // jvbDump($parent, 'Parent'); |
| | | $attrs = $block['attrs']??[]; |
| | | $logo = ''; |
| | | if (array_key_exists('className', $attrs) && $attrs['className'] === 'is-style-logo'){ |
| | | $logo = apply_filters('jvbSeparatorLogo', 'logo'); |
| | | if (!empty($logo)) { |
| | | $logo = jvbIcon($logo); |
| | | } |
| | | } |
| | | return sprintf( |
| | | '<hr%s>', |
| | | $this->getClassesAndStyles($attrs), |
| | | // $logo |
| | | ); |
| | | } |
| | | |
| | | public function render_core_spacer(array $block):string |
| | | public function prerender_core_spacer(array $block, ?string $content, ?WP_Block $parent):?string |
| | | { |
| | | return '<div'.$this->getClassesAndStyles($block['attrs'], ['spacer'], ['height:2rem']). |
| | | |
| | | // jvbDump($block, 'spsacer'); |
| | | // jvbDump($parent, 'Parent'); |
| | | return '<div'.$this->getClassesAndStyles($block['attrs']??[], ['spacer'], ['height:2rem']). |
| | | ' aria-hidden="true"></div>'; |
| | | } |
| | | //core_table_of_contents |
| | |
| | | * Media Blocks |
| | | */ |
| | | //core_audio |
| | | public function render_core_cover(array $block):string |
| | | public function prerender_core_cover(array $block, ?string $content, ?WP_Block $parent):?string |
| | | { |
| | | |
| | | // jvbDump($block, 'cover'); |
| | | // jvbDump($parent, 'Parent'); |
| | | // Extract block attributes |
| | | $attrs = $block['attrs'] ?? []; |
| | | $attrs = $block['attrs'] ?:[]; |
| | | $innerContent = $this->innerBlocks($block); |
| | | |
| | | $position = 'object-position: center;'; |
| | |
| | | |
| | | //core_file |
| | | |
| | | public function render_core_gallery(array $block):string |
| | | public function prerender_core_gallery(array $block, ?string $content, ?WP_Block $parent):?string |
| | | { |
| | | return '<ul'.$this->getClassesAndStyles($block['attrs'], ['gallery']).'>'. |
| | | // jvbDump($block, 'gallery'); |
| | | // jvbDump($parent, 'Parent'); |
| | | return '<ul'.$this->getClassesAndStyles($block['attrs']??[], ['gallery']).'>'. |
| | | $this->innerBlocks($block,'<li>', '</li>'). |
| | | '</ul>'; |
| | | } |
| | | |
| | | public function render_core_image(array $block):string |
| | | public function prerender_core_image(array $block, ?string $content, ?WP_Block $parent):?string |
| | | { |
| | | // jvbDump($block, 'image'); |
| | | // jvbDump($parent, 'Parent'); |
| | | $ID = $this->imageID('', $block); |
| | | if (!$ID) { |
| | | return ''; |
| | |
| | | wp_get_attachment_caption($ID) . |
| | | '</figcaption>' : |
| | | '<figcaption>' . $title . '</figcaption>'; |
| | | $size = array_key_exists('sizeSlug', $block['attrs']) ? $block['attrs']['sizeSlug'] : 'large'; |
| | | $size = array_key_exists('sizeSlug', $block['attrs']??[]) ? $block['attrs']['sizeSlug'] : 'large'; |
| | | return '<figure'. |
| | | $this->getClassesAndStyles($block['attrs']).'>'. |
| | | $this->getClassesAndStyles($block['attrs']??[]).'>'. |
| | | $this->imageLink(true, $ID, 'tiny', $size) . |
| | | $caption.'</figure>'; |
| | | } |
| | | |
| | | public function render_core_media_text(array $block):string |
| | | public function prerender_core_media_text(array $block, ?string $content, ?WP_Block $parent):?string |
| | | { |
| | | |
| | | // jvbDump($block, 'media text'); |
| | | // jvbDump($parent, 'Parent'); |
| | | $ID = $this->imageID('', $block); |
| | | $attrs = $block['attrs']??[]; |
| | | |
| | | $size = array_key_exists('mediaSizeSlug', $block['attrs']) ? $block['attrs']['mediaSizeSlug'] : 'large'; |
| | | $size = array_key_exists('mediaSizeSlug', $attrs) ? $attrs['mediaSizeSlug'] : 'large'; |
| | | $imgLink = ($ID) ? $this->imageLink(true, $ID, 'tiny', $size) : ''; |
| | | |
| | | $inner = $this->innerBlocks($block); |
| | | |
| | | |
| | | $classes = ['media-text', 'row']; |
| | | if (array_key_exists('isStackedOnMobile', $block['attrs'])) { |
| | | $classes[] = 'nowrap'; |
| | | $classes = ['media-text', 'row', 'nowrap']; |
| | | if (!array_key_exists('isStackedOnMobile', $attrs) || $attrs['isStackedOnMobile'] === true) { |
| | | $classes[] = 'stack-small'; |
| | | } |
| | | $content = '<div'.$this->getClassesAndStyles($block['attrs'], $classes).'>'; |
| | | $content .= (array_key_exists( |
| | | 'mediaPosition', |
| | | $block['attrs'] |
| | | ) && $block['attrs']['mediaPosition'] == 'right') ? |
| | | '<div>'.$inner.'</div><figure>'.$imgLink.'</figure>' : |
| | | '<figure>'.$imgLink.'</figure><div>'.$inner.'</div>'; |
| | | $content .= '</div>'; |
| | | return $content; |
| | | |
| | | $inside = array_key_exists('mediaPosition', $attrs) && $attrs['mediaPosition'] === 'right' |
| | | ? sprintf( |
| | | '<div>%s</div><figure>%s</figure>', |
| | | $inner, $imgLink |
| | | ) : sprintf( |
| | | '<figure>%s</figure><div>%s</div>', |
| | | $imgLink, $inner |
| | | ); |
| | | |
| | | return sprintf( |
| | | '<div%s>%s</div>', |
| | | $this->getClassesAndStyles($attrs, $classes), |
| | | $inside |
| | | ); |
| | | } |
| | | //core_video |
| | | |
| | | public function prerender_core_video(array $block, ?string $content, ?WP_Block $parent):?string |
| | | { |
| | | jvbDump($block, 'video'); |
| | | // jvbDump($parent, 'Parent'); |
| | | $ID = $this->imageID('', $block); |
| | | if (!$ID) { |
| | | return ''; |
| | | } |
| | | |
| | | jvbDump($ID); |
| | | |
| | | $title = (get_the_title($ID) !== '') ? '<b>'.get_the_title($ID).'</b>' : ''; |
| | | $caption = (wp_get_attachment_caption($ID)) ? |
| | | '<figcaption>' . |
| | | $title . |
| | | wp_get_attachment_caption($ID) . |
| | | '</figcaption>' : |
| | | '<figcaption>' . $title . '</figcaption>'; |
| | | $size = array_key_exists('sizeSlug', $block['attrs']??[]) ? $block['attrs']['sizeSlug'] : 'large'; |
| | | return '<figure'. |
| | | $this->getClassesAndStyles($block['attrs']??[]).'>'. |
| | | $this->imageLink(true, $ID, 'tiny', $size) . |
| | | $caption.'</figure>'; |
| | | } |
| | | |
| | | /** |
| | | * Reusable blocks |
| | |
| | | /** |
| | | * Text Blocks |
| | | */ |
| | | //render_core_code |
| | | //render_core_details |
| | | //render_core_footnotes |
| | | //render_core_classic |
| | | public function render_core_heading(array $block):string |
| | | //prerender_core_code |
| | | //prerender_core_details |
| | | //prerender_core_footnotes |
| | | //prerender_core_classic |
| | | public function prerender_core_heading(array $block, ?string $content, ?WP_Block $parent):?string |
| | | { |
| | | $level = (array_key_exists('level', $block['attrs'])) ? $block['attrs']['level'] : '2'; |
| | | $level = (array_key_exists('level', $block['attrs']??[])) ? $block['attrs']['level'] : '2'; |
| | | $content = $this->inside($block); |
| | | $id = sanitize_title(wp_strip_all_tags($this->stripTagContents('small', $content))); |
| | | return '<h'.$level.' id="'.$id.'"'.$this->getClassesAndStyles($block['attrs']).'>'. |
| | | return '<h'.$level.' id="'.$id.'"'.$this->getClassesAndStyles($block['attrs']??[]).'>'. |
| | | $content. |
| | | '</h'.$level.'>'; |
| | | } |
| | | |
| | | public function render_core_list(array $block):string |
| | | public function prerender_core_list(array $block, ?string $content, ?WP_Block $parent):?string |
| | | { |
| | | $tag = (array_key_exists('ordered', $block['attrs'])) ? 'ol' : 'ul'; |
| | | return '<'.$tag.$this->getClassesAndStyles($block['attrs']).'>'.$this->innerBlocks($block).'</'.$tag.'>'; |
| | | // jvbDump($block, 'list'); |
| | | // jvbDump($parent, 'Parent'); |
| | | $tag = (array_key_exists('ordered', $block['attrs']??[])) ? 'ol' : 'ul'; |
| | | $output = '<'.$tag.$this->getClassesAndStyles($block['attrs']??[]).'>'.$this->innerBlocks($block).'</'.$tag.'>'; |
| | | return $output; |
| | | } |
| | | |
| | | // public function render_core_list_item(array $block):string |
| | | // public function prerender_core_list_item(array $block):string |
| | | // { |
| | | // return '<li'.$this->getClassesAndStyles($block['attrs']).'>'.$this->inside($block).'</li>'; |
| | | // } |
| | | //render_core_missing |
| | | //prerender_core_missing |
| | | |
| | | public function render_core_paragraph(array $block):string |
| | | public function prerender_core_paragraph(array $block, ?string $content, ?WP_Block $parent):?string |
| | | { |
| | | return '<p'.$this->getClassesAndStyles($block['attrs']).'>'. |
| | | $this->inside($block, 'p'). |
| | | '</p>'; |
| | | // jvbDump($block, 'paragraph'); |
| | | // jvbDump($parent, 'Parent'); |
| | | $inside = $this->inside($block); |
| | | return empty($inside) ? '' : sprintf( |
| | | '<p%s>%s</p>', |
| | | $this->getClassesAndStyles($block['attrs']??[]), |
| | | $inside |
| | | ); |
| | | } |
| | | public function render_core_quote(array $block): string |
| | | public function prerender_core_quote(array $block, ?string $content, ?WP_Block $parent): ?string |
| | | { |
| | | // jvbDump($block, 'quote'); |
| | | // jvbDump($parent, 'Parent'); |
| | | $innerHTML = $block['innerHTML']; |
| | | |
| | | // Extract cite content first |
| | |
| | | $citeHtml = ($cite === '') ? '' : '<cite>— '.$cite.'</cite>'; |
| | | |
| | | // Get the blockquote content |
| | | $content = $this->inside($block, 'blockquote'); |
| | | $content = $this->innerBlocks($block); |
| | | |
| | | // Remove the cite element from content if it exists |
| | | if ($cite !== '') { |
| | | $content = $this->stripTagContents('cite', $content); |
| | | } |
| | | |
| | | return '<blockquote'.$this->getClassesAndStyles($block['attrs']).'> |
| | | return '<blockquote'.$this->getClassesAndStyles($block['attrs']??[]).'> |
| | | <div class="content">'.$content.'</div>'. |
| | | $citeHtml. |
| | | '</blockquote>'; |
| | | } |
| | | public function render_core_pullquote(array $block): string |
| | | public function prerender_core_pullquote(array $block, ?string $content, ?WP_Block $parent):?string |
| | | { |
| | | // jvbDump($block, 'pullquote'); |
| | | // jvbDump($parent, 'Parent'); |
| | | $innerHTML = $block['innerHTML']; |
| | | |
| | | // Extract cite content first |
| | |
| | | } |
| | | $content = jvb_filter_content( $content); |
| | | |
| | | return '<blockquote'.$this->getClassesAndStyles($block['attrs'], ['pull']).'>'. |
| | | return '<blockquote'.$this->getClassesAndStyles($block['attrs']??[], ['pull']).'>'. |
| | | $content. |
| | | $citeHtml. |
| | | '</blockquote>'; |
| | | } |
| | | //render_core_table |
| | | //render_core_verse |
| | | //prerender_core_table |
| | | //prerender_core_verse |
| | | |
| | | /** |
| | | * Theme Blocks |
| | | */ |
| | | //core_avatar |
| | | //core_loginout |
| | | public function prerender_core_loginout(array $block, ?string $content, ?WP_Block $parent):?string |
| | | { |
| | | $action = is_user_logged_in() ? 'logout' : 'login'; |
| | | $attrs = $block['attrs']; |
| | | $redirect = ''; |
| | | if (array_key_exists('redirectToCurrent', $attrs) && $attrs['redirectToCurrent']) { |
| | | global $wp; |
| | | $redirect = get_home_url(null, $wp->request); |
| | | } |
| | | |
| | | if (array_key_exists('displayLoginAsForm', $attrs) && $attrs['displayLoginAsForm']) { |
| | | LoginManager::getInstance()->setAction($action); |
| | | return LoginManager::getInstance()->renderLoginForm($action, $redirect, '<h2>Login</h2>'); |
| | | |
| | | } |
| | | |
| | | return sprintf( |
| | | '<a href="%s"%s>%s</a>', |
| | | wp_login_url($redirect), |
| | | $this->getClassesAndStyles($attrs), |
| | | $action === 'login' ? jvbIcon('sign-in').'<span>Log in</span>' : jvbIcon('sign-out').'<span>Logout</span>' |
| | | ); |
| | | } |
| | | //core_pattern |
| | | |
| | | public function render_core_site_logo(array $block, string $content):string |
| | | public function prerender_core_site_logo(array $block, ?string $content, ?WP_Block $parent = null):?string |
| | | { |
| | | // jvbDump($block, 'site logo'); |
| | | // jvbDump($parent, 'Parent'); |
| | | $attrs = $block['attrs']??[]; |
| | | $open = $close = ''; |
| | | |
| | | if (!is_home() && !is_front_page()) { |
| | | $open = '<a href="'.get_home_url().'" rel="home">'; |
| | | if ((!is_home() && !is_front_page()) && (!array_key_exists('isLink', $attrs) || $attrs['isLink'] === true)) { |
| | | $open = '<a href="'.get_home_url().'" rel="home" class="logo">'; |
| | | $close = '</a>'; |
| | | } |
| | | $img = get_theme_mod('custom_logo'); |
| | | $img = $this->image($img, 'tiny', 'thumbnail'); |
| | | $img = str_replace('<img', '<img'.$this->getClassesAndStyles($block['attrs']), $img); |
| | | $img = sprintf( |
| | | '<figure%s>%s</figure>', |
| | | $this->getClassesAndStyles($attrs, ['logo']), |
| | | $this->image($img, 'tiny', 'thumbnail') |
| | | ); |
| | | return $open.$img.$close; |
| | | } |
| | | //core_site_title_tagline |
| | | public function prerender_core_site_tagline(array $block, ?string $content, ?WP_Block $parent):?string |
| | | { |
| | | $tagline = get_bloginfo('description'); |
| | | |
| | | public function render_core_site_title(array $block, string $content):string |
| | | return empty($tagline) ? '' : sprintf( |
| | | '<p%s>%s</p>', |
| | | $this->getClassesAndStyles($block['attrs']??[], ['tagline']), |
| | | $tagline |
| | | ); |
| | | } |
| | | |
| | | public function prerender_core_site_title(array $block, ?string $content, ?WP_Block $parent):?string |
| | | { |
| | | $tag = (array_key_exists('level', $block['attrs'])) ? $block['attrs']['level'] : 1; |
| | | // jvbDump($block, 'site title'); |
| | | // jvbDump($parent, 'Parent'); |
| | | $attrs = $block['attrs']??[]; |
| | | $tag = (array_key_exists('level', $attrs)) ? $attrs['level'] : 1; |
| | | $tag = ($tag == 0) ? 'p' : 'h'.$tag; |
| | | |
| | | $open = $close = ''; |
| | | if (!is_front_page()) { |
| | | $open = '<a href="' . get_home_url() . '" rel="home">'; |
| | | if (!is_front_page() && (!array_key_exists('isLink', $attrs) || $attrs['isLink'] === true)) { |
| | | $open = sprintf( |
| | | '<a href="%s" rel="home">', |
| | | get_home_url() |
| | | ); |
| | | $close = '</a>'; |
| | | } |
| | | $class = ($tag === 'p') ? |
| | | $this->getClassesAndStyles($block['attrs'], ['title']) : |
| | | $this->getClassesAndStyles($block['attrs']); |
| | | $this->getClassesAndStyles($block['attrs']??[], ['title']) : |
| | | $this->getClassesAndStyles($block['attrs']??[]); |
| | | |
| | | |
| | | return '<'.$tag.$class.'>'. |
| | | $open. |
| | | get_bloginfo('name'). |
| | | $close. |
| | | '</'.$tag.'>'; |
| | | return sprintf( |
| | | '<%s%s>%s%s%s</%s>', |
| | | $tag, |
| | | $class, |
| | | $open, |
| | | get_bloginfo('name'), |
| | | $close, |
| | | $tag |
| | | ); |
| | | } |
| | | |
| | | /** |
| | |
| | | /** |
| | | * Theme Navigation Blocks |
| | | */ |
| | | public function render_core_navigation(array $block, string $content):string |
| | | public function prerender_core_navigation(array $block, ?string $content, ?WP_Block $parent):?string |
| | | { |
| | | $ID = (array_key_exists('ref', $block['attrs'])) ? $block['attrs']['ref'] : false; |
| | | // jvbDump($block, 'navigation'); |
| | | // jvbDump($parent, 'Parent'); |
| | | // jvbDump($block, 'navigation'); |
| | | $ID = (array_key_exists('ref', $block['attrs']??[])) ? $block['attrs']['ref'] : false; |
| | | |
| | | if (empty($block['innerBlocks']) && $ID && get_post($ID)) { |
| | | $block['innerBlocks'] = parse_blocks(get_post($ID)->post_content); |
| | | } |
| | | $attrs = $block['attrs']??[]; |
| | | |
| | | $toggle = (array_key_exists('overlayMenu', $block['attrs']) |
| | | && $block['attrs']['overlayMenu'] == 'never') ? |
| | | '': |
| | | '<button class="toggle main" |
| | | data-action="toggle-menu" |
| | | aria-label="Open Menu" |
| | | aria-controls="navigation-' .$ID. '" |
| | | aria-expanded="false">'. |
| | | jvbIcon('list', ['title'=>'Toggle Menu']). |
| | | jvbIcon('x', ['title'=>'Toggle Menu']). |
| | | '</button>'; |
| | | $class = ($toggle === '') ? |
| | | $this->getClassesAndStyles($block['attrs'], ['mobile']) : |
| | | $this->getClassesAndStyles($block['attrs']); |
| | | $helpmenu = (get_the_title($ID) === 'Main') ? |
| | | '<nav><ul>'.jvbNotificationMenu().jvbHelpMenu().'</ul></nav>' : |
| | | ''; |
| | | $toggle = ''; |
| | | $classes = []; |
| | | if (!array_key_exists('overlayMenu', $attrs) || $attrs['overlayMenu'] !== 'never') { |
| | | $toggle = sprintf( |
| | | '<button class="toggle main" |
| | | data-action="toggle-menu" |
| | | aria-label="Open Menu" |
| | | aria-controls="navigation-%d" |
| | | aria-expanded="false">%s%s</button>', |
| | | $ID, |
| | | jvbIcon('list'), |
| | | jvbIcon('x') |
| | | ); |
| | | $classes[] = 'mobile'; |
| | | if (array_key_exists('overlayMenu', $attrs) && $attrs['overlayMenu'] === 'always') { |
| | | $classes[] = 'always'; |
| | | } |
| | | } |
| | | if (!array_key_exists('layout', $attrs)) { |
| | | $classes[] = 'left'; |
| | | $classes[] = 'row'; |
| | | } |
| | | $class = $this->getClassesAndStyles($attrs, $classes); |
| | | |
| | | $helpmenu = ''; |
| | | $title = get_the_title($ID); |
| | | $isMain = false; |
| | | if ($title === 'Main') { |
| | | $isMain = true; |
| | | $helpmenu = sprintf( |
| | | '<nav><ul>%s%s</ul></nav>', |
| | | jvbNotificationMenu(), |
| | | jvbHelpMenu() |
| | | ); |
| | | } |
| | | |
| | | |
| | | //Allows to add custom items to a menu, based on the menu name |
| | | $helpmenu = apply_filters('jvbMenuExtraAfter', $helpmenu, get_the_title($ID)); |
| | | $main = trim(apply_filters('jvbMenuExtra', $this->innerBlocks($block), get_the_title($ID), $block)); |
| | | $helpmenu = apply_filters('jvbMenuExtraAfter', $helpmenu, $title, $ID); |
| | | $main = trim(apply_filters('jvbMenuExtra', $this->innerBlocks($block), $title, $block)); |
| | | |
| | | $main = str_starts_with($main, '<ul') ? $main : '<ul>'.$main.'</ul>'; |
| | | $main = str_starts_with($main, '<ul') ? $main : sprintf('<ul>%s</ul>',$main); |
| | | |
| | | return '<nav'.$class.' id="navigation-' . $ID . '"aria-label="Navigation"> |
| | | <span class="screen-reader-text"> |
| | | $skipToContent = $isMain ? '<span class="screen-reader-text"> |
| | | <a href="#content">Skip to Content</a> |
| | | </span>' . |
| | | $toggle . |
| | | $main. |
| | | '</nav>'.$helpmenu; |
| | | </span>' : ''; |
| | | return sprintf( |
| | | '<nav%s id="navigation-%d"aria-label="Navigation"> |
| | | %s%s%s</nav>%s', |
| | | $class, |
| | | $ID, |
| | | $skipToContent, |
| | | $toggle, |
| | | $main, |
| | | $helpmenu |
| | | ); |
| | | } |
| | | |
| | | public function render_core_navigation_link(array $block):string |
| | | public function prerender_core_navigation_link(array $block, ?string $content, ?WP_Block $parent):?string |
| | | { |
| | | // jvbDump($block, 'navigation link'); |
| | | // jvbDump($parent, 'Parent'); |
| | | global $wp; |
| | | $url = (str_starts_with($block['attrs']['url'],'/')) ? |
| | | home_url($block['attrs']['url']) : |
| | | $block['attrs']['url']; |
| | | if (!array_key_exists('attrs', $block)) { |
| | | return ''; |
| | | } |
| | | $attrs = $block['attrs']??[]; |
| | | $url = (str_starts_with($attrs['url'],'/')) ? |
| | | home_url($attrs['url']) : |
| | | $attrs['url']; |
| | | $current = (home_url($wp->request.'/') == $url); |
| | | $temp = $block['attrs']; |
| | | unset($temp['url']); |
| | | $attrs['url'] = $url; |
| | | $classes = ($current) ? |
| | | $this->getClassesAndStyles($temp, ['current']): |
| | | $this->getClassesAndStyles($temp); |
| | | $this->getClassesAndStyles($attrs, ['current']): |
| | | $this->getClassesAndStyles($attrs); |
| | | $aria = ''; |
| | | if ($current) { |
| | | $aria = ' aria-current="page"'; |
| | | } |
| | | $linkOpen = $this->build_navigation_link($block['attrs'], $aria); |
| | | $linkOpen = $this->buildNavigationLink($attrs, $aria); |
| | | |
| | | |
| | | return '<li'.$classes.'>'.$linkOpen.$block['attrs']['label'].'</a></li>'; |
| | | } |
| | | |
| | | public function render_core_navigation_submenu(array $block):string |
| | | public function prerender_core_navigation_submenu(array $block, ?string $content, ?WP_Block $parent):?string |
| | | { |
| | | // jvbDump($block, 'navigation submenu'); |
| | | // jvbDump($parent, 'Parent'); |
| | | global $wp; |
| | | $url = (str_starts_with($block['attrs']['url'],'/')) ? |
| | | home_url($block['attrs']['url']) : |
| | | $block['attrs']['url']; |
| | | $current = (home_url($wp->request) == $url); |
| | | |
| | | $temp = $block['attrs']; |
| | | unset($temp['url']); |
| | | $attrs = $block['attrs']??[]; |
| | | $attrs['url'] = $url; |
| | | $classes = ($current) ? |
| | | $this->getClassesAndStyles($temp, ['has-submenu', 'current']): |
| | | $this->getClassesAndStyles($temp, ['has-submenu']); |
| | | $this->getClassesAndStyles($attrs, ['has-submenu', 'current']): |
| | | $this->getClassesAndStyles($attrs, ['has-submenu']); |
| | | |
| | | $aria = ''; |
| | | if ($current) { |
| | | $aria = ' aria-current="page"'; |
| | | } |
| | | $id = sanitize_title($block['attrs']['label']); |
| | | $linkOpen = $this->build_navigation_link($block['attrs'], $aria); |
| | | $content = '<li'.$classes.'>'.$linkOpen.$block['attrs']['label']. |
| | | '</a><button class="toggle" data-action="toggle-submenu" title="Toggle Submenu" aria-label="Open '.$block['attrs']['label'].' Submenu" aria-expanded="false" aria-controls="'.$id.'-submenu">'. |
| | | jvbIcon('caret-down', ['title'=>'Toggle Submenu']). |
| | | '</button><ul class="submenu" id='.$id.'-submenu">'; |
| | | $linkOpen = $this->buildNavigationLink($attrs, $aria); |
| | | $content = sprintf( |
| | | '<li%s>%s%s</a> |
| | | <button class="toggle" data-action="toggle-submenu" title="Toggle Submenu" aria-label="Open %s Submenu" aria-expanded="false" aria-controls="%s-submenu"> |
| | | %s |
| | | </button> |
| | | <ul class="submenu" id=%s-submenu">', |
| | | $classes, |
| | | $linkOpen, |
| | | $attrs['label'], |
| | | $attrs['label'], |
| | | $id, |
| | | jvbIcon('caret-down', ['title'=>'Toggle Submenu']), |
| | | $id |
| | | ); |
| | | |
| | | $content .= $this->innerBlocks($block); |
| | | $content .= '</ul></li>'; |
| | |
| | | return $content; |
| | | } |
| | | |
| | | protected function build_navigation_link(array $attrs, string $aria):string |
| | | protected function buildNavigationLink(array $attrs, string $aria):string |
| | | { |
| | | global $wp; |
| | | $url =(str_starts_with($attrs['url'],'/')) ? |
| | | home_url($attrs['url']) : |
| | | $attrs['url']; |
| | |
| | | * Theme Query Blocks |
| | | */ |
| | | //core_post_author |
| | | //core_post_author_biography |
| | | //core_post_author_name |
| | | public function render_core_post_content(array $block, string $content = ''):string |
| | | { |
| | | |
| | | $tag = (array_key_exists('tagName', $block['attrs'])) ? |
| | | public function prerender_core_post_author(array $block, ?string $content, ?WP_Block $parent):?string |
| | | { |
| | | $attrs = $block['attrs'] ?? []; |
| | | |
| | | $size = 96; |
| | | if (array_key_exists('avatarSize',$attrs) && is_int($attrs['avatarSize'])) { |
| | | $size = $attrs['avatarSize']; |
| | | } |
| | | $byline = $aOpen = $aClose = $avatar = $bio = ''; |
| | | global $post; |
| | | $user = get_userdata($post->post_author); |
| | | |
| | | if (!array_key_exists('showAvatar', $attrs) || $this->checkAttrs('showAvatar', $attrs)){ |
| | | $avatar = get_avatar($post->post_author, $size); |
| | | } |
| | | if (!array_key_exists('showBio', $attrs) || $this->checkAttrs('showBio', $attrs)) { |
| | | $bio = wpautop($user->description); |
| | | } |
| | | |
| | | $target = ''; |
| | | if (array_key_exists('linkTarget', $attrs) && $attrs['linkTarget']=== '_blank') { |
| | | $target = ' target="_blank"'; |
| | | } |
| | | |
| | | if ($this->checkAttrs('isLink', $attrs)) { |
| | | $aOpen = sprintf( |
| | | '<a href="%s"%s>', |
| | | get_author_posts_url($post->post_author), |
| | | $target |
| | | ); |
| | | $aClose = '</a>'; |
| | | } |
| | | |
| | | if (array_key_exists('byline', $attrs)) { |
| | | $byline = sprintf( |
| | | '<small>%s</small> — ', |
| | | $attrs['byline'] |
| | | ); |
| | | } |
| | | |
| | | $name = $user->display_name; |
| | | |
| | | |
| | | return sprintf( |
| | | '<div%s>%s%s%s<p>%s%s%s%s</p>%s</div>', |
| | | $this->getClassesAndStyles($attrs, ['row','nowrap']), |
| | | $aOpen, |
| | | $avatar, |
| | | $aClose, |
| | | $aOpen, |
| | | $byline, |
| | | $name, |
| | | $aClose, |
| | | $bio |
| | | ); |
| | | } |
| | | //core_post_author_biography |
| | | |
| | | public function prerender_core_post_author_name(array $block, ?string $content, ?WP_Block $parent):?string |
| | | { |
| | | $attrs = $block['attrs']??[]; |
| | | global $post; |
| | | $aOpen = $aClose = ''; |
| | | if ($this->checkAttrs('isLink', $attrs)) { |
| | | |
| | | $aOpen = sprintf( |
| | | '<a href="%s" rel="author">', |
| | | get_author_posts_url($post->post_author) |
| | | ); |
| | | $aClose = '</a>'; |
| | | } |
| | | |
| | | $author = get_userdata($post->post_author); |
| | | return sprintf( |
| | | '<p%s>%s%s%s</p>', |
| | | $this->getClassesAndStyles($attrs, ['author']), |
| | | $aOpen, |
| | | $author->display_name, |
| | | $aClose |
| | | ); |
| | | } |
| | | public function prerender_core_post_content(array $block, ?string $content, ?WP_Block $parent):?string |
| | | { |
| | | // jvbDump($block, 'post content'); |
| | | // jvbDump($parent, 'Parent'); |
| | | |
| | | $tag = (array_key_exists('tagName', $block['attrs']??[])) ? |
| | | $block['attrs']['tagName'] : |
| | | 'main'; |
| | | |
| | | if ($content == '') { |
| | | if(is_singular()) { |
| | | global $post; |
| | | global $post, $page; |
| | | |
| | | $block['innerBlocks'] = parse_blocks($post->post_content); |
| | | $pages = explode('<!--nextpage-->', $post->post_content); |
| | | $currentContent = $pages[max(0, $page - 1)] ?? $pages[0]; |
| | | |
| | | |
| | | if ($page > 1 && !str_contains($currentContent, '<!--nextpage-->')) { |
| | | $currentContent = str_replace('<!-- /wp:nextpage -->','', $currentContent); |
| | | $currentContent .= ' |
| | | <!-- wp:nextpage --> |
| | | <!--nextpage--> |
| | | <!-- /wp:nextpage -->'; |
| | | } |
| | | |
| | | $block['innerBlocks'] = parse_blocks($currentContent); |
| | | $result = $this->innerBlocks($block); |
| | | }else { |
| | | $result = ''; |
| | | } |
| | | } else { |
| | | $result = $this->inside($block, $tag, $content); |
| | | $result = $this->innerBlocks($block); |
| | | } |
| | | |
| | | return apply_filters('jvb_post_content_output', $result, $block); |
| | | } |
| | | //core_post_date |
| | | public function render_core_post_date(array $block):string |
| | | public function prerender_core_post_date(array $block, ?string $content, ?WP_Block $parent):?string |
| | | { |
| | | $postDate = get_the_date('c'); |
| | | return '<time datetime="'.$postDate.'" itemprop="datePublished"'.$this->getClassesAndStyles($block['attrs']).'>'.get_the_date().'</time>'; |
| | | |
| | | // jvbDump($block, 'post date'); |
| | | // return null; |
| | | $attrs = $block['attrs']??[]; |
| | | $postDate = null; |
| | | $itemProp = 'datePublished'; |
| | | $format = array_key_exists('format', $attrs) ? $attrs['format'] : 'M d, Y'; |
| | | $dateFormat = null; |
| | | if (array_key_exists('displayType', $attrs)) { |
| | | switch ($attrs['displayType']) { |
| | | case 'displayType': |
| | | $postDate = get_post_modified_time('c'); |
| | | $dateFormat = get_post_modified_time($format); |
| | | $itemProp = 'dateModified'; |
| | | break; |
| | | |
| | | |
| | | } |
| | | } |
| | | $postDate = is_null($postDate) ? get_the_date('c') : $postDate; |
| | | $dateFormat = is_null($dateFormat) ? get_the_date($format) : $dateFormat; |
| | | |
| | | |
| | | |
| | | $aOpen = $aClose = ''; |
| | | if ($this->checkAttrs('isLink', $attrs) && !is_singular()) { |
| | | $aOpen = sprintf( |
| | | '<a href="%s">', |
| | | get_the_permalink() |
| | | ); |
| | | $aClose = '</a>'; |
| | | } |
| | | // jvbDump($parent, 'Parent'); |
| | | |
| | | return sprintf( |
| | | '<time datetime="%s" itemprop="%s"%s>%s%s%s</time>', |
| | | $postDate, |
| | | $itemProp, |
| | | $this->getClassesAndStyles($attrs), |
| | | $aOpen, |
| | | $dateFormat, |
| | | $aClose |
| | | ); |
| | | } |
| | | //core_post_excerpt |
| | | public function render_core_post_featured_image(array $block):string |
| | | public function prerender_core_post_excerpt(array $block, ?string $content, ?WP_Block $parent):?string |
| | | { |
| | | $attrs = $block['attrs']??[]; |
| | | |
| | | $moreText = array_key_exists('moreText', $attrs) ? $attrs['moreText'] : 'Read more '.jvbIcon('arrow-circle-right'); |
| | | $showMoreOnNewLine = !array_key_exists('showMoreOnNewLine', $attrs) || $this->checkAttrs('showMoreOnNewLine', $attrs); |
| | | // jvbDump($block); |
| | | // jvbDump($showMoreOnNewLine); |
| | | |
| | | $excerpt = array_filter(explode('<p>',wpautop(get_the_excerpt()))); |
| | | $classes = $this->getClassesAndStyles($attrs); |
| | | $excerpt = array_map(function ($line) use ($classes) { |
| | | return sprintf( |
| | | '<p%s>%s', |
| | | $classes, |
| | | $line |
| | | ); |
| | | }, $excerpt); |
| | | |
| | | if (!empty($moreText)) { |
| | | if ($showMoreOnNewLine) { |
| | | $excerpt[] = sprintf( |
| | | '<p%s><a href="%s" class="read-more">%s</a></p>', |
| | | $classes, |
| | | get_the_permalink(), |
| | | $moreText |
| | | ); |
| | | } else { |
| | | $last = array_key_last($excerpt); |
| | | $excerpt[$last] = str_replace('</p>', sprintf('<a href="%s" class="read-more">%s</a>', |
| | | get_the_permalink(), |
| | | $moreText), $excerpt[$last]); |
| | | } |
| | | } |
| | | return implode('',$excerpt); |
| | | } |
| | | public function prerender_core_post_featured_image(array $block, ?string $content, ?WP_Block $parent):?string |
| | | { |
| | | // jvbDump($block, 'featured image'); |
| | | // jvbDump($parent, 'Parent'); |
| | | global $post; |
| | | $attrs = $block['attrs']??[]; |
| | | $ID = get_post_thumbnail_id($post->ID); |
| | | $aOpen = $aClose = ''; |
| | | if(!is_single($post->ID)) { |
| | | $aspectRatio = $aOpen = $aClose = ''; |
| | | if(!is_single($post->ID) && $this->checkAttrs('isLink', $attrs)) { |
| | | $aOpen = '<a href="'.get_the_permalink($post->ID).'">'; |
| | | $aClose = '</a>'; |
| | | } |
| | | if (array_key_exists('aspectRatio', $attrs)) { |
| | | $aspectRatio = $attrs['aspectRatio']; |
| | | } |
| | | |
| | | return '<figure'.$this->getClassesAndStyles($block['attrs']).'>'.$aOpen. |
| | | apply_filters('jvbCoreFeaturedImage', $this->image($ID), $post->post_type). |
| | | $aClose.'</figure>'; |
| | | $img = apply_filters('jvbCoreFeaturedImage', '', $post->post_type, $attrs); |
| | | |
| | | if (empty($img)) { |
| | | $img = $this->image($ID); |
| | | $img = empty($aspectRatio) ? $img : str_replace('<img', '<img style="aspect-ratio:'.$aspectRatio.';"', $img); |
| | | } |
| | | |
| | | |
| | | return !empty($img) ? sprintf( |
| | | '<figure%s>%s%s%s</figure>', |
| | | $this->getClassesAndStyles($attrs), |
| | | $aOpen, |
| | | $img, |
| | | $aClose, |
| | | ):''; |
| | | } |
| | | //core_post_navigation_link |
| | | //core_post_template |
| | | //core_post_terms |
| | | public function render_core_post_terms(array $block):string |
| | | public function prerender_core_post_navigation_link(array $block, ?string $content, ?WP_Block $parent):?string |
| | | { |
| | | $attr = $block['attrs']; |
| | | $isPrevious = $attr['type']==='previous'; |
| | | $title = array_key_exists('showTitle', $attr)&&$attr['showTitle']; |
| | | $linkLabel = array_key_exists('linkLabel', $attr)&&$attr['linkLabel']; |
| | | $label = array_key_exists('label', $attr) ? $attr['label'] : ''; |
| | | $arrow = ''; |
| | | if (array_key_exists('arrow', $attr)) { |
| | | $dir = $isPrevious ? 'left' : 'right'; |
| | | $icon = match($attr['arrow']) { |
| | | 'arrow' => 'arrow-square-', |
| | | 'chevron' => 'caret-circle-' |
| | | }; |
| | | if ($icon) { |
| | | $arrow = jvbIcon($icon.$dir); |
| | | } |
| | | } |
| | | // return $content; |
| | | $linkedLabel = $unlinkedLabel = ''; |
| | | if (!empty($label)) { |
| | | $linkedLabel = $linkLabel ? $label : ''; |
| | | $unlinkedLabel = $linkLabel ? '' : $label; |
| | | } |
| | | if ($title) { |
| | | $linkedLabel .=' %title'; |
| | | } elseif (!empty($label)) { |
| | | $linkedLabel = $label; |
| | | $unlinkedLabel = ''; |
| | | } else { |
| | | $linkedLabel = $isPrevious ? 'Previous' : 'Next'; |
| | | $unlinkedLabel = ''; |
| | | } |
| | | |
| | | $result = $isPrevious ? |
| | | get_previous_post_link( |
| | | $arrow.$unlinkedLabel.' %link', |
| | | $linkedLabel |
| | | ) : |
| | | get_next_post_link( |
| | | '%link '.$unlinkedLabel.$arrow, |
| | | $linkedLabel |
| | | ); |
| | | |
| | | |
| | | return sprintf('<div%s>%s</div>', |
| | | $this->getClassesAndStyles($attr,['row', 'nowrap']), |
| | | $result |
| | | ); |
| | | } |
| | | //core_post_template |
| | | public function prerender_core_post_template(array $block, ?string $content):?string |
| | | { |
| | | $inner = ''; |
| | | |
| | | if (!static::$currentLoop) { |
| | | jvbDump('No loop stored'); |
| | | return $content; |
| | | } |
| | | if (static::$currentLoop->have_posts()) { |
| | | while (static::$currentLoop->have_posts()) { |
| | | static::$currentLoop->the_post(); |
| | | |
| | | $inner .= sprintf( |
| | | '<li>%s</li>', |
| | | $this->innerBlocks($block, '','',$block) |
| | | ); |
| | | } |
| | | } |
| | | return sprintf( |
| | | '<ul%s>%s</ul>', |
| | | $this->getClassesAndStyles($block['attrs']??[], ['loop']), |
| | | $inner |
| | | ); |
| | | } |
| | | //core_post_terms |
| | | public function prerender_core_post_terms(array $block, ?string $content, ?WP_Block $parent):?string |
| | | { |
| | | if (!array_key_exists('attrs', $block)) { |
| | | return ''; |
| | | } |
| | | $terms = get_the_terms(get_the_ID(), $block['attrs']['term']); |
| | | $attrs = $block['attrs']??[]; |
| | | $out = ''; |
| | | if ($terms && !is_wp_error($terms)) { |
| | | $out = '<ul class="term-list">'; |
| | | if (array_key_exists('prefix', $block['attrs'])) { |
| | | $out .= '<li>'.$block['attrs']['prefix'].'</li>'; |
| | | $out = sprintf( |
| | | '<ul%s>', |
| | | $this->getClassesAndStyles($attrs, ['term-list', 'row', 'left']) |
| | | ); |
| | | if (array_key_exists('prefix', $attrs)) { |
| | | $out .= sprintf( |
| | | '<li class="prefix">%s</li>', |
| | | $attrs['prefix'] |
| | | ); |
| | | } |
| | | foreach($terms as $term) { |
| | | $out .= '<li><a href="'.get_term_link($term).'" rel="tag">'.html_entity_decode($term->name).'</a></li>'; |
| | | $out .= sprintf( |
| | | '<li><a href="%s" rel="tag">%s</a></li>', |
| | | get_term_link($term), |
| | | html_entity_decode($term->name) |
| | | ); |
| | | } |
| | | if (array_key_exists('suffix', $block['attrs'])) { |
| | | $out .= '<li>'.$block['attrs']['suffix'].'</li>'; |
| | | if (array_key_exists('suffix', $attrs)) { |
| | | $out .= sprintf( |
| | | '<li class="suffix">%s</li>', |
| | | $attrs['suffix'] |
| | | ); |
| | | } |
| | | $out .= '</ul>'; |
| | | } |
| | | return $out; |
| | | } |
| | | //core_post_time_to_read |
| | | public function render_core_post_title(array $block):string |
| | | public function prerender_core_post_title(array $block, ?string $content, ?WP_Block $parent):?string |
| | | { |
| | | // jvbDump($parent, 'Parent'); |
| | | $open = $close = ''; |
| | | if (array_key_exists('isLink', $block['attrs'])) { |
| | | $rel = (array_key_exists('rel', $block['attrs'])) ? |
| | | $attrs = $block['attrs']??[]; |
| | | if ($this->checkAttrs('isLink', $attrs)) { |
| | | $rel = (array_key_exists('rel', $attrs)) ? |
| | | ' rel="'.$block['attrs']['rel'].'"' : |
| | | ''; |
| | | $target = (array_key_exists('linkTarget', $block['attrs'])) ? |
| | | $target = (array_key_exists('linkTarget', $attrs)) ? |
| | | ' target="'.$block['attrs']['linkTarget'].'"' : |
| | | ''; |
| | | $open = '<a href="' . get_the_permalink() . '"' . $rel . $target . '>'; |
| | | $close = '</a>'; |
| | | } |
| | | if (is_singular(BASE.'partner')) { |
| | | $open .= '<small>edmonton.ink partner:</small> '; |
| | | } |
| | | $level = (array_key_exists('attrs', $block) && |
| | | array_key_exists('level', $block['attrs'])) ? |
| | | $block['attrs']['level'] : |
| | | 2; |
| | | return '<h'.$level.$this->getClassesAndStyles($block['attrs']).'>'. |
| | | $open.get_the_title().$close. |
| | | '</h'.$level.'>'; |
| | | } |
| | | |
| | | public function render_core_query(array $block, string $content):string |
| | | $level = $attrs['level']??2; |
| | | |
| | | $title = (!static::$currentLoop && !is_singular()) |
| | | ? get_the_title(get_queried_object_id()) |
| | | : get_the_title(); |
| | | |
| | | return sprintf( |
| | | '<h%s%s>%s%s%s</h%s>', |
| | | $level, |
| | | $this->getClassesAndStyles($attrs), |
| | | $open, |
| | | $title, |
| | | $close, |
| | | $level |
| | | ); |
| | | } |
| | | public function prerender_core_query(array $block, ?string $content):?string |
| | | { |
| | | $queryID = $block['attrs']['queryId']; |
| | | $args = []; |
| | | $inherit = $block['attrs']['inherit']??false; |
| | | global $wp_query; |
| | | $inherit = $block['attrs']['inherit'] ?? false; |
| | | |
| | | if ($inherit) { |
| | | global $wp_query; |
| | | $loop = $wp_query; |
| | | static::$currentLoop = $wp_query; |
| | | } else { |
| | | foreach ($block['attrs']['query'] as $key => $value) { |
| | | if (empty($value)) { |
| | | continue; |
| | | } |
| | | static::$currentLoop = new WP_Query($this->buildQueryArgs($block['attrs'])); |
| | | } |
| | | static::$currentQueryId = $block['attrs']['queryId'] ?? null; |
| | | |
| | | static::$originalQuery = $wp_query; |
| | | |
| | | $inside = $this->innerBlocks($block); |
| | | |
| | | if (str_contains($inside, 'loop')) { |
| | | $classes = $this->getClassesAndStyles($block['attrs'] ?? [], ['loop']); |
| | | $classes = str_replace(' class="', '', $classes); |
| | | $classes = strtok($classes, '"'); |
| | | $inside = str_replace('loop', $classes, $inside); |
| | | } |
| | | |
| | | |
| | | static::$currentQueryId = null; |
| | | static::$currentLoop = null; |
| | | |
| | | wp_reset_postdata(); |
| | | return $inside; |
| | | } |
| | | // public function render_core_query(array $block, string $content): string |
| | | // { |
| | | // $inside = $this->innerBlocks($block); |
| | | // if (str_contains($inside, 'loop')) { |
| | | // $classes = $this->getClassesAndStyles($block['attrs']??[], ['loop']); |
| | | // $classes = str_replace(' class="', '', $classes); |
| | | // $classes = strtok($classes, '"'); |
| | | // |
| | | // $inside = str_replace('loop', $classes, $inside); |
| | | // } |
| | | // return $inside; |
| | | // } |
| | | protected function buildQueryArgs(array $attrs): array |
| | | { |
| | | $queryID = $attrs['queryId'] ?? null; |
| | | $args = []; |
| | | foreach (($attrs['query'] ?? []) as $key => $value) { |
| | | if (empty($value)) continue; |
| | | switch ($key) { |
| | | case 'postType': |
| | | if ($value === BASE.'progress'){ |
| | | $args['post_parent'] = 0; |
| | | } |
| | | $args['post_type'] = $value; |
| | | break; |
| | | case 'perPage': |
| | | $args['posts_per_page'] = $value; |
| | | break; |
| | | case 'orderBy': |
| | | $args['orderby'] = $value; |
| | | case 'postType': $args['post_type'] = $value; break; |
| | | case 'perPage': $args['posts_per_page'] = $value; break; |
| | | case 'orderBy': $args['orderby'] = $value; break; |
| | | case 'sticky': |
| | | match ($value) { |
| | | 'ignore' => $args['ignore_sticky_posts'] = true, |
| | | 'exclude' => $args['post__not_in'] = get_option('sticky_posts'), |
| | | 'only' => $args['post__in'] = get_option('sticky_posts'), |
| | | default => null |
| | | }; |
| | | break; |
| | | case 'taxQuery': |
| | | $taxQuery = []; |
| | | foreach ($value as $tax => $terms) { |
| | | $taxQuery[] = [ |
| | | 'taxonomy' => $tax, |
| | | 'terms' => $terms |
| | | ]; |
| | | } |
| | | if (!empty($taxQuery)) { |
| | | $args['tax_query'] = $taxQuery; |
| | | if (count($taxQuery) > 1) { |
| | | $args['tax_query']['relation'] = 'OR'; |
| | | } |
| | | } |
| | | $taxQuery = array_map(fn($tax, $terms) => [ |
| | | 'taxonomy' => $tax, 'terms' => $terms |
| | | ], array_keys($value), $value); |
| | | if (count($taxQuery) > 1) $taxQuery['relation'] = 'OR'; |
| | | $args['tax_query'] = $taxQuery; |
| | | break; |
| | | case 'sticky': |
| | | if ($value === 'ignore') { |
| | | $args['ignore_sticky_posts'] = true; |
| | | } else if ($value === 'exclude'){ |
| | | $args['post__not_in'] = get_option('sticky_posts'); |
| | | } else if ($value === 'only') { |
| | | $args['include'] = get_option('sticky_posts'); |
| | | } |
| | | break; |
| | | case 'search': |
| | | $args['s'] = $value; |
| | | break; |
| | | default: |
| | | $args[$key] = $value; |
| | | break; |
| | | |
| | | case 'search': $args['s'] = $value; break; |
| | | default: $args[$key] = $value; break; |
| | | } |
| | | } |
| | | //Add in any args from the query string |
| | | $search = 'query-'.$queryID; |
| | | |
| | | // Handle pagination from query string |
| | | $search = 'q-' . $queryID.'-'; |
| | | foreach ($_GET as $key => $value) { |
| | | if (str_contains($key, $search)) { |
| | | $key = str_replace($search, '', $key); |
| | | if ($key === 'page') { |
| | | $args['paged'] = (int)$value; |
| | | } |
| | | if (str_contains($key, $search) && str_replace($search, '', $key) === 'page') { |
| | | $args['paged'] = (int)$value; |
| | | } |
| | | } |
| | | $loop = new WP_Query($args); |
| | | return $args; |
| | | } |
| | | |
| | | $inner = ''; |
| | | |
| | | foreach ($block['innerBlocks'] as $innerBlock) { |
| | | switch ($innerBlock['blockName']) { |
| | | case 'core/post-template': |
| | | $inner .= '<section class="item-grid">'; |
| | | if ($loop->have_posts()) { |
| | | while($loop->have_posts()) { |
| | | $loop->the_post(); |
| | | $postType = get_post_type(); |
| | | $inner .= '<div class="item '.jvbNoBase($postType).'">'.$this->innerBlocks($innerBlock).'</div>'; |
| | | } |
| | | } |
| | | $inner .= '</section>'; |
| | | break; |
| | | |
| | | } |
| | | protected function buildPaginationUrl(int $page): string |
| | | { |
| | | $param = 'q-' . static::$currentQueryId . '-page'; |
| | | $url = remove_query_arg($param); |
| | | return $page > 1 ? add_query_arg($param, $page, $url) : $url; |
| | | } |
| | | |
| | | |
| | | |
| | | $tagName = (array_key_exists('tagName', $block['attrs'])) ? $block['attrs']['tagName'] : 'div'; |
| | | $out = '<'.$tagName.' class="loop">'.$inner.'</'.$tagName.'>'; |
| | | if ($inherit) { |
| | | wp_reset_postdata(); |
| | | protected function getCurrentPage(): int |
| | | { |
| | | $param = 'q-' . static::$currentQueryId . '-page'; |
| | | return isset($_GET[$param]) ? (int)$_GET[$param] : 1; |
| | | } |
| | | return $out; |
| | | } |
| | | // public function render_core_query(array $block, string $content): string |
| | | // { |
| | | // |
| | | //// $queryID = $block['attrs']['queryId'] ?? null; |
| | | //// $inherit = $block['attrs']['inherit'] ?? false; |
| | | //// |
| | | //// if ($inherit) { |
| | | //// global $wp_query; |
| | | //// $loop = $wp_query; |
| | | //// } else { |
| | | //// $args = []; |
| | | //// foreach (($block['attrs']['query'] ?? []) as $key => $value) { |
| | | //// if (empty($value)) { |
| | | //// continue; |
| | | //// } |
| | | //// switch ($key) { |
| | | //// case 'postType': |
| | | //// if ($value === BASE.'progress'){ |
| | | //// $args['post_parent'] = 0; |
| | | //// } |
| | | //// $args['post_type'] = $value; |
| | | //// break; |
| | | //// case 'perPage': |
| | | //// $args['posts_per_page'] = $value; |
| | | //// break; |
| | | //// case 'orderBy': |
| | | //// $args['orderby'] = $value; |
| | | //// break; |
| | | //// case 'taxQuery': |
| | | //// $taxQuery = []; |
| | | //// foreach ($value as $tax => $terms) { |
| | | //// $taxQuery[] = [ |
| | | //// 'taxonomy' => $tax, |
| | | //// 'terms' => $terms |
| | | //// ]; |
| | | //// } |
| | | //// if (!empty($taxQuery)) { |
| | | //// $args['tax_query'] = $taxQuery; |
| | | //// if (count($taxQuery) > 1) { |
| | | //// $args['tax_query']['relation'] = 'OR'; |
| | | //// } |
| | | //// } |
| | | //// break; |
| | | //// case 'sticky': |
| | | //// if ($value === 'ignore') { |
| | | //// $args['ignore_sticky_posts'] = true; |
| | | //// } else if ($value === 'exclude'){ |
| | | //// $args['post__not_in'] = get_option('sticky_posts'); |
| | | //// } else if ($value === 'only') { |
| | | //// $args['include'] = get_option('sticky_posts'); |
| | | //// } |
| | | //// break; |
| | | //// case 'search': |
| | | //// $args['s'] = $value; |
| | | //// break; |
| | | //// default: |
| | | //// $args[$key] = $value; |
| | | //// break; |
| | | //// |
| | | //// } |
| | | //// } |
| | | //// $search = 'query-' . $queryID; |
| | | //// foreach ($_GET as $key => $value) { |
| | | //// if (str_contains($key, $search)) { |
| | | //// $key = str_replace($search, '', $key); |
| | | //// if ($key === 'page') { |
| | | //// $args['paged'] = (int)$value; |
| | | //// } |
| | | //// } |
| | | //// } |
| | | //// $loop = new WP_Query($args); |
| | | //// } |
| | | //// |
| | | //// $inner = ''; |
| | | //// foreach ($block['innerBlocks'] as $innerBlock) { |
| | | //// switch ($innerBlock['blockName']) { |
| | | //// case 'core/post-template': |
| | | //// $inner .= '<section class="item-grid">'; |
| | | //// if ($loop->have_posts()) { |
| | | //// while ($loop->have_posts()) { |
| | | //// $loop->the_post(); |
| | | //// $postType = get_post_type(); |
| | | //// $inner .= '<div class="item ' . jvbNoBase($postType) . '">' . $this->innerBlocks($innerBlock) . '</div>'; |
| | | //// } |
| | | //// } |
| | | //// $inner .= '</section>'; |
| | | //// break; |
| | | //// } |
| | | //// } |
| | | //// |
| | | //// // Reset only after a custom query, not the main query |
| | | //// if (!$inherit) { |
| | | //// wp_reset_postdata(); |
| | | //// } |
| | | // |
| | | // $tagName = $block['attrs']['tagName'] ?? 'div'; |
| | | //// return sprintf( |
| | | //// '<%s class="loop">%s</%s>', |
| | | //// $tagName, |
| | | //// $this->innerBlocks($block), |
| | | //// $tagName |
| | | //// ); |
| | | // return $this->innerBlocks($block); |
| | | // } |
| | | |
| | | //core_query_no_results |
| | | public function prerender_core_query_no_results(array $block, ?string $content):?string |
| | | { |
| | | if (!static::$currentLoop || static::$currentLoop->have_posts()) { |
| | | return ''; |
| | | } |
| | | |
| | | $inside = $this->innerBlocks($block); |
| | | return empty($inside) ? '' : sprintf( |
| | | '<div%s>%s</div>', |
| | | $this->getClassesAndStyles($block['attrs']??[], ['no-results']), |
| | | $inside |
| | | ); |
| | | } |
| | | //core_query_pagination |
| | | public function prerender_core_query_pagination(array $block, ?string $content):?string |
| | | { |
| | | return sprintf( |
| | | '<nav%s>%s</nav>', |
| | | $this->getClassesAndStyles($block['attrs']??[], ['pagination', 'condensed','btw']), |
| | | $this->innerBlocks($block) |
| | | ); |
| | | } |
| | | |
| | | //core_query_pagination_next |
| | | //core_query_pagination_numbers |
| | | //core_query_pagination_previous |
| | | //core_query_title |
| | | //core_read_more |
| | | public function render_core_template_part(array $block, string $content):string |
| | | { |
| | | |
| | | $isHeaderTemplate = ( |
| | | (array_key_exists('slug', $block['attrs']) && str_contains(strtolower($block['attrs']['slug']), 'header')) || |
| | | (array_key_exists('tagName', $block['attrs']) && str_contains(strtolower($block['attrs']['tagName']), 'header')) |
| | | ) ? 'header' : false; |
| | | $isFooterTemplate = ( |
| | | (array_key_exists('slug', $block['attrs']) && str_contains(strtolower($block['attrs']['slug']), 'footer')) || |
| | | (array_key_exists('tagName', $block['attrs']) && str_contains(strtolower($block['attrs']['tagName']), 'footer')) |
| | | ) ? 'footer' : false; |
| | | public function prerender_core_query_pagination_next(array $block, ?string $content, ?WP_Block $parent):?string |
| | | { |
| | | if (!static::$currentLoop) return ''; |
| | | |
| | | $currentPage = $this->getCurrentPage(); |
| | | $maxPages = static::$currentLoop->max_num_pages; |
| | | |
| | | if (($isHeaderTemplate || $isFooterTemplate)) { |
| | | if ($currentPage >= $maxPages) return ''; |
| | | |
| | | $tag = $isHeaderTemplate ?: $isFooterTemplate ?: 'div'; |
| | | |
| | | $breadcrumbs = $themeSwitch = $afterHeader = $beforeHeader = $footerText= ''; |
| | | if ($isHeaderTemplate) { |
| | | |
| | | $beforeHeader = apply_filters('jvbAboveHeader', $beforeHeader); |
| | | if ($beforeHeader !== '') { |
| | | $beforeHeader = '<aside class="pre-header">'.$beforeHeader.'</aside>'; |
| | | } |
| | | $checked = (is_user_logged_in() && current_user_can('prefers_dark_theme', true)) ? ' checked' : ''; |
| | | $title = ($checked == '') ? 'Toggle Dark Mode' : 'Toggle Light Mode'; |
| | | $showThemeSwitch = (bool)apply_filters('jvb_show_theme_switch', true); |
| | | $themeSwitch = ($showThemeSwitch) ? '<label title="'.$title.'" id="theme-switch" class="toggle-switch" for="theme-switcher"> |
| | | <input class="theme-switch row" id="theme-switcher" name="theme-switcher" type="checkbox"'.$checked.' data-setting="theme" data-theme role="switch" name="dark-mode" aria-label="Toggle dark mode"><span class="slider">'. |
| | | jvbIcon('sun-dim', ['title'=> 'Light Mode']). |
| | | jvbIcon('moon', ['title'=>'Dark Mode']). |
| | | '</span></label>' : ''; |
| | | $breadcrumbs = jvbBuildBreadcrumbs(); |
| | | $afterHeader = apply_filters('jvbBelowHeader', $afterHeader); |
| | | |
| | | if ($afterHeader !== '') { |
| | | $afterHeader = '<aside class="sub-header">'.$afterHeader.'</aside>'; |
| | | } |
| | | $footerText = '<div class="scroll-progress"><div class="bar"></div> |
| | | </div>'; |
| | | } elseif ($isFooterTemplate) { |
| | | $beforeHeader = apply_filters('jvbBeforeFooter', ''); |
| | | if ($beforeHeader !== '') { |
| | | $beforeHeader = '<section class="pre-footer">'.$beforeHeader.'</section>'; |
| | | } |
| | | $footerText = jvbRandomFooterText(); |
| | | $nextLabel = $rArrow = ''; |
| | | $type = get_post_type_object(get_post_type())->label; |
| | | if ($parent) { |
| | | $attrs = $parent->attributes; |
| | | if (array_key_exists('paginationArrow', $attrs)){ |
| | | $rArrow = match($attrs['paginationArrow']) { |
| | | 'chevron' => jvbIcon('caret-circle-right'), |
| | | default => jvbIcon('arrow-circle-right') |
| | | }; |
| | | } |
| | | // jvbDump($beforeHeader,'beforeHeader'); |
| | | // jvbDump('<'.$tag.$this->getClassesAndStyles($block['attrs']).'>','tag'); |
| | | // jvbDump($themeSwitch,'themeSwitch'); |
| | | // jvbDump($this->inside($block, $tag, $content),'inside'); |
| | | // jvbDump($footerText,'footerText'); |
| | | // jvbDump($afterHeader, 'afterheader'); |
| | | // jvbDump($breadcrumbs, 'breadcrumbs'); |
| | | if (!array_key_exists('showLabel', $attrs) || $attrs['showLabel'] === true) { |
| | | |
| | | return $beforeHeader.'<'.$tag.$this->getClassesAndStyles($block['attrs']).'>'. |
| | | $themeSwitch . |
| | | $this->inside($block, $tag, $content) . |
| | | $footerText.'</'.$tag.'>'.$afterHeader.$breadcrumbs; |
| | | } |
| | | $nextLabel = 'Next '.$type; |
| | | } |
| | | } else { |
| | | $rArrow = jvbIcon('caret-circle-right'); |
| | | } |
| | | |
| | | return $content; |
| | | $aOpen = sprintf( |
| | | '<a class="nav next" href="%s" title="Next %s">', |
| | | $this->buildPaginationUrl($currentPage + 1), |
| | | $type |
| | | ); |
| | | $aClose = '</a>'; |
| | | return sprintf( |
| | | '%s%s%s%s', |
| | | $aOpen, |
| | | $nextLabel, |
| | | $rArrow, |
| | | $aClose |
| | | ); |
| | | } |
| | | //core_query_pagination_numbers |
| | | public function prerender_core_query_pagination_numbers(array $block, ?string $content):?string |
| | | { |
| | | if (!static::$currentLoop) return ''; |
| | | $currentPage = $this->getCurrentPage(); |
| | | $maxPages = (int)static::$currentLoop->max_num_pages; |
| | | |
| | | $attrs = $block['attrs']??[]; |
| | | if ($maxPages <= 1) return ''; |
| | | |
| | | $midSize = $attrs['midSize'] ?? 2; |
| | | $endSize = 1; |
| | | |
| | | |
| | | $items = ''; |
| | | $gap = false; |
| | | for ($i = 1; $i <= $maxPages; $i++) { |
| | | if (($i <= min($endSize + 1, $maxPages)) || |
| | | ($i >= max(1, $currentPage - $midSize) && $i <= min($maxPages, $currentPage + $midSize)) || |
| | | ($i >= max(1, $maxPages - $endSize) && $i <= $maxPages)) { |
| | | $gap = true; |
| | | $items .= ($i === $currentPage) |
| | | ? sprintf('<li aria-current="page" class="current">%d</li>', $i) |
| | | : sprintf('<li><a href="%s">%d</a></li>', $this->buildPaginationUrl($i), $i); |
| | | } elseif ($gap) { |
| | | $gap = false; |
| | | $items .= sprintf( |
| | | '<li class="dots"><span>%s</span></li>', |
| | | jvbIcon('dots-three') |
| | | ); |
| | | } |
| | | } |
| | | |
| | | return sprintf('<ul%s>%s</ul>', |
| | | $this->getClassesAndStyles($attrs, ['row', 'nowrap']), |
| | | $items |
| | | ); |
| | | } |
| | | //core_query_pagination_previous |
| | | |
| | | public function prerender_core_query_pagination_previous(array $block, ?string $content, ?WP_Block $parent):?string |
| | | { |
| | | |
| | | if (!static::$currentLoop) return ''; |
| | | |
| | | $currentPage = $this->getCurrentPage(); |
| | | $maxPages = static::$currentLoop->max_num_pages; |
| | | |
| | | if ($currentPage <= 1) return ''; |
| | | |
| | | $nextLabel = $rArrow = ''; |
| | | $type = get_post_type_object(get_post_type())->label; |
| | | if ($parent) { |
| | | $attrs = $parent->attributes; |
| | | if (array_key_exists('paginationArrow', $attrs)){ |
| | | $rArrow = match($attrs['paginationArrow']) { |
| | | 'chevron' => jvbIcon('caret-circle-left'), |
| | | default => jvbIcon('arrow-circle-left') |
| | | }; |
| | | } |
| | | if (!array_key_exists('showLabel', $attrs) || $attrs['showLabel'] === true) { |
| | | |
| | | $nextLabel = 'Previous '.$type; |
| | | } |
| | | } else { |
| | | $rArrow = jvbIcon('caret-circle-left'); |
| | | } |
| | | |
| | | $aOpen = sprintf( |
| | | '<a class="nav prev" href="%s" title="Previous %s">', |
| | | $this->buildPaginationUrl($currentPage - 1), |
| | | $type |
| | | ); |
| | | $aClose = '</a>'; |
| | | return sprintf( |
| | | '%s%s%s%s', |
| | | $aOpen, |
| | | $nextLabel, |
| | | $rArrow, |
| | | $aClose |
| | | ); |
| | | } |
| | | |
| | | public function prerender_core_query_title(array $block, ?string $content, ?WP_Block $parent):?string |
| | | { |
| | | jvbDump($block, 'query title'); |
| | | $attr = $block['attrs']; |
| | | $name = ''; |
| | | $showPrefix = $attr['showPrefix']??false; |
| | | $obj = get_queried_object(); |
| | | if (is_tax()) { |
| | | $name = $showPrefix ? $obj->label.':' : ''; |
| | | $name .= $obj->name; |
| | | } else if (is_post_type_archive()) { |
| | | $name = $showPrefix ? 'Archive: ' : ''; |
| | | $name .= $obj->label; |
| | | } elseif (is_search()) { |
| | | $name = '<small>Search results for:</small> '.get_search_query(); |
| | | } elseif (is_singular()) { |
| | | $name = $obj->post_title; |
| | | } |
| | | $level = array_key_exists('level', $attr) ? 'h'.$attr['level'] : 'h1'; |
| | | |
| | | return sprintf( |
| | | '<%s id="%s">%s</%s>', |
| | | $level, |
| | | sanitize_title($name), |
| | | $name, |
| | | $level |
| | | ); |
| | | } |
| | | //core_read_more |
| | | public function prerender_core_template_part(array $block, ?string $content, ?WP_Block $parent):?string |
| | | { |
| | | // jvbDump($block, 'template part'); |
| | | // jvbDump($parent, 'Parent'); |
| | | |
| | | |
| | | $slug = $block['attrs']['slug'] ?? null; |
| | | $theme = $block['attrs']['theme'] ?? get_stylesheet(); |
| | | $tag = $block['attrs']['tagName'] ?? 'div'; |
| | | if (!$slug) { |
| | | return $content; |
| | | } |
| | | |
| | | // Try to get the template part post (customized via FSE) |
| | | $template_part = get_block_template( "$theme//$slug", 'wp_template_part' ); |
| | | |
| | | if ( $template_part && ! empty( $template_part->content ) ) { |
| | | $block['innerBlocks'] = parse_blocks( $template_part->content ); |
| | | |
| | | $before = $themeSwitch = $after = $beforeClose = ''; |
| | | switch ($tag) { |
| | | case 'header': |
| | | $before = apply_filters('jvbAboveHeader', ''); |
| | | if (!empty($before)) { |
| | | $before = sprintf( |
| | | '<aside class="pre header row x-btw">%s</aside>', |
| | | $before |
| | | ); |
| | | } |
| | | $themeSwitch = jvbDarkModeToggle(); |
| | | |
| | | $after = apply_filters('jvbBelowHeader', $after); |
| | | if (!empty($after)) { |
| | | $after = sprintf( |
| | | '<aside class="sub header row x-btw">%s</aside>', |
| | | $after |
| | | ); |
| | | } |
| | | $after .= BreadcrumbManager::getInstance()->renderNavigation(); |
| | | $beforeClose = '<div class="scroll-progress"><div class="bar"></div></div>'; |
| | | break; |
| | | case 'footer': |
| | | $before = apply_filters('jvbBeforeFooter', $before); |
| | | if (!empty($before)) { |
| | | $before = sprintf( |
| | | '<aside class="pre footer">%s</aside>', |
| | | $before |
| | | ); |
| | | } |
| | | $beforeClose = jvbRandomFooterText(); |
| | | break; |
| | | } |
| | | |
| | | return sprintf( |
| | | '%s<%s%s>%s%s%s</%s>%s', |
| | | $before, |
| | | $tag, |
| | | $this->getClassesAndStyles($block['attrs']??[]), |
| | | $themeSwitch, |
| | | $this->innerBlocks($block), |
| | | $beforeClose, |
| | | $tag, |
| | | $after |
| | | ); |
| | | |
| | | } |
| | | if (JVB_TESTING) { |
| | | jvbDump('Could not create template part block for '.$block['blockName']); |
| | | } |
| | | return $content; |
| | | |
| | | // $isHeaderTemplate = ( |
| | | // (array_key_exists('slug', $block['attrs']??[]) && str_contains(strtolower($block['attrs']['slug']), 'header')) || |
| | | // (array_key_exists('tagName', $block['attrs']??[]) && str_contains(strtolower($block['attrs']['tagName']), 'header')) |
| | | // ) ? 'header' : false; |
| | | // $isFooterTemplate = ( |
| | | // (array_key_exists('slug', $block['attrs']??[]) && str_contains(strtolower($block['attrs']['slug']), 'footer')) || |
| | | // (array_key_exists('tagName', $block['attrs']??[]) && str_contains(strtolower($block['attrs']['tagName']), 'footer')) |
| | | // ) ? 'footer' : false; |
| | | // if (($isHeaderTemplate || $isFooterTemplate)) { |
| | | // $innerContent = $content; |
| | | // |
| | | // $tag = $isHeaderTemplate ?: $isFooterTemplate ?: 'div'; |
| | | // |
| | | // $breadcrumbs = $themeSwitch = $afterHeader = $beforeHeader = $footerText= ''; |
| | | // if ($isHeaderTemplate) { |
| | | // |
| | | // $beforeHeader = apply_filters('jvbAboveHeader', $beforeHeader); |
| | | // if ($beforeHeader !== '') { |
| | | // $beforeHeader = '<aside class="pre header row x-btw">'.$beforeHeader.'</aside>'; |
| | | // } |
| | | // $themeSwitch = jvbDarkModeToggle(); |
| | | // $breadcrumbs = BreadcrumbManager::getInstance()->renderNavigation(); |
| | | // $afterHeader = apply_filters('jvbBelowHeader', $afterHeader); |
| | | // |
| | | // if ($afterHeader !== '') { |
| | | // $afterHeader = '<aside class="sub header row x-btw">'.$afterHeader.'</aside>'; |
| | | // } |
| | | // $footerText = '<div class="scroll-progress"><div class="bar"></div> |
| | | //</div>'; |
| | | // } elseif ($isFooterTemplate) { |
| | | // $beforeHeader = apply_filters('jvbBeforeFooter', ''); |
| | | // if ($beforeHeader !== '') { |
| | | // $beforeHeader = '<aside class="footer">'.$beforeHeader.'</aside>'; |
| | | // } |
| | | // $footerText = jvbRandomFooterText(); |
| | | // } |
| | | // |
| | | // $content = $beforeHeader.'<'.$tag.$this->getClassesAndStyles($block['attrs']??[]).'>'. |
| | | // $themeSwitch . |
| | | // $this->innerBlocks($block). |
| | | //// $this->innerBlocks($block). |
| | | //// $innerContent. |
| | | // $footerText.'</'.$tag.'>'.$afterHeader.$breadcrumbs; |
| | | // } |
| | | // |
| | | // return $content; |
| | | } |
| | | //core_term_description |
| | | |
| | |
| | | * Widgets Blocks |
| | | */ |
| | | //core_archives |
| | | public function render_core_archives(array $block, string $content):string |
| | | { |
| | | jvbDump($block, 'archives'); |
| | | $attrs = $block['attrs']??[]; |
| | | $isDropdown = $this->checkAttrs('displayAsDropdown', $attrs); |
| | | |
| | | $replace = strtok($content,'>').'>'; |
| | | $content = str_replace($replace, '', $content); |
| | | |
| | | if ($isDropdown) { |
| | | $content = sprintf( |
| | | '<div%s>%s', |
| | | $this->getClassesAndStyles($attrs, ['archive dropdown']), |
| | | $content |
| | | ); |
| | | } else { |
| | | $content = sprintf( |
| | | '<ul%s>%s', |
| | | $this->getClassesAndStyles($attrs, ['archive-list']), |
| | | $content |
| | | ); |
| | | } |
| | | |
| | | return $content; |
| | | } |
| | | //core_calendar |
| | | public function render_core_calendar(array $block, string $content):string |
| | | { |
| | | $content = $this->inside($block, false, $content); |
| | | $replace = strtok($content, '>').'>'; |
| | | $content = str_replace($replace, '', $content); |
| | | return sprintf( |
| | | '<table%s>%s', |
| | | $this->getClassesAndStyles($block['attrs']??[], ['calendar']), |
| | | $content |
| | | ); |
| | | } |
| | | //core_categories |
| | | public function prerender_core_categories(array $block, ?string $content, ?WP_Block $parent):?string |
| | | { |
| | | $attrs = $block['attrs']??[]; |
| | | $args = [ |
| | | 'taxonomy' => 'category', |
| | | 'hide_empty' => !$this->checkAttrs('showEmpty', $attrs) |
| | | ]; |
| | | |
| | | $showHierarchy = $this->checkAttrs('showHierarchy', $attrs); |
| | | if ($this->checkAttrs('showOnlyTopLevel', $attrs) || $showHierarchy){ |
| | | $args['parent'] = 0; |
| | | } |
| | | |
| | | $terms = $this->getTerms($args, $showHierarchy); |
| | | if (!$terms){ |
| | | return ''; |
| | | } |
| | | |
| | | |
| | | $showPostCounts = $this->checkAttrs('showPostCounts', $attrs); |
| | | $isDropdown = $this->checkAttrs('displayAsDropdown', $attrs); |
| | | |
| | | if ($isDropdown) { |
| | | $this->counter('core_categories'); |
| | | } |
| | | |
| | | $tax = get_taxonomy($args['taxonomy']); |
| | | $taxonomyName = $tax->label??'Categories'; |
| | | $taxonomySingular = $tax->labels->singular_name??'Category'; |
| | | $inner = $this->buildTermList($terms, $taxonomyName, $taxonomySingular, $isDropdown, $showPostCounts); |
| | | if ($isDropdown) { |
| | | return sprintf( |
| | | '<div%s>%s</div>', |
| | | $this->getClassesAndStyles($attrs, ['taxonomy-dropdown']), |
| | | $inner |
| | | ); |
| | | } |
| | | return sprintf( |
| | | '<ul%s>%s</ul>', |
| | | $this->getClassesAndStyles($attrs, ['taxonomy-list', jvbNoBase($args['taxonomy'])]), |
| | | $inner |
| | | ); |
| | | } |
| | | public function getTerms(array $args, bool $showHierarchy = false):array|false |
| | | { |
| | | $terms = get_terms($args); |
| | | if (!$terms || is_wp_error($terms)) { |
| | | return false; |
| | | } |
| | | $terms = array_map(function ($term) { |
| | | return (array) $term; |
| | | }, $terms); |
| | | |
| | | if ($showHierarchy) { |
| | | $terms = array_map(function ($term) use ($args) { |
| | | $args['parent'] = $term['term_id']; |
| | | $children = $this->getTerms($args, true); |
| | | $term['children'] = $children?:[]; |
| | | return $term; |
| | | }, $terms); |
| | | } |
| | | |
| | | return $terms; |
| | | } |
| | | protected function buildTermList(array $terms, string $taxonomyName, string $taxonomySingular, bool $isDropdown, bool $showPostCounts, bool $isOpening = true, int $level = 0):string |
| | | { |
| | | $out = ''; |
| | | if ($isOpening) { |
| | | $out = $isDropdown ? |
| | | sprintf( |
| | | '<label for="taxonomy-select-%s">%s</label> |
| | | <select name="%s_name" id="taxonomy-select-%s"><option value="">Select %s</option>', |
| | | static::$counters['core_categories'], |
| | | $taxonomyName, |
| | | str_replace('-', '_',sanitize_title(strtolower($taxonomyName))), |
| | | static::$counters['core_categories'], |
| | | $taxonomyName |
| | | ) : |
| | | ''; |
| | | } elseif (!$isDropdown) { |
| | | $out .= '<ul>'; |
| | | } |
| | | |
| | | |
| | | $prefix = ''; |
| | | if ($isDropdown) { |
| | | $base = ' '; |
| | | for ($i = 1; $i <= $level; $i++) { |
| | | $prefix .= $base; |
| | | } |
| | | $prefix .= empty($prefix) ? '' : '- '; |
| | | } |
| | | |
| | | $theTerms = array_map(function ($term) use ($taxonomyName, $taxonomySingular, $isDropdown, $showPostCounts, $prefix, $level) { |
| | | if ($isDropdown) { |
| | | return sprintf( |
| | | '<option value="%s">%s%s%s</option>%s', |
| | | $term['slug'], |
| | | $prefix, |
| | | $term['name'], |
| | | $showPostCounts ? ' ('.$term['count'].')' : '', |
| | | empty($term['children']??[]) ? '' : $this->buildTermList($term['children'], $taxonomyName, $taxonomySingular, $isDropdown, $showPostCounts, false, $level+1) |
| | | ); |
| | | } |
| | | return sprintf( |
| | | '<li><a href="%s">%s%s</a>%s</li>', |
| | | get_term_link($term['term_id']), |
| | | $term['name'], |
| | | $showPostCounts ? ' <span class="count">'.$term['count'].'</span>' : '', |
| | | empty($term['children']??[]) ? '' : $this->buildTermList($term['children'], $taxonomyName, $taxonomySingular, $isDropdown, $showPostCounts, false, $level+1) |
| | | ); |
| | | }, $terms); |
| | | |
| | | $out .= implode('', $theTerms); |
| | | |
| | | if ($isOpening) { |
| | | $out .= $isDropdown ? |
| | | '</select>' : |
| | | ''; |
| | | } else if (!$isDropdown) { |
| | | $out .= '</ul>'; |
| | | } |
| | | |
| | | |
| | | return $out; |
| | | } |
| | | //core_html |
| | | //core_latest_comments |
| | | //core_latest_posts |
| | | public function prerender_core_latest_posts(array $block, ?string $content, ?WP_Block $parent):?string { |
| | | $attrs = $block['attrs']??[]; |
| | | // jvbDump($block, 'latest posts'); |
| | | |
| | | $args = []; |
| | | $title = 'Latest Posts'; |
| | | $args['order'] = array_key_exists('order', $attrs) ? strtoupper($attrs['order']) : 'DESC'; |
| | | $args['orderby'] = array_key_exists('orderBy', $attrs) ? $attrs['orderBy'] : 'date'; |
| | | $args['posts_per_page'] = array_key_exists('postsToShow', $attrs) ? $attrs['postsToShow'] : 5; |
| | | |
| | | if (array_key_exists('categories', $attrs)) { |
| | | $list = jvbCommaList(array_column($attrs['categories'], 'name')); |
| | | $args['tax_query'] = []; |
| | | $args['tax_query'][] = [ |
| | | 'taxonomy' => 'category', |
| | | 'terms' => array_column($attrs['categories'], 'id') |
| | | ]; |
| | | $title .= ' in '.$list; |
| | | } |
| | | |
| | | $posts = new WP_Query($args); |
| | | |
| | | if (!$posts->have_posts()) { |
| | | return ''; |
| | | } |
| | | $posts = array_map(function ($post) use ($attrs) { |
| | | $img = $this->checkAttrs('displayFeaturedImage', $attrs) |
| | | ? $this->image(get_post_thumbnail_id($post->ID), 'tiny', 'thumbnail') |
| | | : ''; |
| | | |
| | | $author = $this->checkAttrs('displayAuthor', $attrs) |
| | | ? sprintf( |
| | | '<a href="%s">%s</a>', |
| | | get_author_posts_url($post->post_author), |
| | | get_userdata($post->post_author)->display_name |
| | | ) |
| | | : ''; |
| | | |
| | | $date = $this->checkAttrs('displayPostDate', $attrs) |
| | | ? sprintf( |
| | | '<time datetime="%s">%s</time>', |
| | | date('Y-m-d', strtotime($post->post_date)), |
| | | date_i18n('M j, Y', strtotime($post->post_date)) |
| | | ) |
| | | : ''; |
| | | $authorDate = $author; |
| | | if (!empty($authorDate) && !empty($date)) { |
| | | $authorDate .= ' | '.$date; |
| | | } else if (!empty($date)) { |
| | | $authorDate = $date; |
| | | } |
| | | |
| | | $excerpt = ''; |
| | | if ($this->checkAttrs('displayPostContent', $attrs)) { |
| | | if (array_key_exists('excerptLength', $attrs)) { |
| | | $excerpt = wp_trim_words(get_the_content($post->ID), $attrs['excerptLength'], '...'); |
| | | } else { |
| | | $excerpt = get_the_excerpt($post->ID); |
| | | } |
| | | } |
| | | if (!empty($excerpt)) { |
| | | $excerpt = wpautop($excerpt); |
| | | } |
| | | |
| | | return sprintf( |
| | | '<li>%s<p><a href="%s">%s</a>%s</p>%s</li>', |
| | | $img, |
| | | get_the_permalink($post->ID), |
| | | $post->post_title, |
| | | !empty($authorDate) ? ' <small>— '.$authorDate.'</small>' : '', |
| | | $excerpt |
| | | ); |
| | | }, $posts->posts); |
| | | |
| | | wp_reset_postdata(); |
| | | return sprintf( |
| | | '<ul%s>%s</ul>', |
| | | // $title, |
| | | $this->getClassesAndStyles($attrs, ['post-list']), |
| | | implode('', $posts) |
| | | ); |
| | | } |
| | | //core_page_list |
| | | //core_page_list_item |
| | | //core_rss |
| | | public function prerender_core_page_list(array $block, ?string $content, ?WP_Block $parent):?string{ |
| | | $attrs = $block['attrs']??[]; |
| | | $parent = array_key_exists('parentPageID', $attrs) ? $attrs['parentPageID'] : 0; |
| | | $pages = new WP_Query([ |
| | | 'post_type' => 'page', |
| | | 'posts_per_page' => -1, |
| | | 'parent' => $parent |
| | | ]); |
| | | |
| | | if (!$pages->have_posts()) { |
| | | return ''; |
| | | } |
| | | $inside = []; |
| | | foreach($pages->posts as $page) { |
| | | jvbDump($page); |
| | | $inside[] = sprintf( |
| | | '<li><a href="%s">%s</a>', |
| | | get_the_permalink($page->ID), |
| | | $page->post_title |
| | | ); |
| | | } |
| | | wp_reset_postdata(); |
| | | return sprintf( |
| | | '<ul%s>%s</ul>', |
| | | $this->getClassesAndStyles($attrs, ['page-list']), |
| | | implode('',$inside) |
| | | ); |
| | | } |
| | | //core_page_list_item (doesn't seem to be a thing) |
| | | // public function prerender_core_page_list_item(array $block, ?string $content, ?WP_Block $parent):?string{ |
| | | // return $content; |
| | | // } |
| | | //core_ |
| | | // public function prerender_core_rss(array $block, ?string $content, ?WP_Block $parent):?string |
| | | // { |
| | | // jvbDump($block, 'rss'); |
| | | // return $content; |
| | | // } |
| | | //core_search |
| | | //core_shortcode |
| | | public function render_core_social_link(array $block, string $content):string |
| | | public function prerender_core_search(array $block, ?string $content, ?WP_Block $parent):?string |
| | | { |
| | | $url = $block['attrs']['url']; |
| | | $service = $block['attrs']['service']; |
| | | // jvbDump($block, 'search'); |
| | | $attrs = $block['attrs']??[]; |
| | | $label = array_key_exists('label', $attrs) && !empty($attrs['label']) ? $attrs['label'] : ''; |
| | | if (array_key_exists('showLabel', $attrs) && $attrs['showLabel'] === false) { |
| | | $label = ''; |
| | | } |
| | | $placeholder = array_key_exists('placeholder', $attrs) ? $attrs['placeholder'] : 'Search...'; |
| | | |
| | | $buttonText = array_key_exists('buttonText', $attrs) && !empty($attrs['buttonText']) ? $attrs['buttonText'] : ''; |
| | | |
| | | $isInside = array_key_exists('buttonPosition', $attrs) && $attrs['buttonPosition'] === 'button-inside'; |
| | | |
| | | $hideInput = $this->checkAttrs('isSearchFieldHidden', $attrs) || (array_key_exists('buttonPosition', $attrs) && $attrs['buttonPosition'] === 'button-only'); |
| | | |
| | | return str_replace('<div class="search-container row left nowrap"', sprintf( |
| | | '<div%s', |
| | | $this->getClassesAndStyles($attrs, ['search-container', 'row', 'left', 'nowrap']) |
| | | ), jvbSearch($placeholder, uniqid(), $label, $buttonText, $isInside, $hideInput)); |
| | | } |
| | | //core_shortcode |
| | | public function prerender_core_social_link(array $block, ?string $content, ?WP_Block $parent):?string |
| | | { |
| | | // jvbDump($block, 'social link'); |
| | | // jvbDump($parent, 'Parent'); |
| | | $parentAttrs = false; |
| | | if ($parent) { |
| | | $parentAttrs = $parent->attributes; |
| | | } |
| | | $attrs = $block['attrs']??[]; |
| | | $url = $attrs['url']??''; |
| | | $service = $attrs['service']?:''; |
| | | $iconName = ($service === 'bluesky') ? 'butterfly' : $service.'-logo'; |
| | | $icon = jvbIcon($iconName); |
| | | if (!$icon) { |
| | | $icon = jvbIcon('link'); |
| | | } |
| | | return '<li><a href="'.$url.'" target="_blank" rel="nofollow" title="Find us on '.ucfirst($service).'">'.$icon.'<span class="screen-reader-text">Find us on '.ucfirst($service).'</span></a></li>'; |
| | | $serviceName = $this->getServiceName($service); |
| | | $label = $parentAttrs && (!array_key_exists('className', $parentAttrs) || !str_contains($parentAttrs['className'], 'logos-only')) |
| | | ? sprintf( |
| | | '<span>%s</span>', |
| | | $serviceName |
| | | ) |
| | | : sprintf( |
| | | '<span class="screen-reader-text">Find us on %s</span>', |
| | | $serviceName |
| | | ); |
| | | $pillShaped = $parentAttrs && (array_key_exists('className', $parentAttrs) && str_contains($parentAttrs['className'], 'pill-shape')) |
| | | ? 'style="border-radius:var(--radius-outer);"' |
| | | : ''; |
| | | return sprintf( |
| | | '<li><a href="%s" target="_blank" rel="nofollow" title="Find us on %s"%s>%s%s</a></li>', |
| | | $url, |
| | | $serviceName, |
| | | $pillShaped, |
| | | $icon, |
| | | $label |
| | | ); |
| | | } |
| | | public function render_core_social_links(array $block, string $content):string |
| | | private function getServiceName(string $service) { |
| | | return match($service){ |
| | | 'wordpress' => 'WordPress', |
| | | default => ucfirst($service) |
| | | }; |
| | | } |
| | | public function prerender_core_social_links(array $block, ?string $content, ?WP_Block $parent):?string |
| | | { |
| | | return '<ul class="socials">'.$this->innerBlocks($block).'</ul>'; |
| | | // jvbDump($block['attrs']??[], 'social links'); |
| | | // jvbDump($parent, 'Parent'); |
| | | |
| | | return sprintf( |
| | | '<ul%s>%s</ul>', |
| | | $this->getClassesAndStyles($block['attrs']??[], ['socials']), |
| | | $this->innerBlocks($block, '','',$block) |
| | | ); |
| | | } |
| | | //core_tag_cloud |
| | | public function prerender_core_tag_cloud(array $block, ?string $content, ?WP_Block $parent):?string |
| | | { |
| | | // jvbDump($block, 'tag cloud'); |
| | | $attrs = $block['attrs']??[]; |
| | | $taxonomy = (array_key_exists('taxonomy', $attrs) && !empty($attrs['taxonomy'])) |
| | | ? $attrs['taxonomy'] |
| | | : 'post_tag'; |
| | | $showCounts = $this->checkAttrs('showTagCounts', $attrs); |
| | | |
| | | $terms = get_terms([ |
| | | 'taxonomy' => $taxonomy, |
| | | 'hide_empty' => true, |
| | | ]); |
| | | |
| | | if (!$terms || is_wp_error($terms)) { |
| | | return ''; |
| | | } |
| | | |
| | | $inside = ''; |
| | | |
| | | foreach ($terms as $term) { |
| | | $url = get_term_link($term->term_id, $taxonomy); |
| | | $count = $showCounts ? |
| | | sprintf( |
| | | '<span class="count">%d</span>', |
| | | $term->count |
| | | ) : |
| | | ''; |
| | | $size = match(true) { |
| | | $term->count <= 2 => 'small', |
| | | $term->count <= 5 => 'x-small', |
| | | $term->count <= 10 => 'medium', |
| | | $term->count <= 15 => 'x-medium', |
| | | $term->count <= 20 => 'large', |
| | | $term->count <= 25 => 'x-large', |
| | | $term->count <= 30 => 'xx-large', |
| | | $term->count > 30 => 'xxx-large', |
| | | }; |
| | | $fontSize = 'font-size: var(--txt-'.$size.');'; |
| | | $inside .= sprintf( |
| | | '<li class="%s");"><a href="%s" rel="tag">%s%s</a></li>', |
| | | $size, |
| | | // $fontSize, |
| | | $url, |
| | | $term->name, |
| | | $count |
| | | ); |
| | | } |
| | | return sprintf( |
| | | '<ul%s>%s</ul>', |
| | | $this->getClassesAndStyles($attrs, ['term-list','cloud', jvbNoBase($taxonomy)]), |
| | | $inside |
| | | ); |
| | | } |
| | | |
| | | |
| | | /** |
| | |
| | | /*********************************** |
| | | * Helpers |
| | | **********************************/ |
| | | public function stripTagContents(string $tag, string $content):string |
| | | public function stripTagContents(string $tag, ?string $content):string |
| | | { |
| | | $clean = preg_replace('/<'.$tag.'\b[^>]*>.*?<\/'.$tag.'>/is', '', $content); |
| | | $clean = preg_replace('/\s+/', ' ', $clean); |
| | | return trim($clean); |
| | | } |
| | | |
| | | public function innerBlocks(array $block, string $before = '', string $after = ''):string |
| | | public function innerBlocks(array $block, string $before = '', string $after = '', ?array $parent = null):string |
| | | { |
| | | if ($parent) { |
| | | $parent = new WP_Block($parent); |
| | | } |
| | | $content = ''; |
| | | foreach ($block['innerBlocks'] as $b) { |
| | | $method = 'render_'.$this->sanitizeBlockName($b); |
| | | $function = BASE.$method; |
| | | |
| | | $content .= $before; |
| | | if (function_exists($function)) { |
| | | $content .= $function($b, ''); |
| | | } else if (method_exists($this, $method)) { |
| | | $content .= $this->$method($b, ''); |
| | | } else { |
| | | $content .= render_block($b); |
| | | } |
| | | $content .= $after; |
| | | $rendered = $parent |
| | | ? $this->checkMethods(null, $b, $parent, true) |
| | | : render_block($b); |
| | | |
| | | $content .= sprintf('%s%s%s', |
| | | $before, |
| | | $rendered, |
| | | $after |
| | | ); |
| | | } |
| | | return $content; |
| | | } |
| | | |
| | | public function inside(array $block, mixed $tag = false, mixed $o = false):string |
| | | { |
| | | if (!$o) { |
| | | $o = trim($block['innerHTML']); |
| | | } |
| | | if (!$tag) { |
| | | //check to see if there was one dynamically set first |
| | | $tag = (array_key_exists('tagName', $block['attrs'])) ? $block['attrs']['tagName'] : ''; |
| | | $tag = ($tag == '') ? str_replace('<', '', strtok($o, '>')) : ''; |
| | | $tag = (str_contains($tag, ' class')) ? strtok($tag, ' class') : $tag; |
| | | $tag = trim($tag); |
| | | } |
| | | if (!str_starts_with($o, '<'.$tag)) { |
| | | return $o; |
| | | public function inside(array $block, mixed $tag = false, mixed $o = false): string |
| | | { |
| | | $html = $o ?: trim($block['innerHTML']); |
| | | |
| | | if (empty($html)) { |
| | | return ''; |
| | | } |
| | | |
| | | $len = strlen('</'.$tag.'>'); |
| | | if (preg_match('/^<(\w+)[^>]*>(.*)<\/\1>$/s', $html, $matches)) { |
| | | if ($tag && strtolower($matches[1]) !== strtolower($tag)) { |
| | | return $html; |
| | | } |
| | | return trim($matches[2]); |
| | | } |
| | | |
| | | return substr_replace( |
| | | str_replace( |
| | | strtok($o, '>').'>', |
| | | ' ', |
| | | $o |
| | | ), |
| | | '', |
| | | -$len, |
| | | $len |
| | | ); |
| | | } |
| | | return $html; |
| | | } |
| | | |
| | | /** |
| | | * Extract content from a specific nested element |
| | |
| | | (!array_key_exists('attrs', $block) && !array_key_exists('id', $block['attrs'])))) { |
| | | $ID = get_post_thumbnail_id(); |
| | | } else { |
| | | if (array_key_exists('id', $block['attrs'])) { |
| | | if (array_key_exists('id', $block['attrs']??[])) { |
| | | $ID = $block['attrs']['id']; |
| | | } elseif (array_key_exists('mediaId', $block['attrs'])) { |
| | | $ID = $block['attrs']['mediaId']; |
| | |
| | | $classes[] = 'col'; |
| | | } |
| | | |
| | | |
| | | // Merge with passed classes and styles |
| | | $styles = array_merge($attr_styles, $styles); |
| | | $classes = array_merge($attr_classes, $classes); |
| | | |
| | | if (!empty(static::$pendingClass)) { |
| | | $classes = array_merge($classes, static::$pendingClass); |
| | | static::$pendingClass = []; |
| | | } |
| | | $classes = array_unique($classes); |
| | | $data = $this->getDataset($attrs); |
| | | |
| | | // Build attribute strings |
| | | $class_string = !empty($classes) ? ' class="' . implode(' ', $classes) . '"' : ''; |
| | | $style_string = !empty($styles) ? ' style="' . implode(';', $styles) . '"' : ''; |
| | | $data_string = ''; |
| | | if (!empty($data)) { |
| | | foreach ($data as $d => $v) { |
| | | if ($d === 'bg-small') { |
| | | $data_string .= ' data-bg-img'; |
| | | } |
| | | $data_string .= sprintf( |
| | | ' data-%s="%s"', |
| | | $d, |
| | | $v |
| | | ); |
| | | } |
| | | } |
| | | |
| | | $return = trim($class_string . $style_string); |
| | | $return = trim($class_string . $style_string . $data_string); |
| | | return ($return=='')? '' : ' '.$return; |
| | | } |
| | | /** |
| | |
| | | $classes = []; |
| | | foreach ($attrs as $key => $value) { |
| | | $class = $this->getClass($key, $value, $attrs); |
| | | if (is_array($class)) { |
| | | $classes = array_merge($classes, $class); |
| | | } else { |
| | | $classes[] = $class; |
| | | } |
| | | if (is_string($class)) { |
| | | $class = explode(' ', $class); |
| | | } |
| | | $classes = array_merge($classes, $class); |
| | | } |
| | | return array_filter($classes, function ($class) { |
| | | return array_unique(array_filter($classes, function ($class) { |
| | | return $class!=='' && !str_starts_with($class, 'wp'); |
| | | }); |
| | | })); |
| | | } |
| | | protected function getClass(string $key, string|bool|array|int $value, array $attrs):string|array |
| | | { |
| | | //TODO: gradient |
| | | switch ($key) { |
| | | //Any additional classes the user adds |
| | | case 'className': |
| | |
| | | default => str_replace('is-style-', '', $value), |
| | | }; |
| | | case 'contentPosition': |
| | | |
| | | $classes = []; |
| | | $pos = explode(' ', $value); |
| | | foreach($pos as $p) { |
| | | switch ($p) { |
| | | case 'top': |
| | | $classes[] = 'a-start'; |
| | | break; |
| | | case 'right': |
| | | $classes[] = 'end'; |
| | | break; |
| | | case 'bottom': |
| | | $classes[] = 'a-end'; |
| | | break; |
| | | case 'left': |
| | | $classes[] = 'start'; |
| | | break; |
| | | } |
| | | } |
| | | return implode(' ', $classes); |
| | | return $this->getContentPosition($value); |
| | | case 'term': |
| | | case 'taxonomy': |
| | | return jvbNoBase($value); |
| | | //Layout attributes |
| | | case 'layout': |
| | | $classes = []; |
| | | $type = 'row'; |
| | | if (array_key_exists('type', $value)) { |
| | | $type = 'col'; |
| | | // if ($value['type'] === 'constrained') { |
| | | // $classes[] = 'container col'; |
| | | // } |
| | | } |
| | | if (array_key_exists('orientation', $value)) { |
| | | $type = 'col'; |
| | | if ($value['orientation'] === 'vertical') { |
| | | $classes[] = 'col'; |
| | | if (in_array('row', $classes)) { |
| | | $index = array_search('row', $classes); |
| | | unset($classes[$index]); |
| | | } |
| | | } |
| | | }else if (array_key_exists('type', $value) && $value['type'] === 'flex') { |
| | | $classes[] = 'row'; |
| | | if (in_array('col', $classes)) { |
| | | $index = array_search('col', $classes); |
| | | unset($classes[$index]); |
| | | } |
| | | } |
| | | //jvbDump($type); |
| | | //jvbDump($value); |
| | | // $check = [$value, $attrs]; |
| | | // foreach ($check as $ch) { |
| | | // |
| | | // } |
| | | if (!array_key_exists('justifyContent', $value) && !array_key_exists('contentPosition', $attrs)) { |
| | | $classes[] = ($type === 'row') ? 'start' : 'a-start'; |
| | | } |
| | | if (array_key_exists('justifyContent', $value) && !array_key_exists('contentPosition', $attrs)) { |
| | | if (in_array($value['justifyContent'], ['left', 'right','space-between'])) { |
| | | // jvbDump($type); |
| | | switch ($value['justifyContent']) { |
| | | case 'right': |
| | | $classes[] = ($type === 'row') ? 'end' : 'a-end'; |
| | | break; |
| | | case 'space-between': |
| | | $classes[] = 'btw'; |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | if (array_key_exists('flexWrap', $value)) { |
| | | if ($value['flexWrap'] === 'nowrap') { |
| | | $classes[] = 'nowrap'; |
| | | } |
| | | } |
| | | return implode(' ', $classes); |
| | | return $this->getLayout($value, $attrs); |
| | | case 'align': |
| | | return !empty($value) ? 'align-'.$value : ''; |
| | | case 'verticalAlignment': |
| | | return !empty($value) ? 'v-align-'.$value : ''; |
| | | case 'isStackedMobile': |
| | | switch ($value) { |
| | | case 'bottom': |
| | | $value = 'btm'; |
| | | break; |
| | | case 'center': |
| | | $value = 'y-mid'; |
| | | default: |
| | | } |
| | | return !empty($value) ? $value : ''; |
| | | case 'isStackedOnMobile': |
| | | return ($value === true) ? 'stack-small' : ''; |
| | | case 'justifyContent': |
| | | return !empty($value) ? 'j-'.$value : ''; |
| | | case 'orientation': |
| | | return $value==='column' ? 'column' : ''; |
| | | case 'width': |
| | | return $this->getWidth($value); |
| | | case 'dimRatio': |
| | | if (is_numeric($value)) { |
| | | $width = match (true) { |
| | | $value < 25 => '25', |
| | | $value < 33 => '33', |
| | | $value <= 50 => '50', |
| | | $value < 66 => '66', |
| | | $value < 75 => '75', |
| | | default => 'full', |
| | | }; |
| | | switch ($key) { |
| | | case 'width': |
| | | return 'width-'.$width; |
| | | case 'dimRatio': |
| | | return 'overlay-'.$width; |
| | | } |
| | | } |
| | | return ''; |
| | | |
| | | return $this->getDimRatio($value); |
| | | case 'overlayColor': |
| | | return $value; |
| | | break; |
| | | //Typography |
| | | case 'textAlign': |
| | | return !empty($value) ? 'text-'.$value : ''; |
| | |
| | | |
| | | //Style base: |
| | | case 'style': |
| | | $classes = []; |
| | | //Margin and Padding |
| | | if (array_key_exists('spacing', $value)) { |
| | | foreach (['margin' => 'm', 'padding'=>'p'] as $search => $c) { |
| | | if (array_key_exists($search, $value['spacing'])) { |
| | | $directions = []; |
| | | |
| | | // Collect ONLY preset spacing values for classes |
| | | foreach ($value['spacing'][$search] as $direction => $size) { |
| | | $presetSize = $this->getPresetSpacing($size); |
| | | if ($presetSize) { |
| | | $directions[$direction] = $presetSize; |
| | | } |
| | | // Non-preset values are skipped here and handled by inline styles below |
| | | } |
| | | |
| | | if (empty($directions)) { |
| | | continue; |
| | | } |
| | | |
| | | // Check what directions we have |
| | | $hasTop = isset($directions['top']); |
| | | $hasBottom = isset($directions['bottom']); |
| | | $hasLeft = isset($directions['left']); |
| | | $hasRight = isset($directions['right']); |
| | | |
| | | // Check if axes match |
| | | $xMatch = $hasLeft && $hasRight && $directions['left'] === $directions['right']; |
| | | $yMatch = $hasTop && $hasBottom && $directions['top'] === $directions['bottom']; |
| | | |
| | | // All 4 directions exist and match → p-3 |
| | | if ($hasTop && $hasBottom && $hasLeft && $hasRight && |
| | | count(array_unique($directions)) === 1) { |
| | | $classes[] = $c . '-' . reset($directions); |
| | | } |
| | | // Both axes match → px-3 py-2 |
| | | elseif ($xMatch && $yMatch) { |
| | | $classes[] = $c . 'x-' . $directions['left']; |
| | | $classes[] = $c . 'y-' . $directions['top']; |
| | | } |
| | | // Only X axis matches → px-3 (+ individual for top/bottom) |
| | | elseif ($xMatch) { |
| | | $classes[] = $c . 'x-' . $directions['left']; |
| | | if ($hasTop) { |
| | | $classes[] = $c . 't-' . $directions['top']; |
| | | } |
| | | if ($hasBottom) { |
| | | $classes[] = $c . 'b-' . $directions['bottom']; |
| | | } |
| | | } |
| | | // Only Y axis matches → py-3 (+ individual for left/right) |
| | | elseif ($yMatch) { |
| | | $classes[] = $c . 'y-' . $directions['top']; |
| | | if ($hasLeft) { |
| | | $classes[] = $c . 'l-' . $directions['left']; |
| | | } |
| | | if ($hasRight) { |
| | | $classes[] = $c . 'r-' . $directions['right']; |
| | | } |
| | | } |
| | | // No matches - individual directions |
| | | else { |
| | | foreach ($directions as $direction => $size) { |
| | | $dir = match($direction) { |
| | | 'top' => 't', |
| | | 'bottom' => 'b', |
| | | 'left' => 'l', |
| | | 'right' => 'r', |
| | | default => $direction |
| | | }; |
| | | $classes[] = $c . $dir . '-' . $size; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | if (array_key_exists('fontSize', $value)) { |
| | | if (in_array($value['fontSize'], ['small', 'large', 'extra-large', 'huge'])) { |
| | | $classes[] = 'font-'.$value['fontSize']; |
| | | } |
| | | if (in_array('fontWeight', $value)) { |
| | | $classes[] = 'text-'.$value['fontWeight']; |
| | | } |
| | | if (in_array('textTransform', $value)) { |
| | | if (in_array($value['textTransform'], ['uppercase', 'capitalize', 'lowercase'])) { |
| | | $classes[] = $value['textTransform']; |
| | | } |
| | | } |
| | | } |
| | | return implode(' ', $classes); |
| | | return $this->getPresetStyles($value); |
| | | case 'fontSize': |
| | | $classes[] = 'font-'.$value; |
| | | return implode(' ', $classes); |
| | | case 'isStackedOnMobile': |
| | | return ($value === true) ? 'stack-small' : ''; |
| | | case 'width': |
| | | if (is_numeric($value)) { |
| | | $width = match (true) { |
| | | $value < 25 => '25', |
| | | $value < 33 => '33', |
| | | $value <= 50 => '50', |
| | | $value < 66 => '66', |
| | | $value < 75 => '75', |
| | | default => 'full', |
| | | }; |
| | | switch ($key) { |
| | | case 'width': |
| | | return 'width-'.$width; |
| | | case 'dimRatio': |
| | | return 'overlay-'.$width; |
| | | } |
| | | case 'postLayout': |
| | | $classes[] = 'item-grid'; |
| | | if (isset($attrs['columns']) && $attrs['columns']!== 3){ |
| | | $classes[] = sprintf( |
| | | 'split-%d', |
| | | $attrs['columns'] |
| | | ); |
| | | } |
| | | return ''; |
| | | return $classes; |
| | | default: |
| | | $ignore = [ |
| | | 'useFeaturedImage', |
| | | 'opacity', |
| | | 'borderColor', |
| | | 'backgroundColor', |
| | | 'textColor', |
| | | 'minHeight', |
| | | 'minHeightUnit', |
| | | 'isDark', |
| | | 'sizeSlug', |
| | | 'isUserOverlayColor', |
| | | 'customOverlayColor', |
| | | 'dimRatio', |
| | | 'placeholder', |
| | | 'alt', |
| | | 'imageFill', |
| | | 'mediaSizeSlug', |
| | | 'isLink', |
| | | 'kind', |
| | | 'label', |
| | | 'type', |
| | | 'id', |
| | | 'url', |
| | | 'label', |
| | | 'shouldSyncIcon', |
| | | 'rel', |
| | | 'opensInNewTab', |
| | | 'title', |
| | | 'ref', |
| | | 'overlayMenu', |
| | | 'slug', |
| | | 'theme', |
| | | 'tagName', |
| | | 'level', |
| | | 'ordered', |
| | | 'area', |
| | | 'mediaId', |
| | | 'mediaLink', |
| | | 'mediaType', |
| | | 'height', //maybe still need? |
| | | ]; |
| | | if (!is_admin() &&!in_array($key, $ignore)) { |
| | | if (JVB_TESTING && !is_admin() &&!in_array($key, $this->ignore)) { |
| | | // TESTING |
| | | // jvbDump($key, 'getClass'); |
| | | // jvbDump($attrs); |
| | | jvbDump($attrs, '[getClass] '.$key); |
| | | } |
| | | |
| | | return ''; |
| | | } |
| | | } |
| | | /*** CLASS HELPERS ***/ |
| | | private function getContentPosition(string $value):string |
| | | { |
| | | $classes = []; |
| | | $pos = explode(' ', $value); |
| | | foreach($pos as $p) { |
| | | switch ($p) { |
| | | case 'top': |
| | | $classes[] = 'top'; |
| | | break; |
| | | case 'right': |
| | | $classes[] = 'right'; |
| | | break; |
| | | case 'bottom': |
| | | $classes[] = 'btm'; |
| | | break; |
| | | case 'left': |
| | | $classes[] = 'left'; |
| | | break; |
| | | } |
| | | } |
| | | return implode(' ', $classes); |
| | | } |
| | | |
| | | private function getLayout(array $value, array $attrs):array |
| | | { |
| | | // jvbDump($value, 'getLayout'); |
| | | $classes = []; |
| | | |
| | | $type = 'row'; |
| | | $isRow = true; |
| | | //Determine type |
| | | if ((array_key_exists('type', $value) && !in_array($value['type'], ['flex', 'grid'])) || |
| | | (array_key_exists('orientation', $value) && $value['orientation'] === 'vertical')) { |
| | | $type = 'col'; |
| | | $isRow = false; |
| | | } elseif (array_key_exists('type', $value) && $value['type'] === 'grid') { |
| | | $type = 'item-grid'; |
| | | $isRow = false; |
| | | if (array_key_exists('columnCount', $value) && $value['columnCount']!== 3) { |
| | | $classes[] = sprintf( |
| | | 'split-%s', |
| | | $value['columnCount'] |
| | | ); |
| | | } |
| | | } |
| | | |
| | | if (array_key_exists('justifyContent', $value) && !array_key_exists('contentPosition', $attrs)) { |
| | | switch ($value['justifyContent']) { |
| | | case 'right': |
| | | $classes[] = 'right'; |
| | | break; |
| | | case 'center': |
| | | $classes[] = 'x-mid'; |
| | | break; |
| | | case 'space-between': |
| | | $classes[] = 'x-btw'; |
| | | break; |
| | | case 'left': |
| | | $classes[] = 'left'; |
| | | break; |
| | | case 'space-evenly': |
| | | $classes[] = 'x-even'; |
| | | break; |
| | | case 'space-around': |
| | | $classes[] = 'x-around'; |
| | | break; |
| | | case 'stretch': |
| | | $classes[] = 'stretch'; |
| | | } |
| | | } else { |
| | | $classes[] = 'left'; |
| | | } |
| | | |
| | | if (array_key_exists('verticalAlignment', $value)) { |
| | | switch ($value['verticalAlignment']) { |
| | | case 'bottom': |
| | | $classes[] = 'btm'; |
| | | break; |
| | | case 'top': |
| | | $classes[] = 'top'; |
| | | break; |
| | | case 'center': |
| | | $classes[] = 'y-mid'; |
| | | break; |
| | | case 'space-between': |
| | | $classes[] = 'y-btw'; |
| | | break; |
| | | case 'space-around': |
| | | $classes[] = 'y-around'; |
| | | break; |
| | | case 'space-even': |
| | | $classes[] = 'y-even'; |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | if (array_key_exists('flexWrap', $value)) { |
| | | if ($value['flexWrap'] === 'nowrap') { |
| | | $classes[] = 'nowrap'; |
| | | } |
| | | } |
| | | |
| | | $classes[] = $type; |
| | | return $classes; |
| | | } |
| | | |
| | | private function getWidth(string $value):string |
| | | { |
| | | $value = (int)str_replace('%', '', $value); |
| | | return sprintf( |
| | | 'width-%d', |
| | | match (true) { |
| | | $value <= 25 => '25', |
| | | $value <= 33 => '33', |
| | | $value <= 50 => '50', |
| | | $value <= 66 => '66', |
| | | $value <= 75 => '75', |
| | | default => 'full', |
| | | } |
| | | ); |
| | | } |
| | | private function getDimRatio(string $value):string |
| | | { |
| | | if (is_numeric($value)) { |
| | | return sprintf( |
| | | 'op-%d', |
| | | match (true) { |
| | | $value <= 14 => '1', |
| | | $value <= 28 => '2', |
| | | $value <= 42 => '3', |
| | | $value <= 56 => '45', |
| | | $value <= 70 => '4', |
| | | $value <= 84 => '5', |
| | | default => '6', |
| | | } |
| | | ); |
| | | } |
| | | return ''; |
| | | } |
| | | |
| | | private function getPresetStyles(array $value):string |
| | | { |
| | | $classes = []; |
| | | //Margin and Padding |
| | | if (array_key_exists('spacing', $value)) { |
| | | $classes = array_merge($classes, $this->buildSpacingClasses($value)); |
| | | } |
| | | if (array_key_exists('color', $value)) { |
| | | if (array_key_exists('duotone', $value['color'])) { |
| | | $preset = explode('|', $value['color']['duotone']); |
| | | $preset = $preset[array_key_last($preset)]; |
| | | if (str_contains($preset, '-')) { |
| | | $preset = explode('-', $preset); |
| | | } else { |
| | | $preset = [$preset]; |
| | | } |
| | | $classes[] = 'duotone'; |
| | | foreach ($preset as $p) { |
| | | $classes[] = $p; |
| | | } |
| | | } |
| | | } |
| | | |
| | | if (array_key_exists('fontSize', $value)) { |
| | | if (in_array($value['fontSize'], ['small', 'large', 'extra-large', 'huge'])) { |
| | | $classes[] = 'font-'.$value['fontSize']; |
| | | } |
| | | if (in_array('fontWeight', $value)) { |
| | | $classes[] = 'text-'.$value['fontWeight']; |
| | | } |
| | | if (in_array('textTransform', $value)) { |
| | | if (in_array($value['textTransform'], ['uppercase', 'capitalize', 'lowercase'])) { |
| | | $classes[] = $value['textTransform']; |
| | | } |
| | | } |
| | | } |
| | | return implode(' ', $classes); |
| | | } |
| | | private function buildSpacingClasses(array $value):array |
| | | { |
| | | $classes = []; |
| | | foreach (['margin' => 'm', 'padding'=>'p'] as $search => $c) { |
| | | if (array_key_exists($search, $value['spacing'])) { |
| | | $directions = []; |
| | | |
| | | // Collect ONLY preset spacing values for classes |
| | | foreach ($value['spacing'][$search] as $direction => $size) { |
| | | $presetSize = $this->getPresetSpacing($size); |
| | | if ($presetSize) { |
| | | $directions[$direction] = $presetSize; |
| | | } |
| | | // Non-preset values are skipped here and handled by inline styles below |
| | | } |
| | | |
| | | if (empty($directions)) { |
| | | continue; |
| | | } |
| | | |
| | | // Check what directions we have |
| | | $hasTop = isset($directions['top']); |
| | | $hasBottom = isset($directions['bottom']); |
| | | $hasLeft = isset($directions['left']); |
| | | $hasRight = isset($directions['right']); |
| | | |
| | | // Check if axes match |
| | | $xMatch = $hasLeft && $hasRight && $directions['left'] === $directions['right']; |
| | | $yMatch = $hasTop && $hasBottom && $directions['top'] === $directions['bottom']; |
| | | |
| | | // All 4 directions exist and match → p-3 |
| | | if ($hasTop && $hasBottom && $hasLeft && $hasRight && |
| | | count(array_unique($directions)) === 1) { |
| | | $classes[] = $c . '-' . reset($directions); |
| | | } |
| | | // Both axes match → px-3 py-2 |
| | | elseif ($xMatch && $yMatch) { |
| | | $classes[] = $c . 'x-' . $directions['left']; |
| | | $classes[] = $c . 'y-' . $directions['top']; |
| | | } |
| | | // Only X axis matches → px-3 (+ individual for top/bottom) |
| | | elseif ($xMatch) { |
| | | $classes[] = $c . 'x-' . $directions['left']; |
| | | if ($hasTop) { |
| | | $classes[] = $c . 't-' . $directions['top']; |
| | | } |
| | | if ($hasBottom) { |
| | | $classes[] = $c . 'b-' . $directions['bottom']; |
| | | } |
| | | } |
| | | // Only Y axis matches → py-3 (+ individual for left/right) |
| | | elseif ($yMatch) { |
| | | $classes[] = $c . 'y-' . $directions['top']; |
| | | if ($hasLeft) { |
| | | $classes[] = $c . 'l-' . $directions['left']; |
| | | } |
| | | if ($hasRight) { |
| | | $classes[] = $c . 'r-' . $directions['right']; |
| | | } |
| | | } |
| | | // No matches - individual directions |
| | | else { |
| | | foreach ($directions as $direction => $size) { |
| | | $dir = match($direction) { |
| | | 'top' => 't', |
| | | 'bottom' => 'b', |
| | | 'left' => 'l', |
| | | 'right' => 'r', |
| | | default => $direction |
| | | }; |
| | | $classes[] = $c . $dir . '-' . $size; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | return $classes; |
| | | } |
| | | |
| | | protected function getInlineStyles(array $attrs):array |
| | | { |
| | |
| | | $styles = []; |
| | | foreach ($attrs as $key => $value) { |
| | | $style = $this->getStyle($key, $value, $attrs); |
| | | if (is_string($style)) { |
| | | $style = [$style]; |
| | | } |
| | | $styles = array_merge($styles, $style); |
| | | } |
| | | return $styles; |
| | | } |
| | | protected function getStyle(string $key, string|bool|array|int $value, array $attrs):array |
| | | protected function getStyle(string $key, string|bool|array|int $value, array $attrs):array|string |
| | | { |
| | | $styles = []; |
| | | switch ($key) { |
| | | // Font family settings |
| | | case 'fontFamily': |
| | | if ($value === 'body') { |
| | | $styles[] = 'font-family: "Open Sans", system-ui, -apple-system, sans-serif'; |
| | | } elseif ($value === 'heading') { |
| | | $styles[] = 'font-family: "Josefin Sans", system-ui, -apple-system, sans-serif'; |
| | | } elseif (!empty($value)) { |
| | | $styles[] = 'font-family: '.$value; |
| | | } |
| | | break; |
| | | case 'size': |
| | | return $this->getIconSizeStyle($value); |
| | | |
| | | case 'fontFamily': |
| | | return $this->getFontFamilyStyle($value); |
| | | |
| | | // Icon color (for icon blocks) |
| | | case 'iconColorValue': |
| | | if (!empty($value)) { |
| | | $styles[] = 'color: '.$value; |
| | | } |
| | | break; |
| | | return $this->getColorStyle($value); |
| | | |
| | | // Minimum height settings |
| | | case 'minHeight': |
| | | if (!empty($value) && isset($attrs['minHeightUnit'])) { |
| | | $styles[] = 'min-height: '.$value.$attrs['minHeightUnit']; |
| | | } elseif (!empty($value)) { |
| | | $styles[] = 'min-height: '.$value.'px'; // Default to px if no unit specified |
| | | } |
| | | break; |
| | | return $this->getMinHeightStyle($value, $attrs); |
| | | |
| | | // Background URL (for cover, media blocks) |
| | | case 'url': |
| | | if (!empty($value) && str_starts_with($value, 'http')) { |
| | | $styles[] = 'background-image: url('.$value.')'; |
| | | return 'background-image: url('.$value.')'; |
| | | } |
| | | break; |
| | | |
| | | // Focal point for background images |
| | | case 'focalPoint': |
| | | $x = (array_key_exists('x', $attrs['focalPoint'])) ? $attrs['focalPoint']['x'] * 100 : 'center'; |
| | | $y = (array_key_exists('y', $attrs['focalPoint'])) ? $attrs['focalPoint']['y'] * 100 : 'center'; |
| | | $styles[] = 'background-position:'.$x.' '.$y.';'; |
| | | |
| | | break; |
| | | return $this->getFocalPointStyle($value); |
| | | |
| | | // Complex style object |
| | | case 'style': |
| | | // Border styles |
| | | if (isset($value['border'])) { |
| | | $border = $value['border']; |
| | | return $this->extractStyles($value, $attrs); |
| | | |
| | | if (isset($border['radius'])) { |
| | | $styles[] = 'border-radius: '.$border['radius']; |
| | | } |
| | | |
| | | if (isset($border['width'])) { |
| | | $styles[] = 'border-width: '.$border['width']; |
| | | } |
| | | |
| | | if (isset($border['style']) && isset($border['width']) && !empty($border['style'])) { |
| | | $styles[] = 'border-style: '.$border['style']; |
| | | } |
| | | |
| | | if (isset($border['color'])) { |
| | | $styles[] = 'border-color: '.$border['color']; |
| | | } |
| | | } |
| | | |
| | | // Color styles |
| | | if (isset($value['color'])) { |
| | | $color = $value['color']; |
| | | |
| | | if (isset($color['background'])) { |
| | | $styles[] = 'background-color: '.$color['background']; |
| | | } |
| | | |
| | | if (isset($color['text'])) { |
| | | $styles[] = 'color: '.$color['text']; |
| | | } |
| | | |
| | | if (isset($color['gradient'])) { |
| | | $styles[] = 'background: '.$color['gradient']; |
| | | } |
| | | } |
| | | |
| | | // Layout styles |
| | | if (isset($value['layout'])) { |
| | | foreach ($value['layout'] as $layout => $option) { |
| | | switch ($layout) { |
| | | case 'selfStretch': |
| | | if ($option === 'fixed' && isset($value['layout']['selfStretchValue'])) { |
| | | $styles[] = 'width: '.$value['layout']['selfStretchValue']; |
| | | } |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | |
| | | // Typography styles |
| | | if (isset($value['typography'])) { |
| | | $typography = $value['typography']; |
| | | |
| | | if (isset($typography['fontSize'])) { |
| | | $styles[] = 'font-size: '.$typography['fontSize']; |
| | | } |
| | | |
| | | if (isset($typography['fontWeight'])) { |
| | | $styles[] = 'font-weight: '.$typography['fontWeight']; |
| | | } |
| | | |
| | | if (isset($typography['textDecoration'])) { |
| | | $styles[] = 'text-decoration: '.$typography['textDecoration']; |
| | | } |
| | | |
| | | if (isset($typography['textTransform'])) { |
| | | $styles[] = 'text-transform: '.$typography['textTransform']; |
| | | } |
| | | |
| | | if (isset($typography['letterSpacing'])) { |
| | | $styles[] = 'letter-spacing: '.$typography['letterSpacing']; |
| | | } |
| | | |
| | | if (isset($typography['lineHeight'])) { |
| | | $styles[] = 'line-height: '.$typography['lineHeight']; |
| | | } |
| | | } |
| | | |
| | | // Spacing styles |
| | | if (isset($value['spacing'])) { |
| | | $spacing = $value['spacing']; |
| | | |
| | | // Don't duplicate margin/padding that's handled by classes |
| | | // Only add specific CSS values here that wouldn't work well as classes |
| | | if (isset($spacing['margin'])) { |
| | | foreach ($spacing['margin'] as $direction => $size) { |
| | | // If not a preset value, add as inline style |
| | | if (!str_contains($size, 'var:preset')) { |
| | | $styles[] = 'margin-'.$direction.': '.$size; |
| | | } |
| | | } |
| | | } |
| | | |
| | | if (isset($spacing['padding'])) { |
| | | foreach ($spacing['padding'] as $direction => $size) { |
| | | // If not a preset value, add as inline style |
| | | if (!str_contains($size, 'var:preset')) { |
| | | $styles[] = 'padding-'.$direction.': '.$size; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | break; |
| | | case 'dimRatio': |
| | | $ratio = (ceil($value /25) *25); |
| | | $s = 'background-color: rgba(var(--base-rgb), '; |
| | | switch ($ratio) { |
| | | case 0: |
| | | $s .= 'var(--rgb-subtle-hover));'; |
| | | break; |
| | | case 25: |
| | | $s .= 'var(--rgb-light));'; |
| | | break; |
| | | case 50: |
| | | $s .= 'var(--rgb-medium));'; |
| | | break; |
| | | default: |
| | | $s .= 'var(--rgb-heavy));'; |
| | | break; |
| | | } |
| | | $styles[] = $s; |
| | | break; |
| | | return $this->getDimRatioStyle($value, $attrs); |
| | | |
| | | // Custom styles (any other attributes that need inline styling) |
| | | case 'backgroundType': |
| | | if ($value === 'video' && isset($attrs['backgroundUrl'])) { |
| | | // Don't set a background image for videos - it will be handled by the video element |
| | | } elseif (isset($attrs['backgroundUrl'])) { |
| | | $styles[] = 'background-image: url('.$attrs['backgroundUrl'].')'; |
| | | return 'background-image: url('.$attrs['backgroundUrl'].')'; |
| | | } |
| | | break; |
| | | |
| | | case 'backgroundColor': |
| | | case 'borderColor': |
| | | case 'textColor': |
| | | $type = ($key === 'backgroundColor') ? 'background-color:' : (($key === 'borderColor') ? 'border-color:' : 'color:'); |
| | | $defaults = apply_filters('jvbColours', ['base', 'contrast', 'action', 'secondary']); |
| | | $continue = true; |
| | | foreach ($defaults as $default) { |
| | | if (str_starts_with($value, $default)) { |
| | | $continue = false; |
| | | $styles[] = $type.'var(--'.$value.')'; |
| | | } |
| | | $type = str_replace('Color', '-color', $key); |
| | | $type = str_replace('text-', '', $type); |
| | | if (isset($attrs['border']['width']) && $key === 'borderColor') { |
| | | break; |
| | | } |
| | | if ($continue) { |
| | | $styles[] = $type.$value; |
| | | } |
| | | break; |
| | | return $this->getColorStyle($value, $type); |
| | | |
| | | // Any other attributes that need direct styling |
| | | default: |
| | | $ignore = [ |
| | | 'useFeaturedImage', |
| | | 'opacity', |
| | | 'textAlign', |
| | | 'minHeightUnit', |
| | | 'isDark', |
| | | 'isUserOverlayColor', |
| | | 'contentPosition', |
| | | 'sizeSlug', |
| | | 'customOverlayColor', |
| | | 'alt', |
| | | 'placeholder', |
| | | 'imageFill', |
| | | 'mediaSizeSlug', |
| | | 'isLink', |
| | | 'kind', |
| | | 'label', |
| | | 'type', |
| | | 'id', |
| | | 'url', |
| | | 'label', |
| | | 'shouldSyncIcon', |
| | | 'rel', |
| | | 'opensInNewTab', |
| | | 'title', |
| | | 'ref', |
| | | 'overlayMenu', |
| | | 'slug', |
| | | 'theme', |
| | | 'tagName', |
| | | 'level', |
| | | 'ordered', |
| | | 'area', |
| | | 'className', |
| | | 'fontSize', |
| | | 'layout', |
| | | 'align', |
| | | 'mediaId', |
| | | 'mediaLink', |
| | | 'mediaType', |
| | | 'isStackedOnMobile', |
| | | 'width', |
| | | 'height', // maybe still need? |
| | | ]; |
| | | if (!is_admin() && !in_array($key, $ignore)) { |
| | | if (JVB_TESTING && !is_admin() && !in_array($key, $this->ignore)) { |
| | | //TESTING |
| | | // jvbDump($key, 'getStyle'); |
| | | // jvbDump($attrs); |
| | | jvbDump($attrs, '[getStyle] '.$key); |
| | | } |
| | | // No default inline styles |
| | | break; |
| | |
| | | |
| | | return $styles; |
| | | } |
| | | private function getIconSizeStyle(string $value):array |
| | | { |
| | | $values = explode(' ', $value); |
| | | $styles = []; |
| | | foreach ($values as $v) { |
| | | switch ($value) { |
| | | case 'has-small-icon-size': |
| | | $styles[] = '--w:var(--txt-x-small)'; |
| | | break; |
| | | case 'has-large-icon-size': |
| | | $styles[] = '--w:var(--txt-large)'; |
| | | break; |
| | | case 'has-huge-icon-size': |
| | | $styles[] = '--w:var(--txt-xx-large)'; |
| | | break; |
| | | default: |
| | | if (JVB_TESTING) { |
| | | jvbDump($value, 'No preset found for size: '.print_r($value, true)); |
| | | } |
| | | } |
| | | } |
| | | return $styles; |
| | | } |
| | | private function getFontFamilyStyle(string $value):string |
| | | { |
| | | return match($value) { |
| | | 'body' => 'font-family: var(--body)', |
| | | 'heading' => 'font-family: var(--heading)', |
| | | default => sprintf('font-family: %s', $value) |
| | | }; |
| | | } |
| | | private function getColorStyle(string $value, ?string $type = 'color'):string |
| | | { |
| | | if (!in_array($type, ['color', 'background','background-color','border-color'])) { |
| | | $type = null; |
| | | } |
| | | return sprintf( |
| | | '%s%s', |
| | | $type ? $type.': ' : '', |
| | | $this->getColor($value) |
| | | ); |
| | | } |
| | | private function getMinHeightStyle(string $value, array $attrs):string |
| | | { |
| | | $out = ''; |
| | | if (!empty($value)) { |
| | | if (isset($attrs['minHeightUnit'])) { |
| | | $out = sprintf( |
| | | 'min-height: %s%s', |
| | | $value, |
| | | $attrs['minHeightUnit'] |
| | | ); |
| | | } else { |
| | | $out = sprintf( |
| | | 'min-height: %spx', |
| | | $value |
| | | ); |
| | | } |
| | | } |
| | | return $out; |
| | | } |
| | | |
| | | private function getFocalPointStyle(array $value):string |
| | | { |
| | | jvbDump($value, 'Focal Point'); |
| | | $x = array_key_exists('x', $value) ? $value['x'] * 100 : 'center'; |
| | | $y = array_key_exists('y', $value) ? $value['y'] * 100 : 'center'; |
| | | |
| | | $y = $x === $y ? '' : ' '.$y; |
| | | return sprintf( |
| | | 'background-position:%s%s', |
| | | $x, |
| | | $y |
| | | ); |
| | | } |
| | | |
| | | private function extractStyles(array $value, array $attrs):array |
| | | { |
| | | $styles = []; |
| | | foreach ($value as $k => $v) { |
| | | switch ($k) { |
| | | case 'border': |
| | | $styles = array_merge($styles, $this->getBorderStyle($v, $attrs)); |
| | | break; |
| | | |
| | | case 'color': |
| | | if (isset($v['background'])) { |
| | | $styles[] = $this->getColorStyle($v['background'], 'background-color'); |
| | | } |
| | | if (isset($v['text'])) { |
| | | $styles[] = $this->getColorStyle($v['text']); |
| | | } |
| | | if (isset($v['gradient'])) { |
| | | jvbDump($v, 'Gradient'); |
| | | } |
| | | break; |
| | | |
| | | case 'layout': |
| | | $styles = array_merge($styles, $this->getLayoutStyle($v, $attrs)); |
| | | break; |
| | | |
| | | case 'typography': |
| | | $styles = array_merge($styles, $this->getTypographyStyle($v, $attrs)); |
| | | break; |
| | | |
| | | case 'spacing': |
| | | if (isset($v['blockGap'])) { |
| | | if (is_array($v['blockGap'])) { |
| | | $inner = []; |
| | | foreach ($v['blockGap'] as $gap) { |
| | | $inner[] = sprintf( |
| | | 'var(--sp%s)', |
| | | $this->getPresetSpacing($gap) |
| | | ); |
| | | } |
| | | if (!empty($inner)) { |
| | | $styles[] = sprintf( |
| | | '--gap: %s', |
| | | implode(' ', $inner) |
| | | ); |
| | | } |
| | | } else { |
| | | $styles[] = '--gap: var(--sp'.$this->getPresetSpacing($v['blockGap']).')'; |
| | | } |
| | | } |
| | | |
| | | // Don't duplicate margin/padding that's handled by classes |
| | | // Only add specific CSS values here that wouldn't work well as classes |
| | | if (isset($v['margin'])) { |
| | | foreach ($v['margin'] as $direction => $size) { |
| | | if (!str_contains($size, 'var:preset')) { |
| | | $styles[] = 'margin-'.$direction.': '.$size; |
| | | } |
| | | } |
| | | } |
| | | |
| | | if (isset($v['padding'])) { |
| | | foreach($v['padding'] as $dir => $size) { |
| | | if (!str_contains($size, 'var:preset')) { |
| | | $styles[] = 'padding-'.$dir.': '.$size; |
| | | } |
| | | } |
| | | } |
| | | break; |
| | | |
| | | case 'background': |
| | | if (array_key_exists('backgroundImage', $v)) { |
| | | $data = Image::getData($v['backgroundImage']['id']); |
| | | if (!empty($data) && array_key_exists('tiny', $data)) { |
| | | $styles[] = sprintf( |
| | | 'background-image: url(%s)', |
| | | $data['tiny'] |
| | | ); |
| | | } |
| | | |
| | | } |
| | | break; |
| | | |
| | | case 'dimensions': |
| | | foreach ($v as $sk => $sv) { |
| | | if ($sk === 'minHeight') { |
| | | $styles[] = sprintf( |
| | | 'min-height: %s', |
| | | $sv |
| | | ); |
| | | } else { |
| | | jvbDump('No config set for dimension '.$sk.': '.print_r($sv, true)); |
| | | } |
| | | } |
| | | |
| | | |
| | | break; |
| | | |
| | | case 'elements': |
| | | if (!empty($v)) { |
| | | // Generate a unique class tied to this block instance |
| | | $uid = 'b-'.substr(md5(serialize($attrs)), 0, 8); |
| | | $this->extractElementStyles($v, $uid); |
| | | // We need the uid added as a class — store it for getClassesAndStyles to pick up |
| | | static::$pendingClass[] = $uid; |
| | | } |
| | | break; |
| | | |
| | | default: |
| | | jvbDump('No config set for '.$k.': '.print_r($v, true)); |
| | | } |
| | | } |
| | | |
| | | return $styles; |
| | | } |
| | | private function getBorderStyle(array $border, array $attrs):array |
| | | { |
| | | $styles = []; |
| | | |
| | | if (isset($border['radius'])) { |
| | | $styles[] = 'border-radius: '.$border['radius']; |
| | | } |
| | | |
| | | if (isset($border['width']) && isset($attrs['borderColor'])) { |
| | | $st = $border['style'] ?? 'solid'; |
| | | $styles[] = sprintf( |
| | | 'border: %s %s %s', |
| | | $border['width'], |
| | | $st, |
| | | $this->getColor($attrs['borderColor']) |
| | | ); |
| | | } elseif (isset($border['width'])) { |
| | | $styles[] = 'border-width: '.$border['width']; |
| | | } elseif (isset($border['style'])) { |
| | | $styles[] = 'border-style: '.$border['style']; |
| | | } |
| | | |
| | | return $styles; |
| | | } |
| | | |
| | | private function getLayoutStyle(array $layout, array $attrs):array |
| | | { |
| | | $styles = []; |
| | | // jvbDump($layout); |
| | | |
| | | foreach ($layout as $l => $option) { |
| | | switch ($l) { |
| | | case 'selfStretch': |
| | | if ($option === 'fixed' && isset($layout['selfStretchValue'])) { |
| | | $styles[] = 'width: '.$layout['selfStretchValue']; |
| | | } elseif ($option === 'fill') { |
| | | $styles[] = 'flex:1'; |
| | | } |
| | | break; |
| | | default: |
| | | $ignore = [ |
| | | 'selfStretchValue', |
| | | 'flexSize', |
| | | ]; |
| | | if (JVB_TESTING && !in_array($l, $ignore)) { |
| | | jvbDump($l, 'No layout style set for: '); |
| | | } |
| | | // case 'type': |
| | | // if ($option === 'grid' && $value['layout']['columnCount'] !== 3) { |
| | | // $styles[] = sprintf( |
| | | // 'grid-template-columns: repeat(1fr, %s)', |
| | | // $value['layout']['columnCount'] |
| | | // ); |
| | | // } |
| | | // break; |
| | | } |
| | | } |
| | | return $styles; |
| | | } |
| | | |
| | | private function getTypographyStyle(array $typography, array $attrs):array |
| | | { |
| | | $styles = []; |
| | | |
| | | if (isset($typography['fontSize'])) { |
| | | $styles[] = 'font-size: '.$typography['fontSize']; |
| | | } |
| | | |
| | | if (isset($typography['fontWeight'])) { |
| | | $styles[] = 'font-weight: '.$typography['fontWeight']; |
| | | } |
| | | |
| | | if (isset($typography['textDecoration'])) { |
| | | $styles[] = 'text-decoration: '.$typography['textDecoration']; |
| | | } |
| | | |
| | | if (isset($typography['textTransform'])) { |
| | | $styles[] = 'text-transform: '.$typography['textTransform']; |
| | | } |
| | | |
| | | if (isset($typography['letterSpacing'])) { |
| | | $styles[] = 'letter-spacing: '.$typography['letterSpacing']; |
| | | } |
| | | |
| | | if (isset($typography['lineHeight'])) { |
| | | $styles[] = 'line-height: '.$typography['lineHeight']; |
| | | } |
| | | return $styles; |
| | | } |
| | | private function extractElementStyles(array $elements, string $uid):void |
| | | { |
| | | foreach ($elements as $element => $states) { |
| | | $selector = match($element) { |
| | | 'link' => "a", |
| | | 'heading' => "h1,h2,h3,h4,h5,h6", |
| | | 'button' => "button,.button", |
| | | default => $element, |
| | | }; |
| | | |
| | | foreach ($states as $state => $rules) { |
| | | $css = []; |
| | | $fullSelector = str_starts_with($state, ':') |
| | | ? ".{$uid} {$selector}{$state}" |
| | | : ".{$uid} {$selector}"; |
| | | |
| | | if (isset($rules['color']['text'])) { |
| | | $css[] = 'color: '.$this->getColor($rules['color']['text']); |
| | | } |
| | | if (isset($rules['color']['background'])) { |
| | | $css[] = 'background-color: '.$this->getColor($rules['color']['background']); |
| | | } |
| | | if (!empty($css)) { |
| | | static::$pendingStyles[] = $fullSelector.' { '.implode('; ', $css).' }'; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | public function maybeOutputCustomStyles(): string |
| | | { |
| | | if (empty(static::$pendingStyles)) return ''; |
| | | $out = '<style>'.implode(' ', static::$pendingStyles).'</style>'; |
| | | static::$pendingStyles = []; |
| | | return $out; |
| | | } |
| | | |
| | | private function getDimRatioStyle(int $value, array $attrs):string |
| | | { |
| | | //TODO: This likely isn't working correctly |
| | | jvbDump($value, 'dimRatio'); |
| | | jvbDump($attrs, 'dimRatio attrs'); |
| | | $s = ''; |
| | | if (!array_key_exists('overlayColor', $attrs)) { |
| | | $s = 'background-color: rgba(var(--base-rgb), '; |
| | | if ($value <= 14) { |
| | | $s .= 'var(--op-1));'; |
| | | } elseif ($value <= 28) { |
| | | $s .= 'var(--op-2));'; |
| | | } elseif ($value <= 42) { |
| | | $s .= 'var(--op-3));'; |
| | | } elseif ($value <= 56) { |
| | | $s .= 'var(--op-45));'; |
| | | } elseif ($value <= 70) { |
| | | $s .= 'var(--op-4));'; |
| | | } elseif ($value <= 84) { |
| | | $s .= 'var(--op-5));'; |
| | | } else { |
| | | $s .= 'var(--op-6));'; |
| | | } |
| | | } |
| | | return $s; |
| | | } |
| | | |
| | | protected function getDataset(array $attrs):array |
| | | { |
| | | $dataset = []; |
| | | if (array_key_exists('style', $attrs)) { |
| | | if (array_key_exists('background', $attrs['style'])){ |
| | | if (array_key_exists('backgroundImage', $attrs['style']['background'])) { |
| | | $id = $attrs['style']['background']['backgroundImage']['id']??false; |
| | | if ($id) { |
| | | $data = Image::getData($id); |
| | | $dataset['bg-small'] = $data['small']; |
| | | $dataset['bg-med'] = $data['medium']; |
| | | $dataset['bg-large'] = $data['large']; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | return $dataset; |
| | | } |
| | | |
| | | public function formatImage(int $ID = 0, string $start = 'tiny', string $replace = 'large'):string |
| | | { |
| | |
| | | return jvbFormatImage($ID, $start, $replace); |
| | | } |
| | | |
| | | protected function checkAttrs(string $test, array $attrs):bool |
| | | { |
| | | return array_key_exists($test, $attrs) && $attrs[$test]===true; |
| | | } |
| | | |
| | | protected function getColor(string $value):string |
| | | { |
| | | $defaults = apply_filters('jvbColours', ['base', 'contrast', 'action', 'secondary']); |
| | | foreach ($defaults as $default) { |
| | | if (str_starts_with($value, $default)) { |
| | | return 'var(--'.$value.')'; |
| | | } |
| | | } |
| | | return $value; |
| | | } |
| | | |
| | | protected function counter(string $key):void |
| | | { |
| | | if (!array_key_exists($key, static::$counters)) { |
| | | static::$counters[$key] = 1; |
| | | } else { |
| | | static::$counters[$key]++; |
| | | } |
| | | } |
| | | } |