' . esc_html__( 'Score', 'prodlyra' ) . '',
'' . esc_html__( 'Settings', 'prodlyra' ) . ''
);
return $links;
}
/**
* Page router.
*/
public static function render() {
if ( ! current_user_can( 'manage_woocommerce' ) ) {
return;
}
// Only selects which tab to display; nothing is changed.
$tab = isset( $_GET['tab'] ) && 'settings' === sanitize_key( wp_unslash( $_GET['tab'] ) ) ? 'settings' : 'score'; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
echo '
';
echo '
' . esc_html__( 'Prodlyra', 'prodlyra' ) . '
';
echo '
' . esc_html__( 'How well AI shopping assistants (ChatGPT, Gemini, Perplexity) can read and recommend your products.', 'prodlyra' ) . '
';
echo '
';
if ( 'settings' === $tab ) {
self::render_settings();
} else {
self::render_score();
}
echo '
';
}
/**
* Score tab.
*/
private static function render_score() {
$r = Prodlyra_Scanner::run();
$score = $r['score'];
$level = $score >= 80 ? 'good' : ( $score >= 50 ? 'medium' : 'low' );
$sections = array(
'access' => __( 'Access for AI assistants', 'prodlyra' ),
'products' => __( 'Product data', 'prodlyra' ),
'policies' => __( 'Shipping and returns', 'prodlyra' ),
'protocols' => __( 'Files for AI agents', 'prodlyra' ),
);
echo '';
echo '
' . esc_html( (string) $score ) . '/100
';
echo '
';
if ( 'good' === $level ) {
echo '
' . esc_html__( 'Your store is easy for AI assistants to read.', 'prodlyra' ) . '
';
} elseif ( 'medium' === $level ) {
echo '
' . esc_html__( 'AI assistants can read your store, with gaps.', 'prodlyra' ) . '
';
} else {
echo '
' . esc_html__( 'AI assistants miss most of what they need.', 'prodlyra' ) . '
';
}
if ( $r['total'] > $r['sampled'] ) {
/* translators: 1: products checked, 2: total products. */
echo '
' . esc_html( sprintf( __( 'Based on your %1$d newest products out of %2$d.', 'prodlyra' ), $r['sampled'], $r['total'] ) ) . '
';
} else {
/* translators: %d: number of products. */
echo '
' . esc_html( sprintf( _n( 'Based on %d product.', 'Based on all %d products.', $r['sampled'], 'prodlyra' ), $r['sampled'] ) ) . '
';
}
echo '
';
// Fixes, biggest gain first.
$fixes = array_filter(
$r['checks'],
function ( $c ) {
return ! $c['passed'] && '' !== $c['fix'];
}
);
usort(
$fixes,
function ( $a, $b ) {
return ( $b['max'] - $b['points'] ) <=> ( $a['max'] - $a['points'] );
}
);
if ( $fixes ) {
echo '' . esc_html__( 'What to fix first', 'prodlyra' ) . '
';
foreach ( $fixes as $fix ) {
$gain = round( $fix['max'] - $fix['points'] );
echo '- ' . esc_html( $fix['label'] ) . ' ';
/* translators: %s: points. */
echo '' . esc_html( sprintf( __( '+%s points', 'prodlyra' ), $gain ) ) . '
';
echo esc_html( $fix['fix'] );
if ( $fix['link'] ) {
echo ' ' . esc_html__( 'Open settings', 'prodlyra' ) . '';
}
echo ' ';
}
echo '
';
}
// Every check, by section.
echo '' . esc_html__( 'All checks', 'prodlyra' ) . '
';
echo '| ' . esc_html__( 'Check', 'prodlyra' ) . ' | ' . esc_html__( 'Result', 'prodlyra' ) . ' | ' . esc_html__( 'Points', 'prodlyra' ) . ' |
';
foreach ( $sections as $key => $title ) {
echo '| ' . esc_html( $title ) . ' |
';
foreach ( $r['checks'] as $c ) {
if ( $c['section'] !== $key ) {
continue;
}
$result = $c['passed'] ? __( 'OK', 'prodlyra' ) : __( 'To fix', 'prodlyra' );
if ( '' !== $c['result'] ) {
$result = $c['result'];
} elseif ( null !== $c['of'] ) {
/* translators: 1: products passing, 2: products checked. */
$result = sprintf( __( '%1$d of %2$d products', 'prodlyra' ), $c['ok'], $c['of'] );
}
printf(
'| %s | %s | %s / %d |
',
esc_html( $c['label'] ),
$c['passed'] ? 'prodlyra-ok' : 'prodlyra-ko',
esc_html( $result ),
esc_html( number_format_i18n( $c['points'], 1 ) ),
absint( $c['max'] )
);
}
}
echo '
';
// Products to fix.
if ( $r['products'] ) {
echo '' . esc_html__( 'Products to fix', 'prodlyra' ) . '
';
if ( $r['to_fix'] > count( $r['products'] ) ) {
/* translators: 1: products shown, 2: products with issues. */
echo '' . esc_html( sprintf( __( 'Showing %1$d of %2$d products with issues.', 'prodlyra' ), count( $r['products'] ), $r['to_fix'] ) ) . '
';
}
echo '| ' . esc_html__( 'Product', 'prodlyra' ) . ' | ' . esc_html__( 'Issues', 'prodlyra' ) . ' |
';
foreach ( $r['products'] as $row ) {
$product = $row['product'];
$edit = get_edit_post_link( $product->get_id() );
printf(
'| %s | %s |
',
esc_url( $edit ? $edit : '' ),
esc_html( $product->get_name() ),
esc_html( implode( ', ', $row['issues'] ) )
);
}
echo '
';
}
echo '';
if ( Prodlyra_Settings::get()['llms_enabled'] ) {
echo '' . esc_html__( 'View llms.txt', 'prodlyra' ) . ' · ';
}
echo '' . esc_html__( 'View robots.txt', 'prodlyra' ) . '';
echo '
';
}
/**
* Settings tab.
*/
private static function render_settings() {
$s = Prodlyra_Settings::get();
$name = Prodlyra_Settings::OPTION;
echo '';
}
/**
* Checkbox row.
*
* @param string $name Option name.
* @param string $key Setting key.
* @param array $s Settings.
* @param string $label Label.
* @param string $help Help text.
*/
private static function checkbox( $name, $key, $s, $label, $help ) {
printf(
'| %1$s | |
',
esc_html( $label ),
esc_attr( $name ),
esc_attr( $key ),
checked( (int) $s[ $key ], 1, false ),
esc_html( $help )
);
}
/**
* Text input row.
*
* @param string $name Option name.
* @param string $key Setting key.
* @param array $s Settings.
* @param string $label Label.
* @param string $help Help text.
* @param string $placeholder Placeholder.
*/
private static function text( $name, $key, $s, $label, $help, $placeholder = '' ) {
printf(
' | %6$s |
',
esc_html( $label ),
esc_attr( $name ),
esc_attr( $key ),
esc_attr( (string) $s[ $key ] ),
esc_attr( $placeholder ),
esc_html( $help )
);
}
/**
* Min–max days row.
*
* @param string $name Option name.
* @param string $prefix "handling" or "transit".
* @param array $s Settings.
* @param string $label Label.
*/
private static function range( $name, $prefix, $s, $label ) {
printf(
'| %1$s | – |
',
esc_html( $label ),
esc_attr( $name ),
esc_attr( $prefix ),
absint( $s[ $prefix . '_min' ] ),
esc_attr__( 'Minimum', 'prodlyra' ),
absint( $s[ $prefix . '_max' ] ),
esc_attr__( 'Maximum', 'prodlyra' )
);
}
}