[ 'label' => __( 'Dashboard', 'clusterlane' ), 'icon' => 'dashicons-chart-area', 'page' => 'clusterlane-dashboard', 'cap' => \Clusterlane\Core\Capabilities::USE, 'g' => 'main' ],
'cluster-inspector' => [ 'label' => __( 'Cluster Inspector', 'clusterlane' ), 'icon' => 'dashicons-networking', 'page' => 'clusterlane-cluster-inspector', 'cap' => \Clusterlane\Core\Capabilities::USE, 'g' => 'main' ],
'article-inspector' => [ 'label' => __( 'Article Inspector', 'clusterlane' ), 'icon' => 'dashicons-visibility', 'page' => 'clusterlane-article-inspector', 'cap' => \Clusterlane\Core\Capabilities::USE, 'g' => 'main' ],
'report' => [ 'label' => __( 'Report', 'clusterlane' ), 'icon' => 'dashicons-media-document', 'page' => 'clusterlane-report', 'cap' => \Clusterlane\Core\Capabilities::USE, 'g' => 'main' ],
'text-match' => [ 'label' => __( 'Text Match', 'clusterlane' ), 'icon' => 'dashicons-search', 'page' => 'clusterlane-text-match', 'cap' => \Clusterlane\Core\Capabilities::USE, 'g' => 'tools' ],
'link-suggest' => [ 'label' => __( 'Link Suggestions', 'clusterlane' ), 'icon' => 'dashicons-admin-links', 'page' => 'clusterlane-link-suggest', 'cap' => \Clusterlane\Core\Capabilities::USE, 'g' => 'tools' ],
'seo-titles' => [ 'label' => __( 'SEO Titles', 'clusterlane' ), 'icon' => 'dashicons-editor-textcolor', 'page' => 'clusterlane-seo-titles', 'cap' => \Clusterlane\Core\Capabilities::USE, 'g' => 'tools' ],
'cluster-settings' => [ 'label' => __( 'Cluster Admin', 'clusterlane' ), 'icon' => 'dashicons-category', 'page' => 'clusterlane-cluster-settings', 'cap' => \Clusterlane\Core\Capabilities::MANAGE, 'g' => 'admin' ],
'settings' => [ 'label' => __( 'Settings', 'clusterlane' ), 'icon' => 'dashicons-admin-settings', 'page' => 'clusterlane-settings', 'cap' => \Clusterlane\Core\Capabilities::MANAGE, 'g' => 'admin' ],
'help' => [ 'label' => __( 'Help', 'clusterlane' ), 'icon' => 'dashicons-editor-help', 'page' => 'clusterlane-help', 'cap' => \Clusterlane\Core\Capabilities::USE, 'g' => 'help' ],
];
?>
$p ):
if ( ! current_user_can( $p['cap'] ) ) continue;
$is_active = ( $key === $active );
$url = admin_url( 'admin.php?page=' . $p['page'] );
$new_group = $prev_group !== '' && $p['g'] !== $prev_group;
$prev_group = $p['g'];
?>
>
/* Fit the tabs before the bar is first painted (0.98.192) — done in the
footer script it made the row jump on every page. The same tabs always
go into More, whichever page is open; More is marked when the current
page is in it. clusterlane-sticky-bar.js calls this again on resize. */
window.clusterlaneFitTabs = function () {
var nav = document.querySelector( '#clusterlane-stickybar .clusterlane-stickybar__nav' ), more = document.getElementById( 'clusterlane-bar-more' ), menu = document.getElementById( 'clusterlane-bar-more-menu' );
if ( ! nav || ! more || ! menu ) return;
var btn = more.querySelector( '.clusterlane-stickybar__more-btn' );
Array.prototype.slice.call( menu.querySelectorAll( '.clusterlane-stickybar__tab' ) ).forEach( function ( t ) { nav.insertBefore( t, more ); } );
more.hidden = true; menu.hidden = true; if ( btn ) btn.setAttribute( 'aria-expanded', 'false' );
if ( nav.scrollWidth <= nav.clientWidth + 1 ) { if ( btn ) btn.classList.remove( 'clusterlane-stickybar__tab--active-in' ); return; }
more.hidden = false;
var tabs = Array.prototype.slice.call( nav.querySelectorAll( ':scope > .clusterlane-stickybar__tab' ) );
for ( var i = tabs.length - 1; i >= 0 && nav.scrollWidth > nav.clientWidth + 1; i-- ) menu.insertBefore( tabs[ i ], menu.firstChild );
if ( btn ) btn.classList.toggle( 'clusterlane-stickybar__tab--active-in', !! menu.querySelector( '.clusterlane-stickybar__tab--active' ) );
};
window.clusterlaneFitTabs();
' ',
'article' => ' ',
'text-match' => ' ',
'link' => ' ',
'admin' => ' ',
'settings' => ' ',
'report' => ' ',
'seo' => ' ',
'help' => ' ',
];
$g = $glyphs[ $name ] ?? $glyphs['cluster'];
return '' . $g . ' ';
}
}
if ( ! function_exists( 'clusterlane_glyph_paths' ) ) {
/** Line glyphs (24×24, stroke = currentColor) — one set for PHP and JS (clusterlaneGlyph). */
function clusterlane_glyph_paths(): array {
return [
'sparkle' => ' ',
'clipboard' => ' ',
'folder' => ' ',
'tag' => ' ',
'pencil' => ' ',
'alert' => ' ',
'search' => ' ',
'expand' => ' ',
'eye' => ' ',
'globe' => ' ',
'chart' => ' ',
'link' => ' ',
'nodes' => ' ',
'bolt' => ' ',
'refresh' => ' ',
'bulb' => ' ',
'plug' => ' ',
'wrench' => ' ',
'trash' => ' ',
'check' => ' ',
'book' => ' ',
'map' => ' ',
'database' => ' ',
'lock' => ' ',
'layers' => ' ',
'server' => ' ',
'shield' => ' ',
'code' => ' ',
'scale' => ' ',
'sliders' => ' ',
'printer' => ' ',
'key' => ' ',
'coins' => ' ',
'award' => ' ',
'target' => ' ',
'arrow' => ' ',
'leaf' => ' ',
'card' => ' ',
'download' => ' ',
'bag' => ' ',
'collapse' => ' ',
'play' => ' ',
'dot' => ' ',
];
}
}
if ( ! function_exists( 'clusterlane_glyph' ) ) {
/**
* Inline glyph for titles, buttons and labels (replaces emoji, which look
* different on every OS). No quotes or newlines, so it is also safe to
* print inside a single-quoted JS string.
*/
/** Allowed SVG markup for wp_kses() — exactly what clusterlane_glyph() produces. */
function clusterlane_kses_svg(): array {
$shape = [ 'd' => true, 'cx' => true, 'cy' => true, 'r' => true, 'rx' => true, 'ry' => true, 'x' => true, 'y' => true, 'width' => true, 'height' => true, 'points' => true, 'x1' => true, 'y1' => true, 'x2' => true, 'y2' => true, 'fill' => true, 'stroke' => true, 'stroke-width' => true ];
return [
'svg' => [ 'class' => true, 'width' => true, 'height' => true, 'viewbox' => true, 'fill' => true, 'stroke' => true, 'stroke-width' => true, 'stroke-linecap' => true, 'stroke-linejoin' => true, 'aria-hidden' => true, 'focusable' => true, 'xmlns' => true ],
'path' => $shape, 'circle' => $shape, 'rect' => $shape, 'ellipse' => $shape,
'line' => $shape, 'polyline' => $shape, 'polygon' => $shape, 'g' => $shape,
];
}
/** Allowed markup for clusterlane_icon(): the tile span and its SVG. */
function clusterlane_kses_icon(): array {
return clusterlane_kses_svg() + [ 'span' => [ 'class' => true, 'aria-hidden' => true ] ];
}
/** Print a page icon tile, escaped (wp_kses with its allowlist). */
function clusterlane_icon_e( string $name ): void {
echo wp_kses( clusterlane_icon( $name ), clusterlane_kses_icon() );
}
/** Print a glyph, escaped (wp_kses with the SVG allowlist). */
function clusterlane_glyph_e( string $name ): void {
echo wp_kses( clusterlane_glyph( $name ), clusterlane_kses_svg() );
}
function clusterlane_glyph( string $name ): string {
$paths = clusterlane_glyph_paths();
if ( ! isset( $paths[ $name ] ) ) return '';
return '' . $paths[ $name ] . ' ';
}
}