From e0ec26e29283b9323e75b526c4df3847438bcd9a Mon Sep 17 00:00:00 2001
From: Christian Wach <needle@haystack.co.uk>
Date: Fri, 6 Mar 2020 15:52:49 +0000
Subject: [PATCH] Move Polylang compatibility to a "plugin compatibility" class

Signed-off-by: Kevin Cristiano <kcristiano@kcristiano.com>
---
 civicrm.php                 |  17 +++-
 includes/civicrm.compat.php | 154 ++++++++++++++++++++++++++++++++++++
 2 files changed, 170 insertions(+), 1 deletion(-)
 create mode 100644 includes/civicrm.compat.php

diff --git a/civicrm.php b/civicrm.php
index efe3a9e01e..08eadf7ef1 100644
--- a/civicrm.php
+++ b/civicrm.php
@@ -204,6 +204,15 @@ class CiviCRM_For_WordPress {
    */
   public $users;
 
+  /**
+   * Compatibility object.
+   *
+   * @since 5.24
+   * @access public
+   * @var object CiviCRM_For_WordPress_Compat The plugin compatibility object.
+   */
+  public $compat;
+
 
   // ---------------------------------------------------------------------------
   // Setup
@@ -527,6 +536,10 @@ class CiviCRM_For_WordPress {
     include_once CIVICRM_PLUGIN_DIR . 'includes/civicrm.basepage.php';
     $this->basepage = new CiviCRM_For_WordPress_Basepage;
 
+    // Include compatibility class
+    include_once CIVICRM_PLUGIN_DIR . 'includes/civicrm.compat.php';
+    $this->compat = new CiviCRM_For_WordPress_Compat;
+
     if ( ! class_exists( 'CiviCRM_WP_REST\Autoloader' ) ) {
       // Include REST API autoloader class
       require_once( CIVICRM_PLUGIN_DIR . 'wp-rest/Autoloader.php' );
@@ -813,10 +826,12 @@ class CiviCRM_For_WordPress {
      * Broadcast the rewrite rules event.
      *
      * @since 5.7
+     * @since 5.24 Added $basepage parameter.
      *
      * @param bool $flush_rewrite_rules True if rules flushed, false otherwise.
+     * @param WP_Post $basepage The Basepage post object.
      */
-    do_action( 'civicrm_after_rewrite_rules', $flush_rewrite_rules );
+    do_action( 'civicrm_after_rewrite_rules', $flush_rewrite_rules, $basepage );
 
   }
 
diff --git a/includes/civicrm.compat.php b/includes/civicrm.compat.php
new file mode 100644
index 0000000000..151761de7c
--- /dev/null
+++ b/includes/civicrm.compat.php
@@ -0,0 +1,154 @@
+<?php
+/*
+ +--------------------------------------------------------------------+
+ | Copyright CiviCRM LLC. All rights reserved.                        |
+ |                                                                    |
+ | This work is published under the GNU AGPLv3 license with some      |
+ | permitted exceptions and without any warranty. For full license    |
+ | and copyright information, see https://civicrm.org/licensing       |
+ +--------------------------------------------------------------------+
+*/
+
+/**
+ *
+ * @package CRM
+ * @copyright CiviCRM LLC https://civicrm.org/licensing
+ *
+ */
+
+
+// This file must not accessed directly
+if ( ! defined( 'ABSPATH' ) ) exit;
+
+
+/**
+ * Define CiviCRM_For_WordPress_Compat Class.
+ *
+ * @since 5.24
+ */
+class CiviCRM_For_WordPress_Compat {
+
+  /**
+   * Plugin object reference.
+   *
+   * @since 5.24
+   * @access public
+   * @var object $civi The plugin object reference.
+   */
+  public $civi;
+
+
+  /**
+   * Instance constructor.
+   *
+   * @since 5.24
+   */
+  public function __construct() {
+
+    // Store reference to CiviCRM plugin object.
+    $this->civi = civi_wp();
+
+    // Register plugin compatibility hooks.
+    $this->register_hooks();
+
+  }
+
+
+  /**
+   * Register plugin compatibility hooks.
+   *
+   * This is called via the constructor during the "plugins_loaded" action which
+   * is much earlier that CiviCRM's own internal hooks. The reason for this is
+   * that compability may need callbacks for events that fire well before "init"
+   * which is when CiviCRM begins to load.
+   *
+   * @since 5.24
+   */
+  public function register_hooks() {
+
+    // Bail if CiviCRM not installed yet.
+    if ( ! CIVICRM_INSTALLED ) {
+      return;
+    }
+
+    // Support Clean URLs when Polylang is active.
+    add_action( 'civicrm_after_rewrite_rules', array( $this, 'rewrite_rules_polylang' ), 10, 2 );
+
+  }
+
+
+  /**
+   * Support Polylang.
+   *
+   * @since 5.24
+   *
+   * @param bool $flush_rewrite_rules True if rules flushed, false otherwise.
+   * @param WP_Post $basepage The Basepage post object.
+   */
+  public function rewrite_rules_polylang( $flush_rewrite_rules, $basepage ) {
+
+    // Bail if Polylang is not present.
+    if (!function_exists('pll_languages_list')) {
+      return;
+    }
+
+    /*
+     * Collect all rewrite rules into an array.
+     *
+     * Because the array of specific Post IDs is added *after* the array of
+     * paths for the Basepage ID, those specific rewrite rules will "win" over
+     * the more general Basepage rules.
+     */
+    $collected_rewrites = [];
+
+    // Support prefixes for a single Basepage.
+    $basepage_url = get_permalink( $basepage->ID );
+    $basepage_raw_url = PLL()->links_model->remove_language_from_link( $basepage_url );
+    $language_slugs = pll_languages_list();
+    foreach ($language_slugs as $slug) {
+      $language = PLL()->model->get_language( $slug );
+      $language_url = PLL()->links_model->add_language_to_link( $basepage_raw_url, $language );
+      $parsed_url = wp_parse_url( $language_url, PHP_URL_PATH );
+      $regex_path = substr( $parsed_url, 1 );
+      $collected_rewrites[$basepage->ID][] = $regex_path;
+      $post_id = pll_get_post( $basepage->ID, $slug );
+      if (!empty($post_id)) {
+        $collected_rewrites[$post_id][] = $regex_path;
+      }
+    };
+
+    // Support prefixes for Basepages in multiple languages.
+    foreach ($language_slugs as $slug) {
+      $post_id = pll_get_post( $basepage->ID, $slug );
+      if (empty($post_id)) {
+        continue;
+      }
+      $url = get_permalink( $post_id );
+      $parsed_url = wp_parse_url( $url, PHP_URL_PATH );
+      $regex_path = substr( $parsed_url, 1 );
+      $collected_rewrites[$basepage->ID][] = $regex_path;
+      $collected_rewrites[$post_id][] = $regex_path;
+    };
+
+    // Make collection unique and add remaining rewrite rules.
+    $rewrites = array_map('array_unique', $collected_rewrites);
+    if (!empty($rewrites)) {
+      foreach ($rewrites as $post_id => $rewrite) {
+        foreach ($rewrite as $path) {
+          add_rewrite_rule(
+            '^' . $path . '([^?]*)?',
+            'index.php?page_id=' . $post_id . '&page=CiviCRM&q=civicrm%2F$matches[1]',
+            'top'
+          );
+        }
+      }
+    }
+
+    // Maybe force flush
+    if ($flush_rewrite_rules) {
+      flush_rewrite_rules();
+    }
+
+  }
+
+} // Class CiviCRM_For_WordPress_Compat ends
-- 
GitLab