Skip to content
Snippets Groups Projects
civicrm.admin.php 27.5 KiB
Newer Older
  • Learn to ignore specific revisions
  • Kevin Cristiano's avatar
    Kevin Cristiano committed
    <?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_Admin Class.
     *
     * @since 5.33
     */
    class CiviCRM_For_WordPress_Admin {
    
      /**
       * @var object
       * Plugin object reference.
       * @since 5.33
       * @access public
       */
      public $civi;
    
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
      /**
       * @var object
       * Settings page object.
       * @since 5.34
       * @access public
       */
      public $page_options;
    
      /**
       * @var object
       * Integration page object.
       * @since 5.34
       * @access public
       */
      public $page_integration;
    
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
      /**
       * @var object
       * Error Information page object.
       * @since 5.40
       * @access public
       */
      public $page_error;
    
      /**
       * @var string
       * Error handling flag to determine whether to show a troubleshooting page.
       * @since 5.40
       * @access public
       */
      public $error_flag = '';
    
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
      /**
       * @var object
       * Quick Add meta box object.
       * @since 5.34
       * @access public
       */
      public $metabox_quick_add;
    
    
      /**
       * @var string
       * Reference to the CiviCRM menu item's hook_suffix, in the WordPress admin menu.
       * @access public
       */
      public $menu_page;
    
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
      /**
       * Instance constructor.
       *
       * @since 5.33
       */
      public function __construct() {
    
        // Store reference to CiviCRM plugin object.
        $this->civi = civi_wp();
    
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
        // Include class files and instantiate.
        $this->include_files();
        $this->setup_objects();
    
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
        // Always check setting for path to "wp-load.php".
        add_action('civicrm_initialized', [$this, 'add_wpload_setting']);
    
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
        // Filter Heartbeat on CiviCRM admin pages as late as is practical.
        add_filter('heartbeat_settings', [$this, 'heartbeat'], 1000, 1);
    
      }
    
      /**
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
       * Include files.
       *
       * @since 5.34
       */
      public function include_files() {
    
        // Include class files.
        include_once CIVICRM_PLUGIN_DIR . 'includes/admin-pages/civicrm.page.options.php';
        include_once CIVICRM_PLUGIN_DIR . 'includes/admin-pages/civicrm.page.integration.php';
        include_once CIVICRM_PLUGIN_DIR . 'includes/admin-metaboxes/civicrm.metabox.contact.add.php';
    
      }
    
      /**
       * Instantiate objects.
       *
       * @since 5.34
       */
      public function setup_objects() {
    
        // Instantiate objects.
        $this->page_options = new CiviCRM_For_WordPress_Admin_Page_Options();
        $this->page_integration = new CiviCRM_For_WordPress_Admin_Page_Integration();
        $this->metabox_quick_add = new CiviCRM_For_WordPress_Admin_Metabox_Contact_Add();
    
      }
    
      /**
       * Register hooks on "init" action.
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
       *
       * @since 4.4
       * @since 5.33 Moved to this class.
       */
      public function register_hooks() {
    
        // Prevent auto-updates.
        add_filter('plugin_auto_update_setting_html', [$this, 'auto_update_prevent'], 10, 3);
    
        // Modify the admin menu.
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
        add_action('admin_menu', [$this, 'add_menu_items'], 9);
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
    
        // Add CiviCRM's resources in the admin header.
        add_action('admin_head', [$this->civi, 'wp_head'], 50);
    
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
        // If settings file does not exist.
        if (!CIVICRM_INSTALLED) {
    
          // Maybe show notice with link to installer.
          add_action('admin_notices', [$this, 'show_setup_warning']);
    
        }
        else {
    
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
          // Listen for changes to the Base Page setting.
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
          add_action('civicrm_postSave_civicrm_setting', [$this, 'settings_change'], 10);
    
          // Set page title.
          add_filter('admin_title', [$this, 'set_admin_title']);
    
        }
    
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
        /**
         * Broadcast that this object has registered its callbacks.
         *
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
         * Used internally by:
         *
         * - CiviCRM_For_WordPress_Admin_Metabox_Contact_Add::register_hooks()
         * - CiviCRM_For_WordPress_Admin_Page_Integration::register_hooks()
         * - CiviCRM_For_WordPress_Admin_Page_Options::register_hooks()
         *
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
         * @since 5.34
         */
        do_action('civicrm/admin/hooks/registered');
    
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
      }
    
      // ---------------------------------------------------------------------------
      // Installation
      // ---------------------------------------------------------------------------
    
      /**
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
       * Show an admin notice on pages other than the CiviCRM Installer.
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
       *
       * @since 4.4
       * @since 5.33 Moved to this class.
       */
      public function show_setup_warning() {
    
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
        // Check user permissions.
        if (!current_user_can('manage_options')) {
          return;
        }
    
        // Get current screen.
        $screen = get_current_screen();
    
        // Bail if it's not what we expect.
        if (!($screen instanceof WP_Screen)) {
          return;
        }
    
        // Bail if we are on our installer page.
    
        if ($screen->id === 'toplevel_page_civicrm-install') {
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
          return;
        }
    
        $message = sprintf(
    
          /* translators: 1: Opening strong tag, 2: Closing strong tag, 3: Opening anchor tag, 4: Closing anchor tag. */
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
          __('%1$sCiviCRM is almost ready.%2$s You must %3$sconfigure CiviCRM%4$s for it to work.', 'civicrm'),
          '<strong>',
          '</strong>',
          '<a href="' . menu_page_url('civicrm-install', FALSE) . '">',
          '</a>'
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
        );
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
    
        echo '<div id="message" class="notice notice-warning">';
        echo '<p>' . $message . '</p>';
        echo '</div>';
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
    
      }
    
      /**
       * Callback method for add_options_page() that runs the CiviCRM installer.
       *
       * @since 4.4
       */
      public function run_installer() {
    
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
        // Set install type.
    
        // phpcs:ignore WordPress.WP.CapitalPDangit.Misspelled
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
        $_GET['civicrm_install_type'] = 'wordpress';
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
    
        $civicrmCore = CIVICRM_PLUGIN_DIR . 'civicrm';
    
        $setupPaths = [
          implode(DIRECTORY_SEPARATOR, ['vendor', 'civicrm', 'civicrm-setup']),
          implode(DIRECTORY_SEPARATOR, ['packages', 'civicrm-setup']),
          implode(DIRECTORY_SEPARATOR, ['setup']),
        ];
    
        foreach ($setupPaths as $setupPath) {
    
          $loader = implode(DIRECTORY_SEPARATOR, [$civicrmCore, $setupPath, 'civicrm-setup-autoload.php']);
    
          if (file_exists($loader)) {
            require_once $loader;
            require_once implode(DIRECTORY_SEPARATOR, [$civicrmCore, 'CRM', 'Core', 'ClassLoader.php']);
            CRM_Core_ClassLoader::singleton()->register();
            \Civi\Setup::assertProtocolCompatibility(1.0);
            \Civi\Setup::init([
              'cms' => 'WordPress',
              'srcPath' => $civicrmCore,
            ]);
            $ctrl = \Civi\Setup::instance()->createController()->getCtrl();
            $ctrl->setUrls([
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
              'ctrl' => menu_page_url('civicrm-install', FALSE),
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
              'res' => CIVICRM_PLUGIN_URL . 'civicrm/' . strtr($setupPath, DIRECTORY_SEPARATOR, '/') . '/res/',
              'jquery.js' => CIVICRM_PLUGIN_URL . 'civicrm/bower_components/jquery/dist/jquery.min.js',
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
              'font-awesome.css' => CIVICRM_PLUGIN_URL . 'civicrm/bower_components/font-awesome/css/all.min.css',
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
              'finished' => admin_url('admin.php?page=CiviCRM&q=civicrm&reset=1'),
            ]);
            \Civi\Setup\BasicRunner::run($ctrl);
            return;
          }
    
        }
    
        wp_die(__('Installer unavailable. Failed to locate CiviCRM libraries.', 'civicrm'));
    
      }
    
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
      // ---------------------------------------------------------------------------
      // Pre-flight check
      // ---------------------------------------------------------------------------
    
      /**
       * Show an admin notice when the PHP version isn't sufficient.
       *
       * @since 5.40
       */
      public function show_php_warning() {
    
        // Check user permissions.
        if (!current_user_can('manage_options')) {
          return;
        }
    
        // Get current screen.
        $screen = get_current_screen();
    
        // Bail if it's not what we expect.
        if (!($screen instanceof WP_Screen)) {
          return;
        }
    
        // Bail if we are on our error page.
    
        if ($screen->id === 'toplevel_page_CiviCRM') {
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
          return;
        }
    
        $message = sprintf(
    
          /* translators: 1: Opening strong tag, 2: Closing strong tag, 3: Opening anchor tag, 4: Closing anchor tag. */
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
          __('%1$sCiviCRM needs your attention.%2$s Please visit the %3$sInformation Page%4$s for details.', 'civicrm'),
          '<strong>',
          '</strong>',
          '<a href="' . menu_page_url('CiviCRM', FALSE) . '">',
          '</a>'
        );
    
        echo '<div id="message" class="notice notice-warning">';
        echo '<p>' . $message . '</p>';
        echo '</div>';
    
      }
    
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
      /**
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
       * Check that the PHP version is supported.
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
       *
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
       * If not, show an admin notice and enable the Error Page instead of CiviCRM's
       * admin UI. This way WordPress is still usable while the issue is sorted out.
       *
       * This check is not necessary for fresh installs because we now have the
       * "Requires PHP:" plugin header. It is, however, necessary for upgrades - but
       * shouldn't render WordPress unusable.
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
       *
       * @since 5.18
       * @since 5.33 Moved to this class.
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
       *
       * @return bool True if the PHP version is supported, false otherwise.
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
       */
      protected function assert_php_support() {
    
        if (version_compare(PHP_VERSION, CIVICRM_WP_PHP_MINIMUM) < 0) {
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
          add_action('admin_notices', [$this, 'show_php_warning']);
          $this->error_flag = 'php-version';
          return FALSE;
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
        return TRUE;
    
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
      }
    
      // ---------------------------------------------------------------------------
      // Initialisation
      // ---------------------------------------------------------------------------
    
      /**
       * Initialize CiviCRM.
       *
       * @since 4.4
       *
       * @return bool $success True if CiviCRM is initialized, false otherwise.
       */
      public function initialize() {
    
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
        static $initialized = NULL;
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
    
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
        if (!is_null($initialized)) {
          return $initialized;
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
        /*
         * CiviCRM must not be initialized if it's not installed. It's okay to
         * return early because the admin notice will be displayed if, for some
         * reason, the initial redirect on install hasn't occured.
         */
        if (!CIVICRM_INSTALLED) {
          $this->error_flag = 'settings-missing';
          $initialized = FALSE;
          return FALSE;
        }
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
    
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
        // Check PHP version in case of upgrade.
        if (!$this->assert_php_support()) {
          $initialized = FALSE;
          return FALSE;
        }
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
    
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
        /*
         * Checks from this point on are for cases where the install has become
         * corrupted in some way. We are trying to fail as gracefully as we can.
         * Since CIVICRM_INSTALLED is set based on the presence of the settings
         * file, we now know it is there.
         */
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
    
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
        // Include settings file - returns int(1) on success.
        $error = include_once CIVICRM_SETTINGS_PATH;
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
    
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
        /*
         * Bail if the settings file returns something other than int(1).
         * When this happens, we should show an admin page with troubleshooting
         * instructions rather than dying and leaving WordPress unusable.
         *
         * Requires a page similar to "civicrm.page.options.php", which we can
         * show instead of "invoking" CiviCRM itself. In order to do that, this
         * method *must* have been called before "add_menu_items()" so that an
         * alternative "add_menu_page()" call can be made. Usefully, this already
         * happens because "register_hooks_clean_urls()" is called first.
         *
         * However, it looks like there may be little that can be done to mitigate
         * path errors - e.g. when $civicrm_root is not set correctly - because
         * including "civicrm.settings.php" will throw a fatal error if $civicrm_root
         * is wrong.
         */
    
        if ($error === FALSE) {
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
          $this->error_flag = 'settings-include';
          $initialized = FALSE;
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
          return FALSE;
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
        }
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
    
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
        // Initialize the Class Loader.
        require_once CIVICRM_PLUGIN_DIR . 'civicrm/CRM/Core/ClassLoader.php';
        CRM_Core_ClassLoader::singleton()->register();
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
    
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
        // Access global defined in "civicrm.settings.php".
        global $civicrm_root;
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
    
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
        // Bail if the config file isn't found.
        if (!file_exists($civicrm_root . 'CRM/Core/Config.php')) {
          $this->error_flag = 'config-missing';
          $initialized = FALSE;
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
          return FALSE;
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
        }
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
    
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
        // Include config file - returns int(1) on success.
        $error = include_once 'CRM/Core/Config.php';
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
    
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
        // Bail if the config file returns something other than int(1).
    
        if ($error === FALSE) {
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
          $this->error_flag = 'config-include';
          $initialized = FALSE;
          return FALSE;
        }
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
    
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
        // Initialize the system by creating a config object.
        $config = CRM_Core_Config::singleton();
    
        // Sync the logged-in WordPress user with CiviCRM.
        global $current_user;
        if ($current_user) {
    
          // Sync procedure sets session values for logged in users.
          require_once 'CRM/Core/BAO/UFMatch.php';
          CRM_Core_BAO_UFMatch::synchronize(
            // User object.
            $current_user,
            // Do not update.
            FALSE,
            // CMS.
            'WordPress',
            $this->civi->users->get_civicrm_contact_type('Individual')
          );
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
        // Success! Set static flag.
        $initialized = TRUE;
    
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
        /**
         * Broadcast that CiviCRM is now initialized.
         *
         * @since 4.4
         */
        do_action('civicrm_initialized');
    
        return $initialized;
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
    
      }
    
      /**
       * Slow down the frequency of WordPress heartbeat calls.
       *
       * Heartbeat is important to WordPress for a number of tasks - e.g. checking
       * continued authentication whilst on a page - but it does consume server
       * resources. Reducing the frequency of calls minimises the impact on servers
       * and can make CiviCRM more responsive.
       *
       * @since 5.29
       * @since 5.33 Moved to this class.
       *
       * @param array $settings The existing heartbeat settings.
       * @return array $settings The modified heartbeat settings.
       */
      public function heartbeat($settings) {
    
        // Access script identifier.
        global $pagenow;
    
        // Bail if not admin.
        if (!is_admin()) {
          return $settings;
        }
    
        // Process the requested URL.
        $requested_url = filter_input(INPUT_SERVER, 'REQUEST_URI', FILTER_SANITIZE_URL);
        if ($requested_url) {
          $current_url = wp_unslash($requested_url);
        }
        else {
          $current_url = admin_url();
        }
        $current_screen = wp_parse_url($current_url);
    
        // Bail if entry is missing for some reason.
        if (!isset($current_screen['query'])) {
          return $settings;
        }
    
        // Bail if this is not CiviCRM admin.
    
        if ($pagenow !== 'admin.php' || FALSE === strpos($current_screen['query'], 'page=CiviCRM')) {
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
          return $settings;
        }
    
        // Defer to any previously set value, but only if it's greater than ours.
        if (!empty($settings['interval']) && intval($settings['interval']) > 120) {
          return $settings;
        }
    
        // Slow down heartbeat.
        $settings['interval'] = 120;
    
        return $settings;
    
      }
    
      /**
       * Force rewrite rules to be recreated.
       *
       * When CiviCRM settings are saved, the method is called post-save. It checks
       * if it's the WordPress Base Page setting that has been saved and causes all
       * rewrite rules to be flushed on the next page load.
       *
       * @since 5.14
       * @since 5.33 Moved to this class.
       *
       * @param obj $dao The CiviCRM database access object.
       */
      public function settings_change($dao) {
    
        // Delete the option if conditions are met.
        if ($dao instanceof CRM_Core_DAO_Setting) {
    
          if (isset($dao->name) && $dao->name === 'wpBasePage') {
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
            delete_option('civicrm_rules_flushed');
          }
        }
    
      }
    
      /**
       * Prevent auto-updates of this plugin in WordPress 5.5.
       *
       * @link https://make.wordpress.org/core/2020/07/15/controlling-plugin-and-theme-auto-updates-ui-in-wordpress-5-5/
       *
       * @since 5.28
       * @since 5.33 Moved to this class.
    
       *
       * @param string $html The auto-update markup.
       * @param string $plugin_file The path to the plugin.
       * @param array $plugin_data An array of plugin data.
       * @return string $html The modified auto-update markup.
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
       */
      public function auto_update_prevent($html, $plugin_file, $plugin_data) {
    
        // Test for this plugin.
        $this_plugin = plugin_basename(dirname(CIVICRM_PLUGIN_FILE) . '/civicrm.php');
        if ($this_plugin === $plugin_file) {
          $html = __('Auto-updates are not available for this plugin.', 'civicrm');
        }
    
        // --<
        return $html;
    
      }
    
      /**
       * Add CiviCRM's title to the header's <title> tag.
       *
       * @since 4.6
       *
       * @param string $title The title to set.
       * @return string The computed title.
       */
      public function set_admin_title($title) {
        global $civicrm_wp_title;
        if (!$civicrm_wp_title) {
          return $title;
        }
        // Replace 1st occurance of "CiviCRM" in the title.
        $pos = strpos($title, 'CiviCRM');
        if ($pos !== FALSE) {
          return substr_replace($title, $civicrm_wp_title, $pos, 7);
        }
        return $civicrm_wp_title;
      }
    
      /**
       * Adds menu items to WordPress admin menu.
       *
       * Callback method for 'admin_menu' hook as set in register_hooks().
       *
       * @since 4.4
       */
      public function add_menu_items() {
    
    
        // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
        $civilogo = file_get_contents(CIVICRM_PLUGIN_DIR . 'assets/images/civilogo.svg.b64');
    
    
        global $wp_version;
        if (version_compare($wp_version, '5.9.9999', '>')) {
          $menu_position = 3;
        }
        else {
          $menu_position = '3.904981';
        }
    
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
        /**
         * Filter the position of the CiviCRM menu item.
         *
    
         * As per the code above, the position was previously set to '3.904981' to
         * reduce risk of conflicts. The position is now conditionally set depending
         * on the version of WordPress.
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
         *
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
         * @since 4.4
         * @since 5.47 Conditionally set because WordPress 6.0 enforces integers.
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
         *
    
         * @param str|int $menu_position The default menu position.
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
         */
    
        $position = apply_filters('civicrm_menu_item_position', $menu_position);
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
    
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
        // Try and initialize CiviCRM.
        $success = $this->initialize();
    
        // If all went well.
        if ($success) {
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
    
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
          // Add the CiviCRM top level menu item.
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
          $this->menu_page = add_menu_page(
            __('CiviCRM', 'civicrm'),
            __('CiviCRM', 'civicrm'),
            'access_civicrm',
            'CiviCRM',
            [$this->civi, 'invoke'],
            $civilogo,
            $position
          );
    
          // Add core resources prior to page load.
          add_action('load-' . $this->menu_page, [$this, 'admin_page_load']);
    
        }
        else {
    
          /*
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
           * Are we here because this is a fresh install or because something is broken?
           *
           * Let's inspect the "error_flag" property for help with the decision. Where
           * the settings file is missing, there's not a lot we can do, so assume it's
           * a fresh install.
           *
           * However, we may be able to detect signs of installs where CiviCRM has been
           * installed but "civicrm.settings.php" can't be found.
           *
           * @see self::detect_existing_install()
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
           */
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
          if ($this->error_flag === 'settings-missing') {
    
            // Add top level menu item.
            $this->menu_page = add_menu_page(
              __('CiviCRM Installer', 'civicrm'),
              __('CiviCRM Installer', 'civicrm'),
              'manage_options',
              'civicrm-install',
              [$this, 'run_installer'],
              $civilogo,
              $position
            );
    
            /*
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
             * Add scripts and styles like this if needed:
             *
             * add_action('admin_print_scripts-' . $this->menu_page, [$this, 'admin_installer_js']);
             * add_action('admin_print_styles-' . $this->menu_page, [$this, 'admin_installer_css']);
             * add_action('admin_head-' . $this->menu_page, [$this, 'admin_installer_head'], 50);
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
             */
    
          }
          else {
    
            // Hand over to our Error Page to provide feedback.
            $this->page_error_init($civilogo, $position);
    
          }
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
      /**
       * Try and detect signs of the existence of CiviCRM.
       *
       * It's possible that CiviCRM has been installed but that something is broken
       * with the current install. This method looks for tell-tale signs.
       *
       * This is not used as yet, but is included as-is to be completed later.
       *
       * @since 5.40
       *
       * @return bool $existing_install True if there are signs of an existing install.
       */
      public function detect_existing_install() {
    
        // Assume there's no evidence.
        $existing_install = FALSE;
    
        // This option is created on activation.
        $existing_option = FALSE;
    
        if ('fjwlws' !== get_option('civicrm_activation_in_progress', 'fjwlws')) {
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
          $existing_option = TRUE;
        }
    
        // Look for a directory in the standard location.
        $existing_uploads_dir = FALSE;
        $upload_dir = wp_upload_dir();
        if (is_dir($upload_dir['basedir'] . DIRECTORY_SEPARATOR . 'civicrm')) {
          $existing_uploads_dir = TRUE;
        }
    
        // Look for a file in the legacy location.
        $existing_legacy_file = FALSE;
        if (file_exists(CIVICRM_PLUGIN_DIR . 'civicrm.settings.php')) {
          $existing_legacy_file = TRUE;
        }
    
        return $existing_install;
    
      }
    
      /**
       * Show Error Information page.
       *
       * In situations where something has gone wrong with the CiviCRM installation,
       * show a page which will help people troubleshoot the problem.
       *
       * @since 5.40
       *
       * @param str $logo The CiviCRM logo.
       * @param str $position The default menu position expressed as a float.
       */
      public function page_error_init($logo, $position) {
    
        // Include and init Error Page.
        include_once CIVICRM_PLUGIN_DIR . 'includes/admin-pages/civicrm.page.error.php';
        $this->page_error = new CiviCRM_For_WordPress_Admin_Page_Error($logo, $position);
    
      }
    
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
      /**
       * Perform necessary stuff prior to CiviCRM's admin page being loaded.
       *
       * @since 4.6
       * @since 5.33 Moved to this class.
       */
      public function admin_page_load() {
    
        // This is required for AJAX calls in WordPress admin.
        $_REQUEST['noheader'] = $_GET['noheader'] = TRUE;
    
        // Add resources for back end.
        $this->civi->add_core_resources(FALSE);
    
      }
    
      /**
       * When CiviCRM is loaded in WordPress Admin, check for the existence of a
       * setting which holds the path to wp-load.php. This is the only reliable way
       * to bootstrap WordPress from CiviCRM.
       *
       * CMW: I'm not entirely happy with this approach, because the value will be
       * different for different installs (e.g. when a dev site is migrated to live)
       * A better approach would be to store this setting in civicrm.settings.php as
       * a constant, but doing that involves a complicated process of getting a new
       * setting registered in the installer.
       *
       * Also, it needs to be decided whether this value should be tied to a CiviCRM
       * 'domain', since a single CiviCRM install could potentially be used by a
       * number of WordPress installs. This is not relevant to its use in WordPress
       * Multisite, because the path to wp-load.php is common to all sites on the
       * network.
       *
       * To get the path to wp-load.php, use:
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
       * $path = Civi::settings()->get('wpLoadPhp');
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
       *
       * @since 4.6.3
       * @since 5.33 Moved to this class.
       */
      public function add_wpload_setting() {
    
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
        if (!CIVICRM_INSTALLED) {
          return;
        }
    
        if (!$this->initialize()) {
          return;
        }
    
        if (version_compare(CRM_Core_BAO_Domain::getDomain()->version, '4.7.0', '<')) {
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
          return;
        }
    
        // Get path to wp-load.php.
        $path = ABSPATH . 'wp-load.php';
    
        // Get the setting, if it exists.
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
        $setting = Civi::settings()->get('wpLoadPhp');
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
    
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
        /*
         * If we don't have a setting, create it. Also set it if it's different to
         * what's stored. This could be because we've changed server or location.
         */
        if (empty($setting) || $setting !== $path) {
          Civi::settings()->set('wpLoadPhp', $path);
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
      /**
       * Get a CiviCRM admin link.
       *
       * @since 5.34
       *
       * @param str $path The CiviCRM path.
       * @param str $params The CiviCRM parameters.
       * @return string $link The URL of the CiviCRM page.
       */
      public function get_admin_link($path = '', $params = NULL) {
    
        // Init link.
        $link = '';
    
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
        if (!$this->initialize()) {
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
          return $link;
        }
    
        // Use CiviCRM to construct link.
        $link = CRM_Utils_System::url(
          $path,
          $params,
          TRUE,
          NULL,
          TRUE,
          FALSE,
          TRUE
        );
    
        // --<
        return $link;
    
      }
    
      /**
       * Clear CiviCRM caches.
       *
       * Another way to do this might be:
       * CRM_Core_Invoke::rebuildMenuAndCaches(TRUE);
       *
       * @since 5.34
       */
      public function clear_caches() {
    
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
        if (!$this->initialize()) {
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
          return;
        }
    
        // Access config object.
        $config = CRM_Core_Config::singleton();
    
        // Clear database cache.
        $config->clearDBCache();
    
        // Cleanup the "templates_c" directory.
        $config->cleanup(1, TRUE);
    
        // Cleanup the session object.
        $session = CRM_Core_Session::singleton();
        $session->reset(1);
    
        // Call system flush.
        CRM_Utils_System::flushCache();
    
      }
    
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
      /**
       * Gets a suggested CiviCRM Contact ID via the "Unsupervised" Dedupe Rule.
       *
       * @since 5.43
       *
       * @param array $contact The array of CiviCRM Contact data.
       * @param string $contact_type The Contact Type.
       * @return integer|bool $contact_id The suggested Contact ID, or false on failure.
       */
      public function get_by_dedupe_unsupervised($contact, $contact_type = 'Individual') {
    
        if (empty($contact)) {
          return FALSE;
        }
    
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
        if (!$this->initialize()) {
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
          return FALSE;
        }
    
        // Get the Dedupe params.
        $dedupe_params = CRM_Dedupe_Finder::formatParams($contact, $contact_type);
        $dedupe_params['check_permission'] = FALSE;
    
        // Use Dedupe Rules to find possible Contact IDs.
        $contact_ids = CRM_Dedupe_Finder::dupesByParams($dedupe_params, $contact_type, 'Unsupervised');
    
        // Return the suggested Contact ID if present.
        $contact_id = 0;
        if (!empty($contact_ids)) {
          $contact_ids = array_reverse($contact_ids);
          $contact_id = (int) array_pop($contact_ids);
        }
    
        // --<
        return $contact_id;
    
      }
    
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
      /**
       * Gets the CiviCRM Shortcode Mode.
       *
       * Defaults to "legacy" to preserve existing behaviour.
       *
       * @since 5.44
       *
       * @return string $shortcode_mode The Shortcode Mode: either 'legacy' or 'modern'.
       */
      public function get_shortcode_mode() {
        return get_option('civicrm_shortcode_mode', 'legacy');
      }
    
      /**
       * Sets the CiviCRM Shortcode Mode.
       *
       * @since 5.44
       *
       * @param string $shortcode_mode The Shortcode Mode: either 'legacy' or 'modern'.
       */
      public function set_shortcode_mode($shortcode_mode) {
        update_option('civicrm_shortcode_mode', $shortcode_mode);
      }
    
      /**
       * Gets the array of CiviCRM Shortcode Modes.
       *
       * @since 5.44
       *
       * @return array $shortcode_modes The array of Shortcode Modes.
       */
      public function get_shortcode_modes() {
        return ['legacy', 'modern'];
      }
    
    
    Kevin Cristiano's avatar
    Kevin Cristiano committed
      /**
       * Gets the CiviCRM Shortcode Theme Compatibility Mode.
       *
       * Defaults to "loop" to preserve existing behaviour.
       *
       * @since 5.80
       *
       * @return string $theme_compatibility_mode The Shortcode Theme Compatibility Mode: either 'loop' or 'filter'.
       */
      public function get_theme_compatibility_mode() {
        return get_option('civicrm_theme_compatibility_mode', 'loop');
      }
    
      /**
       * Sets the CiviCRM Shortcode Theme Compatibility Mode.
       *
       * @since 5.80
       *
       * @param string $theme_compatibility_mode The Shortcode Theme Compatibility Mode: either 'loop' or 'filter'.
       */
      public function set_theme_compatibility_mode($theme_compatibility_mode) {
        update_option('civicrm_theme_compatibility_mode', $theme_compatibility_mode);
      }
    
      /**
       * Gets the array of CiviCRM Shortcode Theme Compatibility Modes.
       *
       * @since 5.80