File: /wordpress/plugins/wp-cloud-client/beta/src/BusinessProfile/ProfileAdminNotice.php
<?php
declare(strict_types=1);
namespace VPlugins\WPCloudClient\BusinessProfile;
use VPlugins\WPCloudClient\Settings\SettingsRepository;
/**
* Renders the "Business Profile Data Missing" notice (with placeholder generation)
* inline within the WP Cloud Client settings page when no profile data exists,
* and handles the AJAX request that populates placeholder profile data.
*/
final class ProfileAdminNotice {
private const AJAX_ACTION = 'wpcc_generate_business_profile';
private const NONCE_KEY = 'wpcc_generate_profile_nonce';
/**
* Constructor.
*
* @param ProfileRepository $repository The profile data repository.
* @param SettingsRepository $settings Settings repository, used for multisite detection.
*/
public function __construct(
private readonly ProfileRepository $repository,
private readonly SettingsRepository $settings,
) {}
/**
* Register the AJAX handler used by the placeholder-generation button.
*
* The notice itself is rendered inline when no profile data exists, so no
* admin_notices hook is registered here.
*
* @return void
*/
public function register(): void {
add_action( 'wp_ajax_' . self::AJAX_ACTION, [ $this, 'handleGenerate' ] );
}
/**
* Render the missing-profile notice HTML.
*
* Emits the warning markup, the "Generate Placeholder Data" button, and an
* inline `<script>` handler that POSTs to the AJAX action registered by
* {@see self::register()} and reloads the page on success. Intended to be
* called from a settings surface when no profile data exists.
*
* @return void
*/
public function render(): void {
$nonce = wp_create_nonce( self::NONCE_KEY );
?>
<div class="notice notice-warning is-dismissible">
<p>
<strong><?php esc_html_e( 'Business Profile Data Missing:', 'wp-cloud-client' ); ?></strong>
<?php esc_html_e( 'Business profile data has not been synced yet. If you need a placeholder, you can generate basic data from your site settings.', 'wp-cloud-client' ); ?>
</p>
<p>
<button
type="button"
id="wpcc-generate-profile"
class="button button-secondary"
data-nonce="<?php echo esc_attr( $nonce ); ?>"
>
<?php esc_html_e( 'Generate Placeholder Data', 'wp-cloud-client' ); ?>
</button>
</p>
</div>
<script>
document.getElementById('wpcc-generate-profile')?.addEventListener('click', function() {
var btn = this;
btn.disabled = true;
btn.textContent = '<?php echo esc_js( __( 'Generating...', 'wp-cloud-client' ) ); ?>';
var data = new FormData();
data.append('action', '<?php echo esc_js( self::AJAX_ACTION ); ?>');
data.append('_wpnonce', btn.dataset.nonce);
fetch(ajaxurl, { method: 'POST', body: data, credentials: 'same-origin' })
.then(function(r) { return r.json(); })
.then(function(r) {
if (r.success) { location.reload(); }
else { btn.disabled = false; btn.textContent = '<?php echo esc_js( __( 'Generate Placeholder Data', 'wp-cloud-client' ) ); ?>'; }
})
.catch(function() { btn.disabled = false; });
});
</script>
<?php
}
/**
* Handle the AJAX request to generate placeholder profile data.
*
* @return void
*/
public function handleGenerate(): void {
if ( false === check_ajax_referer( self::NONCE_KEY, '_wpnonce', false ) ) {
wp_send_json_error( [ 'message' => __( 'Security check failed. Please reload the page and try again.', 'wp-cloud-client' ) ], 403 );
}
// On multisite, this writes to the network's shared main-site profile
// (see ProfileRepository::update()), so only a network super-admin
// may trigger it, regardless of which site's admin fires the request.
$requiredCap = $this->settings->isMultisite() ? 'manage_network_options' : 'manage_options';
if ( ! current_user_can( $requiredCap ) ) {
wp_send_json_error( [ 'message' => __( 'Unauthorized', 'wp-cloud-client' ) ], 403 );
}
$this->repository->update(
[
'company_name' => get_option( 'blogname', '' ),
'description' => get_option( 'blogdescription', '' ),
'contact_email' => get_option( 'admin_email', '' ),
]
);
wp_send_json_success();
}
}