canShowWidget( 'seoSetup' ) &&
apply_filters( 'aioseo_show_seo_setup', true ) &&
( aioseo()->access->isAdmin() || aioseo()->access->hasCapability( 'aioseo_setup_wizard' ) ) &&
! aioseo()->standalone->setupWizard->isCompleted()
) {
wp_add_dashboard_widget(
'aioseo-seo-setup',
// Translators: 1 - The plugin short name ("AIOSEO").
sprintf( esc_html__( '%s Setup', 'all-in-one-seo-pack' ), AIOSEO_PLUGIN_SHORT_NAME ),
[
$this,
'outputSeoSetup',
],
null,
null,
'normal',
'high'
);
}
// Add the SEO Checklist widget.
if (
$this->canShowWidget( 'seoChecklist' ) &&
apply_filters( 'aioseo_show_seo_checklist', true ) &&
( aioseo()->access->isAdmin() || aioseo()->access->hasCapability( 'aioseo_setup_wizard' ) || aioseo()->access->hasCapability( 'aioseo_general_settings' ) ) &&
aioseo()->standalone->setupWizard->isCompleted()
) {
wp_add_dashboard_widget(
'aioseo-seo-checklist',
// Translators: 1 - The plugin short name ("AIOSEO").
sprintf( esc_html__( '%s Checklist', 'all-in-one-seo-pack' ), AIOSEO_PLUGIN_SHORT_NAME ),
[
$this,
'outputSeoChecklist',
],
null,
null,
'normal',
'high'
);
}
// Add the Overview widget.
if (
$this->canShowWidget( 'seoOverview' ) &&
apply_filters( 'aioseo_show_seo_overview', true ) &&
( aioseo()->access->isAdmin() || aioseo()->access->hasCapability( 'aioseo_page_analysis' ) ) &&
aioseo()->options->advanced->truSeo
) {
wp_add_dashboard_widget(
'aioseo-overview',
// Translators: 1 - The plugin short name ("AIOSEO").
sprintf( esc_html__( '%s Overview', 'all-in-one-seo-pack' ), AIOSEO_PLUGIN_SHORT_NAME ),
[
$this,
'outputSeoOverview',
]
);
}
// Add the News widget.
if (
$this->canShowWidget( 'seoNews' ) &&
apply_filters( 'aioseo_show_seo_news', true ) &&
aioseo()->access->isAdmin()
) {
wp_add_dashboard_widget(
'aioseo-rss-feed',
esc_html__( "What's New in AIOSEO", 'all-in-one-seo-pack' ),
[
$this,
'displayRssDashboardWidget',
]
);
}
}
/**
* Whether or not to show the widget.
*
* @since 4.0.0
* @version 4.2.8
*
* @param string $widget The widget to check if can show.
* @return boolean True if yes, false otherwise.
*/
protected function canShowWidget( $widget ) { // phpcs:disable VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
return true;
}
/**
* Output the SEO Setup widget.
*
* @since 4.2.0
*
* @return void
*/
public function outputSeoSetup() {
$this->output( 'aioseo-seo-setup-app' );
}
/**
* Output the SEO Checklist widget.
*
* @since 4.2.0
*
* @return void
*/
public function outputSeoChecklist() {
$this->output( 'aioseo-seo-checklist-app' );
}
/**
* Output the SEO Overview widget.
*
* @since 4.2.0
*
* @return void
*/
public function outputSeoOverview() {
$this->output( 'aioseo-overview-app' );
}
/**
* Output the widget wrapper for the Vue App.
*
* @since 4.2.0
*
* @param string $appId The App ID to print out.
* @return void
*/
private function output( $appId ) {
// Enqueue the scripts for the widget.
$this->enqueue();
// Opening tag.
echo '
';
// Loader element.
require AIOSEO_DIR . '/app/Common/Views/parts/loader.php';
// Closing tag.
echo '
';
}
/**
* Enqueue the scripts and styles.
*
* @since 4.2.0
*
* @return void
*/
private function enqueue() {
aioseo()->core->assets->load( 'src/vue/standalone/dashboard-widgets/main.js', [], aioseo()->helpers->getVueData( 'dashboard' ) );
}
/**
* Returns the items the newsroom widget shows.
*
* NOTE: One slot is held for the newest item of every other product that has any. AIOSEO posts far
* more often than the addons do, so on dates alone their news never reaches the four rows on show —
* which is the whole reason it was invisible here.
*
* @since 5.0.3
*
* @param int $limit How many items to return.
* @return array The items, newest first.
*/
private function getNewsroomWidgetItems( $limit = 4 ) {
// Other products add their own items here; each carries the badge and label the rows render.
$items = apply_filters( 'aioseo_newsroom_dashboard_items', aioseo()->newsroom->getItems(), Newsroom::PRODUCT );
if ( ! is_array( $items ) || ! $items ) {
return [];
}
$byId = [];
foreach ( $items as $item ) {
if ( empty( $item['url'] ) || empty( $item['title'] ) ) {
continue;
}
// An item cross-posted into more than one feed is still one item.
$key = ! empty( $item['id'] ) ? (string) $item['id'] : (string) $item['url'];
if ( ! isset( $byId[ $key ] ) ) {
$byId[ $key ] = $item;
}
}
$items = array_values( $byId );
usort( $items, function ( $a, $b ) {
return strtotime( $b['date'] ?? '' ) <=> strtotime( $a['date'] ?? '' );
} );
$reserved = [];
foreach ( $items as $item ) {
$product = (string) ( $item['product'] ?? '' );
if ( '' === $product || Newsroom::PRODUCT === $product || isset( $reserved[ $product ] ) ) {
continue;
}
$reserved[ $product ] = $item;
}
// Leave room for the reserved items, then fill what is left with the newest of everything.
$reserved = array_slice( array_values( $reserved ), 0, max( 0, $limit - 1 ) );
$reservedKeys = [];
foreach ( $reserved as $item ) {
$reservedKeys[] = ! empty( $item['id'] ) ? (string) $item['id'] : (string) $item['url'];
}
$filled = [];
foreach ( $items as $item ) {
$key = ! empty( $item['id'] ) ? (string) $item['id'] : (string) $item['url'];
if ( in_array( $key, $reservedKeys, true ) ) {
continue;
}
$filled[] = $item;
if ( count( $filled ) >= $limit - count( $reserved ) ) {
break;
}
}
$shown = array_merge( $filled, $reserved );
usort( $shown, function ( $a, $b ) {
return strtotime( $b['date'] ?? '' ) <=> strtotime( $a['date'] ?? '' );
} );
return array_slice( $shown, 0, $limit );
}
/**
* Display RSS Dashboard Widget
*
* @since 4.0.0
*
* @return void
*/
public function displayRssDashboardWidget() {
// Check if the user has chosen not to display this widget through screen options.
$currentScreen = aioseo()->helpers->getCurrentScreen();
if ( empty( $currentScreen->id ) ) {
return;
}
$hiddenWidgets = get_user_meta( get_current_user_id(), 'metaboxhidden_' . $currentScreen->id );
if ( $hiddenWidgets && count( $hiddenWidgets ) > 0 && is_array( $hiddenWidgets[0] ) && in_array( 'aioseo-rss-feed', $hiddenWidgets[0], true ) ) {
return;
}
$items = $this->getNewsroomWidgetItems();
if ( ! $items ) {
esc_html_e( 'Temporarily unable to load feed.', 'all-in-one-seo-pack' );
return;
}
$archiveUrl = aioseo()->newsroom->getArchiveUrl( 'newsroom-dashboard-widget' );
// This widget is plain PHP with no stylesheet in its path — the other dashboard
// widgets are Vue apps. Four rows don't justify pulling that pipeline in, so the
// handful of rules it needs are printed with it.
?>