/** * Save a visit to the post or page. * * @param WP_Post $postObject: The post being generated * @return null **/ function kp_saveVisit($postObject) { global $wp_query, $kp_firstPost; // Check that we are on a Page or Post // !is_single() -- Don't save the post when we aren't on a single post page // !is_page() -- Don't save the post when we aren't on a single page being // !$kp_firstPost -- Don't save the visit after the first post in the loop if (!is_single() && !is_page() && !$kp_firstPost) { return; } // TODO: Create a better way to check if the user is visiting the post // Check if we want to collect statistics if (get_option("kp_CollectStatistics", "true") == "false") { return; } // If we are in test mode and if the current user is an admin, don't collect their visit data if (get_option("kp_AdminTestMode", "false") == "true" && kp_isUserAdmin()) { return; } // At this point, a non-admin user's visit will be tracked even if we are in test mode $kp_firstPost = false; // Set this to false to short circuit when kp_saveVisit is called on the next $postObject in the loop // Get the user's data and save the visit $arr = kp_getUserData(); extract($arr); $recommender = new kp_recommender($ip, $ua); $recommender->saveVisit($wp_query->post->ID); return null; }
<?php // Load configuration, functions, and classes for the plugin include_once "../../../../wp-load.php"; include_once "../kindred-posts-index.php"; // Check that the user is an admin if (!kp_isUserAdmin()) { die("You do not have access to this page, please log in as admin"); } // Load the test classes include_once 'classes\\recommendedpost.php'; include_once 'classes\\recommender.php'; include_once 'classes\\renderer.php'; include_once 'classes\\test.php'; include_once 'classes\\testData.php'; include_once 'classes\\testUser.php'; include_once 'classes\\widget.php'; include_once 'classes\\plugin.php'; $testPostID = 1; // A sample post to use for testing $numTestsToInsert = -1; // Set to <= 0 if you want to insert data $testRenderer = false || isset($_GET["testAll"]) && $_GET["testAll"] == "true"; $testRecommendedPost = false || isset($_GET["testAll"]) && $_GET["testAll"] == "true"; $testRecommender = false || isset($_GET["testAll"]) && $_GET["testAll"] == "true"; $testWidget = false || isset($_GET["testAll"]) && $_GET["testAll"] == "true"; $testPlugin = false || isset($_GET["testAll"]) && $_GET["testAll"] == "true"; $testRenderer = $testRenderer || isset($_GET["testRenderer"]) && $_GET["testRenderer"] == "true"; $testRecommendedPost = $testRecommendedPost || isset($_GET["testRecommendedPost"]) && $_GET["testRecommendedPost"] == "true"; $testRecommender = $testRecommender || isset($_GET["testRecommender"]) && $_GET["testRecommender"] == "true"; $testWidget = $testWidget || isset($_GET["testWidget"]) && $_GET["testWidget"] == "true";
/** * Run the recommendation engine and fill $posts with recommendedPosts objects * * @param int $numToRecommend: The number of posts to recommend * @param int $numClosestUsersToUse: The number of users to use when recommending posts (more is less efficient) * @param array<string> $recommendablePostTypes: An array of post types to recommend (if empty, recommend all post types) * @param bool $testModeValue: Indicates if we are in test mode and what value to look for * @return null */ public function run($numPostsToRecommend = 5, $numClosestUsersToUse = -1, $recommendablePostTypes = array(), $testModeValue = null) { // Get the unique posts and counts for each user global $visitTbl, $wpdb, $defaultNumClosestUsersToUse, $maxPastUpdateDate, $trackUserAgent; // Check if the user is currently on a post, if not, set the current post to -1 if (!isset($curr_post_id)) { $curr_post_id = -1; // This is so $curr_post_id can be used later } // Check if a value was passed in the function or default to the config value set in numClosestUsers if ($numClosestUsersToUse < 0) { $numClosestUsersToUse = $defaultNumClosestUsersToUse; } // Determine if we are test mode and an admin, if so, display the test mode data $isAdmin = kp_isUserAdmin(); if (!isset($testModeValue)) { $isTestMode = get_option("kp_AdminTestMode", "false") == "true" && $isAdmin; if ($isTestMode) { $testModeValue = "1"; } else { $testModeValue = "0"; } } // Reset the recommended posts $this->posts = array(); // Get the user's visit data if ($trackUserAgent) { $sql = "SELECT * FROM {$visitTbl} WHERE IP = %s AND UserAgent = %s"; $args = array($this->ipAddress, $this->userAgent); } else { $sql = "SELECT * FROM {$visitTbl} WHERE IP = %s"; $args = array($this->ipAddress); } $user = $wpdb->get_row($wpdb->prepare($sql, $args), OBJECT); $userVisits = unserialize($user->Visits); // Set up the closest number of users $closestUsers = array(); if ($trackUserAgent) { $sql = "\n\t\t\t\tSELECT * \n\t\t\t\tFROM {$visitTbl} \n\t\t\t\tWHERE \n\t\t\t\t\tTestData = %s AND \n\t\t\t\t\t(IP != %s OR UserAgent != %s) AND\n\t\t\t\t\t(UpdateDate > ADDDATE(NOW(), INTERVAL %d DAY) OR CreateDate > ADDDATE(NOW(), INTERVAL %d DAY))"; // Get the rest of the users within the past Max Update Date (ignore test mode data) $args = array($testModeValue, $this->ipAddress, $this->userAgent, -1 * $maxPastUpdateDate, -1 * $maxPastUpdateDate); } else { $sql = "\n\t\t\t\tSELECT * \n\t\t\t\tFROM {$visitTbl} \n\t\t\t\tWHERE \n\t\t\t\t\tTestData = %s AND \n\t\t\t\t\t(IP != %s) AND\n\t\t\t\t\t(UpdateDate > ADDDATE(NOW(), INTERVAL %d DAY) OR CreateDate > ADDDATE(NOW(), INTERVAL %d DAY))"; // Get the rest of the users within the past Max Update Date (ignore test mode data) $args = array($testModeValue, $this->ipAddress, -1 * $maxPastUpdateDate, -1 * $maxPastUpdateDate); } $otherUsers = $wpdb->get_results($wpdb->prepare($sql, $args), OBJECT); foreach ($otherUsers as $otherUser) { // Get the distance between the user and the other users $dist = $this->getDistance($userVisits, unserialize($otherUser->Visits)); if (count($closestUsers) < $numClosestUsersToUse) { array_push($closestUsers, array($otherUser->Visits, $dist)); } else { // Find the max dist and replace it $maxDist = -1; $maxInd = 0; $i = 0; foreach ($closestUsers as $tempUser) { if ($tempUser[1] > $maxDist && $tempUser[1] > $dist) { $maxDist = $tempUser[1]; $maxInd = $i; } $i = i + 1; } // Unset that array element and push our new close user if ($maxDist != -1) { unset($closestUsers[$maxInd]); $closestUsers[$maxInd] = array($otherUser->Visits, $dist); } } } if (count($closestUsers) > 0) { // Get the top visit posts from the $closestUsers $visitCounts = array(); // will contain {1=>5, 2=>3, 5=>150, post_id=>total visit number} foreach ($closestUsers as $key => $user) { $user[0] = unserialize($user[0]); foreach ($user[0] as $id => $visitCount) { if (!isset($visitCounts[$id])) { $visitCounts[$id] = 0; } $visitCounts[$id] += $visitCount; } } // Sort the final array by the counts arsort($visitCounts); // Build the criteria for the post types to recommend $preparedPostTypes = ""; $preparedPostTypesArray = array(); $preparedPostTypeCriteria = ""; if (count($recommendablePostTypes) > 0) { foreach ($recommendablePostTypes as $postType) { if ($preparedPostTypes != "") { $preparedPostTypes = $preparedPostTypes . ", "; } $preparedPostTypes = $preparedPostTypes . "%s"; $preparedPostTypesArray[] = $postType; } $preparedPostTypeCriteria = " post_type IN (" . $preparedPostTypes . ") AND"; } // Get a list of posts that we can recommend $recommendablePosts = array(); $posts = $wpdb->get_results($wpdb->prepare("SELECT * FROM {$wpdb->posts} WHERE {$preparedPostTypeCriteria} post_status = 'publish' AND post_parent = '0'", $preparedPostTypesArray), OBJECT); foreach ($posts as $post) { $recommendablePosts[$post->ID] = true; } // Remove certain posts if we aren't in test mode if (!$isTestMode) { // Remove the current post if (isset($recommendablePosts[$curr_post_id])) { unset($recommendablePosts[$curr_post_id]); } // Remove posts that the user has already visited if ($userVisits != null && count($userVisits) > 0) { foreach ($userVisits as $postId => $numVisits) { if (isset($recommendablePosts[$postId])) { unset($recommendablePosts[$postId]); } } } } // Recommend posts from the final list $i = 0; foreach ($visitCounts as $id => $visitCount) { // Check that the post isn't in the Ignore list and that we currently aren't on the post // If we are in test mode, we may recommend the current post if ($i < $numPostsToRecommend && $id != "" && isset($recommendablePosts[$id])) { array_push($this->posts, new kp_recommendedPost($id)); $i = $i + 1; } } } else { // Need to do something } return null; }
/** * Generates the widget html on the page * * @param Array $args: The widget arguments * @param Array $instance: Settings related to this instance of the Widget * @param boolean $outputWidgetHtml: Indicates if we should output the widget Html right away * @param string $template: The template to use to render the widget * @param Array $data: Data to use to render the widget * @param Array $recommendedPosts: An array of posts to display (if none, run the recommender) * @param string $ip: The IP Address of the user rendering the widget * @param string $ua: The User Agent of the user rendering the widget * @param bool $testModeValue: Indicates if we are in test mode and what value to look for * @return string: The Html for the widget **/ public function widget($args, $instance, $outputWidgetHtml = true, $template = "", $data = array(), $recommendedPosts = array(), $ip = "", $ua = "", $testModeValue = null) { global $defaultNumPostsToRecommend, $kp_templates, $kp_defaultAlignment; // If we are in test mode and if the user isn't an admin, don't show the widget if (get_option("kp_AdminTestMode", "false") == "true" && !kp_isUserAdmin()) { return array("widgetHtml" => "", "recommender" => null); } // Check if some of the widget arguments have been passed, if not, fix them // so we don't run into any problems rendering the template if (!isset($args["before_widget"])) { $args["before_widget"] = ""; } if (!isset($args["after_widget"])) { $args["after_widget"] = ""; } if (!isset($args["before_title"])) { $args["before_title"] = ""; } if (!isset($args["after_title"])) { $args["after_title"] = ""; } if (!isset($instance["title"])) { $instance["title"] = ""; } if (!isset($instance["featureimage"])) { $instance["featureimage"] = false; } if (!isset($instance["posttitle"])) { $instance["posttitle"] = false; } if (!isset($instance["postauthor"])) { $instance["postauthor"] = false; } if (!isset($instance["postdate"])) { $instance["postdate"] = false; } if (!isset($instance["postteaser"])) { $instance["postteaser"] = false; } // Get the template we are going to render if ($template == "" && isset($kp_templates["kp_widget"])) { $template = $kp_templates["kp_widget"]; } // Check if the user has set the number of posts to recommend if (!isset($instance["numposts"]) || !is_int((int) $instance["numposts"])) { $numPostsToRecommend = $defaultNumPostsToRecommend; } else { $numPostsToRecommend = (int) $instance["numposts"]; } // Get the different types of posts that we should recommend $recommendablePostTypes = array(); $potentialRecommendablePostTypes = array(); // Store this in case we run into no post types being set (default to everything) $postTypes = kp_getRecommendablePostTypes(); foreach ($postTypes as $postType) { $potentialRecommendablePostTypes[] = $postType; // Recommend the Post Type if it is set to true within the Widget if (isset($instance["posttypes-" . $postType]) && (string) $instance["posttypes-" . $postType] == "1") { $recommendablePostTypes[] = $postType; } } // If we aren't recommending any type, default to all using $potentialRecommendablePostTypes if (count($recommendablePostTypes) == 0) { $recommendablePostTypes = $potentialRecommendablePostTypes; } $widgetTitle = apply_filters("widget_title", $instance["title"]); // Start data for this specific widget $alignment = $kp_defaultAlignment; if ($instance["alignment"] == "left") { $alignment = "left"; } else { if ($instance["alignment"] == "right") { $alignment = "right"; } else { if ($instance["alignment"] == "center") { $alignment = "center"; } } } $post_style = "padding-top:10px;padding-bottom:10px;"; $postimage_style = ""; $posttitle_style = ""; $postauthor_style = ""; $postdate_style = ""; $postteaser_style = ""; return kp_renderWidget($numPostsToRecommend, $recommendedPosts, $template, $ip, $ua, $outputWidgetHtml, $widgetTitle, $post_style, $postimage_style, $posttitle_style, $postauthor_style, $postdate_style, $postteaser_style, $args["before_widget"], $args["after_widget"], $args["before_title"], $args["after_title"], $alignment, $instance["featureimage"], $instance["posttitle"], $instance["postauthor"], $instance["postdate"], $instance["postteaser"], $recommendablePostTypes, $trackingCode, $testModeValue); }