prefix . 'aioseo_posts'; } private function terms_table(): string { global $wpdb; return $wpdb->prefix . 'aioseo_terms'; } protected function has_settings(): bool { return '' !== (string) get_option( 'aioseo_options', '' ); } public function counts(): array { global $wpdb; $counts = parent::counts(); if ( $this->table_exists( $this->posts_table() ) ) { // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared $counts['posts'] = max( $counts['posts'], (int) $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM %i WHERE (title IS NOT NULL AND title <> '') OR (description IS NOT NULL AND description <> '')", $this->posts_table() ) ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- table name from this plugin's own Database class/adapter, never from input; values go through $wpdb->prepare(). } if ( $this->table_exists( $this->terms_table() ) ) { // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared $counts['terms'] = max( $counts['terms'], (int) $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM %i WHERE (title IS NOT NULL AND title <> '') OR (description IS NOT NULL AND description <> '')", $this->terms_table() ) ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- table name from this plugin's own Database class/adapter, never from input; values go through $wpdb->prepare(). } return $counts; } public function post_ids( int $after, int $limit ): array { global $wpdb; $ids = parent::post_ids( $after, $limit ); if ( $this->table_exists( $this->posts_table() ) ) { // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared $rows = $wpdb->get_col( $wpdb->prepare( 'SELECT DISTINCT post_id FROM %i WHERE post_id > %d ORDER BY post_id ASC LIMIT %d', $this->posts_table(), $after, max( 1, $limit ) ) ); $ids = array_merge( $ids, array_map( 'intval', (array) $rows ) ); } $ids = array_values( array_unique( $ids ) ); sort( $ids ); return array_slice( $ids, 0, max( 1, $limit ) ); } public function term_ids( int $after, int $limit ): array { global $wpdb; if ( ! $this->table_exists( $this->terms_table() ) ) { return array(); } // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared $rows = $wpdb->get_col( $wpdb->prepare( 'SELECT DISTINCT term_id FROM %i WHERE term_id > %d ORDER BY term_id ASC LIMIT %d', $this->terms_table(), $after, max( 1, $limit ) ) ); return array_map( 'intval', (array) $rows ); } /** * @return array */ private function from_row( ?object $row ): array { if ( ! $row ) { return array(); } $robots = array(); if ( ! empty( $row->robots_noindex ) ) { $robots[] = 'noindex'; } if ( ! empty( $row->robots_nofollow ) ) { $robots[] = 'nofollow'; } if ( ! empty( $row->robots_noarchive ) ) { $robots[] = 'noarchive'; } if ( ! empty( $row->robots_nosnippet ) ) { $robots[] = 'nosnippet'; } if ( ! empty( $row->robots_noimageindex ) ) { $robots[] = 'noimageindex'; } $keywords = array(); $phrases = json_decode( (string) ( $row->keyphrases ?? '' ), true ); if ( is_array( $phrases ) ) { $focus = (string) ( $phrases['focus']['keyphrase'] ?? '' ); if ( '' !== $focus ) { $keywords[] = $focus; } foreach ( (array) ( $phrases['additional'] ?? array() ) as $extra ) { $word = is_array( $extra ) ? (string) ( $extra['keyphrase'] ?? '' ) : (string) $extra; if ( '' !== $word ) { $keywords[] = $word; } } } return $this->clean( array( 'title' => $this->vars( trim( (string) ( $row->title ?? '' ) ) ), 'desc' => $this->vars( trim( (string) ( $row->description ?? '' ) ) ), 'keywords' => array_values( array_unique( $keywords ) ), 'canonical' => trim( (string) ( $row->canonical_url ?? '' ) ), 'robots' => $robots, 'social' => array( 'og_title' => $this->vars( trim( (string) ( $row->og_title ?? '' ) ) ), 'og_desc' => $this->vars( trim( (string) ( $row->og_description ?? '' ) ) ), 'og_image' => trim( (string) ( $row->og_image_custom_url ?? '' ) ), 'tw_title' => $this->vars( trim( (string) ( $row->twitter_title ?? '' ) ) ), 'tw_desc' => $this->vars( trim( (string) ( $row->twitter_description ?? '' ) ) ), 'tw_image' => trim( (string) ( $row->twitter_image_custom_url ?? '' ) ), ), ) ); } public function post_record( int $post_id ): array { global $wpdb; if ( $this->table_exists( $this->posts_table() ) ) { // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared $row = $wpdb->get_row( $wpdb->prepare( 'SELECT * FROM %i WHERE post_id = %d', $this->posts_table(), $post_id ) ); $record = $this->from_row( $row ); if ( ! empty( $record ) ) { return $record; } } // Version 3 fallback. return $this->clean( array( 'title' => $this->vars( $this->meta( $post_id, '_aioseo_title' ) ), 'desc' => $this->vars( $this->meta( $post_id, '_aioseo_description' ) ), 'keywords' => array_values( array_filter( array_map( 'trim', explode( ',', $this->meta( $post_id, '_aioseo_keywords' ) ) ) ) ), ) ); } public function term_record( int $term_id ): array { global $wpdb; if ( ! $this->table_exists( $this->terms_table() ) ) { return array(); } // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared return $this->from_row( $wpdb->get_row( $wpdb->prepare( 'SELECT * FROM %i WHERE term_id = %d', $this->terms_table(), $term_id ) ) ); } public function settings(): array { $raw = get_option( 'aioseo_options', '' ); $all = is_string( $raw ) ? json_decode( $raw, true ) : ( is_array( $raw ) ? $raw : null ); if ( ! is_array( $all ) ) { return array(); } $search = (array) ( $all['searchAppearance'] ?? array() ); $global = (array) ( $search['global'] ?? array() ); $home = (array) ( $search['global']['homePage'] ?? $search['homePage'] ?? array() ); $types = (array) ( $search['postTypes'] ?? array() ); $taxes = (array) ( $search['taxonomies'] ?? array() ); $social = (array) ( $all['social'] ?? array() ); $profiles = (array) ( $social['profiles']['urls'] ?? array() ); $out = array( 'separator' => mb_substr( trim( (string) ( $global['separator'] ?? '' ) ), 0, 3 ), 'home_title' => $this->vars( (string) ( $home['title'] ?? '' ) ), 'home_desc' => $this->vars( (string) ( $home['metaDescription'] ?? '' ) ), ); $templates = array(); $noindex_pt = array(); foreach ( $types as $type => $conf ) { $conf = (array) $conf; $title = $this->vars( (string) ( $conf['title'] ?? '' ) ); $desc = $this->vars( (string) ( $conf['metaDescription'] ?? '' ) ); if ( '' !== $title || '' !== $desc ) { $templates[ (string) $type ] = array( 'title' => $title, 'desc' => $desc ); } if ( ! empty( $conf['advanced']['robotsMeta']['noindex'] ) ) { $noindex_pt[] = (string) $type; } } $tax_templates = array(); $noindex_tax = array(); foreach ( $taxes as $tax => $conf ) { $conf = (array) $conf; $title = $this->vars( (string) ( $conf['title'] ?? '' ) ); $desc = $this->vars( (string) ( $conf['metaDescription'] ?? '' ) ); if ( '' !== $title || '' !== $desc ) { $tax_templates[ (string) $tax ] = array( 'title' => $title, 'desc' => $desc ); } if ( ! empty( $conf['advanced']['robotsMeta']['noindex'] ) ) { $noindex_tax[] = (string) $tax; } } $out['templates'] = $templates; $out['noindex_types'] = $noindex_pt; $out['taxonomy_templates'] = $tax_templates; $out['noindex_taxonomies'] = $noindex_tax; $out['og_default_image'] = (string) ( $social['facebook']['general']['defaultImagePosts'] ?? $social['facebook']['general']['defaultImageSourcePosts'] ?? '' ); $out['twitter_site'] = ltrim( (string) ( $social['twitter']['general']['username'] ?? '' ), '@' ); $out['twitter_card'] = 'summary' === (string) ( $social['twitter']['general']['defaultCardType'] ?? '' ) ? 'summary' : 'summary_large_image'; $out['organisation'] = array( 'name' => (string) ( $search['global']['schema']['organizationName'] ?? $social['profiles']['sameUsername']['username'] ?? '' ), 'logo' => (string) ( $search['global']['schema']['organizationLogo'] ?? '' ), 'type' => 'person' === (string) ( $search['global']['schema']['siteRepresents'] ?? '' ) ? 'person' : 'organization', ); $out['social_profiles'] = array_values( array_filter( array_map( 'strval', $profiles ) ) ); return $out; } }