diff --git a/client-mu-plugins/goodbids/README.md b/client-mu-plugins/goodbids/README.md
index b79a61b86..c32597e92 100644
--- a/client-mu-plugins/goodbids/README.md
+++ b/client-mu-plugins/goodbids/README.md
@@ -67,3 +67,19 @@ Returns the Auction's Goal value. If `$auction_id` is not provided, the current
`goodbids()->auctions->get_expected_high_bid( int $auction_id )`
Returns the Auction's Expected High Bid value. If `$auction_id` is not provided, the current post ID will be used.
+### ACF Block Functions
+
+`goodbids()->acf->blocks()->get_all_blocks()`
+Get all custom registered blocks.
+
+`goodbids()->acf->blocks()->get_block( string $block_name )`
+Get block array by block name.
+
+`goodbids()->acf->blocks()->block_attr()`
+_Use the global `block_attr()` helper function instead._ This will render the block attributes for the current block.
+
+`goodbids()->acf->blocks()->get_block_location( string $block_name, string $return )`
+Get the location of a block. Return values can be: "directory" (Default) or "json" (Returns the path to block.json. _Can also be found in the `path` key of the block array._
+
+`goodbids()->acf->blocks()->get_block_locations()`
+Get all directories where blocks can be found.
diff --git a/client-mu-plugins/goodbids/blocks/authentication/block.json b/client-mu-plugins/goodbids/blocks/authentication/block.json
new file mode 100644
index 000000000..92f634df5
--- /dev/null
+++ b/client-mu-plugins/goodbids/blocks/authentication/block.json
@@ -0,0 +1,14 @@
+{
+ "name": "authentication",
+ "title": "User Authentication Form",
+ "description": "Displays a user login and registration form for GoodBids.",
+ "icon": "feedback",
+ "category": "goodbids",
+ "keywords": ["custom", "sign", "up", "register", "registration", "form", "users", "authentication"],
+ "acf": {
+ "mode": "preview"
+ },
+ "supports": {
+ "jsx": false
+ }
+}
diff --git a/client-mu-plugins/goodbids/blocks/authentication/render.php b/client-mu-plugins/goodbids/blocks/authentication/render.php
new file mode 100644
index 000000000..8fb9d30d9
--- /dev/null
+++ b/client-mu-plugins/goodbids/blocks/authentication/render.php
@@ -0,0 +1,21 @@
+%s
',
+ esc_html__( 'This will render the Login and Registration form if the user is currently not signed in.', 'goodbids' )
+ );
+ return;
+endif;
+?>
+
diff --git a/client-mu-plugins/goodbids/blocks/index.php b/client-mu-plugins/goodbids/blocks/index.php
new file mode 100644
index 000000000..8142269b1
--- /dev/null
+++ b/client-mu-plugins/goodbids/blocks/index.php
@@ -0,0 +1 @@
+get_bid_product_id( $auction_id ) );
}
@@ -207,7 +207,7 @@ public function has_bid_product( int $auction_id ) : bool {
*
* @return int
*/
- public function get_bid_product_id( int $auction_id ) : int {
+ public function get_bid_product_id( int $auction_id ): int {
return intval( get_post_meta( $auction_id, Bids::AUCTION_BID_META_KEY, true ) );
}
@@ -221,7 +221,7 @@ public function get_bid_product_id( int $auction_id ) : int {
*
* @return void
*/
- public function set_bid_product_id( int $auction_id, int $bid_product_id ) : void {
+ public function set_bid_product_id( int $auction_id, int $bid_product_id ): void {
update_post_meta( $auction_id, Bids::AUCTION_BID_META_KEY, $bid_product_id );
}
@@ -235,7 +235,7 @@ public function set_bid_product_id( int $auction_id, int $bid_product_id ) : voi
*
* @return mixed
*/
- public function get_setting( string $meta_key, int $auction_id = null ) : mixed {
+ public function get_setting( string $meta_key, int $auction_id = null ): mixed {
if ( ! $auction_id ) {
$auction_id = get_the_ID();
}
@@ -278,7 +278,7 @@ public function get_estimated_value( int $auction_id = null ) : int {
*
* @return string
*/
- public function get_start_date_time( int $auction_id = null ) : string {
+ public function get_start_date_time( int $auction_id = null ): string {
return $this->get_setting( 'auction_start', $auction_id );
}
@@ -309,7 +309,7 @@ public function has_started( int $auction_id = null ): bool {
*
* @return int
*/
- public function get_bid_increment( int $auction_id = null ) : int {
+ public function get_bid_increment( int $auction_id = null ): int {
return intval( $this->get_setting( 'bid_increment', $auction_id ) );
}
@@ -353,7 +353,7 @@ public function calculate_starting_bid( int $auction_id = null ): int {
*
* @return int
*/
- public function get_goal( int $auction_id = null ) : int {
+ public function get_goal( int $auction_id = null ): int {
return intval( $this->get_setting( 'auction_goal', $auction_id ) );
}
diff --git a/client-mu-plugins/goodbids/src/classes/Core.php b/client-mu-plugins/goodbids/src/classes/Core.php
index d62ca6338..16da17a94 100644
--- a/client-mu-plugins/goodbids/src/classes/Core.php
+++ b/client-mu-plugins/goodbids/src/classes/Core.php
@@ -12,6 +12,7 @@
use GoodBids\Auctions\Auctions;
use GoodBids\Network\Sites;
use GoodBids\Plugins\ACF;
+use GoodBids\Plugins\WooCommerce;
/**
* Core Class
@@ -60,6 +61,12 @@ class Core {
*/
public Auctions $auctions;
+ /**
+ * @since 1.0.0
+ * @var WooCommerce
+ */
+ public WooCommerce $woocommerce;
+
/**
* Constructor
*
@@ -111,6 +118,7 @@ public function init(): void {
return;
}
+ $this->load_dependencies();
$this->load_plugins();
$this->load_modules();
@@ -152,6 +160,17 @@ public function get_config( string $key ): mixed {
return $this->config[ $key ] ?? null;
}
+ /**
+ * Load plugin dependencies.
+ *
+ * @since 1.0.0
+ *
+ * @return void
+ */
+ private function load_dependencies() : void {
+ require_once GOODBIDS_PLUGIN_PATH . '/src/helpers.php';
+ }
+
/**
* Load 3rd Party Plugins.
*
@@ -200,10 +219,11 @@ private function load_modules(): void {
add_action(
'mu_plugin_loaded',
function () {
- $this->acf = new ACF();
- $this->sites = new Sites();
- $this->admin = new Admin();
- $this->auctions = new Auctions();
+ $this->acf = new ACF();
+ $this->sites = new Sites();
+ $this->admin = new Admin();
+ $this->auctions = new Auctions();
+ $this->woocommerce = new WooCommerce();
}
);
}
diff --git a/client-mu-plugins/goodbids/src/classes/Network/Sites.php b/client-mu-plugins/goodbids/src/classes/Network/Sites.php
index 11b0ddf9c..bff589d35 100644
--- a/client-mu-plugins/goodbids/src/classes/Network/Sites.php
+++ b/client-mu-plugins/goodbids/src/classes/Network/Sites.php
@@ -36,11 +36,17 @@ class Sites {
*/
public function __construct() {
$this->init_np_fields();
+
+ // Process New Site Custom Meta Fields.
+ $this->new_site_form_fields();
$this->validate_new_site_fields();
$this->save_new_site_fields();
- $this->save_edit_site_fields();
- $this->new_site_form_fields();
+
+ // Process Edit Site Custom Meta Fields.
$this->edit_site_form_fields();
+ $this->save_edit_site_fields();
+
+ // New Site Actions
$this->activate_child_theme_on_new_site();
}
@@ -185,7 +191,7 @@ function () {
return;
}
- check_admin_referer( 'add-blog', '_wpnonce_add-blog' );
+ check_admin_referer( 'add-np-site', '_wpnonce_add-np-site' );
if ( empty( $_POST[ self::OPTION_SLUG ] ) || ! is_array( $_POST[ self::OPTION_SLUG ] ) ) {
wp_die( esc_html__( 'Missing required Nonprofit data.' ) );
@@ -298,6 +304,8 @@ function ( WP_Site $new_site, array $args ) {
$meta_value = sanitize_text_field( $data[ $key ] );
update_site_meta( $new_site->id, $meta_key, $meta_value );
}
+
+ $this->init_site_defaults( $new_site->id );
},
10,
2
@@ -313,12 +321,13 @@ function ( WP_Site $new_site, array $args ) {
*/
private function save_edit_site_fields(): void {
add_action(
- 'wp_initialize_site',
+ 'wp_update_site',
+
/**
* @param WP_Site $new_site New site object.
* @param WP_Site $old_site Old site object.
*/
- function ( WP_Site $new_site, WP_Site $old_site ) {
+ function ( WP_Site $new_site, WP_Site $old_site ): void {
if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
return;
}
@@ -328,7 +337,7 @@ function ( WP_Site $new_site, WP_Site $old_site ) {
return;
}
- check_admin_referer( 'edit-site' );
+ check_admin_referer( 'edit-np-site', '_wpnonce_edit-np-site' );
$data = $_POST[ self::OPTION_SLUG ]; // phpcs:ignore
@@ -356,22 +365,32 @@ function ( WP_Site $new_site, WP_Site $old_site ) {
*/
private function activate_child_theme_on_new_site(): void {
add_action(
- 'wp_initialize_site',
+ 'goodbids_init_site',
function ( $site_id ) {
$stylesheet = 'goodbids-nonprofit';
- // Switch to the new site
- switch_to_blog( $site_id );
-
- // Check if the Goodbids child theme exists
- if ( ! wp_get_theme( $stylesheet )->exists() ) {
- return;
+ // Check if the Goodbids child theme exists first.
+ if ( wp_get_theme( $stylesheet )->exists() ) {
+ switch_theme( $stylesheet );
}
-
- switch_theme( $stylesheet );
-
- restore_current_blog();
}
);
}
+
+ /**
+ * Initialize new site defaults.
+ *
+ * @since 1.0.0
+ *
+ * @param int $site_id
+ *
+ * @return void
+ */
+ private function init_site_defaults( int $site_id ): void {
+ switch_to_blog( $site_id );
+
+ do_action( 'goodbids_init_site', $site_id );
+
+ restore_current_blog();
+ }
}
diff --git a/client-mu-plugins/goodbids/src/classes/Plugins/ACF.php b/client-mu-plugins/goodbids/src/classes/Plugins/ACF.php
index be66743f9..b73bd2033 100644
--- a/client-mu-plugins/goodbids/src/classes/Plugins/ACF.php
+++ b/client-mu-plugins/goodbids/src/classes/Plugins/ACF.php
@@ -2,11 +2,14 @@
/**
* ACF Functionality
*
+ * @since 1.0.0
* @package GoodBids
*/
namespace GoodBids\Plugins;
+use GoodBids\Plugins\ACF\Blocks;
+
/**
* Class for Advanced Custom Fields Pro
*
@@ -20,6 +23,12 @@ class ACF {
*/
private string $slug = 'advanced-custom-fields-pro/acf.php';
+ /**
+ * @since 1.0.0
+ * @var Blocks
+ */
+ private Blocks $blocks;
+
/**
* Initialize ACF Functionality
*
@@ -30,12 +39,26 @@ public function __construct() {
return;
}
+ // Initialize Submodules.
+ $this->blocks = new Blocks();
+
$this->disable_admin();
$this->discourage_the_field_usage();
$this->modify_save_directory();
$this->disable_database_storage();
}
+ /**
+ * Return the Blocks submodule
+ *
+ * @since 1.0.0
+ *
+ * @return Blocks
+ */
+ public function blocks() : Blocks {
+ return $this->blocks;
+ }
+
/**
* Disable ACF Admin per WP VIP Documentation
*
diff --git a/client-mu-plugins/goodbids/src/classes/plugins/ACF/Blocks.php b/client-mu-plugins/goodbids/src/classes/plugins/ACF/Blocks.php
new file mode 100644
index 000000000..69ab66740
--- /dev/null
+++ b/client-mu-plugins/goodbids/src/classes/plugins/ACF/Blocks.php
@@ -0,0 +1,314 @@
+register_block_category();
+ $this->register_blocks();
+ $this->set_block_callback();
+ }
+
+ /**
+ * Register Custom Blocks
+ *
+ * @since 1.0.0
+ *
+ * @return void
+ */
+ private function register_blocks() : void {
+ add_action(
+ 'acf/init',
+ function () {
+ $blocks = $this->get_all_blocks();
+
+ foreach ( $blocks as $block ) {
+ $include = $block['path'] . '/block.php';
+
+ // Autoload block.php within block directory
+ if ( file_exists( $include ) ) {
+ require $include;
+ }
+
+ register_block_type( trailingslashit( $block['path'] ) . 'block.json' );
+ }
+ }
+ );
+ }
+
+ /**
+ * Get All Available Blocks
+ *
+ * @since 1.0.0
+ *
+ * @return array
+ */
+ public function get_all_blocks() : array {
+ $blocks = [];
+ $locations = $this->get_block_locations();
+
+ foreach ( $locations as $location ) {
+ $group = glob( trailingslashit( $location ) . '**/block.json' );
+
+ foreach ( $group as $block_path ) {
+ $block = json_decode( wpcom_vip_file_get_contents( $block_path ), true );
+
+ // Add path as a property.
+ $block['path'] = dirname( $block_path );
+
+ $blocks[] = $block;
+ }
+ }
+
+ return $blocks;
+ }
+
+ /**
+ * Get block array
+ *
+ * @since 1.0.0
+ *
+ * @param string $block_name
+ *
+ * @return array|false
+ */
+ public function get_block( string $block_name ) : array|false {
+ $block_path = $this->get_block_location( $block_name, 'json' );
+
+ if ( ! $block_path ) {
+ return false;
+ }
+
+ $block = json_decode( wpcom_vip_file_get_contents( $block_path ), true );
+
+ $block['path'] = dirname( $block_path );
+
+ return $block;
+ }
+
+ /**
+ * Get locations where custom blocks can be found.
+ *
+ * @since 1.0.0
+ *
+ * @return array
+ */
+ public function get_block_locations() : array {
+ return apply_filters(
+ 'goodbids_block_locations',
+ [
+ GOODBIDS_PLUGIN_PATH . '/blocks',
+ ]
+ );
+ }
+
+ /**
+ * Get path to block by name.
+ *
+ * @since 1.0.0
+ *
+ * @param string $block_name
+ * @param string $return
+ *
+ * @return false|string
+ */
+ public function get_block_location( string $block_name, string $return = 'directory' ) : false|string {
+ // Only allow ACF blocks
+ if ( str_contains( $block_name, '/' ) && ! str_starts_with( $block_name, $this->block_prefix . '/' ) ) {
+ return false;
+ }
+
+ $block_name = str_replace( $this->block_prefix . '/', '', $block_name );
+ $blocks = $this->get_all_blocks();
+
+ foreach ( $blocks as $block ) {
+ if ( $block_name !== $block['name'] ) {
+ continue;
+ }
+
+ if ( 'json' === $return ) {
+ return trailingslashit( $block['path'] ) . 'block.json';
+ }
+
+ return $block['path'];
+ }
+
+ return false;
+ }
+
+ /**
+ * Register a custom Block Category.
+ *
+ * @since 1.0.0
+ * @return void
+ */
+ private function register_block_category() : void {
+ add_filter(
+ 'block_categories_all',
+ function ( array $categories ) : array {
+ return array_merge(
+ [
+ [
+ 'slug' => 'goodbids',
+ 'title' => __( 'GoodBids', 'goodbids' ),
+ ]
+ ],
+ $categories
+ );
+ }
+ );
+ }
+
+ /**
+ * Automatically add block render callbacks for custom blocks.
+ *
+ * @since 1.0.0
+ *
+ * @return void
+ */
+ private function set_block_callback() : void {
+ add_filter(
+ 'block_type_metadata',
+ function ( array $metadata ) : array { // phpcs:ignore
+ if ( ! function_exists( '\acf_is_acf_block_json' ) || ! \acf_is_acf_block_json( $metadata ) ) {
+ return $metadata;
+ }
+
+ if ( ! empty( $metadata['acf']['renderCallback'] ) || ! empty( $metadata['acf']['renderTemplate'] ) || empty( $metadata['name'] ) ) {
+ return $metadata;
+ }
+
+ $metadata['acf']['renderCallback'] = function( array $block ) : void {
+ $block_name = str_replace( $this->block_prefix . '/', '', $block['name'] );
+ $block['slug'] = sanitize_title( $block_name );
+ if ( empty( $block['path'] ) ) {
+ $block['path'] = $this->get_block_location( $block_name );
+ }
+ $render = $block['path'] . '/render.php';
+
+ if ( ! file_exists( $render ) ) {
+ // TODO: Log error.
+ return;
+ }
+
+ require $render;
+ };
+
+ return $metadata;
+ },
+ 5
+ );
+ }
+
+ /**
+ * Render the ACF block attributes
+ *
+ * @since 1.0.0
+ *
+ * @param array $block
+ * @param string $addl_class
+ * @param array $attr
+ *
+ * @return void
+ */
+ public function block_attr( array $block, string $addl_class = '', array $attr = [] ) : void {
+ $extra = [
+ 'id' => $this->get_block_id( $block ),
+ 'class' => $this->get_block_class( $block, $addl_class ),
+ ];
+
+ if ( ! empty( $block['support']['jsx'] ) ) {
+ $extra['data-supports-jsx'] = 'true';
+ }
+
+ $extra = array_merge( $extra, $attr );
+
+ // Attributes are escaped within get_block_wrapper_attributes.
+ echo get_block_wrapper_attributes( $extra ); // phpcs:ignore
+
+ do_action( 'goodbids_block_attr', $block );
+ }
+
+ /**
+ * Get unique block ID.
+ *
+ * @since 1.0.0
+ *
+ * @param array $block
+ *
+ * @return string
+ */
+ private function get_block_id( array $block ) : string {
+ if ( ! empty( $block['anchor'] ) ) {
+ return $block['anchor'];
+ }
+
+ $prefix = str_replace( $this->block_prefix . '/', '', $block['name'] );
+
+ if ( empty( $block['id'] ) ) {
+ return $prefix . '_' . uniqid();
+ }
+
+ return $prefix . '_' . $block['id'];
+ }
+
+ /**
+ * Get custom block classes.
+ *
+ * @since 1.0.0
+ *
+ * @param array $block
+ * @param string $addl_class
+ *
+ * @return string
+ */
+ private function get_block_class( array $block, string $addl_class = '' ) : string {
+ $class = array_merge(
+ [
+ str_replace( $this->block_prefix . '/', '', $block['name'] ),
+ ],
+ explode( ' ', $addl_class )
+ );
+
+ if ( ! empty( $block['className'] ) ) {
+ $class[] = $block['className'];
+ }
+
+ if ( ! empty( $block['align'] ) ) {
+ $class[] = 'align' . $block['align'];
+ }
+
+ if ( ! empty( $block['align_content'] ) ) {
+ $class[] = 'align-content-' . $block['align_content'];
+ }
+
+ $class = apply_filters( 'goodbids_block_class', $class, $block );
+
+ return trim( implode( ' ', array_unique( $class ) ) );
+ }
+}
diff --git a/client-mu-plugins/goodbids/src/classes/plugins/WooCommerce.php b/client-mu-plugins/goodbids/src/classes/plugins/WooCommerce.php
new file mode 100644
index 000000000..7603c2e99
--- /dev/null
+++ b/client-mu-plugins/goodbids/src/classes/plugins/WooCommerce.php
@@ -0,0 +1,274 @@
+is_plugin_active( $this->slug ) ) {
+ return;
+ }
+
+ $this->configure_new_site();
+ $this->create_auth_page();
+ $this->add_auth_page_setting();
+ $this->display_post_states();
+ $this->authentication_redirect();
+ $this->prevent_wp_login_access();
+ }
+
+ /**
+ * Configure WooCommerce settings for new sites.
+ *
+ * @since 1.0.0
+ *
+ * @return void
+ */
+ private function configure_new_site() : void {
+ add_action(
+ 'goodbids_init_site',
+ function ( int $site_id ) : void {
+ // Disable Guest Checkout.
+ update_option( 'woocommerce_enable_guest_checkout', 'no' );
+
+ // Enable Log in during Checkout.
+ update_option( 'woocommerce_enable_checkout_login_reminder', 'yes' );
+
+ // Enable Account Creation during Checkout.
+ update_option( 'woocommerce_enable_signup_and_login_from_checkout', 'yes' );
+
+ // Enable Account Creation from My Account Page.
+ update_option( 'woocommerce_enable_myaccount_registration', 'yes' );
+
+ // Allow for personal data removal.
+ update_option( 'woocommerce_erasure_request_removes_order_data', 'yes' );
+ update_option( 'woocommerce_allow_bulk_remove_personal_data', 'yes' );
+ },
+ 5
+ );
+ }
+
+ /**
+ * Create a new Authentication Page
+ *
+ * @since 1.0.0
+ *
+ * @return void
+ */
+ private function create_auth_page() : void {
+ add_action(
+ 'woocommerce_page_created',
+ function ( int $page_id, array $page_data ) : void {
+ if ( empty( $page_data['post_name'] ) || 'my-account' !== $page_data['post_name'] ) {
+ return;
+ }
+
+ $auth_page_id = wp_insert_post(
+ [
+ 'post_title' => __( 'Authentication', 'goodbids' ),
+ 'post_name' => 'authentication',
+ 'post_status' => 'publish',
+ 'post_type' => 'page',
+ 'comment_status' => 'closed',
+ 'ping_status' => 'closed',
+ 'post_content' => '',
+ 'post_parent' => $page_id,
+ ],
+ true
+ );
+
+ if ( ! $auth_page_id ) {
+ // TODO: Log Error.
+ return;
+ }
+
+ update_option( 'woocommerce_authentication_page_id', $auth_page_id );
+ },
+ 6,
+ 2
+ );
+ }
+
+ /**
+ * Add Authentication Page setting to WooCommerce Advanced Settings
+ *
+ * @since 1.0.0
+ *
+ * @return void
+ */
+ private function add_auth_page_setting() : void {
+ add_filter(
+ 'woocommerce_settings_pages',
+ function ( array $settings ) : array {
+ $auth_setting = [
+ 'title' => __( 'Authentication', 'goodbids' ),
+ 'desc' => __( 'Page contents: GoodBids Authentication Block.', 'goodbids' ),
+ 'id' => 'woocommerce_authentication_page_id',
+ 'type' => 'single_select_page_with_search',
+ 'default' => '',
+ 'class' => 'wc-page-search',
+ 'css' => 'min-width:300px;',
+ 'args' => [
+ 'exclude' => [ // phpcs:ignore
+ wc_get_page_id( 'cart' ),
+ wc_get_page_id( 'checkout' ),
+ wc_get_page_id( 'my-account' ),
+ ],
+ ],
+ 'desc_tip' => true,
+ 'autoload' => false,
+ ];
+
+ $new_settings = [];
+
+ foreach ( $settings as $setting ) {
+ $new_settings[] = $setting;
+
+ if ( 'woocommerce_myaccount_page_id' === $setting['id'] ) {
+ $new_settings[] = $auth_setting;
+ }
+ }
+
+ return $new_settings;
+ }
+ );
+ }
+
+ /**
+ * Add a post display state for special GoodBids pages.
+ *
+ * @since 1.0.0
+ *
+ * @return void
+ */
+ private function display_post_states() : void {
+ add_filter(
+ 'display_post_states',
+ function ( array $post_states, \WP_Post $post ) : array {
+ if ( wc_get_page_id( 'authentication' ) === $post->ID ) {
+ $post_states['wc_page_for_authentication'] = __( 'Authentication Page', 'goodbids' );
+ }
+
+ return $post_states;
+ },
+ 10,
+ 2
+ );
+ }
+
+ /**
+ * Redirect to Authentication Page if user is not logged in.
+ *
+ * @since 1.0.0
+ *
+ * @return void
+ */
+ private function authentication_redirect() : void {
+ add_action(
+ 'template_redirect',
+ function () : void {
+ global $wp;
+
+ // Make sure we have a My Account & Authentication page.
+ $auth_page_id = wc_get_page_id( 'authentication' );
+ $account_page_id = wc_get_page_id( 'myaccount' );
+
+ if ( ! $auth_page_id || ! $account_page_id ) {
+ return;
+ }
+
+ // If logged in, perform WooCommerce Login Redirect.
+ if ( is_user_logged_in() ) {
+ if ( $auth_page_id === get_queried_object_id() ) {
+ $redirect = apply_filters( 'woocommerce_login_redirect', wc_get_page_permalink( 'myaccount' ) );
+
+ if ( $redirect ) {
+ wp_safe_redirect( $redirect );
+ exit;
+ }
+ }
+
+ return;
+ }
+
+ if ( $account_page_id !== get_queried_object_id() ) {
+ return;
+ }
+
+ $auth_page_url = wc_get_page_permalink( 'authentication' );
+
+ if ( ! $auth_page_url ) {
+ return;
+ }
+
+ $auth_page_url = add_query_arg(
+ 'redirect_to',
+ urlencode( home_url( $wp->request ) ),
+ $auth_page_url
+ );
+
+ wp_safe_redirect( $auth_page_url );
+ exit;
+ }
+ );
+ }
+
+ /**
+ * Prevent access to WP Login page unless user can manage options.
+ *
+ * @since 1.0.0
+ *
+ * @return void
+ */
+ private function prevent_wp_login_access() : void {
+ add_action(
+ 'login_head',
+ function () {
+ $request = ! empty( $_SERVER['REQUEST_URI'] ) ? sanitize_text_field( $_SERVER['REQUEST_URI'] ) : '';
+
+ // Check if the current URL contains /wp-admin or /wp-login.php
+ if ( ! str_contains( $request, '/wp-admin' ) && ! str_contains( $request, '/wp-login.php' ) ) {
+ return;
+ }
+
+ // Allow logged-in users with manage_options permissions.
+ if ( is_user_logged_in() && current_user_can( 'manage_options' ) ) {
+ return;
+ }
+
+ $auth_page_url = wc_get_page_permalink( 'authentication' );
+
+ if ( ! $auth_page_url ) {
+ return;
+ }
+
+ // Redirect to custom Auth page.
+ wp_safe_redirect( $auth_page_url );
+ exit;
+ },
+ 2
+ );
+ }
+}
diff --git a/client-mu-plugins/goodbids/src/helpers.php b/client-mu-plugins/goodbids/src/helpers.php
new file mode 100644
index 000000000..019858d58
--- /dev/null
+++ b/client-mu-plugins/goodbids/src/helpers.php
@@ -0,0 +1,24 @@
+acf->blocks()->block_attr( $block, $addl_class, $attr );
+ }
+}
diff --git a/client-mu-plugins/goodbids/views/network/edit-site-fields.php b/client-mu-plugins/goodbids/views/network/edit-site-fields.php
index 0a38bfb74..0eb3ccf85 100644
--- a/client-mu-plugins/goodbids/views/network/edit-site-fields.php
+++ b/client-mu-plugins/goodbids/views/network/edit-site-fields.php
@@ -13,6 +13,8 @@
?>
+
+