Established in 1996, we have a proven track record in safely and efficiently dealing with Japanese knotweed and other invasive species. Our eco-innovative solutions are designed to give the best results for both our customers, and the environment
<?php /** * Theme functions and definitions * * @package HelloElementorChild */ /** * Load child theme css and optional scripts * * @return void */ function hello_elementor_child_enqueue_scripts() { wp_enqueue_style( 'hello-elementor-child-style', get_stylesheet_directory_uri() . '/style.css', [ 'hello-elementor-theme-style', ], '1.0.0' ); } add_action( 'wp_enqueue_scripts', 'hello_elementor_child_enqueue_scripts', 20 ); // Allow SVG add_filter( 'wp_check_filetype_and_ext', function($data, $file, $filename, $mimes) { global $wp_version; if ( $wp_version !== '4.7.1' ) { return $data; } $filetype = wp_check_filetype( $filename, $mimes ); return [ 'ext' => $filetype['ext'], 'type' => $filetype['type'], 'proper_filename' => $data['proper_filename'] ]; }, 10, 4 ); function cc_mime_types( $mimes ){ $mimes['svg'] = 'image/svg+xml'; return $mimes; } add_filter( 'upload_mimes', 'cc_mime_types' ); function fix_svg() { echo '<style type="text/css"> .attachment-266x266, .thumbnail img { width: 100% !important; height: auto !important; } </style>'; } add_action( 'admin_head', 'fix_svg' ); /*reading time*/ function reading_time() { $content = get_post_field( 'post_content', $post->ID ); $word_count = str_word_count( strip_tags( $content ) ); $readingtime = ceil($word_count / 260); if ($readingtime == 1) { $timer = " minute read"; } else { $timer = " minutes read"; } $totalreadingtime = $readingtime . $timer; return $totalreadingtime; } add_shortcode('wpbread', 'reading_time'); // Add Categories and Tags to Pages function wpse_add_tags_categories_to_pages() { register_taxonomy_for_object_type('post_tag', 'page'); register_taxonomy_for_object_type('category', 'page'); } add_action( 'init', 'wpse_add_tags_categories_to_pages' ); /*add excerpt to wp poststs*/ add_post_type_support( 'page', 'excerpt' ); // Disable XML-RPC add_filter('xmlrpc_enabled', '__return_false'); // Elementor description meta tag function remove_hello_elementor_description_meta_tag() { remove_action( 'wp_head', 'hello_elementor_add_description_meta_tag' ); } add_action( 'after_setup_theme', 'remove_hello_elementor_description_meta_tag' ); add_filter('flying_press_js_delay_timeout', function(){ return 60;}); //Edit something add_action('elementor/editor/before_enqueue_scripts', function() { wp_add_inline_script('elementor-editor', ' window.addEventListener("DOMContentLoaded", function() { const originalEntries = Object.entries; Object.entries = function(obj) { if (obj === null || obj === undefined) { return []; } return originalEntries.call(this, obj); }; }); ', 'before'); }, 5); // Fix Cloudflare Turnstile not loading in Elementor popups // The plugin uses native addEventListener for 'elementor/popup/show' // but Elementor fires it via jQuery. This patch bridges the gap. function cft_turnstile_popup_fix() { ?> <script> (function() { if (typeof jQuery === 'undefined') return; jQuery(document).on('elementor/popup/show', function(event, id, instance) { setTimeout(function() { var settings = window.cfturnstileElementorSettings || {}; if (settings.mode && settings.mode !== 'turnstile') return; if (!window.turnstile) return; // First, process any unprocessed forms in the popup var popupForms = document.querySelectorAll('.elementor-popup-modal .elementor-form:not(.cft-processed)'); popupForms.forEach(function(form, index) { var submitButton = form.querySelector('button[type="submit"]'); if (submitButton && settings.sitekey) { var turnstileDiv = document.createElement('div'); turnstileDiv.className = 'elementor-turnstile-field cf-turnstile'; turnstileDiv.id = 'cf-turnstile-popup-fix-' + id + '-' + index; turnstileDiv.style.cssText = 'display: block; margin: 10px 0 15px 0; width: 100%;'; submitButton.parentNode.insertBefore(turnstileDiv, submitButton); form.classList.add('cft-processed'); } }); // Clean up any stale/failed turnstile children first var popupTurnstile = document.querySelectorAll('.elementor-popup-modal .cf-turnstile'); popupTurnstile.forEach(function(el) { // Remove old failed widget content while (el.firstChild) { el.removeChild(el.firstChild); } try { turnstile.remove('#' + el.id); } catch(e) {} turnstile.render('#' + el.id, { sitekey: settings.sitekey, theme: settings.theme || 'auto', callback: function(token) { if (typeof turnstileElementorCallback === 'function') { turnstileElementorCallback(token); } } }); }); }, 1500); }); })(); </script> <?php } add_action('wp_footer', 'cft_turnstile_popup_fix', 999); add_action('wp_ajax_nopriv_custom_knotweed_form', 'handle_knotweed_form_submission'); add_action('wp_ajax_custom_knotweed_form', 'handle_knotweed_form_submission'); function handle_knotweed_form_submission() { if (!isset($_POST['name'], $_POST['phone'], $_POST['postcode'])) { wp_send_json_error('Required fields are missing'); } $form_fields = [ 'name' => sanitize_text_field($_POST['name']), 'phone' => sanitize_text_field($_POST['phone']), 'postcode' => sanitize_text_field($_POST['postcode']), 'service' => sanitize_text_field($_POST['service'] ?? 'Not selected'), 'email' => sanitize_email($_POST['email'] ?? ''), ]; $uploaded_file_url = ''; $attachment = []; if (!empty($_FILES['photo']['name'])) { require_once(ABSPATH . 'wp-admin/includes/file.php'); $upload = wp_handle_upload($_FILES['photo'], ['test_form' => false]); if (isset($upload['file']) && !empty($upload['file'])) { $uploaded_file_url = $upload['url']; $attachment[] = $upload['file']; $form_fields['photo'] = $uploaded_file_url; } } if (class_exists('\ElementorPro\Modules\Forms\Classes\Record')) { $record = new \ElementorPro\Modules\Forms\Classes\Record([ 'form_name' => 'Hero Knotweed Quote Form', 'form_id' => 'hero_knotweed_form', 'post_id' => get_the_ID(), 'fields' => $form_fields, 'uploaded_files' => !empty($uploaded_file_url) ? ['photo' => ['url' => $uploaded_file_url]] : [], ]); $record->add_submission(); } $to_email = 'expert@environetuk.com'; $subject = 'New Knotweed Quote Request - ' . $form_fields['name']; $message = "New quote request received:\n\n"; $message .= "Name: " . $form_fields['name'] . "\n"; $message .= 'Email: ' . (isset($form_fields['email']) ? $form_fields['email'] : 'N/A') . "\n"; $message .= "Phone: " . $form_fields['phone'] . "\n"; $message .= "Postcode: " . $form_fields['postcode'] . "\n"; $message .= "Service: " . $form_fields['service'] . "\n"; if (!empty($uploaded_file_url)) { $message .= "\nPhoto: " . $uploaded_file_url . "\n"; } $headers = ['Content-Type: text/plain; charset=UTF-8']; wp_mail($to_email, $subject, $message, $headers, $attachment); // Lead prosto do Azure CRM (zamiennik martwego n8n) environet_push_to_crm(array( 'Name' => $form_fields['name'], 'Email' => isset($form_fields['email']) ? $form_fields['email'] : '', 'Telephone' => $form_fields['phone'], 'Postcode' => $form_fields['postcode'], 'Message' => isset($form_fields['service']) ? $form_fields['service'] : '', 'File' => !empty($uploaded_file_url) ? $uploaded_file_url : 'NONE', 'form_id' => 'hero_knotweed_form', 'form_name' => 'Knotweed PPC Form', )); wp_send_json_success('Success'); } /* ========================================================================= * Environet: formularze -> Azure CRM (zamiennik automatyzacji n8n) * ========================================================================= */ /** * Wspolny helper - wysyla zmapowanego leada prosto do funkcji Azure. * Endpoint Azure jest tylko tutaj, w jednym miejscu. */ function environet_push_to_crm( array $body ) { $body = wp_parse_args( $body, array( 'Name' => '', 'Email' => '', 'Telephone' => '', 'Postcode' => '', 'Message' => '', 'File' => 'NONE', 'Terms' => 'I accept the terms and conditions', 'Date' => date_i18n( 'F j, Y' ), 'Time' => date_i18n( 'g:i a' ), 'Page URL' => isset( $_SERVER['HTTP_REFERER'] ) ? esc_url_raw( $_SERVER['HTTP_REFERER'] ) : '', 'form_id' => 'unknown', 'form_name' => 'Unknown Form', ) ); // Koperta w formacie ktorego oczekuje funkcja Azure: tablica z jednym obiektem $payload = array( array( 'headers' => array( 'host' => isset( $_SERVER['HTTP_HOST'] ) ? $_SERVER['HTTP_HOST'] : '', 'user-agent' => isset( $_SERVER['HTTP_USER_AGENT'] ) ? $_SERVER['HTTP_USER_AGENT'] : '', ), 'params' => new stdClass(), 'query' => new stdClass(), 'body' => $body, 'webhookUrl' => '', 'executionMode' => 'production', ), ); $url = 'https://prod-webhookjsontolead-http.azurewebsites.net/api/Function1?code=NJLEOVYNWw/1ZBcRkMCqc/hG4x3OyFaXECwiaALkKsao9cp7Ufejaw=='; $response = wp_remote_post( $url, array( 'method' => 'POST', 'timeout' => 20, 'headers' => array( 'Content-Type' => 'application/json', 'Accept' => '*/*', ), 'body' => wp_json_encode( $payload ), ) ); // Log do debugowania - wlacz WP_DEBUG / WP_DEBUG_LOG w wp-config.php if ( is_wp_error( $response ) ) { error_log( 'Environet CRM error: ' . $response->get_error_message() ); } else { error_log( 'Environet CRM -> ' . wp_remote_retrieve_response_code( $response ) . ' ' . wp_remote_retrieve_body( $response ) ); } return $response; } /** * Formularze Elementor PRO (widget Form). Odpala sie na kazdy submit. * Domyslnie dla KAZDEJ formy - tak jak mialeś webhook wszedzie. * Jesli niektore formy nie maja isc do CRM, wpisz ID tych ktore MAJA isc w $allowed_forms. */ add_action( 'elementor_pro/forms/new_record', 'environet_form_to_crm', 10, 2 ); /** * Environet CRM Integration — Elementor Forms * Sends all Elementor form submissions directly to Dynamics 365 via Azure Function. * Replaces the broken n8n.hyroes.com webhook. * Fixed by IT MATES DIGITAL — 2026-06-17 */ function environet_form_to_crm( $record, $handler ) { $azure_url = 'https://prod-webhookjsontolead-http.azurewebsites.net/api/Function1'; $azure_code = 'NJLEOVYNWw/1ZBcRkMCqc/hG4x3OyFaXECwiaALkKsao9cp7Ufejaw=='; $form_name = $record->get_form_settings( 'form_name' ); $form_id = $record->get_form_settings( 'id' ); $raw_fields = $record->get( 'fields' ); $meta = $record->get( 'meta' ); $f = []; foreach ( $raw_fields as $id => $field ) { $f[ $id ] = sanitize_text_field( $field['value'] ?? '' ); } $body = [ 'Name' => $f['name'] ?? $f['full_name'] ?? '', 'Email' => $f['email'] ?? $f['email_address'] ?? '', 'Telephone' => $f['phone'] ?? $f['telephone'] ?? '', 'Postcode' => $f['postcode'] ?? $f['post_code'] ?? $f['zip'] ?? '', 'Message' => $f['message'] ?? $f['comments'] ?? $f['description'] ?? '', 'File' => $f['files'] ?? $f['file'] ?? 'NONE', 'Terms' => 'I accept the terms and conditions', 'Date' => $meta['date'] ?? wp_date( 'F j, Y' ), 'Time' => $meta['time'] ?? wp_date( 'g:i a' ), 'Page URL' => $meta['page_url'] ?? '', 'form_id' => $form_id, 'form_name' => $form_name, ]; $payload = [ [ 'headers' => [ 'host' => 'www.environetuk.com', 'user-agent' => 'WordPress/' . get_bloginfo( 'version' ) . '; ' . home_url(), ], 'params' => new \stdClass(), 'query' => new \stdClass(), 'body' => $body, 'webhookUrl' => home_url(), 'executionMode' => 'production', ], ]; wp_remote_post( add_query_arg( 'code', $azure_code, $azure_url ), [ 'timeout' => 15, 'blocking' => false, 'headers' => [ 'Content-Type' => 'application/json', 'Accept' => '*/*', ], 'body' => wp_json_encode( $payload ), ] ); } /** * Naprawia bledny atrybut pattern w polach telefonu (Elementor formy). * Pod flaga v w nowych przegladarkach wzorzec z myslnikiem w srodku klasy * jest nieprawidlowy (traktowany jako zakres). Przepisujemy na wersje * z myslnikiem na koncu klasy. Dziala dla WSZYSTKICH form na stronie. */ add_action( 'wp_footer', 'environet_fix_phone_pattern', 99 ); function environet_fix_phone_pattern() { ?> <script> (function () { var BAD = "[0-9()#&+*-=.]+"; var GOOD = "[0-9\\(\\)#&+*=.\\-]+"; function fix() { document.querySelectorAll('input[pattern]').forEach(function (el) { if (el.getAttribute('pattern') === BAD) { el.setAttribute('pattern', GOOD); } }); } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', fix); } else { fix(); } document.addEventListener('submit', fix, true); })(); </script> <?php }