Components
41
Accordion Block Benifits Grid Block 404 Card Stack Careers Grid Case Study Carousel Case Study Hero Content Columns Content Image Content Image Accordion Content Video Cta Block Example Featured Blog Hero Featured Resource Hero Form Cta Form Hero Full Width Image Homepage Hero Hover List Image Hero Image Mask Image Testimonial Carousel Industry Insights Latest News List Columns Logo Scroller Map Block Post Feed Resource Grid Split Hero Split Text Statement Statistics Row Team Filter Team Grid Testimonial Carousel Testimonial Carousel Text Highlight Tools Grid Two Column List

Industry Insights

There are no ACF fields assigned to this component.

				
@import "../../resources/scss/util/variables";
@import "../../resources/scss/util/mixins";
@import "../../resources/scss/vendor/bootstrap/vendor/rfs";

.block-industry-insights {
	@include padding-top(rem-calc(60));
	@include padding-bottom(rem-calc(60));
	position: relative;

	&.loading {
		pointer-events: none;

		&::before {
			content: '';
			position: absolute;
			top: 0;
			left: 0;
			width: 100%;
			height: 100%;
			background-color: rgba(255, 255, 255, 0.8);
			z-index: 100;
			pointer-events: all;
		}

		&::after {
			content: '';
			position: absolute;
			top: 50%;
			left: 50%;
			transform: translate(-50%, -50%);
			width: 50px;
			height: 50px;
			border: 4px solid rgba(0, 0, 0, 0.1);
			border-top-color: var(--primary, #000);
			border-radius: 50%;
			animation: spin 0.8s linear infinite;
			z-index: 101;
		}
	}

	&__filters-title {
		text-align: center;
		margin-bottom: rem-calc(16);
		font-size: rem-calc(16);
		font-weight: 500;

		@include bp($md) {
			font-size: rem-calc(18);
			margin-bottom: rem-calc(20);
		}
	}

	&__filters {
		display: flex;
		flex-wrap: wrap;
		gap: rem-calc(6);
		margin-bottom: rem-calc(40);
		justify-content: center;

		@include bp($md) {
			margin-bottom: rem-calc(60);
			gap: rem-calc(8);
		}
	}

	&__filter {
		display: inline-block;
		padding: rem-calc(10 20);
		border-radius: rem-calc(30);
		border: 1px solid rgba(0, 0, 0, 0.2);
		background-color: $white;
		color: rgba(0, 0, 0, 0.7);
		text-decoration: none;
		font-size: rem-calc(14);
		font-weight: 500;
		transition: all 0.3s ease;
		cursor: pointer;
		font-family: inherit;
		appearance: none;
		-webkit-appearance: none;

		@include bp($md) {
			padding: rem-calc(6 12);
			font-size: rem-calc(12);
		}

		&:hover {
			background-color: rgba(0, 0, 0, 0.05);
			border-color: rgba(0, 0, 0, 0.3);
		}

		&:focus {
			outline: 2px solid var(--primary, #000);
			outline-offset: 2px;
		}

		&--active {
			background-color: var(--primary, #000);
			color: $white;
			border-color: var(--primary, #000);

			&:hover {
				background-color: rgba(0, 0, 0, 0.8);
			}
		}
	}

	&__timeline {
		position: relative;
		padding: rem-calc(40) 0;

		@include bp($md) {
			padding: rem-calc(60) 0;
		}
	}

	&__timeline-line {
		position: absolute; 
		left: rem-calc(20);
		top: 0;
		bottom: 0;
		width: 4px;
		background-color: rgba(0, 0, 0, 0.1);
		z-index: 1;

		@include bp($md) {
			left: 50%;
			transform: translateX(-50%);
		}

		&::before {
			content: '';
			position: absolute;
			top: 0;
			left: 50%;
			transform: translateX(-50%);
			width: 12px;
			height: 12px;
			background-color: var(--primary, #000);
			border-radius: 50%;
			z-index: 2;
		}

		&::after {
			content: '';
			position: absolute;
			bottom: 0;
			left: 50%;
			transform: translateX(-50%);
			width: 12px;
			height: 12px;
			background-color: var(--primary, #000);
			border-radius: 50%;
			z-index: 2;
		}
	}

	&__timeline-items {
		position: relative;
		z-index: 2;
	}

	&__timeline-item {
		position: relative;
		margin-bottom: rem-calc(40);
		padding-left: rem-calc(50);

		@include bp($md) {
			margin-bottom: rem-calc(60);
			padding-left: 0;
			width: calc(50% - 30px);
		}

		&:last-child {
			margin-bottom: 0;
		}

		&--left {
			@include bp($md) {
				margin-right: auto;
			}
		}

		&--right {
			@include bp($md) {
				margin-left: auto;
			}
		}
	}

	&__timeline-marker {
		position: absolute;
		left: rem-calc(12);
		top: rem-calc(20);
		width: 16px;
		height: 16px;
		background-color: var(--primary, #000);
		border: 4px solid $white;
		border-radius: 50%;
		z-index: 3;
		box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);

		@include bp($md) {
			left: auto;
			right: calc(-30px - 8px);
		}

		.block-industry-insights__timeline-item--right & {
			@include bp($md) {
				right: auto;
				left: calc(-30px - 8px);
			}
		}

		// Category-specific marker styles
		// Add custom colors for each category as needed
		&--google-seo, &--google {
			background-color: #34a853;
		}

		&--affiliates {
			background-color: #9badac;
		}

		&--pr {
			background-color: #e0e5e9;
		}

		&--digital {
			background-color: #95e1d3;
		}

		&--ppc {
			background-color: #83c3dc;
		}

		&--social-media {
			background-color: #e12309;
		}

		&--analytics {
			background-color: #f2a600;
		}

		&--meta {
			background-color: #0081fb;
		}

		&--facebook {
			background-color: #1877f2;
		}

		&--tiktok {
			background-color: #ff0050;
		}

		&--bing {
			background-color: #008373;
		}

		&--microsoft {
			background-color: #00a4ef;
		}

		&--tools {
			background-color: #6c757d;
		}

		&--instagram {
			background-color: #c13584;
		}

		&--artificial-intelligence {
			background-color: #6366f1;
		}

		&--linkedin {
			background-color: #0077b5;
		}

		&--pinterest {
			background-color: #bd081c;
		}
	}

	&__timeline-content {
		background-color: $white;
		border-radius: rem-calc(12);
		padding: rem-calc(24);
		box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
		transition: box-shadow 0.3s ease, transform 0.3s ease;

		&:hover {
			box-shadow: 0 4px 20px rgba(0, 0, 0, 0.12);
			transform: translateY(-2px);
		}

		@include bp($md) {
			padding: rem-calc(32);
		}
	}

	&__timeline-image {
		margin-bottom: rem-calc(20);
		border-radius: rem-calc(8);
		overflow: hidden;

		img {
			width: 100%;
			height: auto;
			display: block;
		}
	}

	&__timeline-text {
		position: relative;

        iframe {
            max-width: 100%;
        }
	}

	&__timeline-date {
		font-size: rem-calc(14);
		color: rgba(0, 0, 0, 0.6);
		margin-bottom: rem-calc(12);
		font-weight: 500;
		text-transform: uppercase;
		letter-spacing: 0.5px;
	}

	&__timeline-categories {
		display: flex;
		flex-wrap: wrap;
		gap: rem-calc(6);
		margin-bottom: rem-calc(12);
	}

	&__timeline-category {
		display: inline-block;
		padding: rem-calc(4 12);
		border-radius: rem-calc(20);
		font-size: rem-calc(12);
		font-weight: 500;
		color: $white;
		background-color: var(--primary, #000);
		text-transform: uppercase;
		letter-spacing: 0.5px;

		// Category-specific background colors matching marker styles
		&--google-seo, &--google {
			background-color: #34a853;
		}

		&--affiliates {
			background-color: #9badac;
		}

		&--pr {
			background-color: #e0e5e9;
		}

		&--digital {
			background-color: #95e1d3;
		}

		&--ppc {
			background-color: #83c3dc;
		}

		&--social-media {
			background-color: #e12309;
		}

		&--analytics {
			background-color: #f2a600;
		}

		&--meta {
			background-color: #0081fb;
		}

		&--facebook {
			background-color: #1877f2;
		}

		&--tiktok {
			background-color: #ff0050;
		}

		&--bing {
			background-color: #008373;
		}

		&--microsoft {
			background-color: #00a4ef;
		}

		&--tools {
			background-color: #6c757d;
		}

		&--instagram {
			background-color: #c13584;
		}

		&--artificial-intelligence {
			background-color: #6366f1;
		}

		&--linkedin {
			background-color: #0077b5;
		}

		&--pinterest {
			background-color: #bd081c;
		}
	}

	&__timeline-title {
		margin-bottom: rem-calc(12);
		font-size: rem-calc(20);
		line-height: 1.3;

		@include bp($md) {
			font-size: rem-calc(24);
		}

		a {
			color: inherit;
			text-decoration: none;
			transition: color 0.3s ease;
		}
	}

	&__timeline-excerpt {
		font-size: rem-calc(16);
		line-height: 1.6;
		color: rgba(0, 0, 0, 0.7);
		margin-bottom: rem-calc(16);
	}

	&__timeline-link {
		display: inline-block;
		font-size: rem-calc(14);
		font-weight: 600;
		color: var(--primary, #000);
		text-decoration: none;
		text-transform: uppercase;
		letter-spacing: 0.5px;
		transition: color 0.3s ease;
        font-size: rem-calc(12)!important;
        white-space: break-spaces;

        @media (max-width: 768px) {
            text-align: center;
        }

		&:hover {
			color: #fff
		}
	}

	&__no-results {
		text-align: center;
		padding: rem-calc(60) 0;

		p {
			font-size: rem-calc(18);
			color: rgba(0, 0, 0, 0.6);
		}
	}

	&__load-more-wrapper {
		text-align: center;
		margin-top: rem-calc(40);
		padding-top: rem-calc(40);
		width: 100%;
		display: flex;
		justify-content: center;
		align-items: center;
		clear: both;
        position: relative;
        z-index: 9;

		@include bp($md) {
			margin-top: rem-calc(60);
			padding-top: rem-calc(60);
		}
	}

	&__load-more {
		min-width: rem-calc(200);
		margin: 0;
		display: inline-block;
        background: #FFF;

        &:hover {
            background: var(--primary, #000);
            color: #FFF;
        }
	}

    .background-gradient {
        position: fixed;
        height: 100vh;
    }

	&__back-to-top {
		position: fixed;
		bottom: rem-calc(30);
		right: rem-calc(30);
		width: rem-calc(50);
		height: rem-calc(50);
		border-radius: 50%;
		background-color: var(--primary, #000);
		color: #fff;
		border: 2px solid var(--primary, #000);
		cursor: pointer;
		display: flex;
		align-items: center;
		justify-content: center;
		opacity: 0;
		visibility: hidden;
		transform: translateY(rem-calc(20));
		transition: all 0.3s ease;
		z-index: 1000;
		box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);

		svg {
			width: rem-calc(20);
			height: rem-calc(20);
		}

		&:hover {
			background-color: #fff;
			color: var(--primary, #000);
			transform: translateY(0);
			box-shadow: 0 6px 16px rgba(0, 0, 0, 0.2);
		}

		&--visible {
			opacity: 1 !important;
			visibility: visible !important;
			transform: translateY(0) !important;
		}

		@include bp($md) {
			bottom: rem-calc(40);
			right: rem-calc(40);
			width: rem-calc(60);
			height: rem-calc(60);

			svg {
				width: rem-calc(24);
				height: rem-calc(24);
			}
		}
	}
}

@keyframes spin {
	from {
		transform: translate(-50%, -50%) rotate(0deg);
	}
	to {
		transform: translate(-50%, -50%) rotate(360deg);
	}
}

class IndustryInsightsBlock {
	/**
	 * Create and initialise objects of this class
	 * @param {HTMLElement} block
	 */
	constructor(block) {
		this.block = block;
		this.filters = this.block.querySelectorAll('.block-industry-insights__filter');
		this.timelineContainer = this.block.querySelector('.block-industry-insights__timeline-items');
		this.loadMoreBtn = this.block.querySelector('.block-industry-insights__load-more');
		this.taxonomy = this.block.dataset.taxonomy || 'industry_updates_categories';
		this.postType = this.block.dataset.postType || 'industry_updates';
		this.selectedCategory = '';
		this.currentPage = 1;
		this.postsPerPage = 20;
		this.startIndex = 0;
		this.cache = {}; // Cache for AJAX responses

		this.init();
	}

	init() {
		if (!this.block) return;

		// Get initial values from data attributes
		if (this.timelineContainer) {
			this.postsPerPage = parseInt(this.timelineContainer.dataset.postsPerPage) || 20;
			this.currentPage = parseInt(this.timelineContainer.dataset.currentPage) || 1;
			// Calculate initial start index based on current items
			const currentItems = this.timelineContainer.querySelectorAll('.block-industry-insights__timeline-item');
			this.startIndex = currentItems.length;
		}

		// Detect category from URL on page load (for SEO-friendly URLs)
		this.detectCategoryFromURL();

		this.setupFilters();
		this.setupLoadMore();
		this.setupPopstateListener();
		this.setupBackToTop();
	}

	detectCategoryFromURL() {
		// Check if we're on a category archive page
		const path = window.location.pathname;
		const categoryMatch = path.match(/\/industry-updates\/([^\/]+)\/?$/);

		let categorySlug = '';
		if (categoryMatch) {
			categorySlug = categoryMatch[1];
		}

		// Find the matching filter button
		const matchingFilter = Array.from(this.filters).find(filter => {
			return filter.dataset.category === categorySlug || (categorySlug === '' && filter.dataset.category === 'all');
		});

		if (matchingFilter) {
			this.selectedCategory = categorySlug === '' ? '' : categorySlug;
			// Ensure the correct filter is marked as active
			this.filters.forEach((f) => f.classList.remove('block-industry-insights__filter--active'));
			matchingFilter.classList.add('block-industry-insights__filter--active');
			return true;
		}

		return false;
	}

	setupPopstateListener() {
		// Listen for browser back/forward navigation
		window.addEventListener('popstate', (e) => {
			// Detect category from the restored URL
			const hadCategory = this.detectCategoryFromURL();

			// Reset pagination
			this.currentPage = 1;
			this.startIndex = 0;

			// Fetch results to restore the filtered state
			this.fetchResults(true);
		});
	}

	buildFilterUrl(category) {
		// Get base URL - try to find it from a link filter or construct it
		let baseUrl = window.location.origin + '/industry-updates/';

		// Try to find base URL from an "all" filter link
		const allFilter = Array.from(this.filters).find(f => f.dataset.category === 'all');
		if (allFilter && allFilter.tagName === 'A' && allFilter.href) {
			const url = new URL(allFilter.href);
			baseUrl = url.origin + url.pathname;
		} else {
			// Fallback: construct from current URL
			const pathMatch = window.location.pathname.match(/^(\/industry-updates\/)/);
			if (pathMatch) {
				baseUrl = window.location.origin + pathMatch[1];
			}
		}

		// Build URL based on category
		if (category === 'all' || category === '') {
			return baseUrl;
		} else {
			return baseUrl + category + '/';
		}
	}

	setupFilters() {
		if (!this.filters || this.filters.length === 0) return;

		this.filters.forEach((filter) => {
			filter.addEventListener('click', (e) => {
				const isLink = filter.tagName === 'A';
				const category = filter.dataset.category || '';

				// For links, allow navigation for SEO but enhance with AJAX if possible
				if (isLink && filter.href && !filter.href.match(/^javascript:|^#/)) {
					// Check if we can use AJAX (same domain)
					const url = new URL(filter.href, window.location.origin);
					const isSameDomain = url.origin === window.location.origin;

					if (isSameDomain) {
						e.preventDefault();

						// Update URL without page reload
						window.history.pushState({ category: category }, '', filter.href);

						// Remove active class from all filters
						this.filters.forEach((f) => f.classList.remove('block-industry-insights__filter--active'));

						// Add active class to clicked filter
						filter.classList.add('block-industry-insights__filter--active');

						this.selectedCategory = category === 'all' ? '' : category;

						// Reset pagination
						this.currentPage = 1;
						this.startIndex = 0;

						// Fetch filtered results (reset = true replaces content)
						this.fetchResults(true);
					}
					// If different domain, let the link navigate normally
				} else {
					// Button behavior (AJAX only)
					e.preventDefault();
					
					// Build URL for this filter
					const filterUrl = this.buildFilterUrl(category);
					
					// Update URL without page reload
					window.history.pushState({ category: category }, '', filterUrl);
					
					// Remove active class from all filters
					this.filters.forEach((f) => f.classList.remove('block-industry-insights__filter--active'));
					
					// Add active class to clicked filter
					filter.classList.add('block-industry-insights__filter--active');
					
					this.selectedCategory = category === 'all' ? '' : category;
					
					// Reset pagination
					this.currentPage = 1;
					this.startIndex = 0;
					
					// Fetch filtered results (reset = true replaces content)
					this.fetchResults(true);
				}
			});
		});
	}

	setupLoadMore() {
		if (!this.loadMoreBtn) return;

		this.loadMoreBtn.addEventListener('click', (e) => {
			e.preventDefault();
			this.currentPage++;
			this.fetchResults(false);
		});
	}

	async fetchResults(reset = false) {
		// Create cache key based on category and page
		const cacheKey = `${this.selectedCategory || 'all'}_${this.currentPage}`;

		// Check cache first (only for filtering, not for load more)
		if (reset && this.cache[cacheKey]) {
			// Use cached data instantly
			this.updateResults(this.cache[cacheKey], reset);
			return;
		}

		this.block.classList.add('loading');

		try {
			// Get AJAX URL and nonce from localized script or use defaults
			const ajaxUrl = (typeof industryInsights !== 'undefined' && industryInsights.ajaxurl) 
				? industryInsights.ajaxurl 
				: '/wp-admin/admin-ajax.php';
			const nonce = (typeof industryInsights !== 'undefined' && industryInsights.nonce) 
				? industryInsights.nonce 
				: '';

			const formData = new FormData();
			formData.append('action', 'filter_industry_insights');
			formData.append('nonce', nonce);
			formData.append('post_type', this.postType);
			formData.append('taxonomy', this.taxonomy);
			formData.append('paged', this.currentPage);
			formData.append('posts_per_page', this.postsPerPage);
			formData.append('start_index', this.startIndex);

			// Add category filter if selected
			if (this.selectedCategory) {
				formData.append('category', this.selectedCategory);
			}

			const response = await fetch(ajaxUrl, {
				method: 'POST',
				credentials: 'same-origin',
				body: formData,
			});

			const data = await response.json();

			if (data.success) {
				// Cache the response for future use (only cache first page when filtering)
				if (reset && this.currentPage === 1) {
					this.cache[cacheKey] = data.data;
				}
				
				this.updateResults(data.data, reset);
			} else {
				this.showError(data.data.message || 'Error loading insights');
			}
		} catch (error) {
			console.error('Industry Insights AJAX Error:', error);
			this.showError('Error loading insights. Please try again.');
		} finally {
			this.block.classList.remove('loading');
		}
	}

	updateResults(data, reset = false) {
		if (!this.timelineContainer) return;

		if (reset) {
			// Replace all content when filtering
			this.timelineContainer.innerHTML = data.html || '';
			this.startIndex = 0;
			
			// Scroll to top of timeline smoothly
			const timeline = this.block.querySelector('.block-industry-insights__timeline');
			if (timeline) {
				timeline.scrollIntoView({ behavior: 'smooth', block: 'start' });
			}
		} else {
			// Store current scroll position relative to document
			const scrollPosition = window.pageYOffset || document.documentElement.scrollTop;
			
			// Append new content when loading more
			this.timelineContainer.insertAdjacentHTML('beforeend', data.html || '');
			
			// Restore scroll position after DOM updates to prevent jumping
			// Use requestAnimationFrame to ensure DOM has updated
			requestAnimationFrame(() => {
				window.scrollTo(0, scrollPosition);
			});
		}

		// Update start index for next load
		this.startIndex += data.html ? (data.html.match(/block-industry-insights__timeline-item/g) || []).length : 0;

		// Update load more button visibility
		this.updateLoadMoreButton(data.has_more);
	}

	updateLoadMoreButton(hasMore) {
		if (!this.loadMoreBtn) return;

		const loadMoreWrapper = this.block.querySelector('.block-industry-insights__load-more-wrapper');
		
		if (hasMore) {
			if (loadMoreWrapper) {
				loadMoreWrapper.style.display = 'block';
			}
			this.loadMoreBtn.style.display = 'inline-block';
		} else {
			if (loadMoreWrapper) {
				loadMoreWrapper.style.display = 'none';
			}
			this.loadMoreBtn.style.display = 'none';
		}
	}

	showError(message) {
		if (!this.timelineContainer) return;

		this.timelineContainer.innerHTML = `
			

${message}

`; } setupBackToTop() { const backToTopBtn = this.block.querySelector('.block-industry-insights__back-to-top'); if (!backToTopBtn) { console.warn('Back to top button not found in block:', this.block); return; } // Scroll threshold - show button after scrolling 300px from top of page const scrollThreshold = 300; // Function to toggle button visibility const toggleBackToTop = () => { const scrollY = window.pageYOffset || document.documentElement.scrollTop; // Check if we've scrolled past the threshold if (scrollY > scrollThreshold) { backToTopBtn.classList.add('block-industry-insights__back-to-top--visible'); } else { backToTopBtn.classList.remove('block-industry-insights__back-to-top--visible'); } }; // Listen for scroll events let ticking = false; const handleScroll = () => { if (!ticking) { window.requestAnimationFrame(() => { toggleBackToTop(); ticking = false; }); ticking = true; } }; window.addEventListener('scroll', handleScroll, { passive: true }); // Initial check toggleBackToTop(); // Handle click - scroll to top of block backToTopBtn.addEventListener('click', (e) => { e.preventDefault(); const blockTop = this.block.getBoundingClientRect().top; window.scrollTo({ top: blockTop, behavior: 'smooth' }); }); } } // Initialize all Industry Insights blocks on page load document.addEventListener('DOMContentLoaded', () => { const blocks = document.querySelectorAll('.block-industry-insights'); blocks.forEach((block) => { new IndustryInsightsBlock(block); }); });
{
    "$schema": "https://schemas.wp.org/trunk/block.json",
    "apiVersion": 2,
    "name": "strategiq/industry-insights",
    "title": "Industry insights",
    "description": "Industry insights block",
    "category": "strategiq",
    "icon": "strategiq",
    "acf": {
        "mode": "preview",
        "renderTemplate": "block-industry-insights.php"
    },
    "supports": {
        "anchor": true,
        "align": false,
        "color": {
            "background": true,
            "text": false,
            "gradients": false
        },
        "spacing": {
            "padding": [
				"top",
				"bottom"
			],
            "margin": [
                "top",
                "bottom"
            ]
        }
    },
    "style": "file:../../assets/css/industry-insights/block-industry-insights.css",
    "viewScript": "file:./block-industry-insights.js"
}
This component is not currently used on any pages.
There are is no readme file with this component.