<?php

/**

 * Plugin Name: WPMU Storage Quota Monitor

 * Plugin URI:  https://example.com/

 * Description: Emails the network administrator when a site in a Multisite network approaches its upload storage quota.

 * Version:     1.0

 * Author:      Your Name

 * Author URI:  https://example.com/

 * License:     GPL2

 */


// Exit if accessed directly.

if ( ! defined( 'ABSPATH' ) ) {

    exit;

}


class WPMU_Storage_Quota_Monitor {


    private $threshold_percentage = 80; // Email when usage reaches 80% of the quota

    private $email_interval_hours = 24; // Only send email once every 24 hours per site

    private $option_name_last_notified = 'wpmu_sqm_last_notified';


    public function __construct() {

        if ( is_multisite() ) {

            add_action( 'admin_init', array( $this, 'schedule_quota_check' ) );

            add_action( 'wpmu_storage_quota_check', array( $this, 'check_all_site_quotas' ) );

            add_action( 'admin_menu', array( $this, 'add_settings_page' ) );

            add_action( 'admin_init', array( $this, 'register_settings' ) );

        }

    }


    /**

     * Schedules the daily quota check.

     */

    public function schedule_quota_check() {

        if ( ! wp_next_scheduled( 'wpmu_storage_quota_check' ) ) {

            wp_schedule_event( time(), 'daily', 'wpmu_storage_quota_check' );

        }

    }


    /**

     * Unschedule the event on plugin deactivation.

     */

    public static function unschedule_quota_check_on_deactivation() {

        wp_clear_scheduled_hook( 'wpmu_storage_quota_check' );

    }


    /**

     * Checks the upload quota for all sites in the network.

     */

    public function check_all_site_quotas() {

        // Get the threshold percentage from settings, fallback to default.

        $this->threshold_percentage = get_site_option( 'wpmu_sqm_threshold_percentage', 80 );

        $this->email_interval_hours = get_site_option( 'wpmu_sqm_email_interval_hours', 24 );


        $sites = get_sites( array( 'fields' => 'ids', 'limit' => -1 ) );

        foreach ( $sites as $site_id ) {

            $this->check_single_site_quota( $site_id );

        }

    }


    /**

     * Checks the upload quota for a single site and sends an email if near limit.

     *

     * @param int $site_id The ID of the site to check.

     */

    private function check_single_site_quota( $site_id ) {

        switch_to_blog( $site_id );


        $quota_bytes = get_option( 'blog_upload_space' ); // Quota in MB, convert to bytes.

        if ( empty( $quota_bytes ) || $quota_bytes == 0 ) {

            restore_current_blog();

            return; // No quota set for this site, or quota is unlimited.

        }

        $quota_bytes *= MB_IN_BYTES; // Convert MB to bytes.


        $used_bytes = get_option( 'blog_upload_space_used' ); // Used space in MB, convert to bytes.

        $used_bytes *= MB_IN_BYTES; // Convert MB to bytes.


        if ( $quota_bytes <= 0 ) { // Ensure quota is positive to avoid division by zero.

            restore_current_blog();

            return;

        }


        $percentage_used = ( $used_bytes / $quota_bytes ) * 100;


        if ( $percentage_used >= $this->threshold_percentage ) {

            $this->send_quota_notification_email( $site_id, $used_bytes, $quota_bytes, $percentage_used );

        }


        restore_current_blog();

    }


    /**

     * Sends an email notification if the site is near its quota and not recently notified.

     *

     * @param int    $site_id         The ID of the site.

     * @param int    $used_bytes      The amount of storage used in bytes.

     * @param int    $quota_bytes     The total quota in bytes.

     * @param float  $percentage_used The percentage of quota used.

     */

    private function send_quota_notification_email( $site_id, $used_bytes, $quota_bytes, $percentage_used ) {

        $last_notified = get_site_option( $this->option_name_last_notified . '_' . $site_id );

        $current_time = time();


        // Check if enough time has passed since the last notification for this site.

        if ( $last_notified && ( $current_time - $last_notified ) < ( $this->email_interval_hours * HOUR_IN_SECONDS ) ) {

            return; // Too soon to send another email for this site.

        }


        $network_admin_email = get_site_option( 'admin_email' ); // Get the network admin email.

        if ( ! $network_admin_email ) {

            return; // No network admin email set.

        }


        $site_name = get_blog_details( $site_id )->blogname;

        $site_url  = get_blog_details( $site_id )->siteurl;


        $subject = sprintf( __( 'Storage Quota Alert for %s', 'wpmu-storage-quota-monitor' ), $site_name );


        $message = sprintf(

            __( "Hello Network Administrator,\n\n" .

                "The site '%1\$s' (%2\$s) is nearing its upload storage quota.\n\n" .

                "Current Usage: %3\$s MB (%.2f%% of quota)\n" .

                "Total Quota: %4\$s MB\n\n" .

                "Please consider increasing the site's upload space or advising the site administrator to reduce file usage.\n\n" .

                "This is an automated notification.",

                'wpmu-storage-quota-monitor' ),

            $site_name,

            $site_url,

            round( $used_bytes / MB_IN_BYTES, 2 ),

            $percentage_used,

            round( $quota_bytes / MB_IN_BYTES, 2 )

        );


        $headers = array( 'Content-Type: text/plain; charset=UTF-8' );


        // Send the email.

        if ( wp_mail( $network_admin_email, $subject, $message, $headers ) ) {

            // Update the last notified timestamp for this site.

            update_site_option( $this->option_name_last_notified . '_' . $site_id, $current_time );

        }

    }


    /**

     * Adds the settings page to the Network Admin menu.

     */

    public function add_settings_page() {

        add_submenu_page(

            'settings.php', // Parent slug for Network Settings.

            __( 'Storage Quota Monitor Settings', 'wpmu-storage-quota-monitor' ),

            __( 'Quota Monitor', 'wpmu-storage-quota-monitor' ),

            'manage_network_options', // Capability required to access.

            'wpmu-storage-quota-monitor-settings',

            array( $this, 'settings_page_content' )

        );

    }


    /**

     * Registers plugin settings.

     */

    public function register_settings() {

        add_action( 'network_admin_edit_wpmu_storage_quota_monitor_settings', array( $this, 'save_settings' ) );


        add_settings_section(

            'wpmu_sqm_general_settings',

            __( 'General Settings', 'wpmu-storage-quota-monitor' ),

            null,

            'wpmu-storage-quota-monitor-settings'

        );


        add_settings_field(

            'wpmu_sqm_threshold_percentage',

            __( 'Notification Threshold (%)', 'wpmu-storage-quota-monitor' ),

            array( $this, 'threshold_percentage_callback' ),

            'wpmu-storage-quota-monitor-settings',

            'wpmu_sqm_general_settings'

        );


        add_settings_field(

            'wpmu_sqm_email_interval_hours',

            __( 'Email Notification Interval (hours)', 'wpmu-storage-quota-monitor' ),

            array( $this, 'email_interval_hours_callback' ),

            'wpmu-storage-quota-monitor-settings',

            'wpmu_sqm_general_settings'

        );

    }


    /**

     * Callback for the threshold percentage setting field.

     */

    public function threshold_percentage_callback() {

        $threshold = get_site_option( 'wpmu_sqm_threshold_percentage', 80 );

        echo '<input type="number" name="wpmu_sqm_threshold_percentage" min="1" max="100" value="' . esc_attr( $threshold ) . '"/>';

        echo '<p class="description">' . __( 'Send an email notification when a site\'s upload space usage reaches this percentage of its quota.', 'wpmu-storage-quota-monitor' ) . '</p>';

    }


    /**

     * Callback for the email interval hours setting field.

     */

    public function email_interval_hours_callback() {

        $interval = get_site_option( 'wpmu_sqm_email_interval_hours', 24 );

        echo '<input type="number" name="wpmu_sqm_email_interval_hours" min="1" value="' . esc_attr( $interval ) . '"/>';

        echo '<p class="description">' . __( 'How often (in hours) to send email notifications for the same site if it remains above the threshold. Set to 0 for every check.', 'wpmu-storage-quota-monitor' ) . '</p>';

    }


    /**

     * Saves the plugin settings.

     */

    public function save_settings() {

        if ( ! current_user_can( 'manage_network_options' ) ) {

            wp_die( __( 'You do not have sufficient permissions to access this page.', 'wpmu-storage-quota-monitor' ) );

        }


        check_admin_referer( 'wpmu-storage-quota-monitor-settings-options' ); // Verify nonce.


        $threshold = isset( $_POST['wpmu_sqm_threshold_percentage'] ) ? intval( $_POST['wpmu_sqm_threshold_percentage'] ) : 80;

        $interval = isset( $_POST['wpmu_sqm_email_interval_hours'] ) ? intval( $_POST['wpmu_sqm_email_interval_hours'] ) : 24;


        update_site_option( 'wpmu_sqm_threshold_percentage', max( 1, min( 100, $threshold ) ) );

        update_site_option( 'wpmu_sqm_email_interval_hours', max( 0, $interval ) );


        wp_redirect( add_query_arg( array( 'page' => 'wpmu-storage-quota-monitor-settings', 'updated' => 'true' ), network_admin_url( 'settings.php' ) ) );

        exit();

    }



    /**

     * Displays the settings page content.

     */

    public function settings_page_content() {

        ?>

        <div class="wrap">

            <h1><?php _e( 'WPMU Storage Quota Monitor Settings', 'wpmu-storage-quota-monitor' ); ?></h1>

            <form method="post" action="<?php echo esc_url( network_admin_url( 'edit.php?action=wpmu_storage_quota_monitor_settings' ) ); ?>">

                <?php

                settings_fields( 'wpmu-storage-quota-monitor-settings-options' ); // Nonce for the settings page.

                do_settings_sections( 'wpmu-storage-quota-monitor-settings' );

                submit_button();

                ?>

            </form>

        </div>

        <?php

    }

}


// Initialize the plugin.

$wpmu_storage_quota_monitor = new WPMU_Storage_Quota_Monitor();


// Register deactivation hook.

register_deactivation_hook( __FILE__, array( 'WPMU_Storage_Quota_Monitor', 'unschedule_quota_check_on_deactivation' ) );

People – Computer Science