← All audits

Audit #11 Benign

MainWP Child – Securely Connects to the MainWP Dashboard to Manage Multiple Sites · 700k+ installs · baseline 5.1 → head 5.1.1 · suspect committer thanghoang · by austin · closed 10d ago

Show full summary

Who made the change. Committer thanghoang pushed their first commit to this plugin on 2024-07-09, when their WordPress.org account was only 12 days old (created 2024-06-27). New-account commits on established plugins are the supply-chain-attack signature WP Beacon watches for.

What changed. Version 5.1.1 is the first release under the suspect committer; version 5.1 was the last known-clean release before them. The diff adds roughly 2,444 lines of code, mostly in class/class-mainwp-backup.php, class/class-mainwp-child-actions.php, class/class-mainwp-child-api-backups.php and 1 other file.

Why it's flagged. The metadata event fired (new committer on a young account against an established plugin), but a code-level scan of the head version did not surface any built-in malicious patterns. Human review is still warranted — sophisticated payloads can evade signature matches.

Exposure. At the time of audit, mainwp-child had 700,000 active installations. The plugin is still live on wordpress.org, so the code under review is currently being downloaded by sites.

Investigated — no compromise found.

Audit retained for the record. No action required.

Plugins under the same committer's SVN access

thanghoang holds push access to 4 plugins totalling 825k+ active installs. Each non-target plugin scans clean today but represents a one-commit hijack opportunity.

MainWP Child Reports — clean code, same SVN account (latent risk)
100k+
MainWP Dashboard: Self-hosted WordPress Management for Agencies — clean code, same SVN account (latent risk)
20k+
MainWP Key Maker — clean code, same SVN account (latent risk)
5k+

Plugin version history

Every release on wp.org for this plugin, color-coded by relationship to the incident. The compromise window shows where the wp.org Plugin Review Team deleted the malicious tags from SVN — those versions cannot be re-downloaded today.

  1. Clean 68 earlier releases before the incident
    • 3.4.6
    • 3.4.7
    • 3.4.7.1
    • 3.4.8
    • 3.4.9
    • 3.5
    • 3.5.1
    • 3.5.2
    • 3.5.3
    • 3.5.4
    • 3.5.4.1
    • 3.5.5
    • 3.5.6
    • 3.5.7
    • 4.0
    • 4.0.1
    • 4.0.2
    • 4.0.3
    • 4.0.4
    • 4.0.5
    • 4.0.5.1
    • 4.0.6
    • 4.0.6.1
    • 4.0.6.2
    • 4.0.7
    • 4.0.7.1
    • 4.0.7.2
    • 4.1
    • 4.1.1
    • 4.1.2
    • 4.1.3
    • 4.1.3.1
    • 4.1.4
    • 4.1.5
    • 4.1.6
    • 4.1.6.1
    • 4.1.7
    • 4.1.7.1
    • 4.1.8
    • 4.1.9
    • 4.1.10
    • 4.2
    • 4.2.1
    • 4.2.2
    • 4.2.3
    • 4.2.4
    • 4.2.5
    • 4.2.6
    • 4.3
    • 4.3.0.1
    • 4.3.1
    • 4.4
    • 4.4.0.1
    • 4.4.0.2
    • 4.4.0.3
    • 4.4.0.4
    • 4.4.1
    • 4.4.1.1
    • 4.4.1.2
    • 4.4.1.3
    • 4.5
    • 4.5.1
    • 4.5.2
    • 4.5.3
    • 4.6
    • 5.0
    • 5.0.1
    • 5.0.1.1
  2. 5.1 Last clean Last clean release before incident
  3. 🛑 Compromise window 28 days · 2024-06-18 → 2024-07-16

    Malicious releases pushed during this window were deleted from SVN by the wp.org Plugin Review Team. Last malicious tag: 5.1.1.

  4. 5.1.1 PRT cleanup PRT cleanup release — incident closed
  5. 5.2 Clean Clean (post-cleanup)
  6. 5.2.1 Clean Clean (post-cleanup)
  7. 5.3 Clean Clean (post-cleanup)
  8. 5.3.1 Clean Clean (post-cleanup)
  9. 5.3.2 Clean Clean (post-cleanup)
  10. 5.3.3 Clean Clean (post-cleanup)
  11. 5.3.4 Clean Clean (post-cleanup)
  12. 5.3.5 Clean Clean (post-cleanup)
  13. 5.4 Clean Clean (post-cleanup)
  14. 5.4.0.1 Clean Clean (post-cleanup)
  15. 5.4.0.2 Clean Clean (post-cleanup)
  16. 5.4.0.3 Clean Clean (post-cleanup)
  17. 5.4.0.4 Clean Clean (post-cleanup)
  18. 5.4.0.5 Clean Clean (post-cleanup)
  19. 5.4.0.6 Clean Clean (post-cleanup)
  20. 5.4.0.7 Clean Clean (post-cleanup)
  21. 5.4.0.8 Clean Clean (post-cleanup)
  22. 5.4.0.9 Clean Clean (post-cleanup)
  23. 5.4.0.10 Clean Clean (post-cleanup)
  24. 5.4.0.11 Clean Clean (post-cleanup)
  25. 5.4.0.12 Clean Clean (post-cleanup)
  26. 5.4.0.13 Clean Clean (post-cleanup)
  27. 5.4.0.14 Clean Clean (post-cleanup)
  28. 5.4.0.15 Clean Clean (post-cleanup)
  29. 5.4.1 Clean Clean (post-cleanup)
  30. 6.0 Clean Clean (post-cleanup)
  31. 6.0.1 Clean Clean (post-cleanup)
  32. 6.0.2 Clean Clean (post-cleanup)
  33. 6.0.3 Clean Clean (post-cleanup)
  34. 6.0.4 Clean Clean (post-cleanup)
  35. 6.0.5 Clean Clean (post-cleanup)
  36. 6.0.6 Clean Clean (post-cleanup)
  37. 6.0.7 Clean Clean (post-cleanup)
  38. 6.0.8 Clean Clean (post-cleanup)
  39. 6.0.9 Clean Clean (post-cleanup)
  40. 6.0.10 Current Current release

Audit #11 — mainwp-child

  • Plugin: mainwp-child (MainWP Child – Securely Connects to the MainWP Dashboard to Manage Multiple Sites)
  • Active installs: 700,000
  • Event: #115 new_committer_young_account · critical · 2026-04-22 02:50:47
  • Suspect committer: thanghoang (member since 2024-06-27)
  • First commit on this plugin: 2024-07-09 16:51:02
  • Baseline version: 5.1
  • Head version: 5.1.1
  • Working dir: /tmp/wpbeacon-audits/audit-11

Summary

Who made the change. Committer thanghoang pushed their first commit to this plugin on 2024-07-09, when their WordPress.org account was only 12 days old (created 2024-06-27). New-account commits on established plugins are the supply-chain-attack signature WP Beacon watches for.

What changed. Version 5.1.1 is the first release under the suspect committer; version 5.1 was the last known-clean release before them. The diff adds roughly 2,444 lines of code, mostly in class/class-mainwp-backup.php, class/class-mainwp-child-actions.php, class/class-mainwp-child-api-backups.php and 1 other file.

Why it's flagged. The metadata event fired (new committer on a young account against an established plugin), but a code-level scan of the head version did not surface any built-in malicious patterns. Human review is still warranted — sophisticated payloads can evade signature matches.

Exposure. At the time of audit, mainwp-child had 700,000 active installations. The plugin is still live on wordpress.org, so the code under review is currently being downloaded by sites.

This summary was auto-generated from the scan findings. Edit it freely —
whatever sits under this header at finalize time is what gets stored as audits.summary
and shown at the top of the audit page.

Verdict

benign

Legitimate team onboarding. The mainwp official account stopped committing 2024-06-18; thanghoang took over 2024-07-09 and has pushed 92 commits over 22 months with weekly release cadence. 2,444-line diff concentrated in core class-mainwp-child-* files (backup, DB updates, Jetpack/iThemes integration). Zero suspicious pattern hits. External URLs point only to legitimate destinations (developer.wordpress.org, mainwp.com, ithemes.com). exec(mysqldump ...) and base64_decode(wp_unslash($_POST[...])) have phpcs:ignore comments explaining their role in MainWP's backup/dashboard protocol. MainWP is a Vietnamese-owned company; a Vietnamese-named developer joining their team is consistent with their hiring.

Added files (0)

_No new files between baseline and head._

Suspicious pattern hits (0)

_No matches against built-in patterns or known IOCs._

IOCs to extract

List any indicators found. One per line in the format:
- kind: <domain|url|code_pattern|file_hash|filename|changelog_phrase>, value: <string>, confidence: <high|medium|low>
These get parsed and inserted into wp_wpbeacon_iocs by wp beacon audit finalize.

Full diff

diff -rNu /tmp/wpbeacon-audits/audit-11/baseline/class/class-mainwp-backup.php /tmp/wpbeacon-audits/audit-11/head/class/class-mainwp-backup.php
--- /tmp/wpbeacon-audits/audit-11/baseline/class/class-mainwp-backup.php	2024-06-18 08:24:10
+++ /tmp/wpbeacon-audits/audit-11/head/class/class-mainwp-backup.php	2024-07-09 12:51:02
@@ -1,1341 +1,1341 @@
-<?php
-/**
- * MainWP Backup
- *
- * This file handles all Child Site backup functions.
- *
- * @package MainWP\Child
- */
-
-namespace MainWP\Child;
-
-//phpcs:disable WordPress.WP.AlternativeFunctions, Generic.Metrics.CyclomaticComplexity -- Current complexity is the only way to achieve desired results, pull request solutions appreciated.
-
-/**
- * Class MainWP_Backup
- *
- * Handle all Child Site backup functions.
- */
-class MainWP_Backup {
-
-    /**
-     * Whether to exclude zip archives.
-     *
-     * @var bool true|false
-     */
-    protected $excludeZip;
-
-    /**
-     * Container for zip file.
-     *
-     * @var resource ZIP file
-     */
-    protected $zip;
-
-    /**
-     * Backup files count.
-     *
-     * @var int Files count.
-     */
-    protected $zipArchiveFileCount;
-
-    /**
-     * Backup archive file size.
-     *
-     * @var float File size.
-     */
-    protected $zipArchiveSizeCount;
-
-    /**
-     * Backup archive file name.
-     *
-     * @var string File name.
-     */
-    protected $zipArchiveFileName;
-
-    /**
-     * Backup file descriptors.
-     *
-     * @var int File descriptors.
-     */
-    protected $file_descriptors;
-
-    /**
-     * Whether to load file before zip.
-     *
-     * @var bool true|false
-     */
-    protected $loadFilesBeforeZip;
-
-    /**
-     * Hold the current timeout length.
-     *
-     * @var int Timeout length.
-     */
-    protected $timeout;
-
-    /**
-     * Last time a backup has been run.
-     *
-     * @var string Last backup run.
-     */
-    protected $lastRun;
-
-    /**
-     * Garbage collection count.
-     *
-     * @var int Garbage collection count.
-     */
-    protected $gcCnt = 0;
-
-    /**
-     * Archive test content.
-     *
-     * @var bool Test backup content.
-     */
-    protected $testContent;
-
-    /**
-     * Backup process archiver.
-     *
-     * @var object Backup process archiver.
-     */
-    protected $archiver = null;
-
-    /**
-     * Protected static variable to hold the single instance of the class.
-     *
-     * @var mixed Default null
-     */
-    protected static $instance = null;
-
-    /**
-     * Create a public static instance.
-     *
-     * @return mixed Class instance.
-     */
-    public static function get() {
-        if ( null === self::$instance ) {
-            self::$instance = new self();
-        }
-        return self::$instance;
-    }
-
-    /**
-     * Create full backup.
-     *
-     * @param array  $excludes           Files to exclude from the backup.
-     * @param string $filePrefix         Backup archive file prefix.
-     * @param bool   $addConfig          Add config file to backup.
-     * @param bool   $includeCoreFiles   Include WordPress core files.
-     * @param int    $file_descriptors   Number of backup archive file descriptors.
-     * @param bool   $fileSuffix         Backup archive file suffix.
-     * @param bool   $excludezip         Exclude zip files from the backup.
-     * @param bool   $excludenonwp       Exclude non-WordPress directories in site root.
-     * @param bool   $loadFilesBeforeZip Load files before zip.
-     * @param string $ext                Backup file extension.
-     * @param bool   $pid                PID true|false.
-     * @param bool   $append             Append to backup file name.
-     *
-     * @return array|bool Action results on success, false on failure.
-     *
-     * @used-by MainWP_Backup::backup_full()
-     *
-     * @uses \MainWP\Child\Tar_Archiver()
-     * @uses \MainWP\Child\MainWP_Helper::get_mainwp_dir()
-     * @uses \MainWP\Child\MainWP_Helper::instance()->error()
-     * @uses \MainWP\Child\MainWP_Helper::set_limit()
-     */
-    public function create_full_backup(
-        $excludes,
-        $filePrefix = '',
-        $addConfig = false,
-        $includeCoreFiles = false,
-        $file_descriptors = 0,
-        $fileSuffix = false,
-        $excludezip = false,
-        $excludenonwp = false,
-        $loadFilesBeforeZip = true,
-        $ext = 'zip',
-        $pid = false,
-        $append = false
-    ) {
-
-        $this->file_descriptors   = $file_descriptors;
-        $this->loadFilesBeforeZip = $loadFilesBeforeZip;
-
-        $dirs      = MainWP_Helper::get_mainwp_dir( 'backup' );
-        $backupdir = $dirs[0];
-        if ( ! defined( 'PCLZIP_TEMPORARY_DIR' ) ) {
-
-            /**
-             * Defines PCLZIP temporary directory.
-             *
-             * @const ( string ) Temporary backup directory.
-             * @source https://code-reference.mainwp.com/classes/MainWP.Child.MainWP_Backup.html
-             */
-            define( 'PCLZIP_TEMPORARY_DIR', $backupdir );
-        }
-
-        if ( false !== $pid ) {
-            $pid = trailingslashit( $backupdir ) . 'backup-' . $pid . '.pid';
-        }
-
-        // Verify if another backup is running, if so, return an error.
-        $files = glob( $backupdir . '*.pid' );
-        foreach ( $files as $file ) {
-            if ( basename( $file ) === basename( $pid ) ) {
-                continue;
-            }
-
-            if ( ( time() - filemtime( $file ) ) < 160 ) {
-                MainWP_Helper::instance()->error( esc_html__( 'Another backup process is running. Please, try again later.', 'mainwp-child' ) );
-            }
-        }
-
-        $timestamp = time();
-        if ( '' !== $filePrefix ) {
-            $filePrefix .= '-';
-        }
-
-        if ( 'zip' === $ext ) {
-            $this->archiver = null;
-            $ext            = '.zip';
-        } else {
-            $this->archiver = new Tar_Archiver( $this, $ext, $pid );
-            $ext            = $this->archiver->get_extension();
-        }
-
-        if ( ( false !== $fileSuffix ) && ! empty( $fileSuffix ) ) {
-            // Append already contains extension!
-            $file = $fileSuffix . ( true === $append ? '' : $ext );
-        } else {
-            $file = 'backup-' . $filePrefix . $timestamp . $ext;
-        }
-        $filepath = $backupdir . $file;
-        $fileurl  = $file;
-
-        if ( ! $addConfig ) {
-            if ( ! in_array( str_replace( ABSPATH, '', WP_CONTENT_DIR ), $excludes, true ) && ! in_array( 'wp-admin', $excludes, true ) && ! in_array( WPINC, $excludes, true ) ) {
-                $addConfig        = true;
-                $includeCoreFiles = true;
-            }
-        }
-
-        $this->timeout = 20 * 60 * 60;
-        $mem           = '512M';
-        MainWP_Helper::set_limit( $this->timeout, $mem );
-
-        if ( null !== $this->archiver ) {
-            $success = $this->archiver->create_full_backup( $filepath, $excludes, $addConfig, $includeCoreFiles, $excludezip, $excludenonwp, $append );
-        } elseif ( $this->check_zip_support() ) {
-            $success = $this->create_zip_full_backup( $filepath, $excludes, $addConfig, $includeCoreFiles, $excludezip, $excludenonwp );
-        } elseif ( $this->check_zip_console() ) {
-            $success = $this->create_zip_console_full_backup(); // NOSONAR .
-        } else {
-            $success = $this->create_zip_pcl_full_backup2( $filepath, $excludes, $addConfig, $includeCoreFiles, $excludezip, $excludenonwp );
-        }
-
-        return ( $success ) ? array(
-            'timestamp' => $timestamp,
-            'file'      => $fileurl,
-            'filesize'  => filesize( $filepath ), // NOSONAR .
-        ) : false;
-    }
-
-    /**
-     * Check whether the file is an archive or not & create a json_encoded, serialized, base64_encoded string.
-     *
-     * @uses \MainWP\Child\MainWP_Helper::write() Write response data to be sent to the MainWP Dashboard.
-     * @uses \MainWP\Child\MainWP_Helper::get_mainwp_dir() Get the MainWP directory.
-     * @uses \MainWP\Child\MainWP_Clone::is_archive()
-     */
-    public function backup_poll() {
-        // phpcs:disable WordPress.Security.NonceVerification
-        $fileNameUID = isset( $_POST['fileNameUID'] ) ? sanitize_text_field( wp_unslash( $_POST['fileNameUID'] ) ) : '';
-        $fileName    = isset( $_POST['fileName'] ) ? sanitize_text_field( wp_unslash( $_POST['fileName'] ) ) : '';
-        $type        = isset( $_POST['type'] ) ? sanitize_text_field( wp_unslash( $_POST['type'] ) ) : '';
-        // phpcs:enable WordPress.Security.NonceVerification
-        if ( 'full' === $type ) {
-            if ( '' !== $fileName ) {
-                $backupFile = $fileName;
-            } else {
-                $backupFile = 'backup-' . $fileNameUID . '-';
-            }
-
-            $dirs      = MainWP_Helper::get_mainwp_dir( 'backup' );
-            $backupdir = $dirs[0];
-            $result    = glob( $backupdir . $backupFile . '*' ); // NOSONAR .
-
-            // Check if archive, set $archiveFile = $file & break.
-            $archiveFile = false;
-            foreach ( $result as $file ) {
-                if ( MainWP_Clone::is_archive( $file, $backupFile, '(.*)' ) ) {
-                    $archiveFile = $file;
-                    break;
-                }
-            }
-
-            // When not an archive.
-            if ( false === $archiveFile ) {
-                MainWP_Helper::write( array() );
-            }
-
-            // When archive found.
-            MainWP_Helper::write( array( 'size' => filesize( $archiveFile ) ) );
-        } else {
-            // When not an archive.
-            $backupFile = 'dbBackup-' . $fileNameUID . '-*.sql.php';
-            $dirs       = MainWP_Helper::get_mainwp_dir( 'backup' );
-            $backupdir  = $dirs[0];
-            $result     = glob( $backupdir . $backupFile . '*' ); // NOSONAR .
-
-            if ( 0 === count( $result ) ) {
-                MainWP_Helper::write( array() );
-            }
-
-            $size = 0;
-            foreach ( $result as $f ) {
-                $size += filesize( $f );
-            }
-            MainWP_Helper::write( array( 'size' => $size ) );
-            exit();
-        }
-    }
-
-    /**
-     * Check if backup already exists or is in the process of backing up.
-     *
-     * @uses MainWP_Helper::write() Write response data to be sent to the MainWP Dashboard.
-     * @uses MainWP_Helper::get_mainwp_dir() Get the MainWP directory.
-     * @uses MainWP_Helper::get_wp_filesystem() Get the WordPress filesystem.
-     *
-     * @uses WP_Filesystem_Base::is_file() Checks if resource is a file.
-     * @see https://developer.wordpress.org/reference/classes/wp_filesystem_base/is_file/
-     *
-     * @uses WP_Filesystem_Base::mtime() Gets the file modification time.
-     * @see https://developer.wordpress.org/reference/classes/wp_filesystem_base/mtime/
-     *
-     * @uses WP_Filesystem_Base::get_contents() Reads entire file into a string.
-     * @see https://developer.wordpress.org/reference/classes/wp_filesystem_base/get_contents/
-     */
-    public function backup_checkpid() {
-        // phpcs:disable WordPress.Security.NonceVerification
-        $pid = isset( $_POST['pid'] ) ? sanitize_text_field( wp_unslash( $_POST['pid'] ) ) : 0;
-        // phpcs:enable WordPress.Security.NonceVerification
-        $dirs      = MainWP_Helper::get_mainwp_dir( 'backup' );
-        $backupdir = $dirs[0];
-
-        $information = array();
-
-        /**
-         * WordPress files system object.
-         *
-         * @global object
-         */
-        global $wp_filesystem;
-
-        MainWP_Helper::get_wp_filesystem();
-
-        $pidFile  = trailingslashit( $backupdir ) . 'backup-' . $pid . '.pid';
-        $doneFile = trailingslashit( $backupdir ) . 'backup-' . $pid . '.done';
-        if ( $wp_filesystem->is_file( $pidFile ) ) {
-            $time = $wp_filesystem->mtime( $pidFile );
-
-            $minutes = date( 'i', time() ); // phpcs:ignore -- required to achieve desired results, pull request solutions appreciated.
-            $seconds = date( 's', time() ); // phpcs:ignore -- required to achieve desired results, pull request solutions appreciated.
-
-            $file_minutes = date( 'i', $time ); // phpcs:ignore -- required to achieve desired results, pull request solutions appreciated.
-            $file_seconds = date( 's', $time ); // phpcs:ignore -- required to achieve desired results, pull request solutions appreciated.
-
-            $minuteDiff = $minutes - $file_minutes;
-            if ( 59 === $minuteDiff ) {
-                $minuteDiff = 1;
-            }
-            $secondsdiff = ( $minuteDiff * 60 ) + $seconds - $file_seconds;
-
-            $file                = $wp_filesystem->get_contents( $pidFile );
-            $information['file'] = basename( $file );
-            if ( $secondsdiff < 80 ) {
-                $information['status'] = 'busy';
-            } else {
-                $information['status'] = 'stalled';
-            }
-        } elseif ( $wp_filesystem->is_file( $doneFile ) ) {
-            $file                  = $wp_filesystem->get_contents( $doneFile );
-            $information['status'] = 'done';
-            $information['file']   = basename( $file );
-            $information['size']   = filesize( $file );
-        } else {
-            $information['status'] = 'invalid';
-        }
-
-        MainWP_Helper::write( $information );
-    }
-
-    /**
-     * Perform a backup.
-     *
-     * @param bool $write Whether or not to execute MainWP_Helper::write(), Default: true.
-     *
-     * @return array Array of information on the backup containing the type of backup performed, full, or DB & whether or not it was successful.
-     *
-     * @uses \MainWP\Child\MainWP_Helper::set_limit() Set PHP Memory Limit and PHP Max Execution time values.
-     * @uses \MainWP\Child\MainWP_Helper::end_session() End session and flush the output buffer.
-     * @uses \MainWP\Child\MainWP_Helper::get_wp_filesystem() Get the WordPress filesystem.
-     * @uses \MainWP\Child\MainWP_Helper::ends_with() Check if the String 1 ends with the String 2.
-     * @uses \MainWP\Child\MainWP_Helper::write() Write response data to be sent to the MainWP Dashboard.
-     * @uses \MainWP\Child\MainWP_Backup::backup_full() Perform a full backup.
-     * @uses \MainWP\Child\MainWP_Helper::set_limit()
-     * @uses \MainWP\Child\MainWP_Helper::end_session()
-     * @uses \MainWP\Child\MainWP_Helper::get_mainwp_dir()
-     * @uses \MainWP\Child\MainWP_Helper::get_wp_filesystem()
-     * @uses \MainWP\Child\MainWP_Helper::ends_with()
-     * @uses \MainWP\Child\MainWP_Helper::write()
-     */
-    public function backup( $write = true ) {
-
-        $timeout = 20 * 60 * 60;
-        MainWP_Helper::set_limit( $timeout );
-
-        MainWP_Helper::end_session();
-
-        // Cleanup pid files!
-        $dirs      = MainWP_Helper::get_mainwp_dir( 'backup' );
-        $backupdir = trailingslashit( $dirs[0] );
-
-        /**
-         * WordPress files system object.
-         *
-         * @global object
-         */
-        global $wp_filesystem;
-
-        MainWP_Helper::get_wp_filesystem();
-
-        $files = glob( $backupdir . '*' );
-        foreach ( $files as $file ) {
-            if ( MainWP_Helper::ends_with( $file, '/index.php' ) | MainWP_Helper::ends_with( $file, '/.htaccess' ) ) {
-                continue;
-            }
-
-            if ( ( time() - filemtime( $file ) ) > ( 60 * 60 * 3 ) ) {
-                wp_delete_file( $file );
-            }
-        }
-
-        // phpcs:disable WordPress.Security.NonceVerification
-        $fileName = isset( $_POST['fileUID'] ) ? sanitize_text_field( wp_unslash( $_POST['fileUID'] ) ) : '';
-        $type     = isset( $_POST['type'] ) ? sanitize_text_field( wp_unslash( $_POST['type'] ) ) : '';
-
-        if ( 'full' === $type ) {
-
-            $res = $this->backup_full( $fileName );
-
-            if ( ! $res ) {
-                $information['full'] = false;
-            } else {
-                $information['full'] = $res['file'];
-                $information['size'] = $res['filesize'];
-            }
-            $information['db'] = false;
-        } elseif ( 'db' === $type ) {
-            $ext = isset( $_POST['ext'] ) ? sanitize_text_field( wp_unslash( $_POST['ext'] ) ) : 'zip';
-            $res = $this->backup_db( $fileName, $ext );
-            if ( ! $res ) {
-                $information['db'] = false;
-            } else {
-                $information['db']   = $res['file'];
-                $information['size'] = $res['filesize'];
-            }
-            $information['full'] = false;
-        } else {
-            $information['full'] = false;
-            $information['db']   = false;
-        }
-
-        if ( $write ) {
-            MainWP_Helper::write( $information );
-        }
-        // phpcs:enable WordPress.Security.NonceVerification
-        return $information;
-    }
-
-    /**
-     * Perform a full backup.
-     *
-     * @param string $fileName Backup archive file name.
-     *
-     * @return array|bool Returns an array containing the Backup location & file size. Return FALSE on failure.
-     *
-     * @uses \MainWP\Child\MainWP_Backup::create_full_backup() Create full backup.
-     * @uses \MainWP\Child\MainWP_Helper::get_mainwp_dir()
-     */
-    public function backup_full( $fileName ) { //phpcs:ignore -- complex method.
-        // phpcs:disable WordPress.Security.NonceVerification
-        $excludes   = ( isset( $_POST['exclude'] ) ? explode( ',', wp_unslash( $_POST['exclude'] ) ) : array() ); //phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- ok.
-        $excludes[] = str_replace( ABSPATH, '', WP_CONTENT_DIR ) . '/uploads/mainwp';
-        $uploadDir  = MainWP_Helper::get_mainwp_dir();
-        $uploadDir  = $uploadDir[0];
-        $excludes[] = str_replace( ABSPATH, '', $uploadDir );
-        $excludes[] = str_replace( ABSPATH, '', WP_CONTENT_DIR ) . '/object-cache.php';
-
-        if ( function_exists( 'posix_uname' ) ) {
-            $uname = posix_uname();
-            if ( is_array( $uname ) && isset( $uname['nodename'] ) ) {
-                if ( stristr( $uname['nodename'], 'hostgator' ) ) {
-                    if ( ! isset( $_POST['file_descriptors'] ) || '0' === $_POST['file_descriptors'] || $_POST['file_descriptors'] > 1000 ) {
-                        $_POST['file_descriptors'] = 1000;
-                    }
-                    $_POST['file_descriptors_auto'] = 0;
-                    $_POST['loadFilesBeforeZip']    = false;
-                }
-            }
-        }
-
-        $file_descriptors      = ( isset( $_POST['file_descriptors'] ) ? intval( wp_unslash( $_POST['file_descriptors'] ) ) : 0 );
-        $file_descriptors_auto = ( isset( $_POST['file_descriptors_auto'] ) ? intval( wp_unslash( $_POST['file_descriptors_auto'] ) ) : 0 );
-        if ( 1 === (int) $file_descriptors_auto ) {
-            if ( function_exists( 'posix_getrlimit' ) ) {
-                $result = posix_getrlimit();
-                if ( isset( $result['soft openfiles'] ) ) {
-                    $file_descriptors = $result['soft openfiles'];
-                }
-            }
-        }
-
-        $loadFilesBeforeZip = ( isset( $_POST['loadFilesBeforeZip'] ) ? sanitize_text_field( wp_unslash( $_POST['loadFilesBeforeZip'] ) ) : true );
-
-        $newExcludes = array();
-        foreach ( $excludes as $exclude ) {
-            $newExcludes[] = sanitize_text_field( rtrim( $exclude, '/' ) );
-        }
-
-        $excludebackup = ( isset( $_POST['excludebackup'] ) && '1' === $_POST['excludebackup'] );
-        $excludecache  = ( isset( $_POST['excludecache'] ) && '1' === $_POST['excludecache'] );
-        $excludezip    = ( isset( $_POST['excludezip'] ) && '1' === $_POST['excludezip'] );
-        $excludenonwp  = ( isset( $_POST['excludenonwp'] ) && '1' === $_POST['excludenonwp'] );
-
-        if ( $excludebackup ) {
-            $newExcludes[] = str_replace( ABSPATH, '', WP_CONTENT_DIR ) . '/uploads/backupbuddy_backups';
-            $newExcludes[] = str_replace( ABSPATH, '', WP_CONTENT_DIR ) . '/uploads/backupbuddy_temp';
-            $newExcludes[] = str_replace( ABSPATH, '', WP_CONTENT_DIR ) . '/uploads/pb_backupbuddy';
-            $newExcludes[] = str_replace( ABSPATH, '', WP_CONTENT_DIR ) . '/managewp';
-            $newExcludes[] = str_replace( ABSPATH, '', WP_CONTENT_DIR ) . '/infinitewp';
-            $newExcludes[] = str_replace( ABSPATH, '', WP_CONTENT_DIR ) . '/backups';
-            $newExcludes[] = str_replace( ABSPATH, '', WP_CONTENT_DIR ) . '/backups';
-            $newExcludes[] = str_replace( ABSPATH, '', WP_CONTENT_DIR ) . '/uploads/backwpup*';
-            $newExcludes[] = str_replace( ABSPATH, '', WP_CONTENT_DIR ) . '/plugins/wp-complete-backup/storage';
-            $newExcludes[] = str_replace( ABSPATH, '', WP_CONTENT_DIR ) . '/backups';
-            $newExcludes[] = '/administrator/backups';
-        }
-
-        if ( $excludecache ) {
-            $newExcludes[] = str_replace( ABSPATH, '', WP_CONTENT_DIR ) . '/w3tc-cache';
-            $newExcludes[] = str_replace( ABSPATH, '', WP_CONTENT_DIR ) . '/w3tc';
-            $newExcludes[] = str_replace( ABSPATH, '', WP_CONTENT_DIR ) . '/cache/config';
-            $newExcludes[] = str_replace( ABSPATH, '', WP_CONTENT_DIR ) . '/cache/minify';
-            $newExcludes[] = str_replace( ABSPATH, '', WP_CONTENT_DIR ) . '/cache/page_enhanced';
-            $newExcludes[] = str_replace( ABSPATH, '', WP_CONTENT_DIR ) . '/cache/tmp';
-            $newExcludes[] = str_replace( ABSPATH, '', WP_CONTENT_DIR ) . '/cache/supercache';
-            $newExcludes[] = str_replace( ABSPATH, '', WP_CONTENT_DIR ) . '/cache/quick-cache';
-            $newExcludes[] = str_replace( ABSPATH, '', WP_CONTENT_DIR ) . '/hyper-cache/cache';
-            $newExcludes[] = str_replace( ABSPATH, '', WP_CONTENT_DIR ) . '/cache/all';
-            $newExcludes[] = str_replace( ABSPATH, '', WP_CONTENT_DIR ) . '/cache/wp-rocket';
-        }
-
-        $file = false;
-        if ( isset( $_POST['f'] ) ) {
-            $file = ! empty( $_POST['f'] ) ? sanitize_text_field( wp_unslash( $_POST['f'] ) ) : false;
-        } elseif ( isset( $_POST['file'] ) ) {
-            $file = ! empty( $_POST['file'] ) ? sanitize_text_field( wp_unslash( $_POST['file'] ) ) : false;
-        }
-
-        $ext = isset( $_POST['ext'] ) ? sanitize_text_field( wp_unslash( $_POST['ext'] ) ) : 'zip';
-        $pid = isset( $_POST['pid'] ) ? sanitize_text_field( wp_unslash( $_POST['pid'] ) ) : false;
-
-        $append = ( isset( $_POST['append'] ) && ( '1' === $_POST['append'] ) );
-        // phpcs:enable WordPress.Security.NonceVerification
-        return $this->create_full_backup( $newExcludes, $fileName, true, true, $file_descriptors, $file, $excludezip, $excludenonwp, $loadFilesBeforeZip, $ext, $pid, $append );
-    }
-
-    /**
-     * Backup site database.
-     *
-     * @param string $fileName Backup arhive file name.
-     * @param string $ext      Backup achive extension.
-     *
-     * @uses \MainWP\Child\MainWP_Helper::update_option() Update database option by option name.
-     * @uses \MainWP\Child\MainWP_Helper::get_mainwp_dir() Get the MainWP directory.
-     * @uses \MainWP\Child\MainWP_Backup::create_backup_db() Create database backup.
-     *
-     * @return array|bool $success Returns an array containing the Backup location & file size. Return FALSE on failure.
-     */
-    public function backup_db( $fileName = '', $ext = 'zip' ) {
-        $dirs      = MainWP_Helper::get_mainwp_dir( 'backup' );
-        $dir       = $dirs[0];
-        $timestamp = time();
-
-        if ( '' !== $fileName ) {
-            $fileName .= '-';
-        }
-
-        $filepath_prefix = $dir . 'dbBackup-' . $fileName . $timestamp;
-
-        $dh = opendir( $dir );
-
-        if ( $dh ) {
-            while ( ( $file = readdir( $dh ) ) !== false ) {
-                if ( '.' !== $file && '..' !== $file && ( preg_match( '/dbBackup-(.*).sql(\.zip|\.tar|\.tar\.gz|\.tar\.bz2|\.tmp)?$/', $file ) ) ) {
-                    wp_delete_file( $dir . $file );
-                }
-                if ( '.' !== $file && '..' !== $file && ( preg_match( '/dbBackup-(.*).sql.php(\.zip|\.tar|\.tar\.gz|\.tar\.bz2|\.tmp)?$/', $file ) ) ) {
-                    wp_delete_file( $dir . $file );
-                }
-            }
-            closedir( $dh );
-        }
-
-        // $ext !== false, the fuction will return in format: array( 'filepath' => $filepath );.
-        $result = $this->create_backup_db( $filepath_prefix, $ext );
-
-        MainWP_Helper::update_option( 'mainwp_child_last_db_backup_size', filesize( $result['filepath'] ) ); // NOSONAR .
-
-        return ( ! $result ) ? false : array(
-            'timestamp' => $timestamp,
-            'file'      => basename( $result['filepath'] ),
-            'filesize'  => filesize( $result['filepath'] ), // NOSONAR .
-        );
-    }
-
-    /**
-     * Create the ZIP file.
-     *
-     * @param array  $files Files to zip.
-     * @param string $archive Type of archive to create.
-     *
-     * @return bool Return FALSE on failure, TRUE on success.
-     *
-     * @uses \MainWP\Child\MainWP_Helper::set_limit() Set PHP memory limit.
-     */
-    public function zip_file( $files, $archive ) {
-        $this->timeout = 20 * 60 * 60;
-        $mem           = '512M';
-        MainWP_Helper::set_limit( $this->timeout, $mem );
-
-        if ( ! is_array( $files ) ) {
-            $files = array( $files );
-        }
-
-        if ( null !== $this->archiver ) {
-            $success = $this->archiver->zip_file( $files, $archive );
-        } elseif ( $this->check_zip_support() ) {
-            $success = $this->m_zip_file( $files, $archive );
-        } elseif ( $this->check_zip_console() ) {
-            $success = $this->m_zip_file_console( $files, $archive );
-        } else {
-            $success = $this->m_zip_file_pcl( $files, $archive );
-        }
-
-        return $success;
-    }
-
-    /**
-     * Create m_zip_file.
-     *
-     * @param array  $files   Files to zip.
-     * @param string $archive Type of archive to create.
-     *
-     * @return bool Return false on failure.
-     */
-    public function m_zip_file( $files, $archive ) {
-        $this->zip                 = new \ZipArchive();
-        $this->zipArchiveFileCount = 0;
-        $this->zipArchiveSizeCount = 0;
-
-        $zipRes = $this->zip->open( $archive, \ZipArchive::CREATE );
-        if ( $zipRes ) {
-            foreach ( $files as $file ) {
-                $this->add_file_to_zipp( $file, basename( $file ) );
-            }
-
-            return $this->zip->close();
-        }
-
-        return false;
-    }
-
-    /**
-     * Method m_zip_file_console().
-     *
-     * @return bool Return false.
-     */
-    public function m_zip_file_console() {
-        return false;
-    }
-
-    /**
-     * Use pclzip to add files to the zip archive.
-     *
-     * @param array  $files   Files to zip.
-     * @param string $archive Type of archive to create.
-     *
-     * @return array $rslt Return array of results.
-     */
-    public function m_zip_file_pcl( $files, $archive ) {
-        // Zip this backup folder.
-        require_once ABSPATH . 'wp-admin/includes/class-pclzip.php';
-        $this->zip = new \PclZip( $archive );
-
-        $error = false;
-        foreach ( $files as $file ) {
-            $rslt = $this->zip->add( $file, PCLZIP_OPT_REMOVE_PATH, dirname( $file ) );
-            if ( empty( $rslt ) ) {
-                $error = true;
-            }
-        }
-
-        return ! $error;
-    }
-
-    /**
-     * Check for default PHP zip support.
-     *
-     * @return bool Returns true if class_name is a defined class, false otherwise.
-     */
-    public function check_zip_support() {
-        return class_exists( '\ZipArchive' );
-    }
-
-    /**
-     * Check if we could run zip on console
-     *
-     * @return bool Return false.
-     */
-    public function check_zip_console() {
-        return false;
-    }
-
-    /**
-     * Create full backup using default PHP zip library.
-     *
-     * @param string $filepath           File path to create.
-     * @param array  $excludes           Files to exclude from the backup.
-     * @param bool   $addConfig          Add config file to backup.
-     * @param bool   $includeCoreFiles   Include WordPress core files.
-     * @param bool   $excludezip         Exclude zip files from the backup.
-     * @param bool   $excludenonwp       Exclude non-WordPress directories in site root.
-     *
-     * @uses \MainWP\Child\MainWP_Helper::starts_with() Check if the String 1 starts with the String 2.
-     * @uses \MainWP\Child\MainWP_Helper::in_excludes() Check if the value is in the excludes list.
-     * @uses \MainWP\Child\MainWP_Backup::include_core_files() Include core files in backup.
-     * @uses \MainWP\Child\MainWP_Backup::add_config() Add config file to backup.
-     *
-     * @return bool Return true on success & false on failure.
-     */
-    public function create_zip_full_backup(
-        $filepath,
-        $excludes,
-        $addConfig,
-        $includeCoreFiles,
-        $excludezip,
-        $excludenonwp
-    ) {
-
-        $this->excludeZip          = $excludezip;
-        $this->zip                 = new \ZipArchive();
-        $this->zipArchiveFileCount = 0;
-        $this->zipArchiveSizeCount = 0;
-        $this->zipArchiveFileName  = $filepath;
-        $zipRes                    = $this->zip->open( $filepath, \ZipArchive::CREATE );
-        if ( $zipRes ) {
-            $nodes = glob( ABSPATH . '*' );
-            if ( ! $includeCoreFiles ) {
-                $this->include_core_files( $nodes );
-            }
-
-            $db_files = $this->create_backup_db( dirname( $filepath ) . DIRECTORY_SEPARATOR . 'dbBackup' );
-            foreach ( $db_files as $db_file ) {
-                $this->add_file_to_zipp( $db_file, basename( WP_CONTENT_DIR ) . '/' . basename( $db_file ) );
-            }
-
-            if ( file_exists( ABSPATH . '.htaccess' ) ) {
-                $this->add_file_to_zipp( ABSPATH . '.htaccess', 'mainwp-htaccess' );
-            }
-
-            foreach ( $nodes as $node ) {
-                if ( $excludenonwp && is_dir( $node ) ) {
-                    if ( ! MainWP_Helper::starts_with( $node, WP_CONTENT_DIR ) && ! MainWP_Helper::starts_with( $node, ABSPATH . 'wp-admin' ) && ! MainWP_Helper::starts_with( $node, ABSPATH . WPINC ) ) {
-                        continue;
-                    }
-                }
-
-                if ( ! MainWP_Helper::in_excludes( $excludes, str_replace( ABSPATH, '', $node ) ) ) {
-                    if ( is_dir( $node ) ) {
-                        $this->zip_add_dir( $node, $excludes );
-                    } elseif ( is_file( $node ) ) {
-                        $this->add_file_to_zipp( $node, str_replace( ABSPATH, '', $node ) );
-                    }
-                }
-            }
-
-            if ( $addConfig ) {
-                $this->add_config();
-            }
-
-            $return = $this->zip->close();
-            foreach ( $db_files as $db_file ) {
-                wp_delete_file( $db_file ); // NOSONAR .
-            }
-
-            return true;
-        }
-
-        return false;
-    }
-
-    /**
-     * Exclude certain core files from the backup.
-     *
-     * @param array $nodes Default nodes.
-     *
-     * @uses \MainWP\Child\MainWP_Helper::starts_with() Check if the String 1 starts with the String 2.
-     */
-    private function include_core_files( &$nodes ) {
-        $coreFiles = array(
-            'favicon.ico',
-            'index.php',
-            'license.txt',
-            'readme.html',
-            'wp-activate.php',
-            'wp-app.php',
-            'wp-blog-header.php',
-            'wp-comments-post.php',
-            'wp-config.php',
-            'wp-config-sample.php',
-            'wp-cron.php',
-            'wp-links-opml.php',
-            'wp-load.php',
-            'wp-login.php',
-            'wp-mail.php',
-            'wp-pass.php',
-            'wp-register.php',
-            'wp-settings.php',
-            'wp-signup.php',
-            'wp-trackback.php',
-            'xmlrpc.php',
-        );
-        foreach ( $nodes as $key => $node ) {
-            if ( MainWP_Helper::starts_with( $node, ABSPATH . WPINC ) ) {
-                unset( $nodes[ $key ] );
-            } elseif ( MainWP_Helper::starts_with( $node, ABSPATH . basename( admin_url( '' ) ) ) ) {
-                unset( $nodes[ $key ] );
-            } else {
-                foreach ( $coreFiles as $coreFile ) {
-                    if ( ABSPATH . $coreFile === $node ) {
-                        unset( $nodes[ $key ] );
-                    }
-                }
-            }
-        }
-        unset( $coreFiles );
-    }
-
-    /**
-     * Add config file to backup.
-     *
-     * @uses wp_json_encode() Encode a variable into JSON, with some sanity checks.
-     * @see https://developer.wordpress.org/reference/functions/wp_json_encode/
-     *
-     * @uses get_option() Get option by name.
-     * @see https://developer.wordpress.org/reference/functions/get_option/
-     */
-    public function add_config() {
-
-        /**
-         * WordPress Database instance.
-         *
-         * @global object $wpdb
-         */
-        global $wpdb;
-
-        $plugins = array();
-        $dir     = WP_CONTENT_DIR . '/plugins/';
-        $fh      = opendir( $dir );
-        while ( $entry = readdir( $fh ) ) {
-            if ( ! is_dir( $dir . $entry ) ) {
-                continue;
-            }
-            if ( ( '.' === $entry ) || ( '..' === $entry ) ) {
-                continue;
-            }
-            $plugins[] = $entry;
-        }
-        closedir( $fh );
-
-        $themes = array();
-        $dir    = WP_CONTENT_DIR . '/themes/';
-        $fh     = opendir( $dir );
-        while ( $entry = readdir( $fh ) ) {
-            if ( ! is_dir( $dir . $entry ) ) {
-                continue;
-            }
-            if ( ( '.' === $entry ) || ( '..' === $entry ) ) {
-                continue;
-            }
-            $themes[] = $entry;
-        }
-        closedir( $fh );
-        $string = wp_json_encode(
-            array(
-                'siteurl' => get_option( 'siteurl' ),
-                'home'    => get_option( 'home' ),
-                'abspath' => ABSPATH,
-                'prefix'  => $wpdb->prefix,
-                'lang'    => defined( 'WPLANG' ) ? WPLANG : '',
-                'plugins' => $plugins,
-                'themes'  => $themes,
-            )
-        );
-        $this->add_file_from_string_to_zip( 'clone/config.txt', $string );
-    }
-
-    /**
-     * Copy directory.
-     *
-     * @param array  $nodes        Default nodes.
-     * @param array  $excludes     Files & directories to exclude.
-     * @param string $backupfolder Backup folder.
-     * @param bool   $excludenonwp Whether or not to exclude any wp core files.
-     *
-     * @uses \MainWP\Child\MainWP_Helper::starts_with() Check if the String 1 starts with the String 2.
-     * @uses \MainWP\Child\MainWP_Helper::in_excludes() Check if the value is in the excludes list.
-     * @uses \MainWP\Child\MainWP_Helper::ends_with() Check if the String 1 ends with the String 2.
-     */
-    public function copy_dir( $nodes, $excludes, $backupfolder, $excludenonwp ) {
-        if ( ! is_array( $nodes ) ) {
-            return;
-        }
-
-        foreach ( $nodes as $node ) {
-            if ( $excludenonwp && is_dir( $node ) ) {
-                if ( ! MainWP_Helper::starts_with( $node, WP_CONTENT_DIR ) && ! MainWP_Helper::starts_with( $node, ABSPATH . 'wp-admin' ) && ! MainWP_Helper::starts_with( $node, ABSPATH . WPINC ) ) {
-                    continue;
-                }
-            }
-
-            if ( ! MainWP_Helper::in_excludes( $excludes, str_replace( ABSPATH, '', $node ) ) ) {
-                if ( is_dir( $node ) ) {
-                    if ( ! file_exists( str_replace( ABSPATH, $backupfolder, $node ) ) ) {
-                        mkdir( str_replace( ABSPATH, $backupfolder, $node ) ); // phpcs:ignore -- required to achieve desired results. Pull requests appreciated.
-                    }
-
-                    $newnodes = glob( $node . DIRECTORY_SEPARATOR . '*' );
-                    $this->copy_dir( $newnodes, $excludes, $backupfolder, $excludenonwp, false );
-                    unset( $newnodes );
-                } elseif ( is_file( $node ) ) {
-                    if ( $this->excludeZip && MainWP_Helper::ends_with( $node, '.zip' ) ) {
-                        continue;
-                    }
-
-                    copy( $node, str_replace( ABSPATH, $backupfolder, $node ) ); // phpcs:ignore -- required to achieve desired results. Pull requests appreciated - // NOSONAR .
-                }
-            }
-        }
-    }
-
-    /**
-     * Create PCL zip full backup 2.
-     *
-     * @param string $filepath         Path to file.
-     * @param array  $excludes         Files & directories to exclude.
-     * @param bool   $addConfig        Add config file to backup.
-     * @param bool   $includeCoreFiles Whether to include core files.
-     * @param bool   $excludezip       Whether to exclude zip archives.
-     * @param bool   $excludenonwp     Whether or not to exclude any wp core files.
-     *
-     * @return bool Return true on success.
-     *
-     * @uses \MainWP\Child\MainWP_Helper::delete_dir() Delete wanted directory.
-     * @uses \MainWP\Child\MainWP_Helper::starts_with() Check if the String 1 starts with the String 2.
-     * @uses \MainWP\Child\MainWP_Backup::create_backup_db() Create database backup.
-     * @uses \MainWP\Child\MainWP_Backup::add_file_from_string_to_pcl_zip() Add file from a string to pclzip file.
-     *
-     * @uses wp_json_encode() Encode a variable into JSON, with some sanity checks.
-     * @see https://developer.wordpress.org/reference/functions/wp_json_encode/
-     *
-     * @uses get_option() Get option by name.
-     * @see https://developer.wordpress.org/reference/functions/get_option/
-     */
-    public function create_zip_pcl_full_backup2( $filepath, $excludes, $addConfig, $includeCoreFiles, $excludezip, $excludenonwp ) {
-        // Create backup folder.
-        $backupFolder = dirname( $filepath ) . DIRECTORY_SEPARATOR . 'backup' . DIRECTORY_SEPARATOR;
-
-        mkdir( $backupFolder ); // phpcs:ignore -- required to achieve desired results. Pull requests appreciated.
-
-        // Create DB backup.
-        $db_files = $this->create_backup_db( $backupFolder . 'dbBackup' );
-
-        // Copy installation to backup folder.
-        $nodes = glob( ABSPATH . '*' );
-        if ( ! $includeCoreFiles ) {
-            $coreFiles = array(
-                'favicon.ico',
-                'index.php',
-                'license.txt',
-                'readme.html',
-                'wp-activate.php',
-                'wp-app.php',
-                'wp-blog-header.php',
-                'wp-comments-post.php',
-                'wp-config.php',
-                'wp-config-sample.php',
-                'wp-cron.php',
-                'wp-links-opml.php',
-                'wp-load.php',
-                'wp-login.php',
-                'wp-mail.php',
-                'wp-pass.php',
-                'wp-register.php',
-                'wp-settings.php',
-                'wp-signup.php',
-                'wp-trackback.php',
-                'xmlrpc.php',
-            );
-            foreach ( $nodes as $key => $node ) {
-                if ( MainWP_Helper::starts_with( $node, ABSPATH . WPINC ) ) {
-                    unset( $nodes[ $key ] );
-                } elseif ( MainWP_Helper::starts_with( $node, ABSPATH . basename( admin_url( '' ) ) ) ) {
-                    unset( $nodes[ $key ] );
-                } else {
-                    foreach ( $coreFiles as $coreFile ) {
-                        if ( ABSPATH . $coreFile === $node ) {
-                            unset( $nodes[ $key ] );
-                        }
-                    }
-                }
-            }
-            unset( $coreFiles );
-        }
-        $this->copy_dir( $nodes, $excludes, $backupFolder, $excludenonwp, true );
-
-        foreach ( $db_files as $db_file ) {
-            copy( $db_file, $backupFolder . basename( WP_CONTENT_DIR ) . '/' . basename( $db_file ) ); // phpcs:ignore -- required to achieve desired results. Pull requests appreciated // NOSONAR .
-            wp_delete_file( $db_file ); // phpcs:ignore -- required to achieve desired results. Pull requests appreciated // NOSONAR.
-        }
-
-        unset( $nodes );
-
-        // Zip this backup folder.
-        require_once ABSPATH . 'wp-admin/includes/class-pclzip.php';
-        $this->zip = new \PclZip( $filepath );
-        $this->zip->create( $backupFolder, PCLZIP_OPT_REMOVE_PATH, $backupFolder );
-        if ( $addConfig ) {
-
-            /**
-             * WordPress Database instance.
-             *
-             * @global object $wpdb
-             */
-            global $wpdb;
-
-            $string = wp_json_encode(
-                array(
-                    'siteurl' => get_option( 'siteurl' ),
-                    'home'    => get_option( 'home' ),
-                    'abspath' => ABSPATH,
-                    'prefix'  => $wpdb->prefix,
-                    'lang'    => WPLANG,
-                )
-            );
-
-            $this->add_file_from_string_to_pcl_zip( 'clone/config.txt', $string, $filepath );
-        }
-        // Remove backup folder.
-        MainWP_Helper::delete_dir( $backupFolder );
-
-        return true;
-    }
-
-    /**
-     * Recursively add directory to default PHP zip library.
-     *
-     * @param string $path     Path to directory.
-     * @param array  $excludes Files or directories to exclude.
-     *
-     * @uses \MainWP\Child\MainWP_Helper::in_excludes() Check if the value is in the excludes list.
-     */
-    public function zip_add_dir( $path, $excludes ) {
-
-        if ( $this->zip instanceof \ZipArchive ) {
-            $this->zip->addEmptyDir( str_replace( ABSPATH, '', $path ) );
-        } else {
-            $this->zip->add_empty_dir( str_replace( ABSPATH, '', $path ) );
-        }
-
-        if ( file_exists( rtrim( $path, '/' ) . '/.htaccess' ) ) {
-            $this->add_file_to_zipp( rtrim( $path, '/' ) . '/.htaccess', rtrim( str_replace( ABSPATH, '', $path ), '/' ) . '/mainwp-htaccess' );
-        }
-
-        $iterator = new \RecursiveIteratorIterator( new \RecursiveDirectoryIterator( $path ), \RecursiveIteratorIterator::SELF_FIRST );
-
-        foreach ( $iterator as $path ) {
-            $name = $path->__toString();
-            if ( ( '.' === basename( $name ) ) || ( '..' === basename( $name ) ) ) {
-                continue;
-            }
-
-            if ( ! MainWP_Helper::in_excludes( $excludes, str_replace( ABSPATH, '', $name ) ) ) {
-                if ( $path->isDir() ) {
-                    $this->zip_add_dir( $name, $excludes );
-                } else {
-                    $this->add_file_to_zipp( $name, str_replace( ABSPATH, '', $name ) );
-                }
-            }
-            $name = null;
-            unset( $name );
-        }
-
-        $iterator = null;
-        unset( $iterator );
-    }
-
-    /**
-     * Add file from a string to zip file.
-     *
-     * @param resource $file   File to add to zip.
-     * @param string   $str String to add.
-     *
-     * @return bool true|false.
-     */
-    public function add_file_from_string_to_zip( $file, $str ) {
-        return $this->zip->addFromString( $file, $str );
-    }
-
-    /**
-     * Add file from a string to pclzip file.
-     *
-     * @param resource $file     File to add to zip.
-     * @param string   $str   String to add.
-     * @param string   $filepath Path to file.
-     *
-     * @return bool true|false.
-     */
-    public function add_file_from_string_to_pcl_zip( $file, $str, $filepath ) {
-        $file        = preg_replace( '/(?:\.|\/)*(.*)/', '$1', $file );
-        $localpath   = dirname( $file );
-        $tmpfilename = dirname( $filepath ) . '/' . basename( $file );
-        if ( false !== MainWP_Helper::file_put_contents( $tmpfilename, $str ) ) { //phpcs:ignore WordPress.WP.AlternativeFunctions
-            $this->zip->delete( PCLZIP_OPT_BY_NAME, $file );
-            $add = $this->zip->add(
-                $tmpfilename,
-                PCLZIP_OPT_REMOVE_PATH,
-                dirname( $filepath ),
-                PCLZIP_OPT_ADD_PATH,
-                $localpath
-            );
-            wp_delete_file( $tmpfilename ); // NOSONAR .
-            if ( ! empty( $add ) ) {
-                return true;
-            }
-        }
-
-        return false;
-    }
-
-    /**
-     * Add file to zip.
-     *
-     * @param string $path         Path to zip file.
-     * @param string $zipEntryName File to add to zip.
-     *
-     * @return bool True|false.
-     *
-     * @uses \MainWP\Child\MainWP_Helper::ends_with()
-     */
-    public function add_file_to_zipp( $path, $zipEntryName ) {
-        if ( time() - $this->lastRun > 20 ) {
-            set_time_limit( $this->timeout ); // phpcs:ignore -- required to achieve desired results. Pull requests appreciated.
-            $this->lastRun = time();
-        }
-
-        if ( $this->excludeZip && MainWP_Helper::ends_with( $path, '.zip' ) ) {
-            return false;
-        }
-
-        $this->zipArchiveSizeCount += filesize( $path );
-        ++$this->gcCnt;
-
-        if ( ! $this->loadFilesBeforeZip || ( filesize( $path ) > 5 * 1024 * 1024 ) ) { // NOSONAR .
-            ++$this->zipArchiveFileCount;
-            if ( $this->zip instanceof \ZipArchive ) {
-                $added = $this->zip->addFile( $path, $zipEntryName );
-            } else {
-                $added = $this->zip->add_file( $path, $zipEntryName );
-            }
-        } else {
-            ++$this->zipArchiveFileCount;
-
-            $this->testContent = file_get_contents( $path ); //phpcs:ignore WordPress.WP.AlternativeFunctions -- // NOSONAR .
-            if ( false === $this->testContent ) {
-                return false;
-            }
-            $added = $this->zip->addFromString( $zipEntryName, $this->testContent );
-        }
-
-        if ( $this->gcCnt > 20 ) {
-            if ( function_exists( 'gc_enable' ) ) {
-                gc_enable();
-            }
-            if ( function_exists( 'gc_collect_cycles' ) ) {
-                gc_collect_cycles();
-            }
-            $this->gcCnt = 0;
-        }
-
-        if ( ( ( $this->file_descriptors > 0 ) && ( $this->zipArchiveFileCount > $this->file_descriptors ) ) ) {
-            $this->zip->close();
-            $this->zip = null;
-            unset( $this->zip );
-            if ( function_exists( 'gc_enable' ) ) {
-                gc_enable();
-            }
-            if ( function_exists( 'gc_collect_cycles' ) ) {
-                gc_collect_cycles();
-            }
-            $this->zip = new \ZipArchive();
-            $this->zip->open( $this->zipArchiveFileName );
-            $this->zipArchiveFileCount = 0;
-            $this->zipArchiveSizeCount = 0;
-        }
-
-        return $added;
-    }
-
-    /**
-     * Create full backup via console.
-     *
-     * @return bool Return false.
-     */
-    public function create_zip_console_full_backup() {
-        return false;
-    }
-
-    /**
-     * Create DB backup.
-     *
-     * @param string $filepath_prefix File path prefix.
-     * @param bool   $archiveExt      Archive extension.
-     * @param object $archiver        Archiver.
-     *
-     * @return array|string[] Action response.
-     *
-     * @uses \MainWP\Child\MainWP_Helper::sanitize_filename() Sanitize filename.
-     * @uses \MainWP\Child\MainWP_Helper::set_limit() Set PHP memory limit.
-     * @uses \MainWP\Child\MainWP_Child_DB::to_query() Run a mysqli query & get a result.
-     * @uses \MainWP\Child\MainWP_Child_DB::fetch_array()
-     * @uses \MainWP\Child\MainWP_Child_DB::real_escape_string()
-     * @uses \MainWP\Child\Tar_Archiver()
-     *
-     * @uses wpdb::get_results() Retrieve an entire SQL result set from the database (i.e., many rows).
-     * @see  https://developer.wordpress.org/reference/classes/wpdb/get_results/
-     *
-     * @uses wpdb::get_row() Retrieve one row from the database.
-     * @see  https://developer.wordpress.org/reference/classes/wpdb/get_row/
-     */
-    public function create_backup_db( $filepath_prefix, $archiveExt = false, &$archiver = null ) {
-
-        $timeout = 20 * 60 * 60;
-        $mem     = '512M';
-        MainWP_Helper::set_limit( $timeout, $mem );
-
-        /**
-         * WordPress Database instance.
-         *
-         * @global object $wpdb
-         */
-        global $wpdb;
-
-        //phpcs:disable WordPress.WP.AlternativeFunctions
-        $db_files  = array();
-        $tables_db = $wpdb->get_results( 'SHOW TABLES FROM `' . DB_NAME . '`', ARRAY_N );  // phpcs:ignore -- required to achieve desired results. Pull requests appreciated.
-        foreach ( $tables_db as $curr_table ) {
-            if ( null !== $archiver ) {
-                $archiver->update_pid_file();
-            }
-
-            $table = $curr_table[0];
-
-            $currentfile = $filepath_prefix . '-' . MainWP_Helper::sanitize_filename( $table ) . '.sql.php';
-            $db_files[]  = $currentfile;
-            if ( file_exists( $currentfile ) ) {
-                continue;
-            }
-            $fh = fopen( $currentfile . '.tmp', 'w' ); // NOSONAR .
-
-            $protect_content_string = '<?php exit(); ?>';
-
-            fwrite( $fh, $protect_content_string );
-            fwrite( $fh, "\n\n" . 'DROP TABLE IF EXISTS ' . $table . ';' );
-            $table_create = $wpdb->get_row( 'SHOW CREATE TABLE ' . $table, ARRAY_N ); // phpcs:ignore -- required to achieve desired results. Pull requests appreciated.
-            fwrite( $fh, "\n" . $table_create[1] . ";\n\n" );
-
-            $rows = MainWP_Child_DB::to_query( 'SELECT * FROM ' . $table, $wpdb->dbh ); // phpcs:ignore -- required to achieve desired results. Pull requests appreciated.
-
-            if ( $rows ) {
-                $i            = 0;
-                $table_insert = 'INSERT INTO `' . $table . '` VALUES (';
-
-                while ( $row = MainWP_Child_DB::fetch_array( $rows ) ) {
-                    $query = $table_insert;
-                    foreach ( $row as $value ) {
-                        if ( null === $value ) {
-                            $query .= 'NULL, ';
-                        } else {
-                            $query .= '"' . MainWP_Child_DB::real_escape_string( $value ) . '", ';
-                        }
-                    }
-                    $query = trim( $query, ', ' ) . ');';
-
-                    fwrite( $fh, "\n" . $query );
-                    ++$i;
-
-                    if ( $i >= 50 ) {
-                        fflush( $fh );
-                        $i = 0;
-                    }
-
-                    $query = null;
-                    $row   = null;
-                }
-            }
-            $rows = null;
-            fflush( $fh );
-            fclose( $fh );
-            rename( $currentfile . '.tmp', $currentfile ); // NOSONAR .
-        }
-
-        fclose( fopen( $filepath_prefix . '.sql', 'w' ) ); // NOSONAR .
-        $db_files[] = $filepath_prefix . '.sql';
-
-        $archivefilePath = null;
-        if ( false !== $archiveExt ) {
-            $archivefilePath = $filepath_prefix . '.sql.' . $archiveExt;
-
-            if ( 'zip' === $archiveExt ) {
-                $this->archiver = null;
-            } else {
-                $this->archiver = new Tar_Archiver( $this, $archiveExt );
-            }
-
-            if ( $this->zip_file( $db_files, $archivefilePath ) && file_exists( $archivefilePath ) ) {
-                foreach ( $db_files as $db_file ) {
-                    wp_delete_file( $db_file );
-                }
-            }
-        }
-        //phpcs:enable WordPress.WP.AlternativeFunctions
-
-        return false !== $archiveExt ? array( 'filepath' => $archivefilePath ) : $db_files;
-    }
-}
+<?php
+/**
+ * MainWP Backup
+ *
+ * This file handles all Child Site backup functions.
+ *
+ * @package MainWP\Child
+ */
+
+namespace MainWP\Child;
+
+//phpcs:disable WordPress.WP.AlternativeFunctions, Generic.Metrics.CyclomaticComplexity -- Current complexity is the only way to achieve desired results, pull request solutions appreciated.
+
+/**
+ * Class MainWP_Backup
+ *
+ * Handle all Child Site backup functions.
+ */
+class MainWP_Backup {
+
+    /**
+     * Whether to exclude zip archives.
+     *
+     * @var bool true|false
+     */
+    protected $excludeZip;
+
+    /**
+     * Container for zip file.
+     *
+     * @var resource ZIP file
+     */
+    protected $zip;
+
+    /**
+     * Backup files count.
+     *
+     * @var int Files count.
+     */
+    protected $zipArchiveFileCount;
+
+    /**
+     * Backup archive file size.
+     *
+     * @var float File size.
+     */
+    protected $zipArchiveSizeCount;
+
+    /**
+     * Backup archive file name.
+     *
+     * @var string File name.
+     */
+    protected $zipArchiveFileName;
+
+    /**
+     * Backup file descriptors.
+     *
+     * @var int File descriptors.
+     */
+    protected $file_descriptors;
+
+    /**
+     * Whether to load file before zip.
+     *
+     * @var bool true|false
+     */
+    protected $loadFilesBeforeZip;
+
+    /**
+     * Hold the current timeout length.
+     *
+     * @var int Timeout length.
+     */
+    protected $timeout;
+
+    /**
+     * Last time a backup has been run.
+     *
+     * @var string Last backup run.
+     */
+    protected $lastRun;
+
+    /**
+     * Garbage collection count.
+     *
+     * @var int Garbage collection count.
+     */
+    protected $gcCnt = 0;
+
+    /**
+     * Archive test content.
+     *
+     * @var bool Test backup content.
+     */
+    protected $testContent;
+
+    /**
+     * Backup process archiver.
+     *
+     * @var object Backup process archiver.
+     */
+    protected $archiver = null;
+
+    /**
+     * Protected static variable to hold the single instance of the class.
+     *
+     * @var mixed Default null
+     */
+    protected static $instance = null;
+
+    /**
+     * Create a public static instance.
+     *
+     * @return mixed Class instance.
+     */
+    public static function get() {
+        if ( null === self::$instance ) {
+            self::$instance = new self();
+        }
+        return self::$instance;
+    }
+
+    /**
+     * Create full backup.
+     *
+     * @param array  $excludes           Files to exclude from the backup.
+     * @param string $filePrefix         Backup archive file prefix.
+     * @param bool   $addConfig          Add config file to backup.
+     * @param bool   $includeCoreFiles   Include WordPress core files.
+     * @param int    $file_descriptors   Number of backup archive file descriptors.
+     * @param bool   $fileSuffix         Backup archive file suffix.
+     * @param bool   $excludezip         Exclude zip files from the backup.
+     * @param bool   $excludenonwp       Exclude non-WordPress directories in site root.
+     * @param bool   $loadFilesBeforeZip Load files before zip.
+     * @param string $ext                Backup file extension.
+     * @param bool   $pid                PID true|false.
+     * @param bool   $append             Append to backup file name.
+     *
+     * @return array|bool Action results on success, false on failure.
+     *
+     * @used-by MainWP_Backup::backup_full()
+     *
+     * @uses \MainWP\Child\Tar_Archiver()
+     * @uses \MainWP\Child\MainWP_Helper::get_mainwp_dir()
+     * @uses \MainWP\Child\MainWP_Helper::instance()->error()
+     * @uses \MainWP\Child\MainWP_Helper::set_limit()
+     */
+    public function create_full_backup(
+        $excludes,
+        $filePrefix = '',
+        $addConfig = false,
+        $includeCoreFiles = false,
+        $file_descriptors = 0,
+        $fileSuffix = false,
+        $excludezip = false,
+        $excludenonwp = false,
+        $loadFilesBeforeZip = true,
+        $ext = 'zip',
+        $pid = false,
+        $append = false
+    ) {
+
+        $this->file_descriptors   = $file_descriptors;
+        $this->loadFilesBeforeZip = $loadFilesBeforeZip;
+
+        $dirs      = MainWP_Helper::get_mainwp_dir( 'backup' );
+        $backupdir = $dirs[0];
+        if ( ! defined( 'PCLZIP_TEMPORARY_DIR' ) ) {
+
+            /**
+             * Defines PCLZIP temporary directory.
+             *
+             * @const ( string ) Temporary backup directory.
+             * @source https://code-reference.mainwp.com/classes/MainWP.Child.MainWP_Backup.html
+             */
+            define( 'PCLZIP_TEMPORARY_DIR', $backupdir );
+        }
+
+        if ( false !== $pid ) {
+            $pid = trailingslashit( $backupdir ) . 'backup-' . $pid . '.pid';
+        }
+
+        // Verify if another backup is running, if so, return an error.
+        $files = glob( $backupdir . '*.pid' );
+        foreach ( $files as $file ) {
+            if ( basename( $file ) === basename( $pid ) ) {
+                continue;
+            }
+
+            if ( ( time() - filemtime( $file ) ) < 160 ) {
+                MainWP_Helper::instance()->error( esc_html__( 'Another backup process is running. Please, try again later.', 'mainwp-child' ) );
+            }
+        }
+
+        $timestamp = time();
+        if ( '' !== $filePrefix ) {
+            $filePrefix .= '-';
+        }
+
+        if ( 'zip' === $ext ) {
+            $this->archiver = null;
+            $ext            = '.zip';
+        } else {
+            $this->archiver = new Tar_Archiver( $this, $ext, $pid );
+            $ext            = $this->archiver->get_extension();
+        }
+
+        if ( ( false !== $fileSuffix ) && ! empty( $fileSuffix ) ) {
+            // Append already contains extension!
+            $file = $fileSuffix . ( true === $append ? '' : $ext );
+        } else {
+            $file = 'backup-' . $filePrefix . $timestamp . $ext;
+        }
+        $filepath = $backupdir . $file;
+        $fileurl  = $file;
+
+        if ( ! $addConfig ) {
+            if ( ! in_array( str_replace( ABSPATH, '', WP_CONTENT_DIR ), $excludes, true ) && ! in_array( 'wp-admin', $excludes, true ) && ! in_array( WPINC, $excludes, true ) ) {
+                $addConfig        = true;
+                $includeCoreFiles = true;
+            }
+        }
+
+        $this->timeout = 20 * 60 * 60;
+        $mem           = '512M';
+        MainWP_Helper::set_limit( $this->timeout, $mem );
+
+        if ( null !== $this->archiver ) {
+            $success = $this->archiver->create_full_backup( $filepath, $excludes, $addConfig, $includeCoreFiles, $excludezip, $excludenonwp, $append );
+        } elseif ( $this->check_zip_support() ) {
+            $success = $this->create_zip_full_backup( $filepath, $excludes, $addConfig, $includeCoreFiles, $excludezip, $excludenonwp );
+        } elseif ( $this->check_zip_console() ) {
+            $success = $this->create_zip_console_full_backup(); // NOSONAR .
+        } else {
+            $success = $this->create_zip_pcl_full_backup2( $filepath, $excludes, $addConfig, $includeCoreFiles, $excludezip, $excludenonwp );
+        }
+
+        return ( $success ) ? array(
+            'timestamp' => $timestamp,
+            'file'      => $fileurl,
+            'filesize'  => filesize( $filepath ), // NOSONAR .
+        ) : false;
+    }
+
+    /**
+     * Check whether the file is an archive or not & create a json_encoded, serialized, base64_encoded string.
+     *
+     * @uses \MainWP\Child\MainWP_Helper::write() Write response data to be sent to the MainWP Dashboard.
+     * @uses \MainWP\Child\MainWP_Helper::get_mainwp_dir() Get the MainWP directory.
+     * @uses \MainWP\Child\MainWP_Clone::is_archive()
+     */
+    public function backup_poll() {
+        // phpcs:disable WordPress.Security.NonceVerification
+        $fileNameUID = isset( $_POST['fileNameUID'] ) ? sanitize_text_field( wp_unslash( $_POST['fileNameUID'] ) ) : '';
+        $fileName    = isset( $_POST['fileName'] ) ? sanitize_text_field( wp_unslash( $_POST['fileName'] ) ) : '';
+        $type        = isset( $_POST['type'] ) ? sanitize_text_field( wp_unslash( $_POST['type'] ) ) : '';
+        // phpcs:enable WordPress.Security.NonceVerification
+        if ( 'full' === $type ) {
+            if ( '' !== $fileName ) {
+                $backupFile = $fileName;
+            } else {
+                $backupFile = 'backup-' . $fileNameUID . '-';
+            }
+
+            $dirs      = MainWP_Helper::get_mainwp_dir( 'backup' );
+            $backupdir = $dirs[0];
+            $result    = glob( $backupdir . $backupFile . '*' ); // NOSONAR .
+
+            // Check if archive, set $archiveFile = $file & break.
+            $archiveFile = false;
+            foreach ( $result as $file ) {
+                if ( MainWP_Clone::is_archive( $file, $backupFile, '(.*)' ) ) {
+                    $archiveFile = $file;
+                    break;
+                }
+            }
+
+            // When not an archive.
+            if ( false === $archiveFile ) {
+                MainWP_Helper::write( array() );
+            }
+
+            // When archive found.
+            MainWP_Helper::write( array( 'size' => filesize( $archiveFile ) ) );
+        } else {
+            // When not an archive.
+            $backupFile = 'dbBackup-' . $fileNameUID . '-*.sql.php';
+            $dirs       = MainWP_Helper::get_mainwp_dir( 'backup' );
+            $backupdir  = $dirs[0];
+            $result     = glob( $backupdir . $backupFile . '*' ); // NOSONAR .
+
+            if ( 0 === count( $result ) ) {
+                MainWP_Helper::write( array() );
+            }
+
+            $size = 0;
+            foreach ( $result as $f ) {
+                $size += filesize( $f );
+            }
+            MainWP_Helper::write( array( 'size' => $size ) );
+            exit();
+        }
+    }
+
+    /**
+     * Check if backup already exists or is in the process of backing up.
+     *
+     * @uses MainWP_Helper::write() Write response data to be sent to the MainWP Dashboard.
+     * @uses MainWP_Helper::get_mainwp_dir() Get the MainWP directory.
+     * @uses MainWP_Helper::get_wp_filesystem() Get the WordPress filesystem.
+     *
+     * @uses WP_Filesystem_Base::is_file() Checks if resource is a file.
+     * @see https://developer.wordpress.org/reference/classes/wp_filesystem_base/is_file/
+     *
+     * @uses WP_Filesystem_Base::mtime() Gets the file modification time.
+     * @see https://developer.wordpress.org/reference/classes/wp_filesystem_base/mtime/
+     *
+     * @uses WP_Filesystem_Base::get_contents() Reads entire file into a string.
+     * @see https://developer.wordpress.org/reference/classes/wp_filesystem_base/get_contents/
+     */
+    public function backup_checkpid() {
+        // phpcs:disable WordPress.Security.NonceVerification
+        $pid = isset( $_POST['pid'] ) ? sanitize_text_field( wp_unslash( $_POST['pid'] ) ) : 0;
+        // phpcs:enable WordPress.Security.NonceVerification
+        $dirs      = MainWP_Helper::get_mainwp_dir( 'backup' );
+        $backupdir = $dirs[0];
+
+        $information = array();
+
+        /**
+         * WordPress files system object.
+         *
+         * @global object
+         */
+        global $wp_filesystem;
+
+        MainWP_Helper::get_wp_filesystem();
+
+        $pidFile  = trailingslashit( $backupdir ) . 'backup-' . $pid . '.pid';
+        $doneFile = trailingslashit( $backupdir ) . 'backup-' . $pid . '.done';
+        if ( $wp_filesystem->is_file( $pidFile ) ) {
+            $time = $wp_filesystem->mtime( $pidFile );
+
+            $minutes = date( 'i', time() ); // phpcs:ignore -- required to achieve desired results, pull request solutions appreciated.
+            $seconds = date( 's', time() ); // phpcs:ignore -- required to achieve desired results, pull request solutions appreciated.
+
+            $file_minutes = date( 'i', $time ); // phpcs:ignore -- required to achieve desired results, pull request solutions appreciated.
+            $file_seconds = date( 's', $time ); // phpcs:ignore -- required to achieve desired results, pull request solutions appreciated.
+
+            $minuteDiff = $minutes - $file_minutes;
+            if ( 59 === $minuteDiff ) {
+                $minuteDiff = 1;
+            }
+            $secondsdiff = ( $minuteDiff * 60 ) + $seconds - $file_seconds;
+
+            $file                = $wp_filesystem->get_contents( $pidFile );
+            $information['file'] = basename( $file );
+            if ( $secondsdiff < 80 ) {
+                $information['status'] = 'busy';
+            } else {
+                $information['status'] = 'stalled';
+            }
+        } elseif ( $wp_filesystem->is_file( $doneFile ) ) {
+            $file                  = $wp_filesystem->get_contents( $doneFile );
+            $information['status'] = 'done';
+            $information['file']   = basename( $file );
+            $information['size']   = filesize( $file );
+        } else {
+            $information['status'] = 'invalid';
+        }
+
+        MainWP_Helper::write( $information );
+    }
+
+    /**
+     * Perform a backup.
+     *
+     * @param bool $write Whether or not to execute MainWP_Helper::write(), Default: true.
+     *
+     * @return array Array of information on the backup containing the type of backup performed, full, or DB & whether or not it was successful.
+     *
+     * @uses \MainWP\Child\MainWP_Helper::set_limit() Set PHP Memory Limit and PHP Max Execution time values.
+     * @uses \MainWP\Child\MainWP_Helper::end_session() End session and flush the output buffer.
+     * @uses \MainWP\Child\MainWP_Helper::get_wp_filesystem() Get the WordPress filesystem.
+     * @uses \MainWP\Child\MainWP_Helper::ends_with() Check if the String 1 ends with the String 2.
+     * @uses \MainWP\Child\MainWP_Helper::write() Write response data to be sent to the MainWP Dashboard.
+     * @uses \MainWP\Child\MainWP_Backup::backup_full() Perform a full backup.
+     * @uses \MainWP\Child\MainWP_Helper::set_limit()
+     * @uses \MainWP\Child\MainWP_Helper::end_session()
+     * @uses \MainWP\Child\MainWP_Helper::get_mainwp_dir()
+     * @uses \MainWP\Child\MainWP_Helper::get_wp_filesystem()
+     * @uses \MainWP\Child\MainWP_Helper::ends_with()
+     * @uses \MainWP\Child\MainWP_Helper::write()
+     */
+    public function backup( $write = true ) {
+
+        $timeout = 20 * 60 * 60;
+        MainWP_Helper::set_limit( $timeout );
+
+        MainWP_Helper::end_session();
+
+        // Cleanup pid files!
+        $dirs      = MainWP_Helper::get_mainwp_dir( 'backup' );
+        $backupdir = trailingslashit( $dirs[0] );
+
+        /**
+         * WordPress files system object.
+         *
+         * @global object
+         */
+        global $wp_filesystem;
+
+        MainWP_Helper::get_wp_filesystem();
+
+        $files = glob( $backupdir . '*' );
+        foreach ( $files as $file ) {
+            if ( MainWP_Helper::ends_with( $file, '/index.php' ) | MainWP_Helper::ends_with( $file, '/.htaccess' ) ) {
+                continue;
+            }
+
+            if ( ( time() - filemtime( $file ) ) > ( 60 * 60 * 3 ) ) {
+                wp_delete_file( $file );
+            }
+        }
+
+        // phpcs:disable WordPress.Security.NonceVerification
+        $fileName = isset( $_POST['fileUID'] ) ? sanitize_text_field( wp_unslash( $_POST['fileUID'] ) ) : '';
+        $type     = isset( $_POST['type'] ) ? sanitize_text_field( wp_unslash( $_POST['type'] ) ) : '';
+
+        if ( 'full' === $type ) {
+
+            $res = $this->backup_full( $fileName );
+
+            if ( ! $res ) {
+                $information['full'] = false;
+            } else {
+                $information['full'] = $res['file'];
+                $information['size'] = $res['filesize'];
+            }
+            $information['db'] = false;
+        } elseif ( 'db' === $type ) {
+            $ext = isset( $_POST['ext'] ) ? sanitize_text_field( wp_unslash( $_POST['ext'] ) ) : 'zip';
+            $res = $this->backup_db( $fileName, $ext );
+            if ( ! $res ) {
+                $information['db'] = false;
+            } else {
+                $information['db']   = $res['file'];
+                $information['size'] = $res['filesize'];
+            }
+            $information['full'] = false;
+        } else {
+            $information['full'] = false;
+            $information['db']   = false;
+        }
+
+        if ( $write ) {
+            MainWP_Helper::write( $information );
+        }
+        // phpcs:enable WordPress.Security.NonceVerification
+        return $information;
+    }
+
+    /**
+     * Perform a full backup.
+     *
+     * @param string $fileName Backup archive file name.
+     *
+     * @return array|bool Returns an array containing the Backup location & file size. Return FALSE on failure.
+     *
+     * @uses \MainWP\Child\MainWP_Backup::create_full_backup() Create full backup.
+     * @uses \MainWP\Child\MainWP_Helper::get_mainwp_dir()
+     */
+    public function backup_full( $fileName ) { //phpcs:ignore -- complex method.
+        // phpcs:disable WordPress.Security.NonceVerification
+        $excludes   = ( isset( $_POST['exclude'] ) ? explode( ',', wp_unslash( $_POST['exclude'] ) ) : array() ); //phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- ok.
+        $excludes[] = str_replace( ABSPATH, '', WP_CONTENT_DIR ) . '/uploads/mainwp';
+        $uploadDir  = MainWP_Helper::get_mainwp_dir();
+        $uploadDir  = $uploadDir[0];
+        $excludes[] = str_replace( ABSPATH, '', $uploadDir );
+        $excludes[] = str_replace( ABSPATH, '', WP_CONTENT_DIR ) . '/object-cache.php';
+
+        if ( function_exists( 'posix_uname' ) ) {
+            $uname = posix_uname();
+            if ( is_array( $uname ) && isset( $uname['nodename'] ) ) {
+                if ( stristr( $uname['nodename'], 'hostgator' ) ) {
+                    if ( ! isset( $_POST['file_descriptors'] ) || '0' === $_POST['file_descriptors'] || $_POST['file_descriptors'] > 1000 ) {
+                        $_POST['file_descriptors'] = 1000;
+                    }
+                    $_POST['file_descriptors_auto'] = 0;
+                    $_POST['loadFilesBeforeZip']    = false;
+                }
+            }
+        }
+
+        $file_descriptors      = ( isset( $_POST['file_descriptors'] ) ? intval( wp_unslash( $_POST['file_descriptors'] ) ) : 0 );
+        $file_descriptors_auto = ( isset( $_POST['file_descriptors_auto'] ) ? intval( wp_unslash( $_POST['file_descriptors_auto'] ) ) : 0 );
+        if ( 1 === (int) $file_descriptors_auto ) {
+            if ( function_exists( 'posix_getrlimit' ) ) {
+                $result = posix_getrlimit();
+                if ( isset( $result['soft openfiles'] ) ) {
+                    $file_descriptors = $result['soft openfiles'];
+                }
+            }
+        }
+
+        $loadFilesBeforeZip = ( isset( $_POST['loadFilesBeforeZip'] ) ? sanitize_text_field( wp_unslash( $_POST['loadFilesBeforeZip'] ) ) : true );
+
+        $newExcludes = array();
+        foreach ( $excludes as $exclude ) {
+            $newExcludes[] = sanitize_text_field( rtrim( $exclude, '/' ) );
+        }
+
+        $excludebackup = ( isset( $_POST['excludebackup'] ) && '1' === $_POST['excludebackup'] );
+        $excludecache  = ( isset( $_POST['excludecache'] ) && '1' === $_POST['excludecache'] );
+        $excludezip    = ( isset( $_POST['excludezip'] ) && '1' === $_POST['excludezip'] );
+        $excludenonwp  = ( isset( $_POST['excludenonwp'] ) && '1' === $_POST['excludenonwp'] );
+
+        if ( $excludebackup ) {
+            $newExcludes[] = str_replace( ABSPATH, '', WP_CONTENT_DIR ) . '/uploads/backupbuddy_backups';
+            $newExcludes[] = str_replace( ABSPATH, '', WP_CONTENT_DIR ) . '/uploads/backupbuddy_temp';
+            $newExcludes[] = str_replace( ABSPATH, '', WP_CONTENT_DIR ) . '/uploads/pb_backupbuddy';
+            $newExcludes[] = str_replace( ABSPATH, '', WP_CONTENT_DIR ) . '/managewp';
+            $newExcludes[] = str_replace( ABSPATH, '', WP_CONTENT_DIR ) . '/infinitewp';
+            $newExcludes[] = str_replace( ABSPATH, '', WP_CONTENT_DIR ) . '/backups';
+            $newExcludes[] = str_replace( ABSPATH, '', WP_CONTENT_DIR ) . '/backups';
+            $newExcludes[] = str_replace( ABSPATH, '', WP_CONTENT_DIR ) . '/uploads/backwpup*';
+            $newExcludes[] = str_replace( ABSPATH, '', WP_CONTENT_DIR ) . '/plugins/wp-complete-backup/storage';
+            $newExcludes[] = str_replace( ABSPATH, '', WP_CONTENT_DIR ) . '/backups';
+            $newExcludes[] = '/administrator/backups';
+        }
+
+        if ( $excludecache ) {
+            $newExcludes[] = str_replace( ABSPATH, '', WP_CONTENT_DIR ) . '/w3tc-cache';
+            $newExcludes[] = str_replace( ABSPATH, '', WP_CONTENT_DIR ) . '/w3tc';
+            $newExcludes[] = str_replace( ABSPATH, '', WP_CONTENT_DIR ) . '/cache/config';
+            $newExcludes[] = str_replace( ABSPATH, '', WP_CONTENT_DIR ) . '/cache/minify';
+            $newExcludes[] = str_replace( ABSPATH, '', WP_CONTENT_DIR ) . '/cache/page_enhanced';
+            $newExcludes[] = str_replace( ABSPATH, '', WP_CONTENT_DIR ) . '/cache/tmp';
+            $newExcludes[] = str_replace( ABSPATH, '', WP_CONTENT_DIR ) . '/cache/supercache';
+            $newExcludes[] = str_replace( ABSPATH, '', WP_CONTENT_DIR ) . '/cache/quick-cache';
+            $newExcludes[] = str_replace( ABSPATH, '', WP_CONTENT_DIR ) . '/hyper-cache/cache';
+            $newExcludes[] = str_replace( ABSPATH, '', WP_CONTENT_DIR ) . '/cache/all';
+            $newExcludes[] = str_replace( ABSPATH, '', WP_CONTENT_DIR ) . '/cache/wp-rocket';
+        }
+
+        $file = false;
+        if ( isset( $_POST['f'] ) ) {
+            $file = ! empty( $_POST['f'] ) ? sanitize_text_field( wp_unslash( $_POST['f'] ) ) : false;
+        } elseif ( isset( $_POST['file'] ) ) {
+            $file = ! empty( $_POST['file'] ) ? sanitize_text_field( wp_unslash( $_POST['file'] ) ) : false;
+        }
+
+        $ext = isset( $_POST['ext'] ) ? sanitize_text_field( wp_unslash( $_POST['ext'] ) ) : 'zip';
+        $pid = isset( $_POST['pid'] ) ? sanitize_text_field( wp_unslash( $_POST['pid'] ) ) : false;
+
+        $append = ( isset( $_POST['append'] ) && ( '1' === $_POST['append'] ) );
+        // phpcs:enable WordPress.Security.NonceVerification
+        return $this->create_full_backup( $newExcludes, $fileName, true, true, $file_descriptors, $file, $excludezip, $excludenonwp, $loadFilesBeforeZip, $ext, $pid, $append );
+    }
+
+    /**
+     * Backup site database.
+     *
+     * @param string $fileName Backup arhive file name.
+     * @param string $ext      Backup achive extension.
+     *
+     * @uses \MainWP\Child\MainWP_Helper::update_option() Update database option by option name.
+     * @uses \MainWP\Child\MainWP_Helper::get_mainwp_dir() Get the MainWP directory.
+     * @uses \MainWP\Child\MainWP_Backup::create_backup_db() Create database backup.
+     *
+     * @return array|bool $success Returns an array containing the Backup location & file size. Return FALSE on failure.
+     */
+    public function backup_db( $fileName = '', $ext = 'zip' ) {
+        $dirs      = MainWP_Helper::get_mainwp_dir( 'backup' );
+        $dir       = $dirs[0];
+        $timestamp = time();
+
+        if ( '' !== $fileName ) {
+            $fileName .= '-';
+        }
+
+        $filepath_prefix = $dir . 'dbBackup-' . $fileName . $timestamp;
+
+        $dh = opendir( $dir );
+
+        if ( $dh ) {
+            while ( ( $file = readdir( $dh ) ) !== false ) {
+                if ( '.' !== $file && '..' !== $file && ( preg_match( '/dbBackup-(.*).sql(\.zip|\.tar|\.tar\.gz|\.tar\.bz2|\.tmp)?$/', $file ) ) ) {
+                    wp_delete_file( $dir . $file );
+                }
+                if ( '.' !== $file && '..' !== $file && ( preg_match( '/dbBackup-(.*).sql.php(\.zip|\.tar|\.tar\.gz|\.tar\.bz2|\.tmp)?$/', $file ) ) ) {
+                    wp_delete_file( $dir . $file );
+                }
+            }
+            closedir( $dh );
+        }
+
+        // $ext !== false, the fuction will return in format: array( 'filepath' => $filepath );.
+        $result = $this->create_backup_db( $filepath_prefix, $ext );
+
+        MainWP_Helper::update_option( 'mainwp_child_last_db_backup_size', filesize( $result['filepath'] ) ); // NOSONAR .
+
+        return ( ! $result ) ? false : array(
+            'timestamp' => $timestamp,
+            'file'      => basename( $result['filepath'] ),
+            'filesize'  => filesize( $result['filepath'] ), // NOSONAR .
+        );
+    }
+
+    /**
+     * Create the ZIP file.
+     *
+     * @param array  $files Files to zip.
+     * @param string $archive Type of archive to create.
+     *
+     * @return bool Return FALSE on failure, TRUE on success.
+     *
+     * @uses \MainWP\Child\MainWP_Helper::set_limit() Set PHP memory limit.
+     */
+    public function zip_file( $files, $archive ) {
+        $this->timeout = 20 * 60 * 60;
+        $mem           = '512M';
+        MainWP_Helper::set_limit( $this->timeout, $mem );
+
+        if ( ! is_array( $files ) ) {
+            $files = array( $files );
+        }
+
+        if ( null !== $this->archiver ) {
+            $success = $this->archiver->zip_file( $files, $archive );
+        } elseif ( $this->check_zip_support() ) {
+            $success = $this->m_zip_file( $files, $archive );
+        } elseif ( $this->check_zip_console() ) {
+            $success = $this->m_zip_file_console( $files, $archive );
+        } else {
+            $success = $this->m_zip_file_pcl( $files, $archive );
+        }
+
+        return $success;
+    }
+
+    /**
+     * Create m_zip_file.
+     *
+     * @param array  $files   Files to zip.
+     * @param string $archive Type of archive to create.
+     *
+     * @return bool Return false on failure.
+     */
+    public function m_zip_file( $files, $archive ) {
+        $this->zip                 = new \ZipArchive();
+        $this->zipArchiveFileCount = 0;
+        $this->zipArchiveSizeCount = 0;
+
+        $zipRes = $this->zip->open( $archive, \ZipArchive::CREATE );
+        if ( $zipRes ) {
+            foreach ( $files as $file ) {
+                $this->add_file_to_zipp( $file, basename( $file ) );
+            }
+
+            return $this->zip->close();
+        }
+
+        return false;
+    }
+
+    /**
+     * Method m_zip_file_console().
+     *
+     * @return bool Return false.
+     */
+    public function m_zip_file_console() {
+        return false;
+    }
+
+    /**
+     * Use pclzip to add files to the zip archive.
+     *
+     * @param array  $files   Files to zip.
+     * @param string $archive Type of archive to create.
+     *
+     * @return array $rslt Return array of results.
+     */
+    public function m_zip_file_pcl( $files, $archive ) {
+        // Zip this backup folder.
+        require_once ABSPATH . 'wp-admin/includes/class-pclzip.php';
+        $this->zip = new \PclZip( $archive );
+
+        $error = false;
+        foreach ( $files as $file ) {
+            $rslt = $this->zip->add( $file, PCLZIP_OPT_REMOVE_PATH, dirname( $file ) );
+            if ( empty( $rslt ) ) {
+                $error = true;
+            }
+        }
+
+        return ! $error;
+    }
+
+    /**
+     * Check for default PHP zip support.
+     *
+     * @return bool Returns true if class_name is a defined class, false otherwise.
+     */
+    public function check_zip_support() {
+        return class_exists( '\ZipArchive' );
+    }
+
+    /**
+     * Check if we could run zip on console
+     *
+     * @return bool Return false.
+     */
+    public function check_zip_console() {
+        return false;
+    }
+
+    /**
+     * Create full backup using default PHP zip library.
+     *
+     * @param string $filepath           File path to create.
+     * @param array  $excludes           Files to exclude from the backup.
+     * @param bool   $addConfig          Add config file to backup.
+     * @param bool   $includeCoreFiles   Include WordPress core files.
+     * @param bool   $excludezip         Exclude zip files from the backup.
+     * @param bool   $excludenonwp       Exclude non-WordPress directories in site root.
+     *
+     * @uses \MainWP\Child\MainWP_Helper::starts_with() Check if the String 1 starts with the String 2.
+     * @uses \MainWP\Child\MainWP_Helper::in_excludes() Check if the value is in the excludes list.
+     * @uses \MainWP\Child\MainWP_Backup::include_core_files() Include core files in backup.
+     * @uses \MainWP\Child\MainWP_Backup::add_config() Add config file to backup.
+     *
+     * @return bool Return true on success & false on failure.
+     */
+    public function create_zip_full_backup(
+        $filepath,
+        $excludes,
+        $addConfig,
+        $includeCoreFiles,
+        $excludezip,
+        $excludenonwp
+    ) {
+
+        $this->excludeZip          = $excludezip;
+        $this->zip                 = new \ZipArchive();
+        $this->zipArchiveFileCount = 0;
+        $this->zipArchiveSizeCount = 0;
+        $this->zipArchiveFileName  = $filepath;
+        $zipRes                    = $this->zip->open( $filepath, \ZipArchive::CREATE );
+        if ( $zipRes ) {
+            $nodes = glob( ABSPATH . '*' );
+            if ( ! $includeCoreFiles ) {
+                $this->include_core_files( $nodes );
+            }
+
+            $db_files = $this->create_backup_db( dirname( $filepath ) . DIRECTORY_SEPARATOR . 'dbBackup' );
+            foreach ( $db_files as $db_file ) {
+                $this->add_file_to_zipp( $db_file, basename( WP_CONTENT_DIR ) . '/' . basename( $db_file ) );
+            }
+
+            if ( file_exists( ABSPATH . '.htaccess' ) ) {
+                $this->add_file_to_zipp( ABSPATH . '.htaccess', 'mainwp-htaccess' );
+            }
+
+            foreach ( $nodes as $node ) {
+                if ( $excludenonwp && is_dir( $node ) ) {
+                    if ( ! MainWP_Helper::starts_with( $node, WP_CONTENT_DIR ) && ! MainWP_Helper::starts_with( $node, ABSPATH . 'wp-admin' ) && ! MainWP_Helper::starts_with( $node, ABSPATH . WPINC ) ) {
+                        continue;
+                    }
+                }
+
+                if ( ! MainWP_Helper::in_excludes( $excludes, str_replace( ABSPATH, '', $node ) ) ) {
+                    if ( is_dir( $node ) ) {
+                        $this->zip_add_dir( $node, $excludes );
+                    } elseif ( is_file( $node ) ) {
+                        $this->add_file_to_zipp( $node, str_replace( ABSPATH, '', $node ) );
+                    }
+                }
+            }
+
+            if ( $addConfig ) {
+                $this->add_config();
+            }
+
+            $return = $this->zip->close();
+            foreach ( $db_files as $db_file ) {
+                wp_delete_file( $db_file ); // NOSONAR .
+            }
+
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * Exclude certain core files from the backup.
+     *
+     * @param array $nodes Default nodes.
+     *
+     * @uses \MainWP\Child\MainWP_Helper::starts_with() Check if the String 1 starts with the String 2.
+     */
+    private function include_core_files( &$nodes ) {
+        $coreFiles = array(
+            'favicon.ico',
+            'index.php',
+            'license.txt',
+            'readme.html',
+            'wp-activate.php',
+            'wp-app.php',
+            'wp-blog-header.php',
+            'wp-comments-post.php',
+            'wp-config.php',
+            'wp-config-sample.php',
+            'wp-cron.php',
+            'wp-links-opml.php',
+            'wp-load.php',
+            'wp-login.php',
+            'wp-mail.php',
+            'wp-pass.php',
+            'wp-register.php',
+            'wp-settings.php',
+            'wp-signup.php',
+            'wp-trackback.php',
+            'xmlrpc.php',
+        );
+        foreach ( $nodes as $key => $node ) {
+            if ( MainWP_Helper::starts_with( $node, ABSPATH . WPINC ) ) {
+                unset( $nodes[ $key ] );
+            } elseif ( MainWP_Helper::starts_with( $node, ABSPATH . basename( admin_url( '' ) ) ) ) {
+                unset( $nodes[ $key ] );
+            } else {
+                foreach ( $coreFiles as $coreFile ) {
+                    if ( ABSPATH . $coreFile === $node ) {
+                        unset( $nodes[ $key ] );
+                    }
+                }
+            }
+        }
+        unset( $coreFiles );
+    }
+
+    /**
+     * Add config file to backup.
+     *
+     * @uses wp_json_encode() Encode a variable into JSON, with some sanity checks.
+     * @see https://developer.wordpress.org/reference/functions/wp_json_encode/
+     *
+     * @uses get_option() Get option by name.
+     * @see https://developer.wordpress.org/reference/functions/get_option/
+     */
+    public function add_config() {
+
+        /**
+         * WordPress Database instance.
+         *
+         * @global object $wpdb
+         */
+        global $wpdb;
+
+        $plugins = array();
+        $dir     = WP_CONTENT_DIR . '/plugins/';
+        $fh      = opendir( $dir );
+        while ( $entry = readdir( $fh ) ) {
+            if ( ! is_dir( $dir . $entry ) ) {
+                continue;
+            }
+            if ( ( '.' === $entry ) || ( '..' === $entry ) ) {
+                continue;
+            }
+            $plugins[] = $entry;
+        }
+        closedir( $fh );
+
+        $themes = array();
+        $dir    = WP_CONTENT_DIR . '/themes/';
+        $fh     = opendir( $dir );
+        while ( $entry = readdir( $fh ) ) {
+            if ( ! is_dir( $dir . $entry ) ) {
+                continue;
+            }
+            if ( ( '.' === $entry ) || ( '..' === $entry ) ) {
+                continue;
+            }
+            $themes[] = $entry;
+        }
+        closedir( $fh );
+        $string = wp_json_encode(
+            array(
+                'siteurl' => get_option( 'siteurl' ),
+                'home'    => get_option( 'home' ),
+                'abspath' => ABSPATH,
+                'prefix'  => $wpdb->prefix,
+                'lang'    => defined( 'WPLANG' ) ? WPLANG : '',
+                'plugins' => $plugins,
+                'themes'  => $themes,
+            )
+        );
+        $this->add_file_from_string_to_zip( 'clone/config.txt', $string );
+    }
+
+    /**
+     * Copy directory.
+     *
+     * @param array  $nodes        Default nodes.
+     * @param array  $excludes     Files & directories to exclude.
+     * @param string $backupfolder Backup folder.
+     * @param bool   $excludenonwp Whether or not to exclude any wp core files.
+     *
+     * @uses \MainWP\Child\MainWP_Helper::starts_with() Check if the String 1 starts with the String 2.
+     * @uses \MainWP\Child\MainWP_Helper::in_excludes() Check if the value is in the excludes list.
+     * @uses \MainWP\Child\MainWP_Helper::ends_with() Check if the String 1 ends with the String 2.
+     */
+    public function copy_dir( $nodes, $excludes, $backupfolder, $excludenonwp ) {
+        if ( ! is_array( $nodes ) ) {
+            return;
+        }
+
+        foreach ( $nodes as $node ) {
+            if ( $excludenonwp && is_dir( $node ) ) {
+                if ( ! MainWP_Helper::starts_with( $node, WP_CONTENT_DIR ) && ! MainWP_Helper::starts_with( $node, ABSPATH . 'wp-admin' ) && ! MainWP_Helper::starts_with( $node, ABSPATH . WPINC ) ) {
+                    continue;
+                }
+            }
+
+            if ( ! MainWP_Helper::in_excludes( $excludes, str_replace( ABSPATH, '', $node ) ) ) {
+                if ( is_dir( $node ) ) {
+                    if ( ! file_exists( str_replace( ABSPATH, $backupfolder, $node ) ) ) {
+                        mkdir( str_replace( ABSPATH, $backupfolder, $node ) ); // phpcs:ignore -- required to achieve desired results. Pull requests appreciated.
+                    }
+
+                    $newnodes = glob( $node . DIRECTORY_SEPARATOR . '*' );
+                    $this->copy_dir( $newnodes, $excludes, $backupfolder, $excludenonwp, false );
+                    unset( $newnodes );
+                } elseif ( is_file( $node ) ) {
+                    if ( $this->excludeZip && MainWP_Helper::ends_with( $node, '.zip' ) ) {
+                        continue;
+                    }
+
+                    copy( $node, str_replace( ABSPATH, $backupfolder, $node ) ); // phpcs:ignore -- required to achieve desired results. Pull requests appreciated - // NOSONAR .
+                }
+            }
+        }
+    }
+
+    /**
+     * Create PCL zip full backup 2.
+     *
+     * @param string $filepath         Path to file.
+     * @param array  $excludes         Files & directories to exclude.
+     * @param bool   $addConfig        Add config file to backup.
+     * @param bool   $includeCoreFiles Whether to include core files.
+     * @param bool   $excludezip       Whether to exclude zip archives.
+     * @param bool   $excludenonwp     Whether or not to exclude any wp core files.
+     *
+     * @return bool Return true on success.
+     *
+     * @uses \MainWP\Child\MainWP_Helper::delete_dir() Delete wanted directory.
+     * @uses \MainWP\Child\MainWP_Helper::starts_with() Check if the String 1 starts with the String 2.
+     * @uses \MainWP\Child\MainWP_Backup::create_backup_db() Create database backup.
+     * @uses \MainWP\Child\MainWP_Backup::add_file_from_string_to_pcl_zip() Add file from a string to pclzip file.
+     *
+     * @uses wp_json_encode() Encode a variable into JSON, with some sanity checks.
+     * @see https://developer.wordpress.org/reference/functions/wp_json_encode/
+     *
+     * @uses get_option() Get option by name.
+     * @see https://developer.wordpress.org/reference/functions/get_option/
+     */
+    public function create_zip_pcl_full_backup2( $filepath, $excludes, $addConfig, $includeCoreFiles, $excludezip, $excludenonwp ) {
+        // Create backup folder.
+        $backupFolder = dirname( $filepath ) . DIRECTORY_SEPARATOR . 'backup' . DIRECTORY_SEPARATOR;
+
+        mkdir( $backupFolder ); // phpcs:ignore -- required to achieve desired results. Pull requests appreciated.
+
+        // Create DB backup.
+        $db_files = $this->create_backup_db( $backupFolder . 'dbBackup' );
+
+        // Copy installation to backup folder.
+        $nodes = glob( ABSPATH . '*' );
+        if ( ! $includeCoreFiles ) {
+            $coreFiles = array(
+                'favicon.ico',
+                'index.php',
+                'license.txt',
+                'readme.html',
+                'wp-activate.php',
+                'wp-app.php',
+                'wp-blog-header.php',
+                'wp-comments-post.php',
+                'wp-config.php',
+                'wp-config-sample.php',
+                'wp-cron.php',
+                'wp-links-opml.php',
+                'wp-load.php',
+                'wp-login.php',
+                'wp-mail.php',
+                'wp-pass.php',
+                'wp-register.php',
+                'wp-settings.php',
+                'wp-signup.php',
+                'wp-trackback.php',
+                'xmlrpc.php',
+            );
+            foreach ( $nodes as $key => $node ) {
+                if ( MainWP_Helper::starts_with( $node, ABSPATH . WPINC ) ) {
+                    unset( $nodes[ $key ] );
+                } elseif ( MainWP_Helper::starts_with( $node, ABSPATH . basename( admin_url( '' ) ) ) ) {
+                    unset( $nodes[ $key ] );
+                } else {
+                    foreach ( $coreFiles as $coreFile ) {
+                        if ( ABSPATH . $coreFile === $node ) {
+                            unset( $nodes[ $key ] );
+                        }
+                    }
+                }
+            }
+            unset( $coreFiles );
+        }
+        $this->copy_dir( $nodes, $excludes, $backupFolder, $excludenonwp, true );
+
+        foreach ( $db_files as $db_file ) {
+            copy( $db_file, $backupFolder . basename( WP_CONTENT_DIR ) . '/' . basename( $db_file ) ); // phpcs:ignore -- required to achieve desired results. Pull requests appreciated // NOSONAR .
+            wp_delete_file( $db_file ); // phpcs:ignore -- required to achieve desired results. Pull requests appreciated // NOSONAR.
+        }
+
+        unset( $nodes );
+
+        // Zip this backup folder.
+        require_once ABSPATH . 'wp-admin/includes/class-pclzip.php';
+        $this->zip = new \PclZip( $filepath );
+        $this->zip->create( $backupFolder, PCLZIP_OPT_REMOVE_PATH, $backupFolder );
+        if ( $addConfig ) {
+
+            /**
+             * WordPress Database instance.
+             *
+             * @global object $wpdb
+             */
+            global $wpdb;
+
+            $string = wp_json_encode(
+                array(
+                    'siteurl' => get_option( 'siteurl' ),
+                    'home'    => get_option( 'home' ),
+                    'abspath' => ABSPATH,
+                    'prefix'  => $wpdb->prefix,
+                    'lang'    => WPLANG,
+                )
+            );
+
+            $this->add_file_from_string_to_pcl_zip( 'clone/config.txt', $string, $filepath );
+        }
+        // Remove backup folder.
+        MainWP_Helper::delete_dir( $backupFolder );
+
+        return true;
+    }
+
+    /**
+     * Recursively add directory to default PHP zip library.
+     *
+     * @param string $path     Path to directory.
+     * @param array  $excludes Files or directories to exclude.
+     *
+     * @uses \MainWP\Child\MainWP_Helper::in_excludes() Check if the value is in the excludes list.
+     */
+    public function zip_add_dir( $path, $excludes ) {
+
+        if ( $this->zip instanceof \ZipArchive ) {
+            $this->zip->addEmptyDir( str_replace( ABSPATH, '', $path ) );
+        } else {
+            $this->zip->add_empty_dir( str_replace( ABSPATH, '', $path ) );
+        }
+
+        if ( file_exists( rtrim( $path, '/' ) . '/.htaccess' ) ) {
+            $this->add_file_to_zipp( rtrim( $path, '/' ) . '/.htaccess', rtrim( str_replace( ABSPATH, '', $path ), '/' ) . '/mainwp-htaccess' );
+        }
+
+        $iterator = new \RecursiveIteratorIterator( new \RecursiveDirectoryIterator( $path ), \RecursiveIteratorIterator::SELF_FIRST );
+
+        foreach ( $iterator as $path ) {
+            $name = $path->__toString();
+            if ( ( '.' === basename( $name ) ) || ( '..' === basename( $name ) ) ) {
+                continue;
+            }
+
+            if ( ! MainWP_Helper::in_excludes( $excludes, str_replace( ABSPATH, '', $name ) ) ) {
+                if ( $path->isDir() ) {
+                    $this->zip_add_dir( $name, $excludes );
+                } else {
+                    $this->add_file_to_zipp( $name, str_replace( ABSPATH, '', $name ) );
+                }
+            }
+            $name = null;
+            unset( $name );
+        }
+
+        $iterator = null;
+        unset( $iterator );
+    }
+
+    /**
+     * Add file from a string to zip file.
+     *
+     * @param resource $file   File to add to zip.
+     * @param string   $str String to add.
+     *
+     * @return bool true|false.
+     */
+    public function add_file_from_string_to_zip( $file, $str ) {
+        return $this->zip->addFromString( $file, $str );
+    }
+
+    /**
+     * Add file from a string to pclzip file.
+     *
+     * @param resource $file     File to add to zip.
+     * @param string   $str   String to add.
+     * @param string   $filepath Path to file.
+     *
+     * @return bool true|false.
+     */
+    public function add_file_from_string_to_pcl_zip( $file, $str, $filepath ) {
+        $file        = preg_replace( '/(?:\.|\/)*(.*)/', '$1', $file );
+        $localpath   = dirname( $file );
+        $tmpfilename = dirname( $filepath ) . '/' . basename( $file );
+        if ( false !== MainWP_Helper::file_put_contents( $tmpfilename, $str ) ) { //phpcs:ignore WordPress.WP.AlternativeFunctions
+            $this->zip->delete( PCLZIP_OPT_BY_NAME, $file );
+            $add = $this->zip->add(
+                $tmpfilename,
+                PCLZIP_OPT_REMOVE_PATH,
+                dirname( $filepath ),
+                PCLZIP_OPT_ADD_PATH,
+                $localpath
+            );
+            wp_delete_file( $tmpfilename ); // NOSONAR .
+            if ( ! empty( $add ) ) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * Add file to zip.
+     *
+     * @param string $path         Path to zip file.
+     * @param string $zipEntryName File to add to zip.
+     *
+     * @return bool True|false.
+     *
+     * @uses \MainWP\Child\MainWP_Helper::ends_with()
+     */
+    public function add_file_to_zipp( $path, $zipEntryName ) {
+        if ( time() - $this->lastRun > 20 ) {
+            set_time_limit( $this->timeout ); // phpcs:ignore -- required to achieve desired results. Pull requests appreciated.
+            $this->lastRun = time();
+        }
+
+        if ( $this->excludeZip && MainWP_Helper::ends_with( $path, '.zip' ) ) {
+            return false;
+        }
+
+        $this->zipArchiveSizeCount += filesize( $path );
+        ++$this->gcCnt;
+
+        if ( ! $this->loadFilesBeforeZip || ( filesize( $path ) > 5 * 1024 * 1024 ) ) { // NOSONAR .
+            ++$this->zipArchiveFileCount;
+            if ( $this->zip instanceof \ZipArchive ) {
+                $added = $this->zip->addFile( $path, $zipEntryName );
+            } else {
+                $added = $this->zip->add_file( $path, $zipEntryName );
+            }
+        } else {
+            ++$this->zipArchiveFileCount;
+
+            $this->testContent = file_get_contents( $path ); //phpcs:ignore WordPress.WP.AlternativeFunctions -- // NOSONAR .
+            if ( false === $this->testContent ) {
+                return false;
+            }
+            $added = $this->zip->addFromString( $zipEntryName, $this->testContent );
+        }
+
+        if ( $this->gcCnt > 20 ) {
+            if ( function_exists( 'gc_enable' ) ) {
+                gc_enable();
+            }
+            if ( function_exists( 'gc_collect_cycles' ) ) {
+                gc_collect_cycles();
+            }
+            $this->gcCnt = 0;
+        }
+
+        if ( ( ( $this->file_descriptors > 0 ) && ( $this->zipArchiveFileCount > $this->file_descriptors ) ) ) {
+            $this->zip->close();
+            $this->zip = null;
+            unset( $this->zip );
+            if ( function_exists( 'gc_enable' ) ) {
+                gc_enable();
+            }
+            if ( function_exists( 'gc_collect_cycles' ) ) {
+                gc_collect_cycles();
+            }
+            $this->zip = new \ZipArchive();
+            $this->zip->open( $this->zipArchiveFileName );
+            $this->zipArchiveFileCount = 0;
+            $this->zipArchiveSizeCount = 0;
+        }
+
+        return $added;
+    }
+
+    /**
+     * Create full backup via console.
+     *
+     * @return bool Return false.
+     */
+    public function create_zip_console_full_backup() {
+        return false;
+    }
+
+    /**
+     * Create DB backup.
+     *
+     * @param string $filepath_prefix File path prefix.
+     * @param bool   $archiveExt      Archive extension.
+     * @param object $archiver        Archiver.
+     *
+     * @return array|string[] Action response.
+     *
+     * @uses \MainWP\Child\MainWP_Helper::sanitize_filename() Sanitize filename.
+     * @uses \MainWP\Child\MainWP_Helper::set_limit() Set PHP memory limit.
+     * @uses \MainWP\Child\MainWP_Child_DB::to_query() Run a mysqli query & get a result.
+     * @uses \MainWP\Child\MainWP_Child_DB::fetch_array()
+     * @uses \MainWP\Child\MainWP_Child_DB::real_escape_string()
+     * @uses \MainWP\Child\Tar_Archiver()
+     *
+     * @uses wpdb::get_results() Retrieve an entire SQL result set from the database (i.e., many rows).
+     * @see  https://developer.wordpress.org/reference/classes/wpdb/get_results/
+     *
+     * @uses wpdb::get_row() Retrieve one row from the database.
+     * @see  https://developer.wordpress.org/reference/classes/wpdb/get_row/
+     */
+    public function create_backup_db( $filepath_prefix, $archiveExt = false, &$archiver = null ) {
+
+        $timeout = 20 * 60 * 60;
+        $mem     = '512M';
+        MainWP_Helper::set_limit( $timeout, $mem );
+
+        /**
+         * WordPress Database instance.
+         *
+         * @global object $wpdb
+         */
+        global $wpdb;
+
+        //phpcs:disable WordPress.WP.AlternativeFunctions
+        $db_files  = array();
+        $tables_db = $wpdb->get_results( 'SHOW TABLES FROM `' . DB_NAME . '`', ARRAY_N );  // phpcs:ignore -- required to achieve desired results. Pull requests appreciated.
+        foreach ( $tables_db as $curr_table ) {
+            if ( null !== $archiver ) {
+                $archiver->update_pid_file();
+            }
+
+            $table = $curr_table[0];
+
+            $currentfile = $filepath_prefix . '-' . MainWP_Helper::sanitize_filename( $table ) . '.sql.php';
+            $db_files[]  = $currentfile;
+            if ( file_exists( $currentfile ) ) {
+                continue;
+            }
+            $fh = fopen( $currentfile . '.tmp', 'w' ); // NOSONAR .
+
+            $protect_content_string = '<?php exit(); ?>';
+
+            fwrite( $fh, $protect_content_string );
+            fwrite( $fh, "\n\n" . 'DROP TABLE IF EXISTS ' . $table . ';' );
+            $table_create = $wpdb->get_row( 'SHOW CREATE TABLE ' . $table, ARRAY_N ); // phpcs:ignore -- required to achieve desired results. Pull requests appreciated.
+            fwrite( $fh, "\n" . $table_create[1] . ";\n\n" );
+
+            $rows = MainWP_Child_DB::to_query( 'SELECT * FROM ' . $table, $wpdb->dbh ); // phpcs:ignore -- required to achieve desired results. Pull requests appreciated.
+
+            if ( $rows ) {
+                $i            = 0;
+                $table_insert = 'INSERT INTO `' . $table . '` VALUES (';
+
+                while ( $row = MainWP_Child_DB::fetch_array( $rows ) ) {
+                    $query = $table_insert;
+                    foreach ( $row as $value ) {
+                        if ( null === $value ) {
+                            $query .= 'NULL, ';
+                        } else {
+                            $query .= '"' . MainWP_Child_DB::real_escape_string( $value ) . '", ';
+                        }
+                    }
+                    $query = trim( $query, ', ' ) . ');';
+
+                    fwrite( $fh, "\n" . $query );
+                    ++$i;
+
+                    if ( $i >= 50 ) {
+                        fflush( $fh );
+                        $i = 0;
+                    }
+
+                    $query = null;
+                    $row   = null;
+                }
+            }
+            $rows = null;
+            fflush( $fh );
+            fclose( $fh );
+            rename( $currentfile . '.tmp', $currentfile ); // NOSONAR .
+        }
+
+        fclose( fopen( $filepath_prefix . '.sql', 'w' ) ); // NOSONAR .
+        $db_files[] = $filepath_prefix . '.sql';
+
+        $archivefilePath = null;
+        if ( false !== $archiveExt ) {
+            $archivefilePath = $filepath_prefix . '.sql.' . $archiveExt;
+
+            if ( 'zip' === $archiveExt ) {
+                $this->archiver = null;
+            } else {
+                $this->archiver = new Tar_Archiver( $this, $archiveExt );
+            }
+
+            if ( $this->zip_file( $db_files, $archivefilePath ) && file_exists( $archivefilePath ) ) {
+                foreach ( $db_files as $db_file ) {
+                    wp_delete_file( $db_file );
+                }
+            }
+        }
+        //phpcs:enable WordPress.WP.AlternativeFunctions
+
+        return false !== $archiveExt ? array( 'filepath' => $archivefilePath ) : $db_files;
+    }
+}
diff -rNu /tmp/wpbeacon-audits/audit-11/baseline/class/class-mainwp-child-actions.php /tmp/wpbeacon-audits/audit-11/head/class/class-mainwp-child-actions.php
--- /tmp/wpbeacon-audits/audit-11/baseline/class/class-mainwp-child-actions.php	2024-06-18 08:24:10
+++ /tmp/wpbeacon-audits/audit-11/head/class/class-mainwp-child-actions.php	2024-07-09 12:51:02
@@ -1,984 +1,984 @@
-<?php
-/**
- * MainWP Child Actions.
- *
- * Handle MainWP Child Actions.
- *
- * @package MainWP\Child
- */
-
-namespace MainWP\Child;
-
-/**
- * Class MainWP_Child_Actions
- *
- * Handle MainWP Child Actions.
- */
-class MainWP_Child_Actions { //phpcs:ignore -- NOSONAR - multi method.
-
-    /**
-     * Public static variable to hold the single instance of the class.
-     *
-     * @var mixed Default null
-     */
-    protected static $instance = null;
-
-    /**
-     * Public static variable.
-     *
-     * @var mixed Default null
-     */
-    protected $init_actions = array();
-
-    /**
-     * Public static variable.
-     *
-     * @var mixed Default null
-     */
-    protected static $actions_data = null;
-
-    /**
-     * Public static variable.
-     *
-     * @var mixed Default null
-     */
-    protected static $sending = null;
-
-    /**
-     * Public static variable.
-     *
-     * @var mixed Default null.
-     */
-    protected static $connected_admin = null;
-
-    /**
-     * Public static variable.
-     *
-     * @var mixed Default null.
-     */
-    protected static $enable_actions_notification = null;
-
-    /**
-     * Old plugins.
-     *
-     * @var array Old plugins array.
-     * */
-    public $current_plugins_info = array();
-
-    /**
-     * Old themes.
-     *
-     * @var array Old themes array.
-     * */
-    public $current_themes_info = array();
-
-
-    /**
-     * Method get_class_name()
-     *
-     * Get class name.
-     *
-     * @return string __CLASS__ Class name.
-     */
-    public static function get_class_name() {
-        return __CLASS__;
-    }
-
-    /**
-     * MainWP_Child_Callable constructor.
-     *
-     * Run any time class is called.
-     */
-    public function __construct() {
-        static::$connected_admin             = get_option( 'mainwp_child_connected_admin', '' );
-        static::$enable_actions_notification = (int) get_option( 'mainwp_child_actions_notification_enable', 0 );
-        $this->init_actions                  = array(
-            'upgrader_pre_install',
-            'upgrader_process_complete',
-            'activate_plugin',
-            'deactivate_plugin',
-            'switch_theme',
-            'delete_site_transient_update_themes',
-            'pre_option_uninstall_plugins',
-            'deleted_plugin',
-            '_core_updated_successfully',
-        );
-    }
-
-    /**
-     * Method instance()
-     *
-     * Create a public static instance.
-     *
-     * @return mixed Class instance.
-     */
-    public static function get_instance() {
-        if ( null === static::$instance ) {
-            static::$instance = new self();
-            static::get_actions_data();
-        }
-        return static::$instance;
-    }
-
-    /**
-     * Method init_hooks().
-     *
-     * Init WP hooks.
-     */
-    public function init_hooks() {
-        // avoid actions.
-        if ( MainWP_Helper::is_dashboard_request() ) {
-            return;
-        }
-
-        // not connected, avoid actions.
-        if ( empty( static::$connected_admin ) ) {
-            return;
-        }
-
-        $pubkey = get_option( 'mainwp_child_pubkey' );
-        // not connected, avoid actions.
-        if ( empty( $pubkey ) ) {
-            return;
-        }
-
-        foreach ( $this->init_actions as $action ) {
-            add_action( $action, array( $this, 'callback' ), 10, 99 );
-        }
-        if ( 1 === static::$enable_actions_notification ) {
-            static::$enable_actions_notification = 0; // to do.
-        }
-    }
-
-    /**
-     * Method init_custom_hooks().
-     *
-     * Init WP custom hooks.
-     *
-     * @param string $actions action name.
-     */
-    public function init_custom_hooks( $actions ) {
-
-        if ( is_string( $actions ) ) {
-            $actions = array( $actions );
-        }
-
-        if ( ! is_array( $actions ) ) {
-            return;
-        }
-
-        $allow_acts = array(
-            'upgrader_pre_install',
-        );
-        foreach ( $actions as $action ) {
-            if ( ! in_array( $action, $allow_acts ) ) {
-                continue;
-            }
-            add_action( $action, array( $this, 'callback' ), 10, 99 );
-        }
-    }
-
-    /**
-     * Method get_current_plugins_info().
-     *
-     * Get current plugins info.
-     */
-    public function get_current_plugins_info() {
-        return $this->current_plugins_info;
-    }
-
-
-    /**
-     * Method get_current_themes_info().
-     *
-     * Get current themes info.
-     */
-    public function get_current_themes_info() {
-        return $this->current_themes_info;
-    }
-
-    /**
-     * Callback for all registered hooks.
-     * Looks for a class method with the convention: "callback_{action name}"
-     */
-    public function callback() {
-        $current  = current_filter();
-        $callback = array( $this, 'callback_' . preg_replace( '/[^A-Za-z0-9_\-]/', '_', $current ) ); // to fix A-Z charater in callback name.
-
-        // Call the real function.
-        if ( is_callable( $callback ) ) {
-            return call_user_func_array( $callback, func_get_args() );
-        }
-    }
-
-    /**
-     * Method to get actions info.
-     */
-    public static function get_actions_data() {
-        if ( null === static::$actions_data ) {
-            static::$actions_data = get_option( 'mainwp_child_actions_saved_data', array() );
-            if ( ! is_array( static::$actions_data ) ) {
-                static::$actions_data = array();
-            }
-            $username = get_option( 'mainwp_child_connected_admin', '' );
-            if ( ! isset( static::$actions_data['connected_admin'] ) ) {
-                static::$actions_data['connected_admin'] = $username;
-            } elseif ( '' !== $username && $username !== static::$actions_data['connected_admin'] ) {
-                static::$actions_data = array( 'connected_admin' => $username ); // if it is not same the connected user then clear the actions data.
-                update_option( 'mainwp_child_actions_saved_data', static::$actions_data );
-                delete_option( 'mainwp_child_send_action_notification_next_time' );
-            }
-            static::check_actions_data();
-        }
-        return static::$actions_data;
-    }
-
-
-    /**
-     * Method to save actions info.
-     *
-     * @param int   $index index.
-     * @param array $data Action data .
-     *
-     * @return bool Return TRUE.
-     */
-    private function update_actions_data( $index, $data ) {
-        $index                          = strval( $index );
-        static::$actions_data[ $index ] = $data;
-        update_option( 'mainwp_child_actions_saved_data', static::$actions_data );
-        return true;
-    }
-
-
-    /**
-     * Method to check actions data.
-     * Clear old the action info.
-     */
-    public static function check_actions_data() { //phpcs:ignore -- NOSONAR - complex.
-        // NOSONAR - WP compatible.
-        $checked = intval( get_option( 'mainwp_child_actions_data_checked', 0 ) );
-        if ( empty( $checked ) ) {
-            update_option( 'mainwp_child_actions_data_checked', time() );
-        } else {
-            $checked = date( 'Y-m-d', $checked ); // phpcs:ignore -- Use local time to achieve desired results, pull request solutions appreciated.
-            if ( $checked !== date( 'Y-m-d' ) ) { // phpcs:ignore -- Use local time to achieve desired results, pull request solutions appreciated.
-                $days_number = intval( get_option( 'mainwp_child_actions_saved_number_of_days', 30 ) );
-                $days_number = apply_filters( 'mainwp_child_actions_saved_number_of_days', $days_number );
-                $days_number = ( 3 > $days_number || 6 * 30 < $days_number ) ? 30 : $days_number;
-                $check_time  = $days_number * \DAY_IN_SECONDS;
-
-                $updated = false;
-                foreach ( static::$actions_data as $index => $data ) {
-
-                    if ( 'connected_admin' === strval( $index ) ) {
-                        continue;
-                    }
-
-                    if ( ! is_array( $data ) || $check_time < time() - intval( $data['created'] ) || empty( $data['action_user'] ) ) {
-                        unset( static::$actions_data[ $index ] );
-                        $updated = true;
-                    }
-                }
-
-                if ( $updated ) {
-                    update_option( 'mainwp_child_actions_saved_data', static::$actions_data );
-                }
-                update_option( 'mainwp_child_actions_data_checked', time() );
-            }
-        }
-    }
-
-    /**
-     * Log plugin installations.
-     *
-     * @action transition_post_status.
-     *
-     * @param \WP_Upgrader $upgrader WP_Upgrader class object.
-     * @param array        $extra Extra attributes array.
-     *
-     * @return bool Return TRUE|FALSE.
-     */
-    public function callback_upgrader_process_complete( $upgrader, $extra ) { // phpcs:ignore -- NOSONAR - required to achieve desired results, pull request solutions appreciated.
-        $logs    = array();
-        $success = ! is_wp_error( $upgrader->skin->result );
-        $error   = null;
-
-        if ( ! $success ) {
-            $errors = $upgrader->skin->result->errors;
-
-            list( $error ) = reset( $errors );
-        }
-
-        // This would have failed down the road anyway.
-        if ( ! isset( $extra['type'] ) ) {
-            return false;
-        }
-
-        $type   = $extra['type'];
-        $action = $extra['action'];
-
-        if ( ! in_array( $type, array( 'plugin', 'theme' ), true ) ) {
-            return false;
-        }
-
-        if ( 'install' === $action ) {
-            if ( 'plugin' === $type ) {
-                $path = $upgrader->plugin_info();
-
-                if ( ! $path ) {
-                    return false;
-                }
-
-                $data    = get_plugin_data( $upgrader->skin->result['local_destination'] . '/' . $path );
-                $slug    = $upgrader->result['destination_name'];
-                $name    = $data['Name'];
-                $version = $data['Version'];
-            } else { // theme.
-                $slug = $upgrader->theme_info();
-
-                if ( ! $slug ) {
-                    return false;
-                }
-
-                wp_clean_themes_cache();
-
-                $theme   = wp_get_theme( $slug );
-                $name    = $theme->name;
-                $version = $theme->version;
-            }
-
-            $action = 'installed';
-            // translators: Placeholders refer to a plugin/theme type, a plugin/theme name, and a plugin/theme version (e.g. "plugin", "Stream", "4.2").
-            $message = _x(
-                'Installed %1$s: %2$s %3$s',
-                'Plugin/theme installation. 1: Type (plugin/theme), 2: Plugin/theme name, 3: Plugin/theme version',
-                'mainwp-child'
-            );
-
-            $logs[] = compact( 'slug', 'name', 'version', 'message', 'action' );
-        } elseif ( 'update' === $action ) {
-
-            if ( is_object( $upgrader ) && property_exists( $upgrader, 'skin' ) && 'Automatic_Upgrader_Skin' === get_class( $upgrader->skin ) ) {
-                return false;
-            }
-
-            $action = 'updated';
-            // translators: Placeholders refer to a plugin/theme type, a plugin/theme name, and a plugin/theme version (e.g. "plugin", "Stream", "4.2").
-            $message = _x(
-                'Updated %1$s: %2$s %3$s',
-                'Plugin/theme update. 1: Type (plugin/theme), 2: Plugin/theme name, 3: Plugin/theme version',
-                'mainwp-child'
-            );
-
-            if ( 'plugin' === $type ) {
-                if ( isset( $extra['bulk'] ) && true === $extra['bulk'] ) {
-                    $slugs = $extra['plugins'];
-                } else {
-                    $slugs = array( $upgrader->skin->plugin );
-                }
-
-                foreach ( $slugs as $slug ) {
-                    $plugin_data = get_plugin_data( WP_PLUGIN_DIR . '/' . $slug );
-                    $name        = $plugin_data['Name'];
-                    $version     = $plugin_data['Version'];
-                    // ( Net-Concept - Xavier NUEL ) : get old versions.
-                    if ( isset( $this->current_plugins_info[ $slug ] ) ) {
-                        $old_version = $this->current_plugins_info[ $slug ]['Version'];
-                    } else {
-                        $old_version = $upgrader->skin->plugin_info['Version']; // to fix old version.
-                    }
-
-                    if ( version_compare( $version, $old_version, '>' ) ) {
-                        $logs[] = compact( 'slug', 'name', 'old_version', 'version', 'message', 'action' );
-                    }
-                }
-            } else { // theme.
-                if ( isset( $extra['bulk'] ) && true === $extra['bulk'] ) {
-                    $slugs = $extra['themes'];
-                } else {
-                    $slugs = array( $upgrader->skin->theme );
-                }
-
-                foreach ( $slugs as $slug ) {
-                    $theme      = wp_get_theme( $slug );
-                    $stylesheet = $theme['Stylesheet Dir'] . '/style.css';
-                    $theme_data = get_file_data(
-                        $stylesheet,
-                        array(
-                            'Version' => 'Version',
-                        )
-                    );
-                    $name       = $theme['Name'];
-                    $version    = $theme_data['Version'];
-
-                    $old_version = '';
-
-                    if ( isset( $this->current_themes_info[ $slug ] ) ) {
-                        $old_theme = $this->current_themes_info[ $slug ];
-
-                        if ( isset( $old_theme['version'] ) ) {
-                            $old_version = $old_theme['version'];
-                        }
-                    } elseif ( ! empty( $upgrader->skin->theme_info ) ) {
-                        $old_version = $upgrader->skin->theme_info->get( 'Version' ); // to fix old version  //$theme['Version'].
-                    }
-
-                    $logs[] = compact( 'slug', 'name', 'old_version', 'version', 'message', 'action' );
-                }
-            }
-        } else {
-            return false;
-        }
-
-        $context = $type . 's';
-
-        foreach ( $logs as $log ) {
-            $name        = isset( $log['name'] ) ? $log['name'] : null;
-            $version     = isset( $log['version'] ) ? $log['version'] : null;
-            $slug        = isset( $log['slug'] ) ? $log['slug'] : null;
-            $old_version = isset( $log['old_version'] ) ? $log['old_version'] : null;
-            $message     = isset( $log['message'] ) ? $log['message'] : null;
-            $action      = isset( $log['action'] ) ? $log['action'] : null;
-
-            $this->save_actions(
-                $message,
-                compact( 'type', 'name', 'version', 'slug', 'success', 'error', 'old_version' ),
-                $context,
-                $action
-            );
-        }
-        return true;
-    }
-
-
-    /**
-     * Activate plugin callback.
-     *
-     * @param string $slug Plugin slug.
-     * @param bool   $network_wide Check if network wide.
-     */
-    public function callback_activate_plugin( $slug, $network_wide = false ) {
-        $_plugins     = $this->get_plugins();
-        $name         = $_plugins[ $slug ]['Name'];
-        $network_wide = $network_wide ? esc_html__( 'network wide', 'mainwp-child' ) : null;
-
-        if ( empty( $name ) ) {
-            return;
-        }
-
-        $this->save_actions(
-            _x(
-                '"%1$s" plugin activated %2$s',
-                '1: Plugin name, 2: Single site or network wide',
-                'mainwp-child'
-            ),
-            compact( 'name', 'network_wide', 'slug' ),
-            'plugins',
-            'activated'
-        );
-    }
-
-    /**
-     * Decativate plugin callback.
-     *
-     * @param string $slug Plugin slug.
-     * @param bool   $network_wide Check if network wide.
-     */
-    public function callback_deactivate_plugin( $slug, $network_wide = false ) {
-        $_plugins     = $this->get_plugins();
-        $name         = $_plugins[ $slug ]['Name'];
-        $network_wide = $network_wide ? esc_html__( 'network wide', 'mainwp-child' ) : null;
-
-        $this->save_actions(
-            _x(
-                '"%1$s" plugin deactivated %2$s',
-                '1: Plugin name, 2: Single site or network wide',
-                'mainwp-child'
-            ),
-            compact( 'name', 'network_wide', 'slug' ),
-            'plugins',
-            'deactivated'
-        );
-    }
-
-    /**
-     * Switch theme callback.
-     *
-     * @param string $name Theme name.
-     * @param string $theme Theme slug.
-     */
-    public function callback_switch_theme( $name, $theme ) {
-        unset( $theme );
-        $this->save_actions(
-            esc_html__( '"%s" theme activated', 'mainwp-child' ),
-            compact( 'name' ),
-            'themes',
-            'activated'
-        );
-    }
-
-    /**
-     * Update theme & transient delete callback.
-     *
-     * @devtodo Core needs a delete_theme hook
-     */
-    public function callback_delete_site_transient_update_themes() {
-        $backtrace = debug_backtrace(); // @codingStandardsIgnoreLine This is used as a hack to determine a theme was deleted.
-        $delete_theme_call = null;
-
-        foreach ( $backtrace as $call ) {
-            if ( isset( $call['function'] ) && 'delete_theme' === $call['function'] ) {
-                $delete_theme_call = $call;
-                break;
-            }
-        }
-
-        if ( empty( $delete_theme_call ) ) {
-            return;
-        }
-
-        $name = $delete_theme_call['args'][0];
-        // @devtodo Can we get the name of the theme? Or has it already been eliminated
-
-        $this->save_actions(
-            esc_html__( '"%s" theme deleted', 'mainwp-child' ),
-            compact( 'name' ),
-            'themes',
-            'deleted'
-        );
-    }
-
-    /**
-     * Uninstall plugins callback.
-     */
-    public function callback_pre_option_uninstall_plugins() {
-        // phpcs:disable WordPress.Security.NonceVerification
-        if ( ! isset( $_POST['action'] ) || 'delete-plugin' !== $_POST['action'] ) {
-            return false;
-        }
-        $plugin = isset( $_POST['plugin'] ) ? sanitize_text_field( wp_unslash( $_POST['plugin'] ) ) : '';
-        // phpcs:enable
-        $_plugins                     = $this->get_plugins();
-        $plugins_to_delete            = array();
-        $plugins_to_delete[ $plugin ] = isset( $_plugins[ $plugin ] ) ? $_plugins[ $plugin ] : array();
-        update_option( 'wp_mainwp_stream_plugins_to_delete', $plugins_to_delete );
-        return false;
-    }
-
-    /**
-     * Uninstall plugins callback.
-     *
-     * @param string $plugin_file  plugin file name.
-     * @param bool   $deleted deleted or not.
-     */
-    public function callback_deleted_plugin( $plugin_file, $deleted ) {
-        if ( $deleted ) {
-
-            if ( ! isset( $_POST['action'] ) || 'delete-plugin' !== $_POST['action'] ) { // phpcs:ignore WordPress.Security.NonceVerification
-                return;
-            }
-            $plugins_to_delete = get_option( 'wp_mainwp_stream_plugins_to_delete' );
-            if ( ! $plugins_to_delete ) {
-                return;
-            }
-            foreach ( $plugins_to_delete as $plugin => $data ) {
-                if ( $plugin_file === $plugin ) {
-                    $name         = $data['Name'];
-                    $network_wide = $data['Network'] ? esc_html__( 'network wide', 'mainwp-child' ) : '';
-
-                    $this->save_actions(
-                        esc_html__( '"%s" plugin deleted', 'mainwp-child' ),
-                        compact( 'name', 'plugin', 'network_wide' ),
-                        'plugins',
-                        'deleted'
-                    );
-                }
-            }
-            delete_option( 'wp_mainwp_stream_plugins_to_delete' );
-        }
-    }
-
-    /**
-     * Logs WordPress core upgrades
-     *
-     * @action automatic_updates_complete
-     *
-     * @param string $update_results  Update results.
-     * @return mixed bool|null.
-     */
-    public function callback_automatic_updates_complete( $update_results ) {
-        global $pagenow, $wp_version;
-
-        if ( ! is_array( $update_results ) || ! isset( $update_results['core'] ) ) {
-            return false;
-        }
-
-        $info = $update_results['core'][0];
-
-        $old_version  = $wp_version;
-        $new_version  = $info->item->version;
-        $auto_updated = true;
-
-        $message = esc_html__( 'WordPress auto-updated to %s', 'stream' );
-
-        $this->save_actions(
-            $message,
-            compact( 'new_version', 'old_version', 'auto_updated' ),
-            'wordpress', // phpcs:ignore -- fix format text.
-            'updated'
-        );
-    }
-
-    /**
-     * Core updated successfully callback.
-     */
-    public function callback__core_updated_successfully() {
-
-        /**
-         * Global variables.
-         *
-         * @global string $pagenow Current page.
-         * @global string $wp_version WordPress version.
-         */
-        global $pagenow, $wp_version;
-
-        $old_version  = $wp_version;
-        $auto_updated = ( 'update-core.php' !== $pagenow );
-
-        if ( $auto_updated ) {
-            // translators: Placeholder refers to a version number (e.g. "4.2").
-            $message = esc_html__( 'WordPress auto-updated to %s', 'mainwp-child' );
-        } else {
-            // translators: Placeholder refers to a version number (e.g. "4.2").
-            $message = esc_html__( 'WordPress updated to %s', 'mainwp-child' );
-        }
-
-        $this->save_actions(
-            $message,
-            compact( 'new_version', 'old_version', 'auto_updated' ),
-            'wordpress', // phpcs:ignore -- fix format text.
-            'updated'
-        );
-    }
-
-    /**
-     * Upgrader pre-instaler callback.
-     */
-    public function callback_upgrader_pre_install() { //phpcs:ignore -- NOSONAR - complex.
-        // NOSONAR - WP compatible.
-        if ( empty( $this->current_plugins_info ) ) {
-            $this->current_plugins_info = $this->get_plugins();
-        }
-
-        if ( empty( $this->current_themes_info ) ) {
-            $this->current_themes_info = array();
-
-            if ( ! function_exists( '\wp_get_themes' ) ) {
-                require_once ABSPATH . '/wp-admin/includes/theme.php'; // NOSONAR - WP compatible.
-            }
-
-            $themes = wp_get_themes();
-
-            if ( is_array( $themes ) ) {
-                $theme_name  = wp_get_theme()->get( 'Name' );
-                $parent_name = '';
-                $parent      = wp_get_theme()->parent();
-                if ( $parent ) {
-                    $parent_name = $parent->get( 'Name' );
-                }
-                foreach ( $themes as $theme ) {
-
-                    $_slug = $theme->get_stylesheet();
-                    if ( isset( $this->current_themes_info[ $_slug ] ) ) {
-                        continue;
-                    }
-
-                    $out                  = array();
-                    $out['name']          = $theme->get( 'Name' );
-                    $out['title']         = $theme->display( 'Name', true, false );
-                    $out['version']       = $theme->display( 'Version', true, false );
-                    $out['active']        = ( $theme->get( 'Name' ) === $theme_name ) ? 1 : 0;
-                    $out['slug']          = $_slug;
-                    $out['parent_active'] = ( $parent_name === $out['name'] ) ? 1 : 0;
-
-                    $this->current_themes_info[ $_slug ] = $out;
-                }
-            }
-        }
-    }
-
-    /**
-     * Wrapper method for calling get_plugins().
-     *
-     * @return array Installed plugins.
-     */
-    public function get_plugins() {
-        if ( ! function_exists( 'get_plugins' ) ) {
-            require_once ABSPATH . 'wp-admin/includes/plugin.php'; // NOSONAR - WP compatible.
-        }
-
-        return get_plugins();
-    }
-
-    /**
-     * Log handler.
-     *
-     * @param string $message           sprintf-ready error message string.
-     * @param array  $args              sprintf (and extra) arguments to use.
-     * @param string $context           Context of the event.
-     * @param string $action            Action of the event.
-     */
-    public function save_actions( $message, $args, $context, $action ) { // phpcs:ignore -- NOSONAR - complex.
-
-        /**
-         * Global variable.
-         *
-         * @global object $wp_roles WordPress user roles object.
-         * */
-        global $wp_roles;
-
-        if ( defined( 'WP_IMPORTING' ) && WP_IMPORTING ) {
-            return false;
-        }
-
-        $context_label = $this->get_valid_context( $context );
-        if ( empty( $context_label ) ) { // not valid.
-            return false;
-        }
-
-        $action_label = $this->get_valid_action( $action );
-        if ( empty( $action_label ) ) { // not valid.
-            return false;
-        }
-
-        $user_id = get_current_user_id();
-        $user    = get_user_by( 'id', $user_id );
-
-        $connected_user = get_option( 'mainwp_child_connected_admin', '' );
-
-        if ( ! empty( $user->user_login ) && $connected_user === $user->user_login && MainWP_Helper::is_dashboard_request( true ) ) {
-            return false;  // not save action.
-        }
-
-        $actions_save = apply_filters( 'mainwp_child_actions_save_data', true, $context, $action, $args, $message, $user_id );
-
-        if ( ! $actions_save ) {
-            return false;
-        }
-
-        $user_role_label = '';
-        $role            = '';
-        $roles           = MainWP_Utility::instance()->get_roles();
-        if ( ! empty( $user->roles ) ) {
-            $user_roles      = array_values( $user->roles );
-            $role            = $user_roles[0];
-            $user_role_label = isset( $roles[ $role ] ) ? $roles[ $role ] : $role;
-        }
-
-        $userlogin = (string) ( ! empty( $user->user_login ) ? $user->user_login : '' );
-
-        $agent     = $this->get_current_agent();
-        $meta_data = array(
-            'user_id'         => (int) $user_id,
-            'display_name'    => (string) $this->get_display_name( $user ),
-            'action_user'     => (string) $userlogin,
-            'role'            => (string) $role,
-            'user_role_label' => (string) $user_role_label,
-            'agent'           => (string) $agent,
-        );
-
-        if ( 'wp_cli' === $agent && function_exists( 'posix_getuid' ) ) {
-            $uid       = posix_getuid();
-            $user_info = posix_getpwuid( $uid );
-
-            $meta_data['system_user_id']   = (int) $uid;
-            $meta_data['system_user_name'] = (string) $user_info['name'];
-        }
-
-        // Prevent any meta with null values from being logged.
-        $other_meta = array_filter(
-            $args,
-            function ( $val ) {
-                return ! is_null( $val );
-            }
-        );
-
-        // Add user meta to Stream meta.
-        $other_meta['meta_data'] = $meta_data;
-
-        $created = MainWP_Helper::get_timestamp();
-
-        $action = (string) $action;
-
-        $new_action = 0;
-        if ( 1 === static::$enable_actions_notification ) {
-            $new_action = 1; // new to notification.
-        }
-
-        $recordarr = array(
-            'context'     => $context,
-            'action'      => $action,
-            'action_user' => $userlogin,
-            'created'     => $created,
-            'summary'     => (string) vsprintf( $message, $args ),
-            'meta_data'   => $other_meta,
-            'new'         => $new_action,
-        );
-        $index     = time() . rand( 1000, 9999 ); // phpcs:ignore -- ok for index.
-        $this->update_actions_data( $index, $recordarr );
-
-        if ( 1 === $new_action ) {
-            update_option( 'mainwp_child_send_action_notification_next_time', time() + 5 * MINUTE_IN_SECONDS );
-        }
-    }
-
-
-    /**
-     * Delete actions logs.
-     */
-    public function delete_actions() {
-        delete_option( 'mainwp_child_actions_saved_data' );
-        delete_option( 'mainwp_child_send_action_notification_next_time' );
-        MainWP_Helper::write( array( 'success' => 'ok' ) );
-    }
-
-    /**
-     * Get valid context.
-     *
-     * @param string $context  Context.
-     *
-     * @return string Context label.
-     */
-    public function get_valid_context( $context ) {
-        $context = (string) $context;
-        $valid   = array(
-            'plugins'   => 'Plugins',
-            'themes'    => 'Themes',
-            'wordpress' => 'WordPress'  // phpcs:ignore -- fix format text.
-        );
-        return isset( $valid[ $context ] ) ? $valid[ $context ] : '';
-    }
-
-    /**
-     * Get valid action.
-     *
-     * @param string $action  action.
-     *
-     * @return string action label.
-     */
-    public function get_valid_action( $action ) {
-        $action = (string) $action;
-        $valid  = array(
-            'updated'     => 'updated',
-            'deleted'     => 'deleted',
-            'activated'   => 'activated',
-            'deactivated' => 'deactivated',
-            'installed'   => 'installed',
-        );
-        return isset( $valid[ $action ] ) ? $valid[ $action ] : '';
-    }
-
-    /**
-     * Get the display name of the user
-     *
-     * @param mixed $user  User object.
-     *
-     * @return string Return User Login or Display Names.
-     */
-    public function get_display_name( $user ) {
-        if ( empty( $user->ID ) ) {
-            if ( 'wp_cli' === $this->get_current_agent() ) {
-                return 'WP-CLI';
-            }
-            $title = esc_html__( 'N/A', 'mainwp-child' );
-        } elseif ( ! empty( $user->display_name ) ) {
-            $title = $user->display_name;
-        } else {
-            $title = $user->user_login;
-        }
-        return $title;
-    }
-
-    /**
-     * Get agent.
-     *
-     * @return string
-     */
-    public function get_current_agent() {
-        $agent = '';
-        if ( defined( '\WP_CLI' ) && \WP_CLI ) {
-            $agent = 'wp_cli';
-        } elseif ( $this->is_doing_wp_cron() ) {
-            $agent = 'wp_cron';
-        }
-        return $agent;
-    }
-
-    /**
-     * True if doing WP Cron, otherwise false.
-     *
-     * @return bool
-     */
-    public function is_doing_wp_cron() {
-        return $this->is_cron_enabled() && defined( 'DOING_CRON' ) && DOING_CRON;
-    }
-
-    /**
-     * True if native WP Cron is enabled, otherwise false.
-     *
-     * @return bool
-     */
-    public function is_cron_enabled() {
-        return ( defined( 'DISABLE_WP_CRON' ) && DISABLE_WP_CRON ) ? false : true;
-    }
-
-    /**
-     * Method send_installer_notification()
-     *
-     * To send email notification for plugins/themes/core change.
-     *
-     * @param array $data  Action Data.
-     */
-    public function send_actions_notification( $data ) {
-
-        if ( 1 !== static::$enable_actions_notification ) {
-            return;
-        }
-
-        $username = get_option( 'mainwp_child_connected_admin', '' );
-        $user     = get_user_by( 'login', $username );
-        $email    = ! empty( $user->user_email ) ? $user->user_email : '';
-
-        if ( empty( $email ) ) {
-            return;
-        }
-
-        $actions = static::get_actions_data();
-
-        ksort( $actions );
-        // site info.
-        $blog = get_bloginfo( 'name' );
-
-        $content = '<div>Actions notification</div><div></div><br>';
-
-        foreach ( $actions as $index => $data ) {
-            if ( 'connected_admin' === strval( $index ) ) {
-                continue;
-            }
-            if ( is_array( $data ) && ! empty( $data['action_user'] ) && isset( $data['new'] ) && 1 === (int) $data['new'] ) {
-                $content    .= $data['action_user'] . ' - ' . $data['summray'] . ' - ' . MainWP_Helper::format_timestamp( ( $data['created'] ) ) . '<br>';
-                $data['new'] = 0;
-                $this->update_actions_data( $index, $data );
-            }
-        }
-
-        MainWP_Utility::instance()->send_wp_mail(
-            $email,
-            'MainWP - Actions notification: ' . $blog,
-            MainWP_Child_Format::format_email( $content ),
-            array(
-                'content-type: text/html',
-            )
-        );
-    }
-}
+<?php
+/**
+ * MainWP Child Actions.
+ *
+ * Handle MainWP Child Actions.
+ *
+ * @package MainWP\Child
+ */
+
+namespace MainWP\Child;
+
+/**
+ * Class MainWP_Child_Actions
+ *
+ * Handle MainWP Child Actions.
+ */
+class MainWP_Child_Actions { //phpcs:ignore -- NOSONAR - multi method.
+
+    /**
+     * Public static variable to hold the single instance of the class.
+     *
+     * @var mixed Default null
+     */
+    protected static $instance = null;
+
+    /**
+     * Public static variable.
+     *
+     * @var mixed Default null
+     */
+    protected $init_actions = array();
+
+    /**
+     * Public static variable.
+     *
+     * @var mixed Default null
+     */
+    protected static $actions_data = null;
+
+    /**
+     * Public static variable.
+     *
+     * @var mixed Default null
+     */
+    protected static $sending = null;
+
+    /**
+     * Public static variable.
+     *
+     * @var mixed Default null.
+     */
+    protected static $connected_admin = null;
+
+    /**
+     * Public static variable.
+     *
+     * @var mixed Default null.
+     */
+    protected static $enable_actions_notification = null;
+
+    /**
+     * Old plugins.
+     *
+     * @var array Old plugins array.
+     * */
+    public $current_plugins_info = array();
+
+    /**
+     * Old themes.
+     *
+     * @var array Old themes array.
+     * */
+    public $current_themes_info = array();
+
+
+    /**
+     * Method get_class_name()
+     *
+     * Get class name.
+     *
+     * @return string __CLASS__ Class name.
+     */
+    public static function get_class_name() {
+        return __CLASS__;
+    }
+
+    /**
+     * MainWP_Child_Callable constructor.
+     *
+     * Run any time class is called.
+     */
+    public function __construct() {
+        static::$connected_admin             = get_option( 'mainwp_child_connected_admin', '' );
+        static::$enable_actions_notification = (int) get_option( 'mainwp_child_actions_notification_enable', 0 );
+        $this->init_actions                  = array(
+            'upgrader_pre_install',
+            'upgrader_process_complete',
+            'activate_plugin',
+            'deactivate_plugin',
+            'switch_theme',
+            'delete_site_transient_update_themes',
+            'pre_option_uninstall_plugins',
+            'deleted_plugin',
+            '_core_updated_successfully',
+        );
+    }
+
+    /**
+     * Method instance()
+     *
+     * Create a public static instance.
+     *
+     * @return mixed Class instance.
+     */
+    public static function get_instance() {
+        if ( null === static::$instance ) {
+            static::$instance = new self();
+            static::get_actions_data();
+        }
+        return static::$instance;
+    }
+
+    /**
+     * Method init_hooks().
+     *
+     * Init WP hooks.
+     */
+    public function init_hooks() {
+        // avoid actions.
+        if ( MainWP_Helper::is_dashboard_request() ) {
+            return;
+        }
+
+        // not connected, avoid actions.
+        if ( empty( static::$connected_admin ) ) {
+            return;
+        }
+
+        $pubkey = get_option( 'mainwp_child_pubkey' );
+        // not connected, avoid actions.
+        if ( empty( $pubkey ) ) {
+            return;
+        }
+
+        foreach ( $this->init_actions as $action ) {
+            add_action( $action, array( $this, 'callback' ), 10, 99 );
+        }
+        if ( 1 === static::$enable_actions_notification ) {
+            static::$enable_actions_notification = 0; // to do.
+        }
+    }
+
+    /**
+     * Method init_custom_hooks().
+     *
+     * Init WP custom hooks.
+     *
+     * @param string $actions action name.
+     */
+    public function init_custom_hooks( $actions ) {
+
+        if ( is_string( $actions ) ) {
+            $actions = array( $actions );
+        }
+
+        if ( ! is_array( $actions ) ) {
+            return;
+        }
+
+        $allow_acts = array(
+            'upgrader_pre_install',
+        );
+        foreach ( $actions as $action ) {
+            if ( ! in_array( $action, $allow_acts ) ) {
+                continue;
+            }
+            add_action( $action, array( $this, 'callback' ), 10, 99 );
+        }
+    }
+
+    /**
+     * Method get_current_plugins_info().
+     *
+     * Get current plugins info.
+     */
+    public function get_current_plugins_info() {
+        return $this->current_plugins_info;
+    }
+
+
+    /**
+     * Method get_current_themes_info().
+     *
+     * Get current themes info.
+     */
+    public function get_current_themes_info() {
+        return $this->current_themes_info;
+    }
+
+    /**
+     * Callback for all registered hooks.
+     * Looks for a class method with the convention: "callback_{action name}"
+     */
+    public function callback() {
+        $current  = current_filter();
+        $callback = array( $this, 'callback_' . preg_replace( '/[^A-Za-z0-9_\-]/', '_', $current ) ); // to fix A-Z charater in callback name.
+
+        // Call the real function.
+        if ( is_callable( $callback ) ) {
+            return call_user_func_array( $callback, func_get_args() );
+        }
+    }
+
+    /**
+     * Method to get actions info.
+     */
+    public static function get_actions_data() {
+        if ( null === static::$actions_data ) {
+            static::$actions_data = get_option( 'mainwp_child_actions_saved_data', array() );
+            if ( ! is_array( static::$actions_data ) ) {
+                static::$actions_data = array();
+            }
+            $username = get_option( 'mainwp_child_connected_admin', '' );
+            if ( ! isset( static::$actions_data['connected_admin'] ) ) {
+                static::$actions_data['connected_admin'] = $username;
+            } elseif ( '' !== $username && $username !== static::$actions_data['connected_admin'] ) {
+                static::$actions_data = array( 'connected_admin' => $username ); // if it is not same the connected user then clear the actions data.
+                update_option( 'mainwp_child_actions_saved_data', static::$actions_data );
+                delete_option( 'mainwp_child_send_action_notification_next_time' );
+            }
+            static::check_actions_data();
+        }
+        return static::$actions_data;
+    }
+
+
+    /**
+     * Method to save actions info.
+     *
+     * @param int   $index index.
+     * @param array $data Action data .
+     *
+     * @return bool Return TRUE.
+     */
+    private function update_actions_data( $index, $data ) {
+        $index                          = strval( $index );
+        static::$actions_data[ $index ] = $data;
+        update_option( 'mainwp_child_actions_saved_data', static::$actions_data );
+        return true;
+    }
+
+
+    /**
+     * Method to check actions data.
+     * Clear old the action info.
+     */
+    public static function check_actions_data() { //phpcs:ignore -- NOSONAR - complex.
+        // NOSONAR - WP compatible.
+        $checked = intval( get_option( 'mainwp_child_actions_data_checked', 0 ) );
+        if ( empty( $checked ) ) {
+            update_option( 'mainwp_child_actions_data_checked', time() );
+        } else {
+            $checked = date( 'Y-m-d', $checked ); // phpcs:ignore -- Use local time to achieve desired results, pull request solutions appreciated.
+            if ( $checked !== date( 'Y-m-d' ) ) { // phpcs:ignore -- Use local time to achieve desired results, pull request solutions appreciated.
+                $days_number = intval( get_option( 'mainwp_child_actions_saved_number_of_days', 30 ) );
+                $days_number = apply_filters( 'mainwp_child_actions_saved_number_of_days', $days_number );
+                $days_number = ( 3 > $days_number || 6 * 30 < $days_number ) ? 30 : $days_number;
+                $check_time  = $days_number * \DAY_IN_SECONDS;
+
+                $updated = false;
+                foreach ( static::$actions_data as $index => $data ) {
+
+                    if ( 'connected_admin' === strval( $index ) ) {
+                        continue;
+                    }
+
+                    if ( ! is_array( $data ) || $check_time < time() - intval( $data['created'] ) || empty( $data['action_user'] ) ) {
+                        unset( static::$actions_data[ $index ] );
+                        $updated = true;
+                    }
+                }
+
+                if ( $updated ) {
+                    update_option( 'mainwp_child_actions_saved_data', static::$actions_data );
+                }
+                update_option( 'mainwp_child_actions_data_checked', time() );
+            }
+        }
+    }
+
+    /**
+     * Log plugin installations.
+     *
+     * @action transition_post_status.
+     *
+     * @param \WP_Upgrader $upgrader WP_Upgrader class object.
+     * @param array        $extra Extra attributes array.
+     *
+     * @return bool Return TRUE|FALSE.
+     */
+    public function callback_upgrader_process_complete( $upgrader, $extra ) { // phpcs:ignore -- NOSONAR - required to achieve desired results, pull request solutions appreciated.
+        $logs    = array();
+        $success = ! is_wp_error( $upgrader->skin->result );
+        $error   = null;
+
+        if ( ! $success ) {
+            $errors = $upgrader->skin->result->errors;
+
+            list( $error ) = reset( $errors );
+        }
+
+        // This would have failed down the road anyway.
+        if ( ! isset( $extra['type'] ) ) {
+            return false;
+        }
+
+        $type   = $extra['type'];
+        $action = $extra['action'];
+
+        if ( ! in_array( $type, array( 'plugin', 'theme' ), true ) ) {
+            return false;
+        }
+
+        if ( 'install' === $action ) {
+            if ( 'plugin' === $type ) {
+                $path = $upgrader->plugin_info();
+
+                if ( ! $path ) {
+                    return false;
+                }
+
+                $data    = get_plugin_data( $upgrader->skin->result['local_destination'] . '/' . $path );
+                $slug    = $upgrader->result['destination_name'];
+                $name    = $data['Name'];
+                $version = $data['Version'];
+            } else { // theme.
+                $slug = $upgrader->theme_info();
+
+                if ( ! $slug ) {
+                    return false;
+                }
+
+                wp_clean_themes_cache();
+
+                $theme   = wp_get_theme( $slug );
+                $name    = $theme->name;
+                $version = $theme->version;
+            }
+
+            $action = 'installed';
+            // translators: Placeholders refer to a plugin/theme type, a plugin/theme name, and a plugin/theme version (e.g. "plugin", "Stream", "4.2").
+            $message = _x(
+                'Installed %1$s: %2$s %3$s',
+                'Plugin/theme installation. 1: Type (plugin/theme), 2: Plugin/theme name, 3: Plugin/theme version',
+                'mainwp-child'
+            );
+
+            $logs[] = compact( 'slug', 'name', 'version', 'message', 'action' );
+        } elseif ( 'update' === $action ) {
+
+            if ( is_object( $upgrader ) && property_exists( $upgrader, 'skin' ) && 'Automatic_Upgrader_Skin' === get_class( $upgrader->skin ) ) {
+                return false;
+            }
+
+            $action = 'updated';
+            // translators: Placeholders refer to a plugin/theme type, a plugin/theme name, and a plugin/theme version (e.g. "plugin", "Stream", "4.2").
+            $message = _x(
+                'Updated %1$s: %2$s %3$s',
+                'Plugin/theme update. 1: Type (plugin/theme), 2: Plugin/theme name, 3: Plugin/theme version',
+                'mainwp-child'
+            );
+
+            if ( 'plugin' === $type ) {
+                if ( isset( $extra['bulk'] ) && true === $extra['bulk'] ) {
+                    $slugs = $extra['plugins'];
+                } else {
+                    $slugs = array( $upgrader->skin->plugin );
+                }
+
+                foreach ( $slugs as $slug ) {
+                    $plugin_data = get_plugin_data( WP_PLUGIN_DIR . '/' . $slug );
+                    $name        = $plugin_data['Name'];
+                    $version     = $plugin_data['Version'];
+                    // ( Net-Concept - Xavier NUEL ) : get old versions.
+                    if ( isset( $this->current_plugins_info[ $slug ] ) ) {
+                        $old_version = $this->current_plugins_info[ $slug ]['Version'];
+                    } else {
+                        $old_version = $upgrader->skin->plugin_info['Version']; // to fix old version.
+                    }
+
+                    if ( version_compare( $version, $old_version, '>' ) ) {
+                        $logs[] = compact( 'slug', 'name', 'old_version', 'version', 'message', 'action' );
+                    }
+                }
+            } else { // theme.
+                if ( isset( $extra['bulk'] ) && true === $extra['bulk'] ) {
+                    $slugs = $extra['themes'];
+                } else {
+                    $slugs = array( $upgrader->skin->theme );
+                }
+
+                foreach ( $slugs as $slug ) {
+                    $theme      = wp_get_theme( $slug );
+                    $stylesheet = $theme['Stylesheet Dir'] . '/style.css';
+                    $theme_data = get_file_data(
+                        $stylesheet,
+                        array(
+                            'Version' => 'Version',
+                        )
+                    );
+                    $name       = $theme['Name'];
+                    $version    = $theme_data['Version'];
+
+                    $old_version = '';
+
+                    if ( isset( $this->current_themes_info[ $slug ] ) ) {
+                        $old_theme = $this->current_themes_info[ $slug ];
+
+                        if ( isset( $old_theme['version'] ) ) {
+                            $old_version = $old_theme['version'];
+                        }
+                    } elseif ( ! empty( $upgrader->skin->theme_info ) ) {
+                        $old_version = $upgrader->skin->theme_info->get( 'Version' ); // to fix old version  //$theme['Version'].
+                    }
+
+                    $logs[] = compact( 'slug', 'name', 'old_version', 'version', 'message', 'action' );
+                }
+            }
+        } else {
+            return false;
+        }
+
+        $context = $type . 's';
+
+        foreach ( $logs as $log ) {
+            $name        = isset( $log['name'] ) ? $log['name'] : null;
+            $version     = isset( $log['version'] ) ? $log['version'] : null;
+            $slug        = isset( $log['slug'] ) ? $log['slug'] : null;
+            $old_version = isset( $log['old_version'] ) ? $log['old_version'] : null;
+            $message     = isset( $log['message'] ) ? $log['message'] : null;
+            $action      = isset( $log['action'] ) ? $log['action'] : null;
+
+            $this->save_actions(
+                $message,
+                compact( 'type', 'name', 'version', 'slug', 'success', 'error', 'old_version' ),
+                $context,
+                $action
+            );
+        }
+        return true;
+    }
+
+
+    /**
+     * Activate plugin callback.
+     *
+     * @param string $slug Plugin slug.
+     * @param bool   $network_wide Check if network wide.
+     */
+    public function callback_activate_plugin( $slug, $network_wide = false ) {
+        $_plugins     = $this->get_plugins();
+        $name         = $_plugins[ $slug ]['Name'];
+        $network_wide = $network_wide ? esc_html__( 'network wide', 'mainwp-child' ) : null;
+
+        if ( empty( $name ) ) {
+            return;
+        }
+
+        $this->save_actions(
+            _x(
+                '"%1$s" plugin activated %2$s',
+                '1: Plugin name, 2: Single site or network wide',
+                'mainwp-child'
+            ),
+            compact( 'name', 'network_wide', 'slug' ),
+            'plugins',
+            'activated'
+        );
+    }
+
+    /**
+     * Decativate plugin callback.
+     *
+     * @param string $slug Plugin slug.
+     * @param bool   $network_wide Check if network wide.
+     */
+    public function callback_deactivate_plugin( $slug, $network_wide = false ) {
+        $_plugins     = $this->get_plugins();
+        $name         = $_plugins[ $slug ]['Name'];
+        $network_wide = $network_wide ? esc_html__( 'network wide', 'mainwp-child' ) : null;
+
+        $this->save_actions(
+            _x(
+                '"%1$s" plugin deactivated %2$s',
+                '1: Plugin name, 2: Single site or network wide',
+                'mainwp-child'
+            ),
+            compact( 'name', 'network_wide', 'slug' ),
+            'plugins',
+            'deactivated'
+        );
+    }
+
+    /**
+     * Switch theme callback.
+     *
+     * @param string $name Theme name.
+     * @param string $theme Theme slug.
+     */
+    public function callback_switch_theme( $name, $theme ) {
+        unset( $theme );
+        $this->save_actions(
+            esc_html__( '"%s" theme activated', 'mainwp-child' ),
+            compact( 'name' ),
+            'themes',
+            'activated'
+        );
+    }
+
+    /**
+     * Update theme & transient delete callback.
+     *
+     * @devtodo Core needs a delete_theme hook
+     */
+    public function callback_delete_site_transient_update_themes() {
+        $backtrace = debug_backtrace(); // @codingStandardsIgnoreLine This is used as a hack to determine a theme was deleted.
+        $delete_theme_call = null;
+
+        foreach ( $backtrace as $call ) {
+            if ( isset( $call['function'] ) && 'delete_theme' === $call['function'] ) {
+                $delete_theme_call = $call;
+                break;
+            }
+        }
+
+        if ( empty( $delete_theme_call ) ) {
+            return;
+        }
+
+        $name = $delete_theme_call['args'][0];
+        // @devtodo Can we get the name of the theme? Or has it already been eliminated
+
+        $this->save_actions(
+            esc_html__( '"%s" theme deleted', 'mainwp-child' ),
+            compact( 'name' ),
+            'themes',
+            'deleted'
+        );
+    }
+
+    /**
+     * Uninstall plugins callback.
+     */
+    public function callback_pre_option_uninstall_plugins() {
+        // phpcs:disable WordPress.Security.NonceVerification
+        if ( ! isset( $_POST['action'] ) || 'delete-plugin' !== $_POST['action'] ) {
+            return false;
+        }
+        $plugin = isset( $_POST['plugin'] ) ? sanitize_text_field( wp_unslash( $_POST['plugin'] ) ) : '';
+        // phpcs:enable
+        $_plugins                     = $this->get_plugins();
+        $plugins_to_delete            = array();
+        $plugins_to_delete[ $plugin ] = isset( $_plugins[ $plugin ] ) ? $_plugins[ $plugin ] : array();
+        update_option( 'wp_mainwp_stream_plugins_to_delete', $plugins_to_delete );
+        return false;
+    }
+
+    /**
+     * Uninstall plugins callback.
+     *
+     * @param string $plugin_file  plugin file name.
+     * @param bool   $deleted deleted or not.
+     */
+    public function callback_deleted_plugin( $plugin_file, $deleted ) {
+        if ( $deleted ) {
+
+            if ( ! isset( $_POST['action'] ) || 'delete-plugin' !== $_POST['action'] ) { // phpcs:ignore WordPress.Security.NonceVerification
+                return;
+            }
+            $plugins_to_delete = get_option( 'wp_mainwp_stream_plugins_to_delete' );
+            if ( ! $plugins_to_delete ) {
+                return;
+            }
+            foreach ( $plugins_to_delete as $plugin => $data ) {
+                if ( $plugin_file === $plugin ) {
+                    $name         = $data['Name'];
+                    $network_wide = $data['Network'] ? esc_html__( 'network wide', 'mainwp-child' ) : '';
+
+                    $this->save_actions(
+                        esc_html__( '"%s" plugin deleted', 'mainwp-child' ),
+                        compact( 'name', 'plugin', 'network_wide' ),
+                        'plugins',
+                        'deleted'
+                    );
+                }
+            }
+            delete_option( 'wp_mainwp_stream_plugins_to_delete' );
+        }
+    }
+
+    /**
+     * Logs WordPress core upgrades
+     *
+     * @action automatic_updates_complete
+     *
+     * @param string $update_results  Update results.
+     * @return mixed bool|null.
+     */
+    public function callback_automatic_updates_complete( $update_results ) {
+        global $pagenow, $wp_version;
+
+        if ( ! is_array( $update_results ) || ! isset( $update_results['core'] ) ) {
+            return false;
+        }
+
+        $info = $update_results['core'][0];
+
+        $old_version  = $wp_version;
+        $new_version  = $info->item->version;
+        $auto_updated = true;
+
+        $message = esc_html__( 'WordPress auto-updated to %s', 'stream' );
+
+        $this->save_actions(
+            $message,
+            compact( 'new_version', 'old_version', 'auto_updated' ),
+            'wordpress', // phpcs:ignore -- fix format text.
+            'updated'
+        );
+    }
+
+    /**
+     * Core updated successfully callback.
+     */
+    public function callback__core_updated_successfully() {
+
+        /**
+         * Global variables.
+         *
+         * @global string $pagenow Current page.
+         * @global string $wp_version WordPress version.
+         */
+        global $pagenow, $wp_version;
+
+        $old_version  = $wp_version;
+        $auto_updated = ( 'update-core.php' !== $pagenow );
+
+        if ( $auto_updated ) {
+            // translators: Placeholder refers to a version number (e.g. "4.2").
+            $message = esc_html__( 'WordPress auto-updated to %s', 'mainwp-child' );
+        } else {
+            // translators: Placeholder refers to a version number (e.g. "4.2").
+            $message = esc_html__( 'WordPress updated to %s', 'mainwp-child' );
+        }
+
+        $this->save_actions(
+            $message,
+            compact( 'new_version', 'old_version', 'auto_updated' ),
+            'wordpress', // phpcs:ignore -- fix format text.
+            'updated'
+        );
+    }
+
+    /**
+     * Upgrader pre-instaler callback.
+     */
+    public function callback_upgrader_pre_install() { //phpcs:ignore -- NOSONAR - complex.
+        // NOSONAR - WP compatible.
+        if ( empty( $this->current_plugins_info ) ) {
+            $this->current_plugins_info = $this->get_plugins();
+        }
+
+        if ( empty( $this->current_themes_info ) ) {
+            $this->current_themes_info = array();
+
+            if ( ! function_exists( '\wp_get_themes' ) ) {
+                require_once ABSPATH . '/wp-admin/includes/theme.php'; // NOSONAR - WP compatible.
+            }
+
+            $themes = wp_get_themes();
+
+            if ( is_array( $themes ) ) {
+                $theme_name  = wp_get_theme()->get( 'Name' );
+                $parent_name = '';
+                $parent      = wp_get_theme()->parent();
+                if ( $parent ) {
+                    $parent_name = $parent->get( 'Name' );
+                }
+                foreach ( $themes as $theme ) {
+
+                    $_slug = $theme->get_stylesheet();
+                    if ( isset( $this->current_themes_info[ $_slug ] ) ) {
+                        continue;
+                    }
+
+                    $out                  = array();
+                    $out['name']          = $theme->get( 'Name' );
+                    $out['title']         = $theme->display( 'Name', true, false );
+                    $out['version']       = $theme->display( 'Version', true, false );
+                    $out['active']        = ( $theme->get( 'Name' ) === $theme_name ) ? 1 : 0;
+                    $out['slug']          = $_slug;
+                    $out['parent_active'] = ( $parent_name === $out['name'] ) ? 1 : 0;
+
+                    $this->current_themes_info[ $_slug ] = $out;
+                }
+            }
+        }
+    }
+
+    /**
+     * Wrapper method for calling get_plugins().
+     *
+     * @return array Installed plugins.
+     */
+    public function get_plugins() {
+        if ( ! function_exists( 'get_plugins' ) ) {
+            require_once ABSPATH . 'wp-admin/includes/plugin.php'; // NOSONAR - WP compatible.
+        }
+
+        return get_plugins();
+    }
+
+    /**
+     * Log handler.
+     *
+     * @param string $message           sprintf-ready error message string.
+     * @param array  $args              sprintf (and extra) arguments to use.
+     * @param string $context           Context of the event.
+     * @param string $action            Action of the event.
+     */
+    public function save_actions( $message, $args, $context, $action ) { // phpcs:ignore -- NOSONAR - complex.
+
+        /**
+         * Global variable.
+         *
+         * @global object $wp_roles WordPress user roles object.
+         * */
+        global $wp_roles;
+
+        if ( defined( 'WP_IMPORTING' ) && WP_IMPORTING ) {
+            return false;
+        }
+
+        $context_label = $this->get_valid_context( $context );
+        if ( empty( $context_label ) ) { // not valid.
+            return false;
+        }
+
+        $action_label = $this->get_valid_action( $action );
+        if ( empty( $action_label ) ) { // not valid.
+            return false;
+        }
+
+        $user_id = get_current_user_id();
+        $user    = get_user_by( 'id', $user_id );
+
+        $connected_user = get_option( 'mainwp_child_connected_admin', '' );
+
+        if ( ! empty( $user->user_login ) && $connected_user === $user->user_login && MainWP_Helper::is_dashboard_request( true ) ) {
+            return false;  // not save action.
+        }
+
+        $actions_save = apply_filters( 'mainwp_child_actions_save_data', true, $context, $action, $args, $message, $user_id );
+
+        if ( ! $actions_save ) {
+            return false;
+        }
+
+        $user_role_label = '';
+        $role            = '';
+        $roles           = MainWP_Utility::instance()->get_roles();
+        if ( ! empty( $user->roles ) ) {
+            $user_roles      = array_values( $user->roles );
+            $role            = $user_roles[0];
+            $user_role_label = isset( $roles[ $role ] ) ? $roles[ $role ] : $role;
+        }
+
+        $userlogin = (string) ( ! empty( $user->user_login ) ? $user->user_login : '' );
+
+        $agent     = $this->get_current_agent();
+        $meta_data = array(
+            'user_id'         => (int) $user_id,
+            'display_name'    => (string) $this->get_display_name( $user ),
+            'action_user'     => (string) $userlogin,
+            'role'            => (string) $role,
+            'user_role_label' => (string) $user_role_label,
+            'agent'           => (string) $agent,
+        );
+
+        if ( 'wp_cli' === $agent && function_exists( 'posix_getuid' ) ) {
+            $uid       = posix_getuid();
+            $user_info = posix_getpwuid( $uid );
+
+            $meta_data['system_user_id']   = (int) $uid;
+            $meta_data['system_user_name'] = (string) $user_info['name'];
+        }
+
+        // Prevent any meta with null values from being logged.
+        $other_meta = array_filter(
+            $args,
+            function ( $val ) {
+                return ! is_null( $val );
+            }
+        );
+
+        // Add user meta to Stream meta.
+        $other_meta['meta_data'] = $meta_data;
+
+        $created = MainWP_Helper::get_timestamp();
+
+        $action = (string) $action;
+
+        $new_action = 0;
+        if ( 1 === static::$enable_actions_notification ) {
+            $new_action = 1; // new to notification.
+        }
+
+        $recordarr = array(
+            'context'     => $context,
+            'action'      => $action,
+            'action_user' => $userlogin,
+            'created'     => $created,
+            'summary'     => (string) vsprintf( $message, $args ),
+            'meta_data'   => $other_meta,
+            'new'         => $new_action,
+        );
+        $index     = time() . rand( 1000, 9999 ); // phpcs:ignore -- ok for index.
+        $this->update_actions_data( $index, $recordarr );
+
+        if ( 1 === $new_action ) {
+            update_option( 'mainwp_child_send_action_notification_next_time', time() + 5 * MINUTE_IN_SECONDS );
+        }
+    }
+
+
+    /**
+     * Delete actions logs.
+     */
+    public function delete_actions() {
+        delete_option( 'mainwp_child_actions_saved_data' );
+        delete_option( 'mainwp_child_send_action_notification_next_time' );
+        MainWP_Helper::write( array( 'success' => 'ok' ) );
+    }
+
+    /**
+     * Get valid context.
+     *
+     * @param string $context  Context.
+     *
+     * @return string Context label.
+     */
+    public function get_valid_context( $context ) {
+        $context = (string) $context;
+        $valid   = array(
+            'plugins'   => 'Plugins',
+            'themes'    => 'Themes',
+            'wordpress' => 'WordPress'  // phpcs:ignore -- fix format text.
+        );
+        return isset( $valid[ $context ] ) ? $valid[ $context ] : '';
+    }
+
+    /**
+     * Get valid action.
+     *
+     * @param string $action  action.
+     *
+     * @return string action label.
+     */
+    public function get_valid_action( $action ) {
+        $action = (string) $action;
+        $valid  = array(
+            'updated'     => 'updated',
+            'deleted'     => 'deleted',
+            'activated'   => 'activated',
+            'deactivated' => 'deactivated',
+            'installed'   => 'installed',
+        );
+        return isset( $valid[ $action ] ) ? $valid[ $action ] : '';
+    }
+
+    /**
+     * Get the display name of the user
+     *
+     * @param mixed $user  User object.
+     *
+     * @return string Return User Login or Display Names.
+     */
+    public function get_display_name( $user ) {
+        if ( empty( $user->ID ) ) {
+            if ( 'wp_cli' === $this->get_current_agent() ) {
+                return 'WP-CLI';
+            }
+            $title = esc_html__( 'N/A', 'mainwp-child' );
+        } elseif ( ! empty( $user->display_name ) ) {
+            $title = $user->display_name;
+        } else {
+            $title = $user->user_login;
+        }
+        return $title;
+    }
+
+    /**
+     * Get agent.
+     *
+     * @return string
+     */
+    public function get_current_agent() {
+        $agent = '';
+        if ( defined( '\WP_CLI' ) && \WP_CLI ) {
+            $agent = 'wp_cli';
+        } elseif ( $this->is_doing_wp_cron() ) {
+            $agent = 'wp_cron';
+        }
+        return $agent;
+    }
+
+    /**
+     * True if doing WP Cron, otherwise false.
+     *
+     * @return bool
+     */
+    public function is_doing_wp_cron() {
+        return $this->is_cron_enabled() && defined( 'DOING_CRON' ) && DOING_CRON;
+    }
+
+    /**
+     * True if native WP Cron is enabled, otherwise false.
+     *
+     * @return bool
+     */
+    public function is_cron_enabled() {
+        return ( defined( 'DISABLE_WP_CRON' ) && DISABLE_WP_CRON ) ? false : true;
+    }
+
+    /**
+     * Method send_installer_notification()
+     *
+     * To send email notification for plugins/themes/core change.
+     *
+     * @param array $data  Action Data.
+     */
+    public function send_actions_notification( $data ) {
+
+        if ( 1 !== static::$enable_actions_notification ) {
+            return;
+        }
+
+        $username = get_option( 'mainwp_child_connected_admin', '' );
+        $user     = get_user_by( 'login', $username );
+        $email    = ! empty( $user->user_email ) ? $user->user_email : '';
+
+        if ( empty( $email ) ) {
+            return;
+        }
+
+        $actions = static::get_actions_data();
+
+        ksort( $actions );
+        // site info.
+        $blog = get_bloginfo( 'name' );
+
+        $content = '<div>Actions notification</div><div></div><br>';
+
+        foreach ( $actions as $index => $data ) {
+            if ( 'connected_admin' === strval( $index ) ) {
+                continue;
+            }
+            if ( is_array( $data ) && ! empty( $data['action_user'] ) && isset( $data['new'] ) && 1 === (int) $data['new'] ) {
+                $content    .= $data['action_user'] . ' - ' . $data['summray'] . ' - ' . MainWP_Helper::format_timestamp( ( $data['created'] ) ) . '<br>';
+                $data['new'] = 0;
+                $this->update_actions_data( $index, $data );
+            }
+        }
+
+        MainWP_Utility::instance()->send_wp_mail(
+            $email,
+            'MainWP - Actions notification: ' . $blog,
+            MainWP_Child_Format::format_email( $content ),
+            array(
+                'content-type: text/html',
+            )
+        );
+    }
+}
diff -rNu /tmp/wpbeacon-audits/audit-11/baseline/class/class-mainwp-child-api-backups.php /tmp/wpbeacon-audits/audit-11/head/class/class-mainwp-child-api-backups.php
--- /tmp/wpbeacon-audits/audit-11/baseline/class/class-mainwp-child-api-backups.php	2024-06-18 08:24:10
+++ /tmp/wpbeacon-audits/audit-11/head/class/class-mainwp-child-api-backups.php	2024-07-09 12:51:02
@@ -1,119 +1,119 @@
-<?php
-/**
- * MainWP Child Site Api Backups
- *
- * Manages MainWP API Backups child site actions when needed.
- *
- * @package MainWP\Child
- */
-
-namespace MainWP\Child;
-
-/**
- * Class MainWP_Child_Api_Backups
- *
- * This class handles all the MainWP API Backups child site actions when needed.
- *
- * @package MainWP\Child
- */
-class MainWP_Child_Api_Backups {
-
-    /**
-     * Public variable to state if supported plugin is installed on the child site.
-     *
-     * @var bool If supported plugin is installed, return true, if not, return false.
-     */
-    public $is_plugin_installed = false;
-
-    /**
-     * Public static variable to hold the single instance of the class.
-     *
-     * @var mixed Default null
-     */
-    protected static $instance = null;
-
-    /**
-     * Method instance()
-     *
-     * Create a public static instance.
-     *
-     * @return mixed Class instance.
-     */
-    public static function instance() {
-        if ( null === static::$instance ) {
-            static::$instance = new self();
-        }
-
-        return static::$instance;
-    }
-
-    /**
-     * MainWP_Child_Api_Backups constructor.
-     *
-     * Run any time class is called.
-     */
-    public function __construct() {
-        // Constructor.
-    }
-
-    /**
-     * Create a backup of the database for the given child site.
-     *
-     * @return void
-     */
-    public function api_backups_mysqldump() {
-
-        // WordPress DB credentials.
-        $database_name = DB_NAME;
-        $user          = DB_USER;
-        $pass          = DB_PASSWORD;
-
-        // Remove ":" & all numbers from "Localhost:3306".
-        $host = str_replace( ':', '', preg_replace( '/\d/', '', DB_HOST ) );
-
-        // Get Site URL.
-        $site_url = str_replace( '/', '.', preg_replace( '#^https?://#i', '', get_bloginfo( 'url' ) ) );
-
-        // Create a timestamp.
-        $current_date_time = current_datetime();
-        $current_date_time = $current_date_time->format( 'm-d-Y_H.i.s.A' );
-
-        // Build the uploads directory.
-        $wp_get_upload_dir = wp_get_upload_dir();
-        $wp_upload_dir     = $wp_get_upload_dir['basedir'] . '/mainwp/api_db_backups/';
-
-        // Build the full path to the backup file.
-        $gzip_full_path = $wp_upload_dir . $database_name . '_' . $site_url . '_' . $current_date_time . '.sql.gz';
-
-        // Create the directory if it doesn't exist.
-        if ( ! file_exists( $wp_upload_dir ) ) { //phpcs:ignore
-            mkdir( $wp_upload_dir, 0755, true ); //phpcs:ignore
-        }
-
-        if ( function_exists( 'exec' ) ) {
-            // Create the backup file. hide from logs ( password ).
-            exec( "mysqldump --user={$user} --password='{$pass}' --host={$host} {$database_name} | gzip > {$gzip_full_path}", $output, $result ); //phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.system_calls_exec
-        }
-
-        // Check if the backup was successful.
-        if ( 0 === $result ) {
-            // Success.
-            MainWP_Helper::write(
-                array(
-                    'result' => 'GOOD',
-                    'output' => $output,
-                    'res'    => $result,
-                )
-            );
-        } else {
-            // Error.
-            MainWP_Helper::write(
-                array(
-                    'result' => 'ERROR',
-                    'output' => $output,
-                    'res'    => $result,
-                )
-            );
-        }
-    }
-}
+<?php
+/**
+ * MainWP Child Site Api Backups
+ *
+ * Manages MainWP API Backups child site actions when needed.
+ *
+ * @package MainWP\Child
+ */
+
+namespace MainWP\Child;
+
+/**
+ * Class MainWP_Child_Api_Backups
+ *
+ * This class handles all the MainWP API Backups child site actions when needed.
+ *
+ * @package MainWP\Child
+ */
+class MainWP_Child_Api_Backups {
+
+    /**
+     * Public variable to state if supported plugin is installed on the child site.
+     *
+     * @var bool If supported plugin is installed, return true, if not, return false.
+     */
+    public $is_plugin_installed = false;
+
+    /**
+     * Public static variable to hold the single instance of the class.
+     *
+     * @var mixed Default null
+     */
+    protected static $instance = null;
+
+    /**
+     * Method instance()
+     *
+     * Create a public static instance.
+     *
+     * @return mixed Class instance.
+     */
+    public static function instance() {
+        if ( null === static::$instance ) {
+            static::$instance = new self();
+        }
+
+        return static::$instance;
+    }
+
+    /**
+     * MainWP_Child_Api_Backups constructor.
+     *
+     * Run any time class is called.
+     */
+    public function __construct() {
+        // Constructor.
+    }
+
+    /**
+     * Create a backup of the database for the given child site.
+     *
+     * @return void
+     */
+    public function api_backups_mysqldump() {
+
+        // WordPress DB credentials.
+        $database_name = DB_NAME;
+        $user          = DB_USER;
+        $pass          = DB_PASSWORD;
+
+        // Remove ":" & all numbers from "Localhost:3306".
+        $host = str_replace( ':', '', preg_replace( '/\d/', '', DB_HOST ) );
+
+        // Get Site URL.
+        $site_url = str_replace( '/', '.', preg_replace( '#^https?://#i', '', get_bloginfo( 'url' ) ) );
+
+        // Create a timestamp.
+        $current_date_time = current_datetime();
+        $current_date_time = $current_date_time->format( 'm-d-Y_H.i.s.A' );
+
+        // Build the uploads directory.
+        $wp_get_upload_dir = wp_get_upload_dir();
+        $wp_upload_dir     = $wp_get_upload_dir['basedir'] . '/mainwp/api_db_backups/';
+
+        // Build the full path to the backup file.
+        $gzip_full_path = $wp_upload_dir . $database_name . '_' . $site_url . '_' . $current_date_time . '.sql.gz';
+
+        // Create the directory if it doesn't exist.
+        if ( ! file_exists( $wp_upload_dir ) ) { //phpcs:ignore
+            mkdir( $wp_upload_dir, 0755, true ); //phpcs:ignore
+        }
+
+        if ( function_exists( 'exec' ) ) {
+            // Create the backup file. hide from logs ( password ).
+            exec( "mysqldump --user={$user} --password='{$pass}' --host={$host} {$database_name} | gzip > {$gzip_full_path}", $output, $result ); //phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.system_calls_exec
+        }
+
+        // Check if the backup was successful.
+        if ( 0 === $result ) {
+            // Success.
+            MainWP_Helper::write(
+                array(
+                    'result' => 'GOOD',
+                    'output' => $output,
+                    'res'    => $result,
+                )
+            );
+        } else {
+            // Error.
+            MainWP_Helper::write(
+                array(
+                    'result' => 'ERROR',
+                    'output' => $output,
+                    'res'    => $result,
+                )
+            );
+        }
+    }
+}
diff -rNu /tmp/wpbeacon-audits/audit-11/baseline/class/class-mainwp-child-back-up-buddy.php /tmp/wpbeacon-audits/audit-11/head/class/class-mainwp-child-back-up-buddy.php
--- /tmp/wpbeacon-audits/audit-11/baseline/class/class-mainwp-child-back-up-buddy.php	2024-06-18 08:24:10
+++ /tmp/wpbeacon-audits/audit-11/head/class/class-mainwp-child-back-up-buddy.php	2024-07-09 12:51:02
@@ -1,3823 +1,3823 @@
-<?php
-/**
- * MainWP Child Backup Buddy
- *
- * The code is used for the MainWP Buddy Extension.
- *
- * Credits
- *
- * Plugin-Name: BackupBuddy
- * Plugin URI: http://ithemes.com/purchase/backupbuddy/
- * Author: iThemes
- * Author URI: http://ithemes.com/
- * iThemes Package: backupbuddy
- *
- * The code is used for the MainWP Buddy Extension
- * Extension URL: https://mainwp.com/extension/mainwpbuddy/
- *
- * @package MainWP\Child
- */
-
-namespace MainWP\Child;
-
-// phpcs:disable -- third party credit.
-
-
-/**
- * Class MainWP_Child_Back_Up_Buddy
- */
-class MainWP_Child_Back_Up_Buddy { //phpcs:ignore -- NOSONAR - multi methods.
-
-    /**
-     * Public static variable to hold the single instance of MainWP_Child_Back_Up_Buddy.
-     * @var null
-     */
-    public static $instance  = null;
-
-    /** @var string $plugin_translate Plugin translation string. */
-    public $plugin_translate = 'mainwp-child';
-
-    /** @var bool $is_backupbuddy_installed Whether or not BackupBuddy is installed. Default: False. */
-    public $is_backupbuddy_installed = false;
-
-    /** @var string $path_core_file path core file. */
-    public $path_core_file = '/classes/core.php';
-
-      /** @var string $backupbuddy_core_class core class name. */
-      public $backupbuddy_core_class = '\backupbuddy_core';
-
-    /**
-     * Create a public static instance of MainWP_Child_Back_Up_Buddy.
-     *
-     * @return MainWP_Child_Back_Up_Buddy|null
-     */
-    public static function instance() {
-        if ( null === static::$instance ) {
-            static::$instance = new self();
-        }
-        return static::$instance;
-    }
-
-    /**
-     * MainWP_Child_Back_Up_Buddy constructor.
-     *
-     * Run any time class is called.
-     */
-    public function __construct() {
-        // To fix bug run dashboard on local machine.
-        if ( class_exists( '\pb_backupbuddy' ) ) {
-            $this->is_backupbuddy_installed = true;
-        }
-
-        if ( ! $this->is_backupbuddy_installed ) {
-            return;
-        }
-
-        add_filter( 'mainwp_site_sync_others_data', array( $this, 'sync_others_data' ), 10, 2 );
-
-        add_action( 'wp_ajax_mainwp_backupbuddy_download_archive', array( $this, 'download_archive' ) );
-        add_action( 'mainwp_child_site_stats', array( $this, 'do_site_stats' ) );
-
-        if ( get_option( 'mainwp_backupbuddy_hide_plugin' ) === 'hide' ) {
-            add_filter( 'all_plugins', array( $this, 'all_plugins' ) );
-            add_action( 'admin_menu', array( $this, 'admin_menu' ) );
-            add_filter( 'site_transient_update_plugins', array( &$this, 'remove_update_nag' ) );
-            add_filter( 'mainwp_child_hide_update_notice', array( &$this, 'hide_update_notice' ) );
-        }
-    }
-
-    /**
-     * Hide Backupbuddy update notice.
-     *
-     * @param string $slugs plugin slug.
-     * @return string $slugs Return slugs array.
-     */
-    public function hide_update_notice( $slugs ) {
-        $slugs[] = 'backupbuddy/backupbuddy.php';
-        return $slugs;
-    }
-
-    /**
-     * Remove update nag.
-     *
-     * @param array $value Plugin slug array.
-     * @return array $value Plugin slug array.
-     *
-     * @uses \MainWP\Child\MainWP_Helper::is_updates_screen()
-     */
-    public function remove_update_nag( $value ) {
-        if ( MainWP_Helper::is_dashboard_request() ) {
-            return $value;
-        }
-
-        if ( ! MainWP_Helper::is_updates_screen() ) {
-            return $value;
-        }
-
-        if ( isset( $value->response['backupbuddy/backupbuddy.php'] ) ) {
-            unset( $value->response['backupbuddy/backupbuddy.php'] );
-        }
-
-        return $value;
-    }
-
-
-    /**
-     * Remove Backup buddy from plugins list.
-     *
-     * @param array $plugins All plugins array.
-     * @return array $plugins All plugins array with backupbuddy removed.
-     */
-    public function all_plugins( $plugins ) {
-        foreach ( $plugins as $key => $value ) {
-            $plugin_slug = basename( $key, '.php' );
-            if ( 'backupbuddy' === $plugin_slug ) {
-                unset( $plugins[ $key ] );
-            }
-        }
-
-        return $plugins;
-    }
-
-    /**
-     * Remove backupbuddy from admin menu.
-     */
-    public function admin_menu() {
-
-        /**
-         * Submenu array.
-         *
-         * @global object
-         */
-        global $submenu;
-
-        remove_menu_page( 'pb_backupbuddy_backup' );
-
-        if ( isset( $_SERVER['REQUEST_URI'] ) && false !== stripos( wp_unslash( $_SERVER['REQUEST_URI'] ), 'admin.php?page=pb_backupbuddy_' ) ) {
-            wp_safe_redirect( get_option( 'siteurl' ) . '/wp-admin/index.php' );
-            exit();
-        }
-    }
-
-
-    /**
-     * Backupbuddy Client Reports log.
-     *
-     * @uses MainWP_Child_Back_Up_Buddy::do_reports_log()
-     */
-    public function do_site_stats() {
-        if ( has_action( 'mainwp_child_reports_log' ) ) {
-            do_action( 'mainwp_child_reports_log', 'backupbuddy' );
-        } else {
-            $this->do_reports_log( 'backupbuddy' );
-        }
-    }
-
-    /**
-     * Create BackupBuddy Client Reports log.
-     *
-     * @param string $ext Extension to create log for.
-     *
-     * @uses \MainWP\Child\MainWP_Child_Back_Up_Buddy::is_backupbuddy_installed()
-     * @uses \MainWP\Child\MainWP_Helper::instance()->check_methods()
-     * @uses \MainWP\Child\MainWP_Helper::instance()->check_properties()
-     * @uses \MainWP\Child\MainWP_Helper::instance()->check_methods()
-     * @uses \MainWP\Child\MainWP_Helper::instance()->check_classes_exists()
-     * @uses \MainWP\Child\MainWP_Helper::instance()->check_methods()
-     * @uses \pb_backupbuddy_fileoptions()
-     * @uses \pb_backupbuddy_fileoptions::is_ok()
-     * @uses \pb_backupbuddy::$format::prettify()
-     * @uses \backupbuddy_live_periodic::get_stats()
-     * @uses MainWP_Exception
-     */
-    public function do_reports_log( $ext = '' ) { // phpcs:ignore -- NOSONAR - complex.
-        if ( 'backupbuddy' !== $ext ) {
-            return;
-        }
-
-        if ( ! $this->is_backupbuddy_installed ) {
-            return;
-        }
-
-        try {
-
-            MainWP_Helper::instance()->check_methods( '\pb_backupbuddy', array( 'plugin_path' ) );
-            if ( ! class_exists( $this->backupbuddy_core_class ) && file_exists( \pb_backupbuddy::plugin_path() . $this->path_core_file ) ) {
-                require_once \pb_backupbuddy::plugin_path() . $this->path_core_file; // NOSONAR - WP compatible.
-            }
-
-            if ( file_exists( \pb_backupbuddy::plugin_path() . '/classes/fileoptions.php' ) ) {
-                require_once \pb_backupbuddy::plugin_path() . '/classes/fileoptions.php'; // NOSONAR - WP compatible.
-            }
-
-            MainWP_Helper::instance()->check_classes_exists( array( $this->backupbuddy_core_class, '\pb_backupbuddy_fileoptions' ) );
-            MainWP_Helper::instance()->check_methods( $this->backupbuddy_core_class, 'getLogDirectory' );
-
-            $pretty_type = array(
-                'full'  => 'Full',
-                'db'    => 'Database',
-                'files' => 'Files',
-            );
-
-            $recentBackups_list = glob( \backupbuddy_core::getLogDirectory() . 'fileoptions/*.txt' );
-
-            foreach ( $recentBackups_list as $backup_fileoptions ) {
-
-                $backup = new \pb_backupbuddy_fileoptions( $backup_fileoptions, true );
-                $result = $backup->is_ok();
-                if ( method_exists( $backup, 'is_ok' ) && true !== $result ) {
-                    continue;
-                }
-
-                $backup = &$backup->options;
-
-                if ( ! isset( $backup['serial'] ) || ( '' === $backup['serial'] ) ) {
-                    continue;
-                }
-
-                $check_finished = false;
-                if ( ( $backup['finish_time'] >= $backup['start_time'] ) && ( 0 !== (int) $backup['start_time'] ) ) {
-                    $check_finished = true;
-                }
-
-                if ( ! $check_finished ) {
-                    continue;
-                }
-
-                $backupType = '';
-                if ( isset( $backup['profile'] ) && isset( $backup['profile']['type'] ) ) {
-                    $chk_pro = false;
-                    if ( true === MainWP_Helper::instance()->check_properties( '\pb_backupbuddy', 'format', true ) ) {
-                        $chk_pro = true;
-                    }
-                    if ( $chk_pro && true === MainWP_Helper::instance()->check_methods( \pb_backupbuddy::$format, array( 'prettify' ), true ) ) {
-                        $backupType = \pb_backupbuddy::$format->prettify( $backup['profile']['type'], $pretty_type );
-                    }
-                } elseif ( true === MainWP_Helper::instance()->check_methods( $this->backupbuddy_core_class, array( 'pretty_backup_type', 'getBackupTypeFromFile' ), true ) ) {
-                    $backupType = \backupbuddy_core::pretty_backup_type( \backupbuddy_core::getBackupTypeFromFile( $backup['archive_file'] ) );
-                }
-
-                if ( '' === $backupType ) {
-                    $backupType = 'Unknown';
-                }
-
-                $finish_time = $backup['finish_time'];
-                $message     = 'BackupBuddy ' . $backupType . ' finished';
-                if ( ! empty( $finish_time ) ) {
-                    do_action( 'mainwp_reports_backupbuddy_backup', $message, $backupType, $finish_time );
-                }
-            }
-
-            if ( file_exists( \pb_backupbuddy::plugin_path() . '/destinations/live/live_periodic.php' ) ) {
-                require_once \pb_backupbuddy::plugin_path() . '/destinations/live/live_periodic.php'; // NOSONAR - WP compatible.
-
-                MainWP_Helper::instance()->check_classes_exists( array( '\backupbuddy_live_periodic' ) );
-                MainWP_Helper::instance()->check_methods( '\backupbuddy_live_periodic', 'get_stats' ); // NOSONAR - WP compatible.
-
-                $state = \backupbuddy_live_periodic::get_stats();
-
-                $chk_last_remote = false;
-                if ( is_array( $state ) && isset( $state['stats'] ) && is_array( $state['stats'] ) && isset( $state['stats']['last_remote_snapshot'] ) && isset( $state['stats']['last_remote_snapshot_response'] ) ) {
-                    $chk_last_remote = true;
-                }
-
-                if( $chk_last_remote ){
-                    $resp = $state['stats']['last_remote_snapshot_response'];
-                    if ( isset( $resp['success'] ) && $resp['success'] ) {
-                        $finish_time = $state['stats']['last_remote_snapshot'];
-                        $backupType  = 'Live Backup to cloud';
-                        $message     = 'BackupBuddy ' . $backupType . ' finished';
-                        if ( ! empty( $finish_time ) ) {
-                            do_action( 'mainwp_reports_backupbuddy_backup', $message, $backupType, $finish_time );
-                        }
-                    }
-                }
-            }
-        } catch ( MainWP_Exception $e ) {
-            // ok!
-        }
-    }
-
-    /**
-     * MainWP Child BackupBuddy actions.
-     *
-     * @uses \MainWP\Child\MainWP_Helper::write()
-     * @uses \MainWP\Child\MainWP_Child_Back_Up_Buddy::is_backupbuddy_installed()
-     * @uses \MainWP\Child\MainWP_Child_Back_Up_Buddy::set_showhide()
-     * @uses \MainWP\Child\MainWP_Child_Back_Up_Buddy::save_settings()
-     * @uses \MainWP\Child\MainWP_Child_Back_Up_Buddy::reset_defaults()
-     * @uses \MainWP\Child\MainWP_Child_Back_Up_Buddy::get_notifications()
-     * @uses \MainWP\Child\MainWP_Child_Back_Up_Buddy::schedules_list()
-     * @uses \MainWP\Child\MainWP_Child_Back_Up_Buddy::run_scheduled_backup()
-     * @uses \MainWP\Child\MainWP_Child_Back_Up_Buddy::save_scheduled_backup()
-     * @uses \MainWP\Child\MainWP_Child_Back_Up_Buddy::delete_scheduled_backup()
-     * @uses \MainWP\Child\MainWP_Child_Back_Up_Buddy::save_profile()
-     * @uses \MainWP\Child\MainWP_Child_Back_Up_Buddy::delete_profile()
-     * @uses \MainWP\Child\MainWP_Child_Back_Up_Buddy::delete_backup()
-     * @uses \MainWP\Child\MainWP_Child_Back_Up_Buddy::backup_list()
-     * @uses \MainWP\Child\MainWP_Child_Back_Up_Buddy::save_note()
-     * @uses \MainWP\Child\MainWP_Child_Back_Up_Buddy::get_hash()
-     * @uses \MainWP\Child\MainWP_Child_Back_Up_Buddy::zip_viewer()
-     * @uses \MainWP\Child\MainWP_Child_Back_Up_Buddy::exclude_tree()
-     * @uses \MainWP\Child\MainWP_Child_Back_Up_Buddy::restore_file_view()
-     * @uses \MainWP\Child\MainWP_Child_Back_Up_Buddy::restore_file_restore()
-     * @uses \MainWP\Child\MainWP_Child_Back_Up_Buddy::view_log()
-     * @uses \MainWP\Child\MainWP_Child_Back_Up_Buddy::view_detail()
-     * @uses \MainWP\Child\MainWP_Child_Back_Up_Buddy::reset_integrity()
-     * @uses \MainWP\Child\MainWP_Child_Back_Up_Buddy::download_archive()
-     * @uses \MainWP\Child\MainWP_Child_Back_Up_Buddy::create_backup()
-     * @uses \MainWP\Child\MainWP_Child_Back_Up_Buddy::start_backup()
-     * @uses \MainWP\Child\MainWP_Child_Back_Up_Buddy::backup_status()
-     * @uses \MainWP\Child\MainWP_Child_Back_Up_Buddy::stop_backup()
-     * @uses \MainWP\Child\MainWP_Child_Back_Up_Buddy::remote_save()
-     * @uses \MainWP\Child\MainWP_Child_Back_Up_Buddy::remote_delete()
-     * @uses \MainWP\Child\MainWP_Child_Back_Up_Buddy::remote_send()
-     * @uses \MainWP\Child\MainWP_Child_Back_Up_Buddy::remote_list()
-     * @uses \MainWP\Child\MainWP_Child_Back_Up_Buddy::get_main_log()
-     * @uses \MainWP\Child\MainWP_Child_Back_Up_Buddy::settings_other()
-     * @uses \MainWP\Child\MainWP_Child_Back_Up_Buddy::malware_scan()
-     * @uses \MainWP\Child\MainWP_Child_Back_Up_Buddy::live_setup()
-     * @uses \MainWP\Child\MainWP_Child_Back_Up_Buddy::live_save_settings()
-     * @uses \MainWP\Child\MainWP_Child_Back_Up_Buddy::live_action_disconnect()
-     * @uses \MainWP\Child\MainWP_Child_Back_Up_Buddy::live_action()
-     * @uses \MainWP\Child\MainWP_Child_Back_Up_Buddy::download_troubleshooting()
-     * @uses \MainWP\Child\MainWP_Child_Back_Up_Buddy::get_live_backups()
-     * @uses \MainWP\Child\MainWP_Child_Back_Up_Buddy::copy_file_to_local()
-     * @uses \MainWP\Child\MainWP_Child_Back_Up_Buddy::delete_file_backup()
-     * @uses \MainWP\Child\MainWP_Child_Back_Up_Buddy::get_live_stats()
-     * @uses \MainWP\Child\MainWP_Child_Back_Up_Buddy::load_products_license()
-     * @uses \MainWP\Child\MainWP_Child_Back_Up_Buddy::save_license_settings()
-     * @uses \MainWP\Child\MainWP_Child_Back_Up_Buddy::activate_package()
-     * @uses \MainWP\Child\MainWP_Child_Back_Up_Buddy::deactivate_package()
-     */
-    public function action() { //phpcs:ignore -- NOSONAR - multi lines.
-        $information = array();
-        if ( ! $this->is_backupbuddy_installed ) {
-            MainWP_Helper::write( array( 'error' => esc_html__( 'Please install the BackupBuddy plugin on the child site.', $this->plugin_translate ) ) );
-        }
-        if ( ! class_exists( $this->backupbuddy_core_class ) ) {
-            require_once \pb_backupbuddy::plugin_path() . $$this->path_core_file; // NOSONAR - WP compatible.
-        }
-
-        if ( ! isset( \pb_backupbuddy::$options ) ) {
-            \pb_backupbuddy::load();
-        }
-
-        $mwp_action = MainWP_System::instance()->validate_params( 'mwp_action' );
-        if ( ! empty( $mwp_action ) ) {
-            switch ( $mwp_action ) { // NOSONAR - multi case.
-                case 'set_showhide':
-                    $information = $this->set_showhide();
-                    break;
-                case 'save_settings':
-                    $information = $this->save_settings();
-                    break;
-                case 'reset_defaults':
-                    $information = $this->reset_defaults();
-                    break;
-                case 'get_notifications':
-                    $information = $this->get_notifications();
-                    break;
-                case 'schedules_list':
-                    $information = $this->schedules_list();
-                    break;
-                case 'run_scheduled_backup':
-                    $information = $this->run_scheduled_backup();
-                    break;
-                case 'save_scheduled_backup':
-                    $information = $this->save_scheduled_backup();
-                    break;
-                case 'delete_scheduled_backup':
-                    $information = $this->delete_scheduled_backup();
-                    break;
-                case 'save_profile':
-                    $information = $this->save_profile();
-                    break;
-                case 'delete_profile':
-                    $information = $this->delete_profile();
-                    break;
-                case 'delete_backup':
-                    $information = $this->delete_backup();
-                    break;
-                case 'backup_list':
-                    $information = $this->backup_list();
-                    break;
-                case 'save_note':
-                    $information = $this->save_note();
-                    break;
-                case 'get_hash':
-                    $information = $this->get_hash();
-                    break;
-                case 'zip_viewer':
-                    $information = $this->zip_viewer();
-                    break;
-                case 'exclude_tree':
-                    $information = $this->exclude_tree();
-                    break;
-                case 'restore_file_view':
-                    $information = $this->restore_file_view();
-                    break;
-                case 'restore_file_restore':
-                    $information = $this->restore_file_restore();
-                    break;
-                case 'view_log':
-                    $information = $this->view_log();
-                    break;
-                case 'view_detail':
-                    $information = $this->view_detail();
-                    break;
-                case 'reset_integrity':
-                    $information = $this->reset_integrity();
-                    break;
-                case 'download_archive':
-                    $this->download_archive();
-                    break;
-                case 'create_backup':
-                    $information = $this->create_backup();
-                    break;
-                case 'start_backup':
-                    $information = $this->start_backup();
-                    break;
-                case 'backup_status':
-                    $information = $this->backup_status();
-                    break;
-                case 'stop_backup':
-                    $information = $this->stop_backup();
-                    break;
-                case 'remote_save':
-                    $information = $this->remote_save();
-                    break;
-                case 'remote_delete':
-                    $information = $this->remote_delete();
-                    break;
-                case 'remote_send':
-                    $information = $this->remote_send();
-                    break;
-                case 'remote_list':
-                    $information = $this->remote_list();
-                    break;
-                case 'get_main_log':
-                    $information = $this->get_main_log();
-                    break;
-                case 'settings_other':
-                    $information = $this->settings_other();
-                    break;
-                case 'malware_scan':
-                    $information = $this->malware_scan();
-                    break;
-                case 'live_setup':
-                    $information = $this->live_setup();
-                    break;
-                case 'live_save_settings':
-                    $information = $this->live_save_settings();
-                    break;
-                case 'live_action_disconnect':
-                    $information = $this->live_action_disconnect();
-                    break;
-                case 'live_action':
-                    $information = $this->live_action();
-                    break;
-                case 'download_troubleshooting':
-                    $information = $this->download_troubleshooting();
-                    break;
-                case 'get_live_backups':
-                    $information = $this->get_live_backups();
-                    break;
-                case 'copy_file_to_local':
-                    $information = $this->copy_file_to_local();
-                    break;
-                case 'delete_file_backup':
-                    $information = $this->delete_file_backup();
-                    break;
-                case 'get_live_stats':
-                    $information = $this->get_live_stats();
-                    break;
-                case 'load_products_license':
-                    $information = $this->load_products_license();
-                    break;
-                case 'save_license_settings':
-                    $information = $this->save_license_settings();
-                    break;
-                case 'activate_package':
-                    $information = $this->activate_package();
-                    break;
-                case 'deactivate_package':
-                    $information = $this->deactivate_package();
-                    break;
-                default:
-                    break;
-            }
-        }
-        MainWP_Helper::write( $information );
-    }
-
-    /**
-     * Set show or hide BackupBuddy Plugin from Admin & plugins list.
-     *
-     * @return array $information Return results.
-     *
-     * @uses \MainWP\Child\MainWP_Helper::update_option()
-     */
-    public function set_showhide() {
-        $hide = MainWP_System::instance()->validate_params( 'showhide' );
-        MainWP_Helper::update_option( 'mainwp_backupbuddy_hide_plugin', $hide );
-        $information['result'] = 'SUCCESS';
-        return $information;
-    }
-
-    /**
-     * Save BackupBuddy settings.
-     *
-     * @return array $out Return response array.
-     *
-     * @uses \pb_backupbuddy::$options()
-     * 

[... diff truncated at 200000 bytes ...]