File "UI.php"
Full Path: /home/siazco/grocery.siazco.se/wp-content/plugins/woocommerce/src/Internal/ProductDownloads/ApprovedDirectories/Admin/UI.php
File size: 14.53 KB
MIME-type: text/x-php
Charset: utf-8
<?php
namespace Automattic\WooCommerce\Internal\ProductDownloads\ApprovedDirectories\Admin;
use Automattic\WooCommerce\Internal\ProductDownloads\ApprovedDirectories\Register;
use Automattic\WooCommerce\Internal\Utilities\Users;
use Exception;
use WC_Admin_Settings;
/**
* Manages user interactions for product download URL safety.
*/
class UI {
/**
* The active register of approved directories.
*
* @var Register
*/
private $register;
/**
* The WP_List_Table instance used to display approved directories.
*
* @var Table
*/
private $table;
/**
* Sets up UI controls for product download URLs.
*
* @internal
*
* @param Register $register Register of approved directories.
*/
final public function init( Register $register ) {
$this->register = $register;
}
/**
* Performs any work needed to add hooks and otherwise integrate with the wider system,
* except in the case where the current user is not a site administrator, no hooks will
* be initialized.
*/
final public function init_hooks() {
if ( ! Users::is_site_administrator() ) {
return;
}
add_filter( 'woocommerce_get_sections_products', array( $this, 'add_section' ) );
add_action( 'load-woocommerce_page_wc-settings', array( $this, 'setup' ) );
add_action( 'woocommerce_settings_products', array( $this, 'render' ) );
}
/**
* Injects our new settings section (when approved directory rules are disabled, it will not show).
*
* @param array $sections Other admin settings sections.
*
* @return array
*/
public function add_section( array $sections ): array {
$sections['download_urls'] = __( 'Approved download directories', 'woocommerce' );
return $sections;
}
/**
* Sets up the table, renders any notices and processes actions as needed.
*/
public function setup() {
if ( ! $this->is_download_urls_screen() ) {
return;
}
$this->table = new Table();
$this->admin_notices();
$this->handle_search();
$this->process_actions();
}
/**
* Renders the UI.
*/
public function render() {
if ( null === $this->table || ! $this->is_download_urls_screen() ) {
return;
}
// phpcs:disable WordPress.Security.NonceVerification.Recommended
if ( isset( $_REQUEST['action'] ) && 'edit' === $_REQUEST['action'] && isset( $_REQUEST['url'] ) ) {
$this->edit_screen( (int) $_REQUEST['url'] );
return;
}
// phpcs:enable
// Show list table.
$this->table->prepare_items();
wp_nonce_field( 'modify_approved_directories', 'check' );
$this->display_title();
$this->table->render_views();
$this->table->search_box( _x( 'Search', 'Approved Directory URLs', 'woocommerce' ), 'download_url_search' );
$this->table->display();
}
/**
* Indicates if we are currently on the download URLs admin screen.
*
* @return bool
*/
private function is_download_urls_screen(): bool {
// phpcs:disable WordPress.Security.NonceVerification.Recommended
return isset( $_GET['tab'] )
&& 'products' === $_GET['tab']
&& isset( $_GET['section'] )
&& 'download_urls' === $_GET['section'];
// phpcs:enable
}
/**
* Process bulk and single-row actions.
*/
private function process_actions() {
// phpcs:disable WordPress.Security.NonceVerification.Recommended
$ids = isset( $_REQUEST['url'] ) ? array_map( 'absint', (array) $_REQUEST['url'] ) : array();
if ( empty( $ids ) || empty( $_REQUEST['action'] ) ) {
return;
}
$this->security_check();
$action = sanitize_text_field( wp_unslash( $_REQUEST['action'] ) );
switch ( $action ) {
case 'edit':
$this->process_edits( current( $ids ) );
break;
case 'delete':
case 'enable':
case 'disable':
$this->process_bulk_actions( $ids, $action );
break;
case 'enable-all':
case 'disable-all':
$this->process_all_actions( $action );
break;
case 'turn-on':
case 'turn-off':
$this->process_on_off( $action );
break;
}
// phpcs:enable
}
/**
* Support pagination across search results.
*
* In the context of the WC settings screen, form data is submitted by the post method: that poses
* a problem for the default WP_List_Table pagination logic which expects the search value to live
* as part of the URL query. This method is a simple shim to bridge the resulting gap.
*/
private function handle_search() {
// phpcs:disable WordPress.Security.NonceVerification.Missing
// phpcs:disable WordPress.Security.NonceVerification.Recommended
// If a search value has not been POSTed, or if it was POSTed but is already equal to the
// same value in the URL query, we need take no further action.
if ( empty( $_POST['s'] ) || sanitize_text_field( wp_unslash( $_GET['s'] ?? '' ) ) === $_POST['s'] ) {
return;
}
wp_safe_redirect(
add_query_arg(
array(
'paged' => absint( $_GET['paged'] ?? 1 ),
's' => sanitize_text_field( wp_unslash( $_POST['s'] ) ),
),
$this->table->get_base_url()
)
);
// phpcs:enable
exit;
}
/**
* Handles updating or adding a new URL to the list of approved directories.
*
* @param int $url_id The ID of the rule to be edited/created. Zero if we are creating a new entry.
*/
private function process_edits( int $url_id ) {
// phpcs:disable WordPress.Security.NonceVerification.Missing
$url = esc_url_raw( wp_unslash( $_POST['approved_directory_url'] ?? '' ) );
$enabled = (bool) sanitize_text_field( wp_unslash( $_POST['approved_directory_enabled'] ?? '' ) );
if ( empty( $url ) ) {
return;
}
$redirect_url = add_query_arg( 'id', $url_id, $this->table->get_action_url( 'edit', $url_id ) );
try {
$upserted = 0 === $url_id
? $this->register->add_approved_directory( $url, $enabled )
: $this->register->update_approved_directory( $url_id, $url, $enabled );
if ( is_integer( $upserted ) ) {
$redirect_url = add_query_arg( 'url', $upserted, $redirect_url );
}
$redirect_url = add_query_arg( 'edit-status', 0 === $url_id ? 'added' : 'updated', $redirect_url );
} catch ( Exception $e ) {
$redirect_url = add_query_arg(
array(
'edit-status' => 'failure',
'submitted-url' => $url,
),
$redirect_url
);
}
wp_safe_redirect( $redirect_url );
exit;
// phpcs:enable WordPress.Security.NonceVerification.Missing
}
/**
* Processes actions that can be applied in bulk (requests to delete, enable
* or disable).
*
* @param int[] $ids The ID(s) to be updates.
* @param string $action The action to be applied.
*/
private function process_bulk_actions( array $ids, string $action ) {
$deletes = 0;
$enabled = 0;
$disabled = 0;
$register = wc_get_container()->get( Register::class );
foreach ( $ids as $id ) {
if ( 'delete' === $action && $register->delete_by_id( $id ) ) {
$deletes++;
} elseif ( 'enable' === $action && $register->enable_by_id( $id ) ) {
$enabled++;
} elseif ( 'disable' === $action && $register->disable_by_id( $id ) ) {
$disabled ++;
}
}
$fails = count( $ids ) - $deletes - $enabled - $disabled;
$redirect = $this->table->get_base_url();
if ( $deletes ) {
$redirect = add_query_arg( 'deleted-ids', $deletes, $redirect );
} elseif ( $enabled ) {
$redirect = add_query_arg( 'enabled-ids', $enabled, $redirect );
} elseif ( $disabled ) {
$redirect = add_query_arg( 'disabled-ids', $disabled, $redirect );
}
if ( $fails ) {
$redirect = add_query_arg( 'bulk-fails', $fails, $redirect );
}
wp_safe_redirect( $redirect );
exit;
}
/**
* Handles the enable/disable-all actions.
*
* @param string $action The action to be applied.
*/
private function process_all_actions( string $action ) {
$register = wc_get_container()->get( Register::class );
$redirect = $this->table->get_base_url();
switch ( $action ) {
case 'enable-all':
$redirect = add_query_arg( 'enabled-all', (int) $register->enable_all(), $redirect );
break;
case 'disable-all':
$redirect = add_query_arg( 'disabled-all', (int) $register->disable_all(), $redirect );
break;
}
wp_safe_redirect( $redirect );
exit;
}
/**
* Handles turning on/off the entire approved download directory system (vs enabling
* and disabling of individual rules).
*
* @param string $action Whether the feature should be turned on or off.
*/
private function process_on_off( string $action ) {
switch ( $action ) {
case 'turn-on':
$this->register->set_mode( Register::MODE_ENABLED );
break;
case 'turn-off':
$this->register->set_mode( Register::MODE_DISABLED );
break;
}
}
/**
* Displays the screen title, etc.
*/
private function display_title() {
$turn_on_off = $this->register->get_mode() === Register::MODE_ENABLED
? '<a href="' . esc_url( $this->table->get_action_url( 'turn-off', 0 ) ) . '" class="page-title-action">' . esc_html_x( 'Stop Enforcing Rules', 'Approved product download directories', 'woocommerce' ) . '</a>'
: '<a href="' . esc_url( $this->table->get_action_url( 'turn-on', 0 ) ) . '" class="page-title-action">' . esc_html_x( 'Start Enforcing Rules', 'Approved product download directories', 'woocommerce' ) . '</a>';
?>
<h2 class='wc-table-list-header'>
<?php esc_html_e( 'Approved Download Directories', 'woocommerce' ); ?>
<a href='<?php echo esc_url( $this->table->get_action_url( 'edit', 0 ) ); ?>' class='page-title-action'><?php esc_html_e( 'Add New', 'woocommerce' ); ?></a>
<?php echo $turn_on_off; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
</h2>
<?php
}
/**
* Renders the editor screen for approved directory URLs.
*
* @param int $url_id The ID of the rule to be edited (may be zero for new rules).
*/
private function edit_screen( int $url_id ) {
$this->security_check();
$existing = $this->register->get_by_id( $url_id );
if ( 0 !== $url_id && ! $existing ) {
WC_Admin_Settings::add_error( _x( 'The provided ID was invalid.', 'Approved product download directories', 'woocommerce' ) );
WC_Admin_Settings::show_messages();
return;
}
$title = $existing
? __( 'Edit Approved Directory', 'woocommerce' )
: __( 'Add New Approved Directory', 'woocommerce' );
// phpcs:disable WordPress.Security.NonceVerification.Recommended
$submitted = sanitize_text_field( wp_unslash( $_GET['submitted-url'] ?? '' ) );
$existing_url = $existing ? $existing->get_url() : '';
$enabled = $existing ? $existing->is_enabled() : true;
// phpcs:enable
?>
<h2 class='wc-table-list-header'>
<?php echo esc_html( $title ); ?>
<?php if ( $existing ) : ?>
<a href="<?php echo esc_url( $this->table->get_action_url( 'edit', 0 ) ); ?>" class="page-title-action"><?php esc_html_e( 'Add New', 'woocommerce' ); ?></a>
<?php endif; ?>
<a href="<?php echo esc_url( $this->table->get_base_url() ); ?> " class="page-title-action"><?php esc_html_e( 'Cancel', 'woocommerce' ); ?></a>
</h2>
<table class='form-table'>
<tbody>
<tr valign='top'>
<th scope='row' class='titledesc'>
<label for='approved_directory_url'> <?php echo esc_html_x( 'Directory URL', 'Approved product download directories', 'woocommerce' ); ?> </label>
</th>
<td class='forminp'>
<input name='approved_directory_url' id='approved_directory_url' type='text' class='input-text regular-input' value='<?php echo esc_attr( empty( $submitted ) ? $existing_url : $submitted ); ?>'>
</td>
</tr>
<tr valign='top'>
<th scope='row' class='titledesc'>
<label for='approved_directory_enabled'> <?php echo esc_html_x( 'Enabled', 'Approved product download directories', 'woocommerce' ); ?> </label>
</th>
<td class='forminp'>
<input name='approved_directory_enabled' id='approved_directory_enabled' type='checkbox' value='1' <?php checked( true, $enabled ); ?>'>
</td>
</tr>
</tbody>
</table>
<input name='id' id='approved_directory_id' type='hidden' value='{$url_id}'>
<?php
}
/**
* Displays any admin notices that might be needed.
*/
private function admin_notices() {
// phpcs:disable WordPress.Security.NonceVerification.Recommended
$successfully_deleted = isset( $_GET['deleted-ids'] ) ? (int) $_GET['deleted-ids'] : 0;
$successfully_enabled = isset( $_GET['enabled-ids'] ) ? (int) $_GET['enabled-ids'] : 0;
$successfully_disabled = isset( $_GET['disabled-ids'] ) ? (int) $_GET['disabled-ids'] : 0;
$failed_updates = isset( $_GET['bulk-fails'] ) ? (int) $_GET['bulk-fails'] : 0;
$edit_status = sanitize_text_field( wp_unslash( $_GET['edit-status'] ?? '' ) );
$edit_url = esc_attr( sanitize_text_field( wp_unslash( $_GET['submitted-url'] ?? '' ) ) );
// phpcs:enable
if ( $successfully_deleted ) {
WC_Admin_Settings::add_message(
sprintf(
/* translators: %d: count */
_n( '%d approved directory URL deleted.', '%d approved directory URLs deleted.', $successfully_deleted, 'woocommerce' ),
$successfully_deleted
)
);
} elseif ( $successfully_enabled ) {
WC_Admin_Settings::add_message(
sprintf(
/* translators: %d: count */
_n( '%d approved directory URL enabled.', '%d approved directory URLs enabled.', $successfully_enabled, 'woocommerce' ),
$successfully_enabled
)
);
} elseif ( $successfully_disabled ) {
WC_Admin_Settings::add_message(
sprintf(
/* translators: %d: count */
_n( '%d approved directory URL disabled.', '%d approved directory URLs disabled.', $successfully_disabled, 'woocommerce' ),
$successfully_disabled
)
);
}
if ( $failed_updates ) {
WC_Admin_Settings::add_error(
sprintf(
/* translators: %d: count */
_n( '%d URL could not be updated.', '%d URLs could not be updated.', $failed_updates, 'woocommerce' ),
$failed_updates
)
);
}
if ( 'added' === $edit_status ) {
WC_Admin_Settings::add_message( __( 'URL was successfully added.', 'woocommerce' ) );
}
if ( 'updated' === $edit_status ) {
WC_Admin_Settings::add_message( __( 'URL was successfully updated.', 'woocommerce' ) );
}
if ( 'failure' === $edit_status && ! empty( $edit_url ) ) {
WC_Admin_Settings::add_error(
sprintf(
/* translators: %s is the submitted URL. */
__( '"%s" could not be saved. Please review, ensure it is a valid URL and try again.', 'woocommerce' ),
$edit_url
)
);
}
}
/**
* Makes sure the user has appropriate permissions and that we have a valid nonce.
*/
private function security_check() {
if ( ! Users::is_site_administrator() || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_REQUEST['check'] ?? '' ) ), 'modify_approved_directories' ) ) {
wp_die( esc_html__( 'You do not have permission to modify the list of approved directories for product downloads.', 'woocommerce' ) );
}
}
}