public function load_report_stats($author_graph, $period_start, $period_end) { global $user_ID, $current_user, $wp_post_types, $wpdb, $word_stats_options; ini_set('max_execution_time', 300); # Loading the stats can timeout on some servers with 30s max execution and "all time" is selected $report['total_keywords'] = $report['recent_posts_rows'] = array(); $report['totals_readability'][0] = $report['totals_readability'][1] = $report['totals_readability'][2] = $report['type_count']['custom'] = $dg_difficult_row = $dg_simple_row = $dg_short_row = $dg_long_row = $dg_no_keywords_row = $cached = $not_cached = 0; # Validate dates $period_start = date('Y-m-d', strtotime($period_start)); $period_end = date('Y-m-d', strtotime($period_end) + 86400); # Last day included $ignore = Word_Stats_Core::get_ignored_keywords(); foreach ($wp_post_types as $post_type) { $report['type_count'][$post_type->name] = 0; # Load only content and custom post types if (Word_Stats_Core::is_content_type($post_type->name)) { $query = $wpdb->prepare("SELECT * FROM {$wpdb->posts}\n\t\t\t\t\tWHERE post_type = %s AND " . (!$word_stats_options['count_unpublished'] ? "post_status = 'publish' AND " : '') . "post_date BETWEEN %s AND %s " . "ORDER BY post_date DESC", $post_type->name, $period_start, $period_end); $posts = $wpdb->get_results($query, OBJECT); foreach ($posts as $post) { # load_report_stats is not meant to be called before all posts are cached. # But in case a post happens to be created while the script was running, we cache it here. if (!get_post_meta($post->ID, 'word_stats_cached', true)) { Word_Stats_Core::cache_stats($post->ID); } $post_word_count = intval(get_post_meta($post->ID, 'word_stats_word_count', true)); $keywords = unserialize(get_post_meta($post->ID, 'word_stats_keywords', true)); # Add up words per author and aggregated. Group per month. $post_month = mysql2date('Y-m', $post->post_date); Word_Stats_Core::add_to_all(array(&$report['author_count'][-1][$post_type->name][$post_month], &$report['author_count'][$post->post_author][$post_type->name][$post_month], &$report['author_count_total'][$post->post_author], &$report['author_count_total'][-1]), $post_word_count); # Divisor to calculate keyword density per 1000 words $density_divisor = intval($post_word_count / 1000) ? intval($post_word_count / 1000) : 1; # Unless the selected author is -1 (all), stats for posts by the selected author only if ($author_graph == -1 || $post->post_author == $author_graph) { $dg_relevant_keywords = $dg_spammed_keywords = array(); $too_short = (int) $word_stats_options['diagnostic_too_short']; # For code readability # Remove ignored words. $keywords = bst_regfilter_keyword_counts($keywords, $ignore); # Aggregate the keywords, then create two lists for keywords flagged as relevant and spammed, according to their density. # Posts that are already flagged as too short aren't diagnosed as having no relevant keywords. if ($keywords && is_array($keywords)) { #empty arrays test false foreach ($keywords as $key => $value) { if ($report['total_keywords'][$key] === null) { $report['total_keywords'][$key] = 0; } $report['total_keywords'][$key] += (int) $value; if ($post_word_count >= $too_short) { $density = $value / $density_divisor; if ($density > (int) $word_stats_options['diagnostic_no_keywords']) { $dg_relevant_keywords[$key] = true; } if ($density > (int) $word_stats_options['diagnostic_spammed_keywords']) { $dg_spammed_keywords[$key] = $value; } } } } # Counts per type. Custom post types are aggregated. if ($post_type->name != 'post' && $post_type->name != 'page') { $report['type_count']['custom']++; } else { $report['type_count'][$post_type->name]++; } # Get the readability index. $ARI = get_post_meta($post->ID, 'readability_ARI', true); $CLI = get_post_meta($post->ID, 'readability_CLI', true); $LIX = get_post_meta($post->ID, 'readability_LIX', true); if ($ARI && $CLI && $LIX) { $ws_index_n = Word_Stats_Core::calc_ws_index($ARI, $CLI, $LIX); # Aggregate levels in 3 tiers (Basic, Intermediate, Advanced) if ($ws_index_n < $word_stats_options['diagnostic_too_simple']) { $ws_index = 0; } elseif ($ws_index_n < $word_stats_options['diagnostic_too_difficult']) { $ws_index = 1; } else { $ws_index = 2; } $report['totals_readability'][$ws_index]++; } # Empty title fix. $post_title = $post->post_title == '' ? '#' . $post->ID . ' ' . __('(no title)', 'word-stats') : htmlentities($post->post_title, null, 'utf-8'); $post_link = current_user_can('edit_post', $post->ID) ? '<a href=\'' . get_edit_post_link($post->ID) . '\'>' . $post_title . '</a>' : $post_title; $common = array($post_link, $post_type->name, mysql2date('Y-m-d', $post->post_date), number_format($post_word_count)); if ($ws_index_n > (int) $word_stats_options['diagnostic_too_difficult'] && $post_word_count >= $too_short) { $report['diagnostic']['too_difficult'][$dg_difficult_row] = Word_Stats_Admin::diagnostics_row($common, 'readability', round($ws_index_n)); $dg_difficult_row++; } if ($ws_index_n < (int) $word_stats_options['diagnostic_too_simple'] && $post_word_count >= $too_short) { $report['diagnostic']['too_simple'][$dg_simple_row] = Word_Stats_Admin::diagnostics_row($common, 'readability', round($ws_index_n)); $dg_simple_row++; } if ($post_word_count < $too_short) { $report['diagnostic']['too_short'][$dg_short_row] = Word_Stats_Admin::diagnostics_row($common, 'readability', round($ws_index_n)); $dg_short_row++; } if ($post_word_count > intval($word_stats_options['diagnostic_too_long'])) { $report['diagnostic']['too_long'][$dg_long_row] = Word_Stats_Admin::diagnostics_row($common, 'readability', round($ws_index_n)); $dg_long_row++; } if (empty($dg_relevant_keywords) && $post_word_count >= $too_short) { $report['diagnostic']['no_keywords'][$dg_no_keywords_row] = Word_Stats_Admin::diagnostics_row($common, 'readability', round($ws_index_n)); $dg_no_keywords_row++; } if (count($dg_spammed_keywords) > 0) { $report['diagnostic']['spammed_keywords'][$dg_spammed_row] = Word_Stats_Admin::diagnostics_row($common, 'keywords', implode(', ', array_keys($dg_spammed_keywords))); $dg_spammed_row++; } } } } } # Sort keywords by frequency, descending asort($report['total_keywords']); $report['total_keywords'] = array_reverse($report['total_keywords'], true); # Sort timeline Word_Stats_Core::safe_ksort($report['author_count'][$author_graph]['post']); Word_Stats_Core::safe_ksort($report['author_count'][$author_graph]['page']); Word_Stats_Core::safe_ksort($report['author_count'][$author_graph]['custom']); return $report; }