$requestData GET-like request data.
*/
public function render( array $requestData ): void {
$brands = $this->brands( $requestData );
$categories = $this->categories( $requestData );
$sort = AmazonDiscountShortcodeRenderer::sortFromAttributes(
array( 'sort' => $requestData['affilun_discount_sort'] ?? null )
);
$perCategory = AmazonDiscountShortcodeRenderer::perCategoryFromAttributes(
array( 'per_category' => $requestData['affilun_discount_per_category'] ?? null )
);
$brandAttribute = $brands === array()
? ''
: sprintf( ' brands="%s"', implode( ',', $brands ) );
$shortcode = sprintf(
'[affilun_amazon_discounts%s categories="%s" sort="%s" per_category="%d"]',
$brandAttribute,
implode( ',', $categories ),
$sort,
$perCategory
);
echo '
';
echo '
' . esc_html( 'Amazon割引商品ショートコード' ) . '
';
echo '
' . esc_html( 'Creators APIから日次取得した割引商品を、カテゴリ見出しとaffilun商品カードで表示します。' ) . '
';
$this->renderSyncNotice( $requestData );
$this->renderStatus();
$this->renderManualSyncForm();
$canConfigureBrands = ! function_exists( 'current_user_can' )
|| current_user_can( AdminCapability::CAP_RUN_SYNC );
$path = $canConfigureBrands ? 'admin-post.php' : 'admin.php';
$url = function_exists( 'admin_url' ) ? admin_url( $path ) : $path;
echo '
';
echo '
';
echo '
';
echo '
';
echo '
' . esc_html( 'プレビュー' ) . '
';
$previewAttributes = array(
'brands' => implode( ',', $brands ),
'categories' => implode( ',', $categories ),
'sort' => $sort,
'per_category' => $perCategory,
);
echo $this->shortcodeRenderer->render( // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Canonical renderer returns escaped plugin HTML.
$previewAttributes,
true
);
echo ' ';
}
/**
* Render the local snapshot status.
*/
private function renderStatus(): void {
$count = $this->repository->count();
$latest = $this->repository->latestFetchedAt();
$text = $latest === null
? sprintf( '保存済み商品: %d件(初回の日次取得待ち)', $count )
: sprintf(
'保存済み商品: %d件 / 最終取得: %s JST',
$count,
$latest->setTimezone( new DateTimeZone( 'Asia/Tokyo' ) )->format( 'Y-m-d H:i' )
);
echo '' . esc_html( $text ) . '
';
if ( function_exists( 'esc_html' ) && $latest !== null && $latest <= AmazonDiscountDisplayPolicy::cutoff( $this->clock->now() ) ) {
echo '' . esc_html(
'保存データは表示期限切れのため非表示です。これは取得失敗の通知とは別の鮮度判定です。'
) . '
';
}
if ( function_exists( 'esc_html' ) ) {
echo '' . esc_html(
'保存件数と表示件数は異なります。取得から24時間以上経過した商品、選択価格の割引を確認できない商品、旧形式のデータは非表示です。同期失敗時も表示期限は延長されません。再取得後に表示が再開します。'
) . '
';
}
}
/**
* Render the nonce-protected background synchronization control.
*/
private function renderManualSyncForm(): void {
$path = 'admin-post.php';
$url = function_exists( 'admin_url' ) ? admin_url( $path ) : $path;
$canRunSync = ! function_exists( 'current_user_can' )
|| current_user_can( AdminCapability::CAP_RUN_SYNC );
$enabled = $this->manualSyncAvailable && $canRunSync;
echo '';
}
/**
* Render the result of a manual synchronization request.
*
* @param array $requestData GET-like request data.
*/
private function renderSyncNotice( array $requestData ): void {
$status = is_string( $requestData[ AmazonDiscountSyncFormToken::STATUS_QUERY ] ?? null )
? $requestData[ AmazonDiscountSyncFormToken::STATUS_QUERY ]
: '';
$notice = match ( $status ) {
'queued' => array( 'notice notice-success inline', 'Amazon割引商品の手動取得を開始しました。' ),
'forbidden' => array( 'notice notice-error inline', '手動取得を実行する権限がありません。' ),
'invalid_nonce' => array( 'notice notice-error inline', '手動取得リクエストを確認できませんでした。' ),
'unavailable' => array( 'notice notice-error inline', 'Amazon Creators APIが設定されていません。' ),
'error' => array( 'notice notice-error inline', '手動取得を開始できませんでした。' ),
default => null,
};
if ( $notice === null ) {
return;
}
echo ''
. self::escapeHtml( $notice[1] ) // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Escaped by the local HTML helper.
. '
';
}
/**
* Escape visible notice text.
*
* @param string $value Raw text.
*/
private static function escapeHtml( string $value ): string {
return htmlspecialchars( $value, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8' );
}
/**
* Escape a notice class attribute.
*
* @param string $value Raw attribute value.
*/
private static function escapeAttribute( string $value ): string {
return htmlspecialchars( $value, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8' );
}
/**
* @param array $requestData Request data.
*
* @return list
*/
private function categories( array $requestData ): array {
$raw = $requestData['affilun_discount_categories'] ?? null;
if ( is_array( $raw ) ) {
$categories = AmazonDiscountCategory::normalize( array_values( $raw ) );
if ( $categories !== array() ) {
return $categories;
}
}
return AmazonDiscountCategory::DEFAULT_SELECTION;
}
/**
* @param array $requestData Request data.
*
* @return list
*/
private function brands( array $requestData ): array {
if ( array_key_exists( 'affilun_discount_brands', $requestData ) ) {
return AmazonDiscountBrand::parse( $requestData['affilun_discount_brands'] );
}
return $this->brandSettings !== null ? $this->brandSettings->load() : array();
}
}