/** * Protek - part enquiry buttons, WhatsApp QR and "can't find your part" capture. */ if ( ! defined( 'ABSPATH' ) ) { exit; } function protek_qr_gf_tables() { static $t = null; if ( $t !== null ) { return $t; } $exp = array(); $log = array(); $x = 1; for ( $i = 0; $i < 256; $i++ ) { $exp[ $i ] = $x; if ( $i < 255 ) { $log[ $x ] = $i; } $x <<= 1; if ( $x & 0x100 ) { $x ^= 0x11d; } } $t = array( $exp, $log ); return $t; } function protek_qr_gf_mul( $a, $b ) { if ( $a == 0 || $b == 0 ) { return 0; } list( $exp, $log ) = protek_qr_gf_tables(); return $exp[ ( $log[ $a ] + $log[ $b ] ) % 255 ]; } function protek_qr_gen_poly( $n ) { $g = array( 1 ); list( $exp, $log ) = protek_qr_gf_tables(); for ( $i = 0; $i < $n; $i++ ) { $ng = array_fill( 0, count( $g ) + 1, 0 ); for ( $j = 0; $j < count( $g ); $j++ ) { $ng[ $j ] ^= protek_qr_gf_mul( $g[ $j ], 1 ); $ng[ $j + 1 ] ^= protek_qr_gf_mul( $g[ $j ], $exp[ $i ] ); } $g = $ng; } return $g; } function protek_qr_ecc( $data, $n ) { $g = protek_qr_gen_poly( $n ); $res = array_merge( $data, array_fill( 0, $n, 0 ) ); $len = count( $data ); for ( $i = 0; $i < $len; $i++ ) { $c = $res[ $i ]; if ( $c == 0 ) { continue; } for ( $j = 0; $j < count( $g ); $j++ ) { $res[ $i + $j ] ^= protek_qr_gf_mul( $g[ $j ], $c ); } } return array_slice( $res, $len, $n ); } function protek_qr_specs() { return array( 1 => array( 19, 1, 7 ), 2 => array( 34, 1, 10 ), 3 => array( 55, 1, 15 ), 4 => array( 80, 1, 20 ), 5 => array( 108, 1, 26 ), 6 => array( 136, 2, 18 ), 7 => array( 156, 2, 20 ), 8 => array( 194, 2, 24 ), 9 => array( 232, 2, 30 ), ); } function protek_qr_align() { return array( 1 => array(), 2 => array( 6, 18 ), 3 => array( 6, 22 ), 4 => array( 6, 26 ), 5 => array( 6, 30 ), 6 => array( 6, 34 ), 7 => array( 6, 22, 38 ), 8 => array( 6, 24, 42 ), 9 => array( 6, 26, 46 ), ); } function protek_qr_bch15( $data ) { $d = $data << 10; for ( $i = 4; $i >= 0; $i-- ) { if ( $d & ( 1 << ( $i + 10 ) ) ) { $d ^= 0x537 << $i; } } return ( ( $data << 10 ) | $d ) ^ 0x5412; } function protek_qr_bch18( $ver ) { $d = $ver << 12; for ( $i = 5; $i >= 0; $i-- ) { if ( $d & ( 1 << ( $i + 12 ) ) ) { $d ^= 0x1f25 << $i; } } return ( $ver << 12 ) | $d; } function protek_qr_matrix( $text ) { $bytes = array_values( unpack( 'C*', $text ) ); $len = count( $bytes ); $specs = protek_qr_specs(); $ver = 0; foreach ( $specs as $v => $s ) { $cap = intdiv( $s[0] * 8 - 4 - 8, 8 ); if ( $len <= $cap ) { $ver = $v; break; } } if ( ! $ver ) { return null; } list( $totalData, $blocks, $ecPer ) = $specs[ $ver ]; $bits = '0100'; $bits .= str_pad( decbin( $len ), 8, '0', STR_PAD_LEFT ); foreach ( $bytes as $b ) { $bits .= str_pad( decbin( $b ), 8, '0', STR_PAD_LEFT ); } $capBits = $totalData * 8; $bits .= str_repeat( '0', min( 4, $capBits - strlen( $bits ) ) ); while ( strlen( $bits ) % 8 !== 0 ) { $bits .= '0'; } $pad = array( 0xEC, 0x11 ); $pi = 0; while ( strlen( $bits ) < $capBits ) { $bits .= str_pad( decbin( $pad[ $pi % 2 ] ), 8, '0', STR_PAD_LEFT ); $pi++; } $dataCw = array(); for ( $i = 0; $i < $capBits; $i += 8 ) { $dataCw[] = bindec( substr( $bits, $i, 8 ) ); } $per = intdiv( $totalData, $blocks ); $dBlocks = array(); $eBlocks = array(); for ( $b = 0; $b < $blocks; $b++ ) { $chunk = array_slice( $dataCw, $b * $per, $per ); $dBlocks[] = $chunk; $eBlocks[] = protek_qr_ecc( $chunk, $ecPer ); } $final = array(); for ( $i = 0; $i < $per; $i++ ) { for ( $b = 0; $b < $blocks; $b++ ) { $final[] = $dBlocks[ $b ][ $i ]; } } for ( $i = 0; $i < $ecPer; $i++ ) { for ( $b = 0; $b < $blocks; $b++ ) { $final[] = $eBlocks[ $b ][ $i ]; } } $size = 17 + 4 * $ver; $m = array(); $res = array(); for ( $r = 0; $r < $size; $r++ ) { $m[ $r ] = array_fill( 0, $size, 0 ); $res[ $r ] = array_fill( 0, $size, 0 ); } $finder = function( $rr, $cc ) use ( &$m, &$res, $size ) { for ( $i = -1; $i <= 7; $i++ ) { for ( $j = -1; $j <= 7; $j++ ) { $r = $rr + $i; $c = $cc + $j; if ( $r < 0 || $c < 0 || $r >= $size || $c >= $size ) { continue; } $on = ( $i >= 0 && $i <= 6 && ( $j == 0 || $j == 6 ) ) || ( $j >= 0 && $j <= 6 && ( $i == 0 || $i == 6 ) ) || ( $i >= 2 && $i <= 4 && $j >= 2 && $j <= 4 ); $m[ $r ][ $c ] = $on ? 1 : 0; $res[ $r ][ $c ] = 1; } } }; $finder( 0, 0 ); $finder( 0, $size - 7 ); $finder( $size - 7, 0 ); for ( $i = 8; $i < $size - 8; $i++ ) { $v = ( $i % 2 == 0 ) ? 1 : 0; $m[ 6 ][ $i ] = $v; $res[ 6 ][ $i ] = 1; $m[ $i ][ 6 ] = $v; $res[ $i ][ 6 ] = 1; } $al = protek_qr_align(); $pts = $al[ $ver ]; foreach ( $pts as $r ) { foreach ( $pts as $c ) { if ( ( $r == 6 && $c == 6 ) || ( $r == 6 && $c == $size - 7 ) || ( $r == $size - 7 && $c == 6 ) ) { continue; } for ( $i = -2; $i <= 2; $i++ ) { for ( $j = -2; $j <= 2; $j++ ) { $on = ( abs( $i ) == 2 || abs( $j ) == 2 || ( $i == 0 && $j == 0 ) ); $m[ $r + $i ][ $c + $j ] = $on ? 1 : 0; $res[ $r + $i ][ $c + $j ] = 1; } } } } for ( $i = 0; $i < 9; $i++ ) { if ( $i != 6 ) { $res[8][ $i ] = 1; $res[ $i ][8] = 1; } } $res[8][6] = 1; $res[6][8] = 1; for ( $i = 0; $i < 8; $i++ ) { $res[8][ $size - 1 - $i ] = 1; $res[ $size - 1 - $i ][8] = 1; } $m[ $size - 8 ][8] = 1; $res[ $size - 8 ][8] = 1; if ( $ver >= 7 ) { $vb = protek_qr_bch18( $ver ); for ( $i = 0; $i < 18; $i++ ) { $bit = ( $vb >> $i ) & 1; $r = intdiv( $i, 3 ); $c = $size - 11 + ( $i % 3 ); $m[ $r ][ $c ] = $bit; $res[ $r ][ $c ] = 1; $m[ $c ][ $r ] = $bit; $res[ $c ][ $r ] = 1; } } $bitStr = ''; foreach ( $final as $cw ) { $bitStr .= str_pad( decbin( $cw ), 8, '0', STR_PAD_LEFT ); } $idx = 0; $dir = -1; $row = $size - 1; for ( $col = $size - 1; $col > 0; $col -= 2 ) { if ( $col == 6 ) { $col = 5; } while ( true ) { for ( $k = 0; $k < 2; $k++ ) { $c = $col - $k; if ( ! $res[ $row ][ $c ] ) { $b = ( $idx < strlen( $bitStr ) ) ? (int) $bitStr[ $idx ] : 0; $idx++; $m[ $row ][ $c ] = $b; } } $row += $dir; if ( $row < 0 || $row >= $size ) { $row -= $dir; $dir = -$dir; break; } } } $maskFn = function( $mask, $r, $c ) { switch ( $mask ) { case 0: return ( ( $r + $c ) % 2 ) == 0; case 1: return ( $r % 2 ) == 0; case 2: return ( $c % 3 ) == 0; case 3: return ( ( $r + $c ) % 3 ) == 0; case 4: return ( ( intdiv( $r, 2 ) + intdiv( $c, 3 ) ) % 2 ) == 0; case 5: return ( ( $r * $c ) % 2 + ( $r * $c ) % 3 ) == 0; case 6: return ( ( ( $r * $c ) % 2 + ( $r * $c ) % 3 ) % 2 ) == 0; default: return ( ( ( $r + $c ) % 2 + ( $r * $c ) % 3 ) % 2 ) == 0; } }; $best = null; $bestScore = PHP_INT_MAX; for ( $mask = 0; $mask < 8; $mask++ ) { $t = $m; for ( $r = 0; $r < $size; $r++ ) { for ( $c = 0; $c < $size; $c++ ) { if ( ! $res[ $r ][ $c ] && $maskFn( $mask, $r, $c ) ) { $t[ $r ][ $c ] ^= 1; } } } $fb = protek_qr_bch15( ( 1 << 3 ) | $mask ); for ( $i = 0; $i < 15; $i++ ) { $bit = ( $fb >> $i ) & 1; if ( $i < 6 ) { $t[ $i ][8] = $bit; } elseif ( $i == 6 ) { $t[7][8] = $bit; } elseif ( $i == 7 ) { $t[8][8] = $bit; } elseif ( $i == 8 ) { $t[8][7] = $bit; } else { $t[8][ 14 - $i ] = $bit; } if ( $i < 8 ) { $t[8][ $size - 1 - $i ] = $bit; } else { $t[ $size - 15 + $i ][8] = $bit; } } $t[ $size - 8 ][8] = 1; $score = protek_qr_penalty( $t, $size ); if ( $score < $bestScore ) { $bestScore = $score; $best = $t; } } return $best; } function protek_qr_penalty( $m, $size ) { $p = 0; for ( $r = 0; $r < $size; $r++ ) { $run = 1; for ( $c = 1; $c < $size; $c++ ) { if ( $m[ $r ][ $c ] === $m[ $r ][ $c - 1 ] ) { $run++; } else { if ( $run >= 5 ) { $p += 3 + ( $run - 5 ); } $run = 1; } } if ( $run >= 5 ) { $p += 3 + ( $run - 5 ); } } for ( $c = 0; $c < $size; $c++ ) { $run = 1; for ( $r = 1; $r < $size; $r++ ) { if ( $m[ $r ][ $c ] === $m[ $r - 1 ][ $c ] ) { $run++; } else { if ( $run >= 5 ) { $p += 3 + ( $run - 5 ); } $run = 1; } } if ( $run >= 5 ) { $p += 3 + ( $run - 5 ); } } for ( $r = 0; $r < $size - 1; $r++ ) { for ( $c = 0; $c < $size - 1; $c++ ) { $v = $m[ $r ][ $c ]; if ( $v === $m[ $r ][ $c + 1 ] && $v === $m[ $r + 1 ][ $c ] && $v === $m[ $r + 1 ][ $c + 1 ] ) { $p += 3; } } } $pat1 = array( 1,0,1,1,1,0,1,0,0,0,0 ); $pat2 = array( 0,0,0,0,1,0,1,1,1,0,1 ); for ( $r = 0; $r < $size; $r++ ) { for ( $c = 0; $c <= $size - 11; $c++ ) { $ok1 = true; $ok2 = true; for ( $k = 0; $k < 11; $k++ ) { if ( $m[ $r ][ $c + $k ] !== $pat1[ $k ] ) { $ok1 = false; } if ( $m[ $r ][ $c + $k ] !== $pat2[ $k ] ) { $ok2 = false; } } if ( $ok1 ) { $p += 40; } if ( $ok2 ) { $p += 40; } } } for ( $c = 0; $c < $size; $c++ ) { for ( $r = 0; $r <= $size - 11; $r++ ) { $ok1 = true; $ok2 = true; for ( $k = 0; $k < 11; $k++ ) { if ( $m[ $r + $k ][ $c ] !== $pat1[ $k ] ) { $ok1 = false; } if ( $m[ $r + $k ][ $c ] !== $pat2[ $k ] ) { $ok2 = false; } } if ( $ok1 ) { $p += 40; } if ( $ok2 ) { $p += 40; } } } $dark = 0; for ( $r = 0; $r < $size; $r++ ) { $dark += array_sum( $m[ $r ] ); } $pct = ( $dark * 100 ) / ( $size * $size ); $p += ( (int) ( abs( $pct - 50 ) / 5 ) ) * 10; return $p; } function protek_qr_svg( $text, $px = 152, $quiet = 4 ) { $m = protek_qr_matrix( $text ); if ( ! $m ) { return ''; } $n = count( $m ); $tot = $n + 2 * $quiet; $path = ''; for ( $r = 0; $r < $n; $r++ ) { for ( $c = 0; $c < $n; $c++ ) { if ( $m[ $r ][ $c ] ) { $path .= 'M' . ( $c + $quiet ) . ' ' . ( $r + $quiet ) . 'h1v1h-1z'; } } } return ''; } function protek_enq_number() { return '971506443625'; } function protek_enq_display() { return '+971 50 644 3625'; } function protek_enq_recipients() { return array( 'info@proteklaundry.com', 'info.parts@protekgroup-me.com' ); } function protek_enq_short_url( $product ) { $sku = is_object( $product ) ? trim( (string) $product->get_sku() ) : ''; if ( $sku !== '' && preg_match( '/^[A-Za-z0-9._-]+$/', $sku ) ) { return home_url( '/p/' . rawurlencode( $sku ) ); } return is_object( $product ) ? get_permalink( $product->get_id() ) : home_url( '/' ); } function protek_p_route() { if ( empty( $_SERVER['REQUEST_URI'] ) ) { return; } $path = trim( (string) wp_parse_url( wp_unslash( $_SERVER['REQUEST_URI'] ), PHP_URL_PATH ), '/' ); if ( strpos( $path, 'p/' ) !== 0 ) { return; } $sku = rawurldecode( substr( $path, 2 ) ); $sku = trim( $sku ); if ( $sku === '' ) { return; } if ( function_exists( 'wc_get_product_id_by_sku' ) ) { $id = wc_get_product_id_by_sku( $sku ); if ( $id ) { wp_safe_redirect( get_permalink( $id ), 302 ); exit; } } wp_safe_redirect( home_url( '/?s=' . rawurlencode( $sku ) ), 302 ); exit; } add_action( 'init', 'protek_p_route', 1 ); function protek_enq_qr_text( $lead, $link = '' ) { $out = $lead; if ( $link !== '' ) { $out .= "\n" . $link; } return $out . "\n" . 'Company: ' . "\n" . 'Name: '; } function protek_enq_wa_link( $text ) { $enc = rawurlencode( $text ); $enc = str_replace( array( '%3A', '%2F' ), array( ':', '/' ), $enc ); return 'https://wa.me/' . protek_enq_number() . '?text=' . $enc; } function protek_enq_is_shop_area() { if ( ! function_exists( 'is_woocommerce' ) ) { return false; } return is_woocommerce() || is_shop() || is_product_category() || is_product_tag() || is_product() || is_search() || is_404(); } function protek_enq_part_context() { if ( ! function_exists( 'is_product' ) || ! is_product() ) { return null; } global $product; if ( ! is_object( $product ) ) { $product = wc_get_product( get_the_ID() ); } if ( ! is_object( $product ) ) { return null; } $sku = trim( (string) $product->get_sku() ); $name = $product->get_name(); return array( 'pn' => ( $sku !== '' ? $sku : $name ), 'name' => $name, 'url' => get_permalink( $product->get_id() ), 'short' => protek_enq_short_url( $product ), ); } function protek_enq_message( $c ) { return 'Enquiry for part number ' . $c['pn'] . "\n" . $c['name'] . "\n" . $c['url'] . "\n\n" . 'Please send price, availability and lead time.'; } function protek_enq_wa_icon() { return ''; } function protek_enq_block() { $GLOBALS['protek_enq_seen'] = true; $c = protek_enq_part_context(); if ( ! $c ) { return; } $msg = protek_enq_message( $c ); $wa = protek_enq_wa_link( protek_enq_qr_text( 'Enquiry: ' . $c['pn'], $c['short'] ) ); echo '
That does not mean we cannot supply it. Our parts desk carries many items that are not listed here, and the same part is often written differently by each machine brand. Send us the details and we will come back with price and availability.
'; } elseif ( $noresults ) { echo 'Tell us the machine and what the part does. Our parts desk carries many items that are not listed on the website, and we will come back to you with price and availability.
'; } else { echo 'Tell us the machine and what the part does. Our parts desk carries many items that are not listed on the website, and we will come back to you with price and availability.
'; } echo '
Scan to WhatsApp or call