ead access, WP_Error object otherwise. */ public function get_item_permissions_check( $request ) { $this->retrieve_widgets(); $sidebar = $this->get_sidebar( $request['id'] ); if ( $sidebar && $this->check_read_permission( $sidebar ) ) { return true; } return $this->do_permissions_check(); } /** * Checks if a sidebar can be read publicly. * * @since 5.9.0 * * @param array $sidebar The registered sidebar configuration. * @return bool Whether the side can be read. */ protected function check_read_permission( $sidebar ) { return ! empty( $sidebar['show_in_rest'] ); } /** * Retrieves one sidebar from the collection. * * @since 5.8.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function get_item( $request ) { $this->retrieve_widgets(); $sidebar = $this->get_sidebar( $request['id'] ); if ( ! $sidebar ) { return new WP_Error( 'rest_sidebar_not_found', __( 'No sidebar exists with that id.' ), array( 'status' => 404 ) ); } return $this->prepare_item_for_response( $sidebar, $request ); } /** * Checks if a given request has access to update sidebars. * * @since 5.8.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has read access, WP_Error object otherwise. */ public function update_item_permissions_check( $request ) { return $this->do_permissions_check(); } /** * Updates a sidebar. * * @since 5.8.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response Response object on success, or WP_Error object on failure. */ public function update_item( $request ) { if ( isset( $request['widgets'] ) ) { $sidebars = wp_get_sidebars_widgets(); foreach ( $sidebars as $sidebar_id => $widgets ) { foreach ( $widgets as $i => $widget_id ) { // This automatically removes the passed widget IDs from any other sidebars in use. if ( $sidebar_id !== $request['id'] && in_array( $widget_id, $request['widgets'], true ) ) { unset( $sidebars[ $sidebar_id ][ $i ] ); } // This automatically removes omitted widget IDs to the inactive sidebar. if ( $sidebar_id === $request['id'] && ! in_array( $widget_id, $request['widgets'], true ) ) { $sidebars['wp_inactive_widgets'][] = $widget_id; } } } $sidebars[ $request['id'] ] = $request['widgets']; wp_set_sidebars_widgets( $sidebars ); } $request['context'] = 'edit'; $sidebar = $this->get_sidebar( $request['id'] ); /** * Fires after a sidebar is updated via the REST API. * * @since 5.8.0 * * @param array $sidebar The updated sidebar. * @param WP_REST_Request $request Request object. */ do_action( 'rest_save_sidebar', $sidebar, $request ); return $this->prepare_item_for_response( $sidebar, $request ); } /** * Checks if the user has permissions to make the request. * * @since 5.8.0 * * @return true|WP_Error True if the request has read access, WP_Error object otherwise. */ protected function do_permissions_check() { /* * Verify if the current user has edit_theme_options capability. * This capability is required to access the widgets screen. */ if ( ! current_user_can( 'edit_theme_options' ) ) { return new WP_Error( 'rest_cannot_manage_widgets', __( 'Sorry, you are not allowed to manage widgets on this site.' ), array( 'status' => rest_authorization_required_code() ) ); } return true; } /** * Retrieves the registered sidebar with the given id. * * @since 5.8.0 * * @param string|int $id ID of the sidebar. * @return array|null The discovered sidebar, or null if it is not registered. */ protected function get_sidebar( $id ) { return wp_get_sidebar( $id ); } /** * Looks for "lost" widgets once per request. * * @since 5.9.0 * * @see retrieve_widgets() */ protected function retrieve_widgets() { if ( ! $this->widgets_retrieved ) { retrieve_widgets(); $this->widgets_retrieved = true; } } /** * Prepares a single sidebar output for response. * * @since 5.8.0 * @since 5.9.0 Renamed `$raw_sidebar` to `$item` to match parent class for PHP 8 named parameter support. * * @global array $wp_registered_sidebars The registered sidebars. * @global array $wp_registered_widgets The registered widgets. * * @param array $item Sidebar instance. * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response Prepared response object. */ public function prepare_item_for_response( $item, $request ) { global $wp_registered_sidebars, $wp_registered_widgets; // Restores the more descriptive, specific name for use within this method. $raw_sidebar = $item; // Don't prepare the response body for HEAD requests. if ( $request->is_method( 'HEAD' ) ) { /** This filter is documented in wp-includes/rest-api/endpoints/class-wp-rest-sidebars-controller.php */ return apply_filters( 'rest_prepare_sidebar', new WP_REST_Response( array() ), $raw_sidebar, $request ); } $id = $raw_sidebar['id']; $sidebar = array( 'id' => $id ); if ( isset( $wp_registered_sidebars[ $id ] ) ) { $registered_sidebar = $wp_registered_sidebars[ $id ]; $sidebar['status'] = 'active'; $sidebar['name'] = isset( $registered_sidebar['name'] ) ? $registered_sidebar['name'] : ''; $sidebar['description'] = isset( $registered_sidebar['description'] ) ? wp_sidebar_description( $id ) : ''; $sidebar['class'] = isset( $registered_sidebar['class'] ) ? $registered_sidebar['class'] : ''; $sidebar['before_widget'] = isset( $registered_sidebar['before_widget'] ) ? $registered_sidebar['before_widget'] : ''; $sidebar['after_widget'] = isset( $registered_sidebar['after_widget'] ) ? $registered_sidebar['after_widget'] : ''; $sidebar['before_title'] = isset( $registered_sidebar['before_title'] ) ? $registered_sidebar['before_title'] : ''; $sidebar['after_title'] = isset( $registered_sidebar['after_title'] ) ? $registered_sidebar['after_title'] : ''; } else { $sidebar['status'] = 'inactive'; $sidebar['name'] = $raw_sidebar['name']; $sidebar['description'] = ''; $sidebar['class'] = ''; } if ( wp_is_block_theme() ) { $sidebar['status'] = 'inactive'; } $fields = $this->get_fields_for_response( $request ); if ( rest_is_field_included( 'widgets', $fields ) ) { $sidebars = wp_get_sidebars_widgets(); $widgets = array_filter( isset( $sidebars[ $sidebar['id'] ] ) ? $sidebars[ $sidebar['id'] ] : array(), static function ( $widget_id ) use ( $wp_registered_widgets ) { return isset( $wp_registered_widgets[ $widget_id ] ); } ); $sidebar['widgets'] = array_values( $widgets ); } $schema = $this->get_item_schema(); $data = array(); foreach ( $schema['properties'] as $property_id => $property ) { if ( isset( $sidebar[ $property_id ] ) && true === rest_validate_value_from_schema( $sidebar[ $property_id ], $property ) ) { $data[ $property_id ] = $sidebar[ $property_id ]; } elseif ( isset( $property['default'] ) ) { $data[ $property_id ] = $property['default']; } } $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; $data = $this->add_additional_fields_to_object( $data, $request ); $data = $this->filter_response_by_context( $data, $context ); $response = rest_ensure_response( $data ); if ( rest_is_field_included( '_links', $fields ) || rest_is_field_included( '_embedded', $fields ) ) { $response->add_links( $this->prepare_links( $sidebar ) ); } /** * Filters the REST API response for a sidebar. * * @since 5.8.0 * * @param WP_REST_Response $response The response object. * @param array $raw_sidebar The raw sidebar data. * @param WP_REST_Request $request The request object. */ return apply_filters( 'rest_prepare_sidebar', $response, $raw_sidebar, $request ); } /** * Prepares links for the sidebar. * * @since 5.8.0 * * @param array $sidebar Sidebar. * @return array Links for the given widget. */ protected function prepare_links( $sidebar ) { return array( 'collection' => array( 'href' => rest_url( sprintf( '%s/%s', $this->namespace, $this->rest_base ) ), ), 'self' => array( 'href' => rest_url( sprintf( '%s/%s/%s', $this->namespace, $this->rest_base, $sidebar['id'] ) ), ), 'https://api.w.org/widget' => array( 'href' => add_query_arg( 'sidebar', $sidebar['id'], rest_url( '/wp/v2/widgets' ) ), 'embeddable' => true, ), ); } /** * Retrieves the block type' schema, conforming to JSON Schema. * * @since 5.8.0 * * @return array Item schema data. */ public function get_item_schema() { if ( $this->schema ) { return $this->add_additional_fields_schema( $this->schema ); } $schema = array( '$schema' => 'http://json-schema.org/draft-04/schema#', 'title' => 'sidebar', 'type' => 'object', 'properties' => array( 'id' => array( 'description' => __( 'ID of sidebar.' ), 'type' => 'string', 'context' => array( 'embed', 'view', 'edit' ), 'readonly' => true, ), 'name' => array( 'description' => __( 'Unique name identifying the sidebar.' ), 'type' => 'string', 'context' => array( 'embed', 'view', 'edit' ), 'readonly' => true, ), 'description' => array( 'description' => __( 'Description of sidebar.' ), 'type' => 'string', 'context' => array( 'embed', 'view', 'edit' ), 'readonly' => true, ), 'class' => array( 'description' => __( 'Extra CSS class to assign to the sidebar in the Widgets interface.' ), 'type' => 'string', 'context' => array( 'embed', 'view', 'edit' ), 'readonly' => true, ), 'before_widget' => array( 'description' => __( 'HTML content to prepend to each widget\'s HTML output when assigned to this sidebar. Default is an opening list item element.' ), 'type' => 'string', 'default' => '', 'context' => array( 'embed', 'view', 'edit' ), 'readonly' => true, ), 'after_widget' => array( 'description' => __( 'HTML content to append to each widget\'s HTML output when assigned to this sidebar. Default is a closing list item element.' ), 'type' => 'string', 'default' => '', 'context' => array( 'embed', 'view', 'edit' ), 'readonly' => true, ), 'before_title' => array( 'description' => __( 'HTML content to prepend to the sidebar title when displayed. Default is an opening h2 element.' ), 'type' => 'string', 'default' => '', 'context' => array( 'embed', 'view', 'edit' ), 'readonly' => true, ), 'after_title' => array( 'description' => __( 'HTML content to append to the sidebar title when displayed. Default is a closing h2 element.' ), 'type' => 'string', 'default' => '', 'context' => array( 'embed', 'view', 'edit' ), 'readonly' => true, ), 'status' => array( 'description' => __( 'Status of sidebar.' ), 'type' => 'string', 'enum' => array( 'active', 'inactive' ), 'context' => array( 'embed', 'view', 'edit' ), 'readonly' => true, ), 'widgets' => array( 'description' => __( 'Nested widgets.' ), 'type' => 'array', 'items' => array( 'type' => array( 'object', 'string' ), ), 'default' => array(), 'context' => array( 'embed', 'view', 'edit' ), ), ), ); $this->schema = $schema; return $this->add_additional_fields_schema( $this->schema ); } } attachment_metadata' ) ) { include_once ABSPATH . 'wp-admin/includes/image.php'; } $image_meta = @wp_read_image_metadata( $upload['file'] ); if ( $image_meta ) { if ( trim( $image_meta['title'] ) && ! is_numeric( sanitize_title( $image_meta['title'] ) ) ) { $title = wc_clean( $image_meta['title'] ); } if ( trim( $image_meta['caption'] ) ) { $content = wc_clean( $image_meta['caption'] ); } } $attachment = array( 'post_mime_type' => $info['type'], 'guid' => $upload['url'], 'post_parent' => $id, 'post_title' => $title ? $title : basename( $upload['file'] ), 'post_content' => $content, ); $attachment_id = wp_insert_attachment( $attachment, $upload['file'], $id ); if ( ! is_wp_error( $attachment_id ) ) { @wp_update_attachment_metadata( $attachment_id, wp_generate_attachment_metadata( $attachment_id, $upload['file'] ) ); } return $attachment_id; } /** * Validate reports request arguments. * * @since 2.6.0 * @param mixed $value Value to validate. * @param WP_REST_Request $request Request instance. * @param string $param Param to validate. * @return WP_Error|boolean */ function wc_rest_validate_reports_request_arg( $value, $request, $param ) { $attributes = $request->get_attributes(); if ( ! isset( $attributes['args'][ $param ] ) || ! is_array( $attributes['args'][ $param ] ) ) { return true; } $args = $attributes['args'][ $param ]; if ( 'string' === $args['type'] && ! is_string( $value ) ) { /* translators: 1: param 2: type */ return new WP_Error( 'woocommerce_rest_invalid_param', sprintf( __( '%1$s is not of type %2$s', 'woocommerce' ), $param, 'string' ) ); } if ( 'date' === $args['format'] ) { $regex = '#^\d{4}-\d{2}-\d{2}$#'; if ( ! preg_match( $regex, $value, $matches ) ) { return new WP_Error( 'woocommerce_rest_invalid_date', __( 'The date you provided is invalid.', 'woocommerce' ) ); } } return true; } /** * Encodes a value according to RFC 3986. * Supports multidimensional arrays. * * @since 2.6.0 * @param string|array $value The value to encode. * @return string|array Encoded values. */ function wc_rest_urlencode_rfc3986( $value ) { if ( is_array( $value ) ) { return array_map( 'wc_rest_urlencode_rfc3986', $value ); } return str_replace( array( '+', '%7E' ), array( ' ', '~' ), rawurlencode( $value ) ); } /** * Check permissions of posts on REST API. * * @since 2.6.0 * @param string $post_type Post type. * @param string $context Request context. * @param int $object_id Post ID. * @return bool */ function wc_rest_check_post_permissions( $post_type, $context = 'read', $object_id = 0 ) { $contexts = array( 'read' => 'read_private_posts', 'create' => 'publish_posts', 'edit' => 'edit_post', 'delete' => 'delete_post', 'batch' => 'edit_others_posts', ); if ( 'revision' === $post_type ) { $permission = false; } else { $cap = $contexts[ $context ]; $post_type_object = get_post_type_object( $post_type ); $permission = false; if ( $post_type_object instanceof WP_Post_Type ) { $permission = current_user_can( $post_type_object->cap->$cap, $object_id ); } } return apply_filters( 'woocommerce_rest_check_permissions', $permission, $context, $object_id, $post_type ); } /** * Check permissions of users on REST API. * * @since 2.6.0 * @since 9.4.0 Became multisite aware. The function now considers whether the user belongs to the current site. * * @param string $context Request context. * @param int $object_id User ID. * @return bool */ function wc_rest_check_user_permissions( $context = 'read', $object_id = 0 ) { $contexts = array( 'read' => 'list_users', 'create' => 'create_customers', 'edit' => 'edit_users', 'delete' => 'delete_users', 'batch' => 'promote_users', ); // Check to allow shop_managers to manage only customers. if ( in_array( $context, array( 'edit', 'delete' ), true ) && wc_current_user_has_role( 'shop_manager' ) ) { $permission = false; $user_data = get_userdata( $object_id ); $shop_manager_editable_roles = apply_filters( 'woocommerce_shop_manager_editable_roles', array( 'customer' ) ); if ( isset( $user_data->roles ) ) { $can_manage_users = array_intersect( $user_data->roles, array_unique( $shop_manager_editable_roles ) ); // Check if Shop Manager can edit customer or with the is same shop manager. if ( 0 < count( $can_manage_users ) || intval( $object_id ) === intval( get_current_user_id() ) ) { $permission = current_user_can( $contexts[ $context ], $object_id ); } } } else { $permission = current_user_can( $contexts[ $context ], $object_id ); } // Possibly revoke $permission if the user is 'out of bounds' from a multisite-network perspective. if ( $permission && ! Users::get_user_in_current_site( $object_id ) ) { $permission = false; } /** * Provides an opportunity to override the permission check made before acting on an object in relation to * REST API requests. * * @since 2.6.0 * * @param bool $permission If we have permission to act on this object. * @param string $context Describes the operation being performed: 'read', 'edit', 'delete', etc. * @param int $object_id Object ID. This could be a user ID, order ID, post ID, etc. * @param string $object_type Type of object ('user', 'shop_order', etc) for which checks are being made. */ return apply_filters( 'woocommerce_rest_check_permissions', $permission, $context, $object_id, 'user' ); } /** * Check permissions of product terms on REST API. * * @since 2.6.0 * @param string $taxonomy Taxonomy. * @param string $context Request context. * @param int $object_id Post ID. * @return bool */ function wc_rest_check_product_term_permissions( $taxonomy, $context = 'read', $object_id = 0 ) { $contexts = array( 'read' => 'manage_terms', 'create' => 'edit_terms', 'edit' => 'edit_terms', 'delete' => 'delete_terms', 'batch' => 'edit_terms', ); $cap = $contexts[ $context ]; $taxonomy_object = get_taxonomy( $taxonomy ); $permission = current_user_can( $taxonomy_object->cap->$cap, $object_id ); return apply_filters( 'woocommerce_rest_check_permissions', $permission, $context, $object_id, $taxonomy ); } /** * Check manager permissions on REST API. * * @since 2.6.0 * @param string $object Object. * @param string $context Request context. * @return bool */ function wc_rest_check_manager_permissions( $object, $context = 'read' ) { $objects = array( 'reports' => 'view_woocommerce_reports', 'settings' => 'manage_woocommerce', 'system_status' => 'manage_woocommerce', 'attributes' => 'manage_product_terms', 'shipping_methods' => 'manage_woocommerce', 'payment_gateways' => 'manage_woocommerce', 'webhooks' => 'manage_woocommerce', ); $permission = current_user_can( $objects[ $object ] ); return apply_filters( 'woocommerce_rest_check_permissions', $permission, $context, 0, $object ); } /** * Check product reviews permissions on REST API. * * @since 3.5.0 * @param string $context Request context. * @param string $object_id Object ID. * @return bool */ function wc_rest_check_product_reviews_permissions( $context = 'read', $object_id = 0 ) { $permission = false; $contexts = array( 'read' => 'moderate_comments', 'create' => 'edit_products', 'edit' => 'edit_products', 'delete' => 'edit_products', 'batch' => 'edit_products', ); if ( $object_id > 0 ) { $object = get_comment( $object_id ); if ( ! is_a( $object, 'WP_Comment' ) || get_comment_type( $object ) !== 'review' ) { return false; } } if ( isset( $contexts[ $context ] ) ) { $permission = current_user_can( $contexts[ $context ], $object_id ); } return apply_filters( 'woocommerce_rest_check_permissions', $permission, $context, $object_id, 'product_review' ); } /** * Returns true if the current REST request is from the product editor. * * @since 8.9.0 * @return bool */ function wc_rest_is_from_product_editor() { return isset( $_SERVER['HTTP_X_WC_FROM_PRODUCT_EDITOR'] ) && '1' === $_SERVER['HTTP_X_WC_FROM_PRODUCT_EDITOR']; } /** * Check if a REST namespace should be loaded. Useful to maintain site performance even when lots of REST namespaces are registered. * * @since 9.2.0. * * @param string $ns The namespace to check. * @param string $rest_route (Optional) The REST route being checked. * * @return bool True if the namespace should be loaded, false otherwise. */ function wc_rest_should_load_namespace( string $ns, string $rest_route = '' ): bool { if ( '' === $rest_route ) { $rest_route = $GLOBALS['wp']->query_vars['rest_route'] ?? ''; } if ( '' === $rest_route ) { return true; } $rest_route = trailingslashit( ltrim( $rest_route, '/' ) ); $ns = trailingslashit( $ns ); /** * Known namespaces that we know are safe to not load if the request is not for them. Namespaces not in this namespace should always be loaded, because we don't know if they won't be making another internal REST request to an unloaded namespace. */ $known_namespaces = array( 'wc/v1', 'wc/v2', 'wc/v3', 'wc/v4', 'wc-telemetry', 'wc-admin', 'wc-analytics', 'wc/store', 'wc/private', ); $known_namespace_request = false; foreach ( $known_namespaces as $known_namespace ) { if ( str_starts_with( $rest_route, $known_namespace ) ) { $known_namespace_request = true; break; } } if ( ! $known_namespace_request ) { return true; } /** * Filters whether a namespace should be loaded. * * @param bool $should_load True if the namespace should be loaded, false otherwise. * @param string $ns The namespace to check. * @param string $rest_route The REST route being checked. * @param array $known_namespaces Known namespaces that we know are safe to not load if the request is not for them. * * @since 9.4 */ return apply_filters( 'wc_rest_should_load_namespace', str_starts_with( $rest_route, $ns ), $ns, $rest_route, $known_namespaces ); } ction complete', 'woocommerce' ); } $this->log( $action_id, $message ); } /** * Log action failure. * * @param int $action_id Action ID. * @param Exception $exception Exception. * @param string $context Action execution context. */ public function log_failed_action( $action_id, Exception $exception, $context = '' ) { if ( ! empty( $context ) ) { /* translators: 1: context 2: exception message */ $message = sprintf( __( 'action failed via %1$s: %2$s', 'woocommerce' ), $context, $exception->getMessage() ); } else { /* translators: %s: exception message */ $message = sprintf( __( 'action failed: %s', 'woocommerce' ), $exception->getMessage() ); } $this->log( $action_id, $message ); } /** * Log action timeout. * * @param int $action_id Action ID. * @param string $timeout Timeout. */ public function log_timed_out_action( $action_id, $timeout ) { /* translators: %s: amount of time */ $this->log( $action_id, sprintf( __( 'action marked as failed after %s seconds. Unknown error occurred. Check server, PHP and database error logs to diagnose cause.', 'woocommerce' ), $timeout ) ); } /** * Log unexpected shutdown. * * @param int $action_id Action ID. * @param mixed[] $error Error. */ public function log_unexpected_shutdown( $action_id, $error ) { if ( ! empty( $error ) ) { /* translators: 1: error message 2: filename 3: line */ $this->log( $action_id, sprintf( __( 'unexpected shutdown: PHP Fatal error %1$s in %2$s on line %3$s', 'woocommerce' ), $error['message'], $error['file'], $error['line'] ) ); } } /** * Log action reset. * * @param int $action_id Action ID. */ public function log_reset_action( $action_id ) { $this->log( $action_id, __( 'action reset', 'woocommerce' ) ); } /** * Log ignored action. * * @param int $action_id Action ID. * @param string $context Action execution context. */ public function log_ignored_action( $action_id, $context = '' ) { if ( ! empty( $context ) ) { /* translators: %s: context */ $message = sprintf( __( 'action ignored via %s', 'woocommerce' ), $context ); } else { $message = __( 'action ignored', 'woocommerce' ); } $this->log( $action_id, $message ); } /** * Log the failure of fetching the action. * * @param string $action_id Action ID. * @param null|Exception $exception The exception which occurred when fetching the action. NULL by default for backward compatibility. */ public function log_failed_fetch_action( $action_id, ?Exception $exception = null ) { if ( ! is_null( $exception ) ) { /* translators: %s: exception message */ $log_message = sprintf( __( 'There was a failure fetching this action: %s', 'woocommerce' ), $exception->getMessage() ); } else { $log_message = __( 'There was a failure fetching this action', 'woocommerce' ); } $this->log( $action_id, $log_message ); } /** * Log the failure of scheduling the action's next instance. * * @param int $action_id Action ID. * @param Exception $exception Exception object. */ public function log_failed_schedule_next_instance( $action_id, Exception $exception ) { /* translators: %s: exception message */ $this->log( $action_id, sprintf( __( 'There was a failure scheduling the next instance of this action: %s', 'woocommerce' ), $exception->getMessage() ) ); } /** * Bulk add cancel action log entries. * * Implemented here for backward compatibility. Should be implemented in parent loggers * for more performant bulk logging. * * @param array $action_ids List of action ID. */ public function bulk_log_cancel_actions( $action_ids ) { if ( empty( $action_ids ) ) { return; } foreach ( $action_ids as $action_id ) { $this->log_canceled_action( $action_id ); } } }
Fatal error: Uncaught Error: Class "ActionScheduler_Logger" not found in /htdocs/wp-content/plugins/woocommerce/packages/action-scheduler/classes/abstracts/ActionScheduler.php:62 Stack trace: #0 /htdocs/wp-content/plugins/woocommerce/packages/action-scheduler/classes/abstracts/ActionScheduler.php(188): ActionScheduler::logger() #1 /htdocs/wp-content/plugins/woocommerce/packages/action-scheduler/action-scheduler.php(60): ActionScheduler::init('/htdocs/wp-cont...') #2 /htdocs/wp-content/plugins/woocommerce/packages/action-scheduler/classes/ActionScheduler_Versions.php(115): action_scheduler_initialize_3_dot_9_dot_3() #3 /htdocs/wp-includes/class-wp-hook.php(339): ActionScheduler_Versions::initialize_latest_version() #4 /htdocs/wp-includes/class-wp-hook.php(365): WP_Hook->apply_filters(NULL, Array) #5 /htdocs/wp-includes/plugin.php(522): WP_Hook->do_action(Array) #6 /htdocs/wp-settings.php(593): do_action('plugins_loaded') #7 /htdocs/wp-config.php(98): require_once('/htdocs/wp-sett...') #8 /htdocs/wp-load.php(50): require_once('/htdocs/wp-conf...') #9 /htdocs/wp-blog-header.php(13): require_once('/htdocs/wp-load...') #10 /htdocs/index.php(17): require('/htdocs/wp-blog...') #11 {main} thrown in /htdocs/wp-content/plugins/woocommerce/packages/action-scheduler/classes/abstracts/ActionScheduler.php on line 62