Wprowadzenie

Dokumentacja jest w trakcie opracowywania. Jeżeli masz jakieś pytania o wdrożenie funkcjonalności – napisz do nas lub zadzwoń.


Wygląd → Dostosuj

Większa część ustawień motywu G44.THEME znajduje się właśnie w tym miejscu: Wygląd → Dostosuj:

  • Tożsamość witryny – możliwość ustawienia loga witryny (jasnego i ciemnego), nazwy i sloganu, ikony (favicon) oraz obrazka Open Graph.
  • G44 THEME – ogólne, liczne ustawienia motywu
  • G44 WooCommerce – ustawienia sklepowe (dostępne tylko po włączeniu wtyczki WooCommerce)
  • G44 Cookie Consent – ustawienia prostego mechanizmu zgody (dostępne po włączeniu w ustawieniach ogólnych)
  • Pozostałe natywne ustawienia WordPress

Motyw potomny G44 THEME CHILD

To miejsce do bardziej zaawansowanych modyfikacji. Wprowadzanie zmian na stronie poprzez motyw potomny pozwala zachować możliwość aktualizacji głównego motywu G44 THEME. Znajdziesz w nim m.in. takie podstawowe pliki jak:

  • functions.php – główny plik PHP motywu potomnego, może zawierać własne funkcje, akcje i filtry, które nadpisują lub rozszerzają logikę motywu nadrzędnego.
  • scripts.js – plik JavaScript przeznaczony do własnych skryptów (np. dodatkowe animacje, obsługa formularzy, interakcje użytkownika). Ładowany na froncie strony.
  • style.css – główny arkusz stylów motywu potomnego. Tutaj możesz dodawać lub nadpisywać reguły CSS. Zawiera też nagłówek informacyjny identyfikujący motyw potomny w panelu WordPress.

Dzięki temu motywowi możesz bezpiecznie rozwijać stronę – wszystkie zmiany są odseparowane od motywu głównego i nie zostaną nadpisane podczas jego aktualizacji.

Tutaj znajdziesz przykładowe, gotowe funkcje do wykorzystania w motywie potomnym.


theme.json

Możesz pobrać plik theme.json z katalogu motywu głównego /g44/ i następnie umieścić go w katalogu motywu potomnego /g44-child/.
Pozwoli to na swobodne modyfikowanie niektórych ustawień stylistycznych jak np. domyślne szerokości kontenerów treści na stronie.


Dostępne shortcode


Banery kontaktowe email oraz phone

Możesz je wstawić np. w pozycji nawigacji, w miejscu „Etykieta nawigacji”.

shortcode
[email icon="envelope" text1="Wsparcie techniczne" text2="Napisz do nas" url="#modal-808" target="_self"]
shortcode
[phone icon="phone" text1="<b>Jan Kowalski</b><br>Doradca techniczny" text2="+48 123 456 789" url="tel:+48123456789"]

Wyświetlanie linku do podstrony

W miejscu ID możesz wpisać ID strony, privacy lub terms (privacy i terms to odnośniki do polityki prywatności oraz regulaminu, zadziała jeżeli zostały ustalone te strony).
URL ma większy priorytet niż ID.

shortcode
[url id="privacy" url="" target="_blank" class=""]polityka prywatności[/url]

Ikona social media z przekierowaniem

Kod pobiera domyślny link do profilu z ustawień, które znajdziesz w Wygląd > Dostosuj > G44 THEME > Linki zewnętrzne.
Uzupełniając URL, link domyślny zostanie zastąpiony podanym adresem.

shortcode
[social page="facebook" url=""]
[social page="instagram"]
[social page="linkedin"]
[social page="youtube"]
[social page="tiktok"]
[social page="x"]

Baner graficzny w nawigacji

Możesz go wstawić np. w pozycji nawigacji, w miejscu „Etykieta nawigacji”.
W miejscu IMG możesz podać ID lub URL do obrazu.
W miejscu SIZE możesz wpisać rozmiar jaki ma zostać wczytany (thumb / medium / large / full) domyślnie: medium

shortcode
[banner img="123" size="medium" title="Opcjonalny tytuł" button="Czytaj więcej" class=""]

Optymalizacja


Iframe

Od wersji 1.2.0 motyw pozwala na leniwe ładowanie iframeów. Aby z tego skorzystać wystarczy zmienić atrybut src na data-src, np.:
<iframe src=„https://… → <iframe data-src=„https://

P.S. Przy okazji pracy z iframe sprawdź czy Twój iframe posiada atrybut title, jezeli nie to warto dodać title=”Krótki tytuł opisujący dany iframe.


Nieblokujący tryb jQuery

Jeżeli Twoja strona wykorzystuje WooCommerce lub inną wtyczkę, która wymaga biblioteki jQuery, to ta informacja jest dla Ciebie.
Na każdej podstronie indywidualnie możesz zaznaczyć opcję Ustaw jQuery na tej podstronie w trybie defer, która uruchomi jQuery w trybie nieblokującym.

Każdorazowe aktywowanie tej funkcji wymaga weryfikacji czy dana podstrona działa prawidłowo i nie generuje żadnych błędów.


Przykładowe, gotowe funkcje

Pamiętaj, aby modyfikować tylko motyw potomny, czyli /wp-content/themes/g44-child/.
Modyfikacja motywu głównego g44 uniemożliwi w przyszłości jego aktualizacje.


Dodawanie własnej czcionki

Poza samym dodaniem kodu musisz odpowiednio przygotować katalog z dodawanym fontem i umieścić go w katalogu motywu potomnego g44-child/
Kliknij i pobierz przykładową paczkę.

Najpierw jednak sprawdź czy font, który chcesz zastosować nie został już przygotowany do użycia na stronie. Sprawdzisz to tutaj: Wygląd → Dostosuj → G44 THEME → Typografia

Po prawidłowym dodaniu fontu, będzie on dostępny do ustawienia w karcie Typografia.

functions.php
// Filtr dodający możliwość wyboru własnego fontu w Customizerze
add_filter('g44_typography_choices', function($choices) {
    $choices['"Roboto", serif'] = 'Roboto';
    return $choices;
});
 
// Filtr dodający własny font do dostępnych fontów (dla motywu potomnego)
add_filter('g44_available_fonts', function($fonts) {
    $fonts['"Roboto", serif'] = get_stylesheet_directory_uri() . '/fonts/roboto/roboto.css'; // Ścieżka do Twojego fontu
    return $fonts;
});

Preload głównych plików czcionki (optymalizacja)

Aby zoptymalizować wczytywanie fontów warto skonfigurować precyzyjny preload plików .woff2 wybranej czcionki.

functions.php
// Preload fontów
add_action('wp_head', function () {
    if (is_admin()) return;
 
    // Konfiguracja
    // base: 'parent' | 'child' - motyw główny lub potomny
    // uri: ścieżka względna od katalogu motywu
    // files: lista .woff2
    $fonts = [
        'dm-sans' => [
            'base'  => 'parent',
            'uri'   => '/assets/fonts/dm-sans/',
            'files' => [
                'rP2Hp2ywxg089UriCZ2IHTWEBlwu8Q.woff2',
                'rP2Hp2ywxg089UriCZOIHTWEBlw.woff2',
            ],
        ],
        'custom-font' => [
            'base'  => 'child',
            'uri'   => '/fonts/custom-font/',
            'files' => [
                'custom-font-file1.woff2',
                'custom-font-file2.woff2',
            ],
        ],
    ];
 
    foreach ($fonts as $cfg) {
        $base = ($cfg['base'] === 'child') ? get_stylesheet_directory_uri() : get_template_directory_uri();
 
        foreach ($cfg['files'] as $file) {
            echo '<link rel="preload" href="' . esc_url($base . $cfg['uri'] . $file) . '" as="font" type="font/woff2" crossorigin>' . "\n";
        }
    }
}, 1);

Konfiguracja wysyłki maili przez SMTP

Zamiast instalować dodatkową wtyczkę do tego zadania możesz skonfigurować SMTP poniższym kodem. Pamiętaj wprowadzić tam dokładne dane Twojej skrzynki pocztowej i serwera.

functions.php
/**
 * Konfiguracja wysyłki maili przez SMTP
 */
add_action('phpmailer_init', function($phpmailer) {
 
    $phpmailer->isSMTP();
    $phpmailer->Host       = 'smtp.twojadomena.com'; // Adres serwera SMTP
    $phpmailer->SMTPAuth   = true; // Wymagane uwierzytelnianie
    $phpmailer->Username   = 'user@twojadomena.com'; // Login SMTP
    $phpmailer->Password = 'haslo'; // Hasło SMTP
    $phpmailer->SMTPSecure = 'tls'; // 'tls' (port 587) lub 'ssl' (port 465)
    $phpmailer->Port       = 587; // Port SMTP (587 dla TLS, 465 dla SSL)
 
    // Nadawca (nagłówki)
    $phpmailer->setFrom('user@twojadomena.com', 'Twoja Nazwa', false); // Adres nadawcy
 
    // Envelope sender / Return-Path
    $phpmailer->Sender = 'user@twojadomena.com';
 
    // HELO/EHLO
    $phpmailer->Helo     = 'twojadomena.com';
    $phpmailer->Hostname = 'twojadomena.com';
}, 20);
 
/*
// Opcjonalne wymuszenie nadawcy
add_filter('wp_mail_from', function() {
    return 'user@twojadomena.com';
});
 
add_filter('wp_mail_from_name', function() {
    return 'Twoja Nazwa';
});
*/

Pozostałe kody

Poniżej nieopisany jeszcze zbiór kodów, które można już wykorzystywać.

functions.php
// POST NAV CUSTOM
add_filter( 'g44_post_navigation_labels', function( $labels, $post_type ) {
    
    if ( $post_type === 'g44_offers' ) {
        $labels['all']  = 'Wszystkie produkty';
        //$labels['all']  = esc_html__( 'All products', 'g44' );
        $labels['prev'] = 'Poprzedni produkt';
        $labels['next'] = 'Następny produkt';
    }
 
    return $labels;
}, 10, 2 );
functions.php
// g44_offers ARCHIVE CUSTOM
add_filter('g44_offers_archive_args', function ($args) {
    $args['type'] = '';
    $args['tax'] = '';
    $args['cat'] = '';
    $args['orderby'] = 'date';
    $args['order'] = 'DESC';
    $args['ppp'] = -1; // post per page
    $args['paged'] = true;
    $args['core'] = 'isotope-grid'; // g44-grid, g44-slider-post, isotope-grid
    $args['isotopelayout'] = 'fitRows'; // masonry, fitRows
    $args['style'] = 1;
    $args['maxcol'] = 3;
    $args['gap'] = 2;
    $args['filter'] = true;
    $args['image'] = true;
    $args['aspect_ratio'] = false; // square
    $args['titleicon'] = false;
    $args['meta'] = false;
    $args['date'] = false;
    $args['excerpt'] = false;
    $args['readmore'] = __('See more', 'g44'); // false
 
    return $args;
});
functions.php
// CPT LOOP ITEM - BEFORE EXCERPT
add_action('g44_loop_item_before_excerpt', function ($post_id, $post_type) {
    if ($post_type !== 'g44_offers') {
        return; // ograniczenie do konkretnego CPT
    }
 
    // Twój kod
    echo 'Hello World!';
 
}, 10, 2);
functions.php
// CPT LOOP ITEM - AFTER EXCERPT
add_action('g44_loop_item_after_excerpt', function ($post_id, $post_type) {
    if ($post_type !== 'g44_offers') {
        return; // ograniczenie do konkretnego CPT
    }
 
    // Twój kod
    echo 'Hello World!';
 
}, 10, 2);
functions.php
// PAGE TITLE: DODATKOWE TREŚCI (przed)
add_action('g44_before_page_title_wrapper', function ($id) {
    if ( is_tax('offers_cat') ) {
        echo '<div class="portfolio-cat-decription">Własny HTML pod tytułem.</div>';
    }
}, 10, 1);
functions.php
// PAGE TITLE: DODATKOWE TREŚCI (po)
add_action('g44_after_page_title', function ($id) {
    if ( is_tax('portfolio_cat') ) {
        echo '<div class="offers-cat-intro">Własny HTML dla kategorii ofert. Miejsca możesz dowolnie określać.</div>';
    }
}, 10, 1);
functions.php
/**
 * Zmiana domyślnej lokalizacji opisu kategorii dla konkretnego typu taxonomii
 */
add_filter( 'theme_mod_g44_cat_description_position', function ( $position ) {
 
    if ( is_tax( 'portfolio_cat' ) ) {
        return 'under_title';
    }
 
    return $position;
} );
functions.php
// Wyłącz reset hasła dla administratorów ze strony wp-login lostpassword
add_filter('allow_password_reset', function($allow, $user_id){
    $user = get_userdata($user_id);
    if (in_array('administrator', (array) $user->roles)) {
        return false;
    }
    return $allow;
}, 10, 2);
functions.php
/**
 * Wyłączenie emotikon tekstowych oraz obsługi emoji WordPressa.
 */
add_filter('option_use_smilies', '__return_false');
 
add_action('init', function () {
    remove_action('wp_head', 'print_emoji_detection_script', 7);
    remove_action('admin_print_scripts', 'print_emoji_detection_script');
 
    remove_action('wp_print_styles', 'print_emoji_styles');
    remove_action('admin_print_styles', 'print_emoji_styles');
 
    remove_filter('the_content_feed', 'wp_staticize_emoji');
    remove_filter('comment_text_rss', 'wp_staticize_emoji');
    remove_filter('wp_mail', 'wp_staticize_emoji_for_email');
});
functions.php
/**
 * Fallback dla bramek, które po opłaceniu ustawiają bezpośrednio status processing, bez użycia WC_Order::payment_complete().
 */
add_action(
	'woocommerce_order_status_processing',
	'g44_maybe_complete_virtual_processing_order',
	20,
	2
);
 
function g44_maybe_complete_virtual_processing_order( $order_id, $order = false ) {
 
	if ( ! $order instanceof WC_Order ) {
		$order = wc_get_order( $order_id );
	}
 
	if ( ! $order instanceof WC_Order ) {
		return;
	}
 
	$items = $order->get_items( 'line_item' );
 
	if ( empty( $items ) ) {
		return;
	}
 
	foreach ( $items as $item ) {
		if ( ! $item instanceof WC_Order_Item_Product ) {
			return;
		}
 
		$product = $item->get_product();
 
		if ( ! $product instanceof WC_Product || ! $product->is_virtual() ) {
			return;
		}
	}
 
	$order->update_status(
		'completed',
		'Zamówienie zawiera wyłącznie produkty wirtualne — automatycznie oznaczono jako zrealizowane.'
	);
}
 
/**
 * Po skutecznej płatności oznacz zamówienie jako zrealizowane, jeżeli wszystkie produkty są wirtualne.
 */
add_filter(
	'woocommerce_payment_complete_order_status',
	'g44_virtual_order_payment_complete_status',
	20,
	3
);
 
function g44_virtual_order_payment_complete_status( $status, $order_id, $order ) {
 
	if ( ! $order instanceof WC_Order ) {
		$order = wc_get_order( $order_id );
	}
 
	if ( ! $order instanceof WC_Order ) {
		return $status;
	}
 
	$items = $order->get_items( 'line_item' );
 
	if ( empty( $items ) ) {
		return $status;
	}
 
	foreach ( $items as $item ) {
		if ( ! $item instanceof WC_Order_Item_Product ) {
			return $status;
		}
 
		$product = $item->get_product();
 
		/*
		 * Nie zgadujemy, gdy produktu nie da się już pobrać.
		 * Bezpieczniej pozostawić processing niż błędnie zakończyć zamówienie.
		 */
		if ( ! $product instanceof WC_Product ) {
			return $status;
		}
 
		if ( ! $product->is_virtual() ) {
			return $status;
		}
	}
 
	return 'completed';
}
functions.php
/**
 * Dodatkowy checkbox w formularzu zamówienia
 * Opcjonalna faktura na firmę
 * Zaznaczenie pokaże pola: NIP (dodany przez Fakturownię) i Nazwa firmy)
 * Działa z ustawieniem Fakturowni: Wystawianie faktur - Zawsze, automatycznie
 */
add_filter( 'woocommerce_checkout_fields', 'g44_add_billing_faktura_checkbox', 20 );
function g44_add_billing_faktura_checkbox( $fields ) {
 
	$fields['billing']['billing_faktura'] = array(
		'type'     => 'checkbox',
		'label'    => 'Chcę otrzymać fakturę na firmę',
		'required' => false,
		'class'    => array( 'form-row-wide', 'g44-company-invoice' ),
		'priority' => 25,
	);
 
	return $fields;
}
 
 
/**
 * Jeżeli checkbox nie jest zaznaczony, wymusza wyczyszczenie
 * nazwy firmy i numeru NIP w danych wysyłanych przez checkout.
 */
add_filter( 'woocommerce_checkout_posted_data', 'g44_clear_company_invoice_data' );
 
function g44_clear_company_invoice_data( $data ) {
 
	$invoice_requested = ! empty( $data['billing_faktura'] );
 
	if ( ! $invoice_requested ) {
		$data['billing_company'] = '';
		$data['billing_nip']     = '';
	}
 
	return $data;
}
 
 
/**
 * Walidacja pól faktury po stronie serwera.
 */
add_action( 'woocommerce_after_checkout_validation', 'g44_validate_company_invoice_fields', 10, 2 );
 
function g44_validate_company_invoice_fields( $data, $errors ) {
 
	if ( empty( $data['billing_faktura'] ) ) {
		return;
	}
 
	$company = isset( $data['billing_company'] )
		? trim( (string) $data['billing_company'] )
		: '';
 
	$nip = isset( $data['billing_nip'] )
		? preg_replace( '/\D+/', '', (string) $data['billing_nip'] )
		: '';
 
	if ( '' === $company ) {
		$errors->add(
			'billing_company_required',
			'Nazwa firmy jest wymagana, jeżeli chcesz otrzymać fakturę na firmę.'
		);
	}
 
	if ( '' === $nip ) {
		$errors->add(
			'billing_nip_required',
			'Numer NIP jest wymagany, jeżeli chcesz otrzymać fakturę na firmę.'
		);
	}
}
 
 
/**
 * Dynamiczna obsługa pól na klasycznym checkout WooCommerce.
 */
add_action( 'wp_footer', 'g44_company_invoice_checkout_script', 50 );
 
function g44_company_invoice_checkout_script() {
 
	if ( ! is_checkout() || is_order_received_page() ) {
		return;
	}
	?>
	<script>
	(function () {
		'use strict';
 
		function setFieldRequired(field, required) {
            if (!field) {
                return;
            }
 
            var input = field.querySelector('input, select, textarea');
            var label = field.querySelector('label');
 
            if (!input) {
                return;
            }
 
            input.required = required;
            input.setAttribute('aria-required', required ? 'true' : 'false');
 
            field.classList.toggle('validate-required', required);
 
            if (!label) {
                return;
            }
 
            var optional = label.querySelector('.optional');
            var requiredMarker = label.querySelector('.required');
 
            function removeMarkerWithSpace(marker) {
                if (!marker) {
                    return;
                }
 
                var previousNode = marker.previousSibling;
 
                if (
                    previousNode &&
                    previousNode.nodeType === Node.TEXT_NODE
                ) {
                    previousNode.nodeValue = previousNode.nodeValue.replace(/\u00A0+$/, '');
 
                    if (!previousNode.nodeValue) {
                        previousNode.remove();
                    }
                }
 
                marker.remove();
            }
 
            function appendMarker(className, text, ariaHidden) {
                label.appendChild(document.createTextNode('\u00A0'));
 
                var marker = document.createElement('span');
 
                marker.className = className;
                marker.textContent = text;
 
                if (ariaHidden) {
                    marker.setAttribute('aria-hidden', 'true');
                }
 
                label.appendChild(marker);
            }
 
            if (required) {
                removeMarkerWithSpace(optional);
 
                label.classList.add('required_field');
 
                if (!label.querySelector('.required')) {
                    appendMarker('required', '*', true);
                }
            } else {
                removeMarkerWithSpace(requiredMarker);
 
                label.classList.remove('required_field');
 
                if (!label.querySelector('.optional')) {
                    appendMarker('optional', '(opcjonalne)', false);
                }
            }
        }
 
		function updateCompanyInvoiceFields() {
			var checkbox = document.getElementById('billing_faktura');
			var companyField = document.getElementById('billing_company_field');
			var nipField = document.getElementById('billing_nip_field');
 
			if (!checkbox || !companyField || !nipField) {
				return;
			}
 
			var companyInput = document.getElementById('billing_company');
			var nipInput = document.getElementById('billing_nip');
			var required = checkbox.checked;
 
			setFieldRequired(companyField, required);
			setFieldRequired(nipField, required);
 
			if (!required) {
				if (companyInput) {
					companyInput.value = '';
					companyInput.dispatchEvent(new Event('change', {
						bubbles: true
					}));
				}
 
				if (nipInput) {
					nipInput.value = '';
					nipInput.dispatchEvent(new Event('change', {
						bubbles: true
					}));
				}
 
				companyField.classList.remove(
					'woocommerce-invalid',
					'woocommerce-invalid-required-field',
					'woocommerce-validated'
				);
 
				nipField.classList.remove(
					'woocommerce-invalid',
					'woocommerce-invalid-required-field',
					'woocommerce-validated'
				);
			}
		}
 
		document.addEventListener('change', function (event) {
			if (event.target && event.target.id === 'billing_faktura') {
				updateCompanyInvoiceFields();
			}
		});
 
		document.addEventListener('DOMContentLoaded', updateCompanyInvoiceFields);
 
		/*
		 * WooCommerce może przebudowywać fragment formularza przez AJAX.
		 * Obsługa zdarzenia bez uzależniania głównej logiki od jQuery.
		 */
		if (window.jQuery) {
			window.jQuery(document.body).on(
				'updated_checkout',
				updateCompanyInvoiceFields
			);
		}
	})();
	</script>
	<?php
}
functions.php
/**
 * Wyłącza formularz kuponu na klasycznej stronie koszyka.
 * Kupony pozostają dostępne na stronie zamówienia.
 */
add_filter( 'woocommerce_coupons_enabled', 'g44_disable_coupons_on_cart' );
 
function g44_disable_coupons_on_cart( $enabled ) {
 
	if ( is_cart() && ! is_checkout() ) {
		return false;
	}
 
	return $enabled;
}
functions.php
// Dodanie [button] w CF7
add_action( 'wpcf7_init', function() {
    wpcf7_add_form_tag( 'button', 'g44_cf7_button_handler' );
});
 
function g44_cf7_button_handler( $tag ) {
    $tag = new WPCF7_FormTag( $tag );
 
    $label = $tag->values[0] ?? __( 'Wyślij', 'contact-form-7' );
    $class = wpcf7_form_controls_class( $tag->type );
 
    if ( $tag->has_option( 'class' ) ) {
        $user_classes = (array) $tag->get_class_option();
        $class .= ' ' . implode( ' ', $user_classes );
    }
 
    $atts = [];
    if ( $tag->has_option( 'id' ) ) {
        $atts[] = 'id="' . esc_attr( $tag->get_id_option() ) . '"';
    }
    if ( $tag->has_option( 'name' ) ) {
        $atts[] = 'name="' . esc_attr( $tag->name ) . '"';
    }
 
    $button = sprintf(
        '<button type="submit" class="button %s" %s>%s</button>',
        esc_attr( trim( $class ) ),
        implode( ' ', $atts ),
        esc_html( $label )
    );
 
    $loader = '<span class="wpcf7-spinner"></span>';
 
    return sprintf(
        '<span class="wpcf7-form-control-wrap %s">%s%s</span>',
        esc_attr( $tag->name ),
        $button,
        $loader
    );
}
functions.php
// Usuń Informacje dodatkowe ze strony zamówienia
add_filter('woocommerce_enable_order_notes_field', '__return_false');
scripts.js
// Obsługa strzałek klawiatury w portfolio
document.addEventListener('DOMContentLoaded', function () {
    document.addEventListener('keydown', function (event) {
        let url = false;
 
        if (event.key === 'j' || event.key === 'ArrowLeft') {
            const prevLink = document.querySelector('.nav-post a.prev');
            if (prevLink) {
                url = prevLink.getAttribute('href');
            }
        }
 
        if (event.key === 'k' || event.key === 'ArrowRight') {
            const nextLink = document.querySelector('.nav-post a.next');
            if (nextLink) {
                url = nextLink.getAttribute('href');
            }
        }
 
        if (url) {
            window.location.href = url;
        }
    });
});