&lt;?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(
		&#039;hello-elementor-child-style&#039;,
		get_stylesheet_directory_uri() . &#039;/style.css&#039;,
		[
			&#039;hello-elementor-theme-style&#039;,
		],
		&#039;1.0.0&#039;
	);
}
add_action( &#039;wp_enqueue_scripts&#039;, &#039;hello_elementor_child_enqueue_scripts&#039;, 20 );

// Allow SVG
add_filter( &#039;wp_check_filetype_and_ext&#039;, function($data, $file, $filename, $mimes) {

  global $wp_version;
  if ( $wp_version !== &#039;4.7.1&#039; ) {
     return $data;
  }

  $filetype = wp_check_filetype( $filename, $mimes );

  return [
      &#039;ext&#039;             =&gt; $filetype[&#039;ext&#039;],
      &#039;type&#039;            =&gt; $filetype[&#039;type&#039;],
      &#039;proper_filename&#039; =&gt; $data[&#039;proper_filename&#039;]
  ];

}, 10, 4 );

function cc_mime_types( $mimes ){
  $mimes[&#039;svg&#039;] = &#039;image/svg+xml&#039;;
  return $mimes;
}
add_filter( &#039;upload_mimes&#039;, &#039;cc_mime_types&#039; );

function fix_svg() {
  echo &#039;&lt;style type=&quot;text/css&quot;&gt;
        .attachment-266x266, .thumbnail img {
             width: 100% !important;
             height: auto !important;
        }
        &lt;/style&gt;&#039;;
}
add_action( &#039;admin_head&#039;, &#039;fix_svg&#039; );

/*reading time*/
function reading_time() {
$content = get_post_field( &#039;post_content&#039;, $post-&gt;ID );
$word_count = str_word_count( strip_tags( $content ) );
$readingtime = ceil($word_count / 260);
if ($readingtime == 1) {
$timer = &quot; minute read&quot;;
} else {
$timer = &quot; minutes read&quot;;
}
$totalreadingtime = $readingtime . $timer;
return $totalreadingtime;
}
add_shortcode(&#039;wpbread&#039;, &#039;reading_time&#039;);

// Add Categories and Tags to Pages
function wpse_add_tags_categories_to_pages() {
  register_taxonomy_for_object_type(&#039;post_tag&#039;, &#039;page&#039;);
  register_taxonomy_for_object_type(&#039;category&#039;, &#039;page&#039;);
}
add_action( &#039;init&#039;, &#039;wpse_add_tags_categories_to_pages&#039; );

/*add excerpt to wp poststs*/
	
add_post_type_support( &#039;page&#039;, &#039;excerpt&#039; );

// Disable XML-RPC
add_filter(&#039;xmlrpc_enabled&#039;, &#039;__return_false&#039;);

// Elementor description meta tag
function remove_hello_elementor_description_meta_tag() {
	remove_action( &#039;wp_head&#039;, &#039;hello_elementor_add_description_meta_tag&#039; );
}
add_action( &#039;after_setup_theme&#039;, &#039;remove_hello_elementor_description_meta_tag&#039; );


add_filter(&#039;flying_press_js_delay_timeout&#039;, function(){ return 60;});

//Edit something
add_action(&#039;elementor/editor/before_enqueue_scripts&#039;, function() {
    wp_add_inline_script(&#039;elementor-editor&#039;, &#039;
        window.addEventListener(&quot;DOMContentLoaded&quot;, function() {
            const originalEntries = Object.entries;
            Object.entries = function(obj) {
                if (obj === null || obj === undefined) {
                    return [];
                }
                return originalEntries.call(this, obj);
            };
        });
    &#039;, &#039;before&#039;);
}, 5);

// Fix Cloudflare Turnstile not loading in Elementor popups
// The plugin uses native addEventListener for &#039;elementor/popup/show&#039;
// but Elementor fires it via jQuery. This patch bridges the gap.
function cft_turnstile_popup_fix() {
    ?&gt;
    &lt;script&gt;
    (function() {
        if (typeof jQuery === &#039;undefined&#039;) return;
        jQuery(document).on(&#039;elementor/popup/show&#039;, function(event, id, instance) {
            setTimeout(function() {
                var settings = window.cfturnstileElementorSettings || {};
                if (settings.mode &amp;&amp; settings.mode !== &#039;turnstile&#039;) return;
                if (!window.turnstile) return;

                // First, process any unprocessed forms in the popup
                var popupForms = document.querySelectorAll(&#039;.elementor-popup-modal .elementor-form:not(.cft-processed)&#039;);
                popupForms.forEach(function(form, index) {
                    var submitButton = form.querySelector(&#039;button[type=&quot;submit&quot;]&#039;);
                    if (submitButton &amp;&amp; settings.sitekey) {
                        var turnstileDiv = document.createElement(&#039;div&#039;);
                        turnstileDiv.className = &#039;elementor-turnstile-field cf-turnstile&#039;;
                        turnstileDiv.id = &#039;cf-turnstile-popup-fix-&#039; + id + &#039;-&#039; + index;
                        turnstileDiv.style.cssText = &#039;display: block; margin: 10px 0 15px 0; width: 100%;&#039;;
                        submitButton.parentNode.insertBefore(turnstileDiv, submitButton);
                        form.classList.add(&#039;cft-processed&#039;);
                    }
                });

                // Clean up any stale/failed turnstile children first
                var popupTurnstile = document.querySelectorAll(&#039;.elementor-popup-modal .cf-turnstile&#039;);
                popupTurnstile.forEach(function(el) {
                    // Remove old failed widget content
                    while (el.firstChild) { el.removeChild(el.firstChild); }
                    try { turnstile.remove(&#039;#&#039; + el.id); } catch(e) {}
                    turnstile.render(&#039;#&#039; + el.id, {
                        sitekey: settings.sitekey,
                        theme: settings.theme || &#039;auto&#039;,
                        callback: function(token) {
                            if (typeof turnstileElementorCallback === &#039;function&#039;) {
                                turnstileElementorCallback(token);
                            }
                        }
                    });
                });
            }, 1500);
        });
    })();
    &lt;/script&gt;
    &lt;?php
}
add_action(&#039;wp_footer&#039;, &#039;cft_turnstile_popup_fix&#039;, 999);

add_action(&#039;wp_ajax_nopriv_custom_knotweed_form&#039;, &#039;handle_knotweed_form_submission&#039;);
add_action(&#039;wp_ajax_custom_knotweed_form&#039;, &#039;handle_knotweed_form_submission&#039;);

function handle_knotweed_form_submission() {
    
    if (!isset($_POST[&#039;name&#039;], $_POST[&#039;phone&#039;], $_POST[&#039;postcode&#039;])) {
        wp_send_json_error(&#039;Required fields are missing&#039;);
    }

    $form_fields = [
        &#039;name&#039;     =&gt; sanitize_text_field($_POST[&#039;name&#039;]),
        &#039;phone&#039;    =&gt; sanitize_text_field($_POST[&#039;phone&#039;]),
        &#039;postcode&#039; =&gt; sanitize_text_field($_POST[&#039;postcode&#039;]),
        &#039;service&#039;  =&gt; sanitize_text_field($_POST[&#039;service&#039;] ?? &#039;Not selected&#039;),
        &#039;email&#039;    =&gt; sanitize_email($_POST[&#039;email&#039;] ?? &#039;&#039;),
    ];

    $uploaded_file_url = &#039;&#039;;
    $attachment = [];

    if (!empty($_FILES[&#039;photo&#039;][&#039;name&#039;])) {
        require_once(ABSPATH . &#039;wp-admin/includes/file.php&#039;);
        $upload = wp_handle_upload($_FILES[&#039;photo&#039;], [&#039;test_form&#039; =&gt; false]);

        if (isset($upload[&#039;file&#039;]) &amp;&amp; !empty($upload[&#039;file&#039;])) {
            $uploaded_file_url = $upload[&#039;url&#039;];
            
            $attachment[] = $upload[&#039;file&#039;];
            
            $form_fields[&#039;photo&#039;] = $uploaded_file_url;
        }
    }

    if (class_exists(&#039;\ElementorPro\Modules\Forms\Classes\Record&#039;)) {
        $record = new \ElementorPro\Modules\Forms\Classes\Record([
            &#039;form_name&#039;      =&gt; &#039;Hero Knotweed Quote Form&#039;,
            &#039;form_id&#039;        =&gt; &#039;hero_knotweed_form&#039;,
            &#039;post_id&#039;        =&gt; get_the_ID(),
            &#039;fields&#039;         =&gt; $form_fields,
            &#039;uploaded_files&#039; =&gt; !empty($uploaded_file_url) ? [&#039;photo&#039; =&gt; [&#039;url&#039; =&gt; $uploaded_file_url]] : [],
        ]);

        $record-&gt;add_submission();
    }

    $to_email = &#039;expert@environetuk.com&#039;;

    $subject = &#039;New Knotweed Quote Request - &#039; . $form_fields[&#039;name&#039;];

    $message = &quot;New quote request received:\n\n&quot;;
    $message .= &quot;Name: &quot; . $form_fields[&#039;name&#039;] . &quot;\n&quot;;
    $message .= &#039;Email: &#039; . (isset($form_fields[&#039;email&#039;]) ? $form_fields[&#039;email&#039;] : &#039;N/A&#039;) . &quot;\n&quot;;
    $message .= &quot;Phone: &quot; . $form_fields[&#039;phone&#039;] . &quot;\n&quot;;
    $message .= &quot;Postcode: &quot; . $form_fields[&#039;postcode&#039;] . &quot;\n&quot;;
    $message .= &quot;Service: &quot; . $form_fields[&#039;service&#039;] . &quot;\n&quot;;
    
    if (!empty($uploaded_file_url)) {
        $message .= &quot;\nPhoto: &quot; . $uploaded_file_url . &quot;\n&quot;;
    }

    $headers = [&#039;Content-Type: text/plain; charset=UTF-8&#039;];

    wp_mail($to_email, $subject, $message, $headers, $attachment);

    // Lead prosto do Azure CRM (zamiennik martwego n8n)
    environet_push_to_crm(array(
        &#039;Name&#039;      =&gt; $form_fields[&#039;name&#039;],
        &#039;Email&#039;     =&gt; isset($form_fields[&#039;email&#039;]) ? $form_fields[&#039;email&#039;] : &#039;&#039;,
        &#039;Telephone&#039; =&gt; $form_fields[&#039;phone&#039;],
        &#039;Postcode&#039;  =&gt; $form_fields[&#039;postcode&#039;],
        &#039;Message&#039;   =&gt; isset($form_fields[&#039;service&#039;]) ? $form_fields[&#039;service&#039;] : &#039;&#039;,
        &#039;File&#039;      =&gt; !empty($uploaded_file_url) ? $uploaded_file_url : &#039;NONE&#039;,
        &#039;form_id&#039;   =&gt; &#039;hero_knotweed_form&#039;,
        &#039;form_name&#039; =&gt; &#039;Knotweed PPC Form&#039;,
    ));

    wp_send_json_success(&#039;Success&#039;);
}


/* =========================================================================
 * Environet: formularze -&gt; 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(
		&#039;Name&#039;      =&gt; &#039;&#039;,
		&#039;Email&#039;     =&gt; &#039;&#039;,
		&#039;Telephone&#039; =&gt; &#039;&#039;,
		&#039;Postcode&#039;  =&gt; &#039;&#039;,
		&#039;Message&#039;   =&gt; &#039;&#039;,
		&#039;File&#039;      =&gt; &#039;NONE&#039;,
		&#039;Terms&#039;     =&gt; &#039;I accept the terms and conditions&#039;,
		&#039;Date&#039;      =&gt; date_i18n( &#039;F j, Y&#039; ),
		&#039;Time&#039;      =&gt; date_i18n( &#039;g:i a&#039; ),
		&#039;Page URL&#039;  =&gt; isset( $_SERVER[&#039;HTTP_REFERER&#039;] ) ? esc_url_raw( $_SERVER[&#039;HTTP_REFERER&#039;] ) : &#039;&#039;,
		&#039;form_id&#039;   =&gt; &#039;unknown&#039;,
		&#039;form_name&#039; =&gt; &#039;Unknown Form&#039;,
	) );

	// Koperta w formacie ktorego oczekuje funkcja Azure: tablica z jednym obiektem
	$payload = array(
		array(
			&#039;headers&#039;       =&gt; array(
				&#039;host&#039;       =&gt; isset( $_SERVER[&#039;HTTP_HOST&#039;] ) ? $_SERVER[&#039;HTTP_HOST&#039;] : &#039;&#039;,
				&#039;user-agent&#039; =&gt; isset( $_SERVER[&#039;HTTP_USER_AGENT&#039;] ) ? $_SERVER[&#039;HTTP_USER_AGENT&#039;] : &#039;&#039;,
			),
			&#039;params&#039;        =&gt; new stdClass(),
			&#039;query&#039;         =&gt; new stdClass(),
			&#039;body&#039;          =&gt; $body,
			&#039;webhookUrl&#039;    =&gt; &#039;&#039;,
			&#039;executionMode&#039; =&gt; &#039;production&#039;,
		),
	);

	$url = &#039;https://prod-webhookjsontolead-http.azurewebsites.net/api/Function1?code=NJLEOVYNWw/1ZBcRkMCqc/hG4x3OyFaXECwiaALkKsao9cp7Ufejaw==&#039;;

	$response = wp_remote_post( $url, array(
		&#039;method&#039;  =&gt; &#039;POST&#039;,
		&#039;timeout&#039; =&gt; 20,
		&#039;headers&#039; =&gt; array(
			&#039;Content-Type&#039; =&gt; &#039;application/json&#039;,
			&#039;Accept&#039;       =&gt; &#039;*/*&#039;,
		),
		&#039;body&#039;    =&gt; wp_json_encode( $payload ),
	) );

	// Log do debugowania - wlacz WP_DEBUG / WP_DEBUG_LOG w wp-config.php
	if ( is_wp_error( $response ) ) {
		error_log( &#039;Environet CRM error: &#039; . $response-&gt;get_error_message() );
	} else {
		error_log( &#039;Environet CRM -&gt; &#039; . wp_remote_retrieve_response_code( $response ) . &#039; &#039; . 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( &#039;elementor_pro/forms/new_record&#039;, &#039;environet_form_to_crm&#039;, 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  = &#039;https://prod-webhookjsontolead-http.azurewebsites.net/api/Function1&#039;;
    $azure_code = &#039;NJLEOVYNWw/1ZBcRkMCqc/hG4x3OyFaXECwiaALkKsao9cp7Ufejaw==&#039;;

    $form_name  = $record-&gt;get_form_settings( &#039;form_name&#039; );
    $form_id    = $record-&gt;get_form_settings( &#039;id&#039; );
    $raw_fields = $record-&gt;get( &#039;fields&#039; );
    $meta       = $record-&gt;get( &#039;meta&#039; );

    $f = [];
    foreach ( $raw_fields as $id =&gt; $field ) {
        $f[ $id ] = sanitize_text_field( $field[&#039;value&#039;] ?? &#039;&#039; );
    }

    $body = [
        &#039;Name&#039;      =&gt; $f[&#039;name&#039;]      ?? $f[&#039;full_name&#039;]  ?? &#039;&#039;,
        &#039;Email&#039;     =&gt; $f[&#039;email&#039;]     ?? $f[&#039;email_address&#039;] ?? &#039;&#039;,
        &#039;Telephone&#039; =&gt; $f[&#039;phone&#039;]     ?? $f[&#039;telephone&#039;]  ?? &#039;&#039;,
        &#039;Postcode&#039;  =&gt; $f[&#039;postcode&#039;]  ?? $f[&#039;post_code&#039;]  ?? $f[&#039;zip&#039;] ?? &#039;&#039;,
        &#039;Message&#039;   =&gt; $f[&#039;message&#039;]   ?? $f[&#039;comments&#039;]   ?? $f[&#039;description&#039;] ?? &#039;&#039;,
        &#039;File&#039;      =&gt; $f[&#039;files&#039;]     ?? $f[&#039;file&#039;]       ?? &#039;NONE&#039;,
        &#039;Terms&#039;     =&gt; &#039;I accept the terms and conditions&#039;,
        &#039;Date&#039;      =&gt; $meta[&#039;date&#039;]   ?? wp_date( &#039;F j, Y&#039; ),
        &#039;Time&#039;      =&gt; $meta[&#039;time&#039;]   ?? wp_date( &#039;g:i a&#039; ),
        &#039;Page URL&#039;  =&gt; $meta[&#039;page_url&#039;] ?? &#039;&#039;,
        &#039;form_id&#039;   =&gt; $form_id,
        &#039;form_name&#039; =&gt; $form_name,
    ];

    $payload = [
        [
            &#039;headers&#039; =&gt; [
                &#039;host&#039;       =&gt; &#039;www.environetuk.com&#039;,
                &#039;user-agent&#039; =&gt; &#039;WordPress/&#039; . get_bloginfo( &#039;version&#039; ) . &#039;; &#039; . home_url(),
            ],
            &#039;params&#039; =&gt; new \stdClass(),
            &#039;query&#039;  =&gt; new \stdClass(),
            &#039;body&#039;   =&gt; $body,
            &#039;webhookUrl&#039;    =&gt; home_url(),
            &#039;executionMode&#039; =&gt; &#039;production&#039;,
        ],
    ];

    wp_remote_post(
        add_query_arg( &#039;code&#039;, $azure_code, $azure_url ),
        [
            &#039;timeout&#039;  =&gt; 15,
            &#039;blocking&#039; =&gt; false,
            &#039;headers&#039;  =&gt; [
                &#039;Content-Type&#039;    =&gt; &#039;application/json&#039;,
                &#039;Accept&#039;          =&gt; &#039;*/*&#039;,
            ],
            &#039;body&#039; =&gt; 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( &#039;wp_footer&#039;, &#039;environet_fix_phone_pattern&#039;, 99 );
function environet_fix_phone_pattern() {
	?&gt;
	&lt;script&gt;
	(function () {
		var BAD  = &quot;[0-9()#&amp;+*-=.]+&quot;;
		var GOOD = &quot;[0-9\\(\\)#&amp;+*=.\\-]+&quot;;
		function fix() {
			document.querySelectorAll(&#039;input[pattern]&#039;).forEach(function (el) {
				if (el.getAttribute(&#039;pattern&#039;) === BAD) {
					el.setAttribute(&#039;pattern&#039;, GOOD);
				}
			});
		}
		if (document.readyState === &#039;loading&#039;) {
			document.addEventListener(&#039;DOMContentLoaded&#039;, fix);
		} else {
			fix();
		}
		document.addEventListener(&#039;submit&#039;, fix, true);
	})();
	&lt;/script&gt;
	&lt;?php
}
<?xml version="1.0" encoding="UTF-8"?><?xml-stylesheet type="text/xsl" href="//www.environetuk.com/wp-content/plugins/wordpress-seo/css/main-sitemap.xsl"?>
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
	<sitemap>
		<loc>https://www.environetuk.com/post-sitemap.xml</loc>
		<lastmod>2026-06-17T09:56:46+00:00</lastmod>
	</sitemap>
	<sitemap>
		<loc>https://www.environetuk.com/page-sitemap.xml</loc>
		<lastmod>2026-06-17T11:14:56+00:00</lastmod>
	</sitemap>
	<sitemap>
		<loc>https://www.environetuk.com/case-study-sitemap.xml</loc>
		<lastmod>2026-05-18T07:59:53+00:00</lastmod>
	</sitemap>
</sitemapindex>
<!-- XML Sitemap generated by Yoast SEO -->