UHLHosting

Consent-oxygen

Oct 27th, 2022
68
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 10.63 KB | None | 0 0
  1. <?php
  2. /*
  3. Plugin Name:  MA Content Consent
  4. Description:  Shortcode for requesting user consent before loading external content.
  5. Author:       <a href="https://www.altmann.de/">Matthias Altmann</a>
  6. Project:      Code Snippet: MA Content Consent
  7. Version:      1.1.0
  8. Plugin URI:   https://www.altmann.de/en/blog-en/code-snippet-shortcode-content-consent/
  9. Description:  en: https://www.altmann.de/en/blog-en/code-snippet-consent-for-external-content/
  10.               de: https://www.altmann.de/blog/code-snippet-zustimmung-fuer-externe-inhalte/
  11. Copyright:    © 2021-2022, Matthias Altmann
  12.  
  13.  
  14.  
  15. Version History:
  16. Date        Version     Description
  17. --------------------------------------------------------------------------------------------------------------
  18. 2022-10-21  1.1.0       Changes:
  19.                         - Added new shortcode parameters block-class, text-class, button-class
  20.                         - Migrated JavaScript from jQuery to vanilla JS (ES6) to eliminate jQuery dependency.
  21.                           (Thanks to André Slotta for the provided code sample)
  22.                         Fixes:
  23.                         - Removed double '.' for German GDPR text.
  24.                           (Thanks to Tobias Maximilian Hietsch for reporting)
  25. 2022-02-04  1.0.1       - Added Dansk translations for notice text and button label
  26.                           (Thanks to Theis L. Soelberg)
  27.                         - Evaluating nested shortcodes
  28.                           (Thanks to Anja Kretzer)
  29. 2022-02-03  1.0.0       Initial release as Code Snippet
  30. 2021-12-29  0.0.1       Initial version for client project
  31. --------------------------------------------------------------------------------------------------------------
  32. */
  33.  
  34. if (!class_exists('MA_Content_Consent')) :
  35.  
  36. class MA_Content_Consent {
  37.     const TITLE                         = 'MA Content Consent';
  38.     const SLUG                          = 'ma-content-consent';
  39.     const VERSION                       = '1.1.0';
  40.  
  41.  
  42.     // ===== CONFIGURATION ==============================================================================================
  43.     public static $timing               = false;    // Write timing info to wordpress debug.log if WP_DEBUG enabled    
  44.     public static $debug                = false;    // Write debug info to wordpress debug.log if WP_DEBUG enabled 
  45.  
  46.     private static $default_consent_text = [        // consent text in different languages
  47.         'da' => ['Når du har trykket, vil indholdet blive hentet fra eksterne servere. Se vores %s for flere informationer.','privatlivspolitik'],
  48.         'de' => ['Bei Klick wird dieser Inhalt von externen Servern geladen. Details siehe %s.', 'Datenschutzerklärung'],
  49.         'en' => ['When clicked, this content is loaded from external servers. See our %s for details.', 'privacy policy'],
  50.         'es' => ['Al hacer clic, este contenido se carga desde servidores externos. Consulte la %s para más detalles.', 'política de privacidad'],
  51.         'fr' => ['En cliquant, ce contenu est chargé depuis des serveurs externes. Voir la %s.', 'politique de confidentialité'],
  52.         'hu' => ['Ha rákattint, ez a tartalom külső szerverekről töltődik be. A részletekért olvassa el az %s oldalt.', 'Adatkezelési Tájékoztatót'],
  53.         'it' => ['Quando viene cliccato, questo contenuto viene caricato da server esterni. Vedere %s per i dettagli.', 'l\'informativa sulla privacy'],
  54.         'jp' => ['クリックすると、このコンテンツが外部サーバーから読み込まれます。弊社のプライバシーポリシーの詳細は、%s', 'を参照してください。'],
  55.     ];
  56.     private static $default_button_text = [         // button text in different languages
  57.         'da' => 'Indlæs eksternt indhold',
  58.         'de' => 'Externen Inhalt laden',
  59.         'en' => 'Load external content',
  60.         'es' => 'Cargar contenido externo',
  61.         'fr' => 'Charger le contenu externe',
  62.         'hu' => 'Külső tartalom betöltése',
  63.         'it' => 'Caricare il contenuto esterno',
  64.         'jp' => '外部のコンテンツを読み込ませます。',
  65.     ];
  66.  
  67.     //-------------------------------------------------------------------------------------------------------------------
  68.     public static function init() {
  69.         $st = microtime(true);
  70.  
  71.         add_shortcode('ma-content-consent', [__CLASS__, 'shortcode']);
  72.  
  73.         $et = microtime(true);
  74.         if (WP_DEBUG && self::$timing) {error_log(sprintf('%s%s::%s() Timing: %.5f sec.', '', __CLASS__, __FUNCTION__, $et-$st));}
  75.     }
  76.     //-------------------------------------------------------------------------------------------------------------------
  77.     private static function get_current_language(){
  78.         $retval = get_locale();
  79.         // Is Polylang available?
  80.         if (function_exists('wpml_current_language')) {$retval = wpml_current_language();}
  81.         $retval = str_replace('_','-',$retval);
  82.         $retval = explode('-',@$retval)[0];
  83.         return $retval;
  84.     }
  85.     //-------------------------------------------------------------------------------------------------------------------
  86.     private static function get_privacy_policy_link($text) {
  87.         // return a link to the privacy policy (if configured) or just the passed text
  88.         $pplink = get_the_privacy_policy_link();
  89.         return  $pplink ? $pplink : $text;
  90.     }
  91.  
  92.     //-------------------------------------------------------------------------------------------------------------------
  93.     public static function shortcode($atts, $content = '') {
  94.         $st = microtime(true);
  95.         $lang = self::get_current_language();
  96.         if (!is_array($atts)) $atts = [];
  97.        
  98.         // fix Gutenberg content: remove </p> ... <p>
  99.         $content = preg_replace('/^<\/p>[ \r\n]*/','',$content); // remove leading </p> tag, spaces, line breaks from shortcode start tag
  100.         $content = preg_replace('/[ \r\n]*<p>$/','',$content); // remove trailing line breaks, spaces, <p> tag from shortcode end tag
  101.         // evaluate nested shortcodes
  102.         $content = do_shortcode($content);
  103.  
  104.         // get defaults for unspecified atts
  105.         $atts = (object)array_merge([
  106.             'slug'                  => self::SLUG,
  107.             'id'                    => uniqid(self::SLUG . '-'),
  108.             'block-style'           => '',
  109.             'block-class'           => '',
  110.             'text'                  => isset(self::$default_consent_text[$lang])
  111.                                         ? sprintf(self::$default_consent_text[$lang][0],self::get_privacy_policy_link(self::$default_consent_text[$lang][1]))
  112.                                         : sprintf(self::$default_consent_text['en'][0],self::get_privacy_policy_link(self::$default_consent_text['en'][1])),
  113.             'text-style'            => '',
  114.             'text-class'            => '',
  115.             'button-text'           => self::$default_button_text[$lang] ?? self::$default_button_text['en'],
  116.             'button-style'          => '',
  117.             'button-class'          => '',
  118.             'background-image'      => null,
  119.             'contentb64'            => base64_encode($content),
  120.         ], $atts);
  121.         $atts->{'background-style'} = $atts->{'background-image'} ? 'background-image:url('.$atts->{'background-image'}.'); background-size:cover; background-position:center center;' : '';
  122.  
  123.         $atts->{'text'} = str_replace('{privacy-policy-url}', get_privacy_policy_url(), $atts->{'text'});
  124.         $atts->{'text'} = str_replace('{privacy-policy-link}', get_the_privacy_policy_link(), $atts->{'text'});
  125.  
  126.  
  127.         $html = <<<END_OF_HTML
  128.         <div id="{$atts->id}" class="{$atts->slug} {$atts->{'block-class'}}" style="display:flex; flex-direction:column; justify-content:center; align-content:center; background-color:#efefef; border: 1px solid lightgray; padding:1em; width: 100%; {$atts->{'background-style'}} {$atts->{'block-style'}} ">
  129.             <div style="text-align:center">
  130.                 <p class="{$atts->slug}__text {$atts->{'text-class'}}" style="font-size:.7em; {$atts->{'text-style'}}">{$atts->{'text'}}</p>
  131.                 <a id="{$atts->id}__button" class="wp-block-button__link {$atts->slug}__button {$atts->{'button-class'}}" style="{$atts->{'button-style'}}">{$atts->{'button-text'}}</a>
  132.             </div>
  133.             <div id="{$atts->id}__content" class="{$atts->slug}__content" style="display:none">{$atts->contentb64}</div>
  134.             <script>
  135.             document.querySelectorAll('#{$atts->id}__button').forEach(function(btn){
  136.                 btn.addEventListener('click',function(){
  137.                     let id = this.closest('div.{$atts->slug}').id;
  138.                     let content = atob(document.querySelector('#'+id+'__content').innerText);
  139.                     this.closest('div.{$atts->slug}').outerHTML = content;
  140.                 });
  141.             });
  142.             </script>
  143.         </div>
  144. END_OF_HTML;
  145.  
  146.         $et = microtime(true);
  147.         if (WP_DEBUG && self::$timing) {error_log(sprintf('%s%s::%s() Timing: %.5f sec.', '-> ', __CLASS__, __FUNCTION__, $et-$st));}
  148.         return $html;
  149.     }
  150. }
  151.  
  152. //===================================================================================================================
  153. // Initialize
  154.  
  155. // Warn about incompatibilities (currently none)
  156. add_action('wp_loaded',function(){
  157.     if (is_admin()) {
  158.         if (!isset($GLOBALS['MA_Content_Consent_Incompatibilities'])) {$GLOBALS['MA_Content_Consent_Incompatibilities'] = [];}
  159.         if (count($GLOBALS['MA_Content_Consent_Incompatibilities'])) {
  160.             if (WP_DEBUG && (MA_Content_Consent::$debug || MA_Content_Consent::$timing))
  161.                 {error_log('MA_Content_Consent / Incompatibilities: '.print_r($GLOBALS['MA_Content_Consent_Incompatibilities'],true));}
  162.             add_action('admin_notices', function(){
  163.                 if (WP_DEBUG ) {error_log('MA_Content_Consent / Incompatibilities: '.print_r($GLOBALS['MA_Content_Consent_Incompatibilities'],true));}
  164.                 $implementation = basename(__FILE__) == 'ma-content-consent.php' ? 'Plugin' : 'Code Snippet';
  165.                 echo '<div class="notice notice-warning xis-dismissible">
  166.                         <p>The '.$implementation.'  "MA Content Consent" is skipped: '.implode(' or ',$GLOBALS['MA_Content_Consent_Incompatibilities']).'</p>
  167.                     </div>';
  168.             });
  169.         }
  170.     }
  171. }, 1000);
  172.  
  173. add_action('wp_loaded',function(){
  174.     if (isset($GLOBALS['MA_Content_Consent_Incompatibilities']) && count($GLOBALS['MA_Content_Consent_Incompatibilities'])) return;
  175.     if (wp_doing_ajax())        return;     // don't run for AJAX requests
  176.     if (wp_doing_cron())        return;     // don't run for CRON requests
  177.     if (wp_is_json_request())   return;     // don't run for JSON requests
  178.     if (is_favicon())           return;     // don't run for favicon request
  179.     if (isset($_SERVER['QUERY_STRING']) && ($_SERVER['QUERY_STRING'] == 'service-worker'))          return; // don't run for service-worker
  180.     if (isset($_SERVER['REQUEST_URI'])  && ($_SERVER['REQUEST_URI'] == '/favicon.ico'))             return; // don't run for favicon
  181.     if (isset($_SERVER['REQUEST_URI'])  && (strpos($_SERVER['REQUEST_URI'],'/wp-content/') === 0))  return; // don't run for dynamic wp-content file
  182.    
  183.     if (is_admin()) {
  184.         global $pagenow;
  185.         if (    ($pagenow != 'post-new.php')
  186.         &&  (   ($pagenow != 'post.php') || ($pagenow == 'post.php' && isset($_REQUEST['action']) && ($_REQUEST['action'] != 'edit'))   )
  187.         ) return; // only load on specific requests where Gutenberg is involved
  188.     }
  189.        
  190.     $implementation = basename(__FILE__) == 'ma-content-consent.php' ? 'Plugin' : 'Code Snippet';
  191.     if (WP_DEBUG && (MA_Content_Consent::$debug || MA_Content_Consent::$timing))
  192.         {error_log(sprintf('MA_Content_Consent: Initializing %s for request URI="%s" action="%s"', $implementation, $_SERVER['REQUEST_URI']??'', $_REQUEST['action']??''));}
  193.  
  194.     MA_Content_Consent::init();
  195.  
  196. }, 1200);
  197.    
  198. endif;
  199.  
Add Comment
Please, Sign In to add comment