steam_array, 'fetched_at' => timestamp] or null function AdvancedSteamWidget_get_cache($id) { $val = get_transient(ADVANCED_STEAM_WIDGET_TRANSIENT_PREFIX . $id); return is_array($val) ? $val : null; } //write the cached payload with a fresh 30-day TTL //$fetched_at can be preserved from an earlier fetch when extending a stale cache function AdvancedSteamWidget_set_cache($id, $data, $fetched_at = null) { set_transient(ADVANCED_STEAM_WIDGET_TRANSIENT_PREFIX . $id, array( 'data' => $data, 'fetched_at' => $fetched_at ?: time(), ), ADVANCED_STEAM_WIDGET_CACHE_TTL); } //drop the cached payload for a widget instance function AdvancedSteamWidget_delete_cache($id) { delete_transient(ADVANCED_STEAM_WIDGET_TRANSIENT_PREFIX . $id); } //normalizes user input into a canonical scheme-less steamcommunity.com URL //returns '' if input can't be parsed into a recognized format //accepted inputs: profiles/ URL, id/ URL, bare 17-digit id, bare vanity slug, STEAM_0:X:Y function AdvancedSteamWidget_normalize_profile_input($raw) { $raw = trim((string)$raw); if ($raw === '') $raw = 'slserpent'; //STEAM_0:X:Y legacy format - convert to SteamID64 via the standard formula if (preg_match('/^(?:STEAM_)?\d+:(\d+):(\d+)$/i', $raw, $m)) { $id64 = ($m[2] * 2) + 0x0110000100000000 + $m[1]; return 'steamcommunity.com/profiles/' . $id64; } //full profiles/ URL - extract the 17-digit id (using hash instead of slash as regex delimiters for URL compatibility) if (preg_match('#steamcommunity\.com/profiles/(\d{17})#i', $raw, $m)) { return 'steamcommunity.com/profiles/' . $m[1]; } //full id/ URL - extract the vanity slug. Steam allows 3-32 chars of letters, digits, underscore, hyphen if (preg_match('#steamcommunity\.com/id/([A-Za-z0-9_-]{2,32})#i', $raw, $m)) { return 'steamcommunity.com/id/' . $m[1]; } //bare 17-digit number - treat as SteamID64 if (preg_match('/^\d{17}$/', $raw)) { return 'steamcommunity.com/profiles/' . $raw; } //bare vanity slug final case if (preg_match('/^[A-Za-z0-9_-]+$/', $raw)) { return 'steamcommunity.com/id/' . $raw; } return ''; } //fetches steam profile XML and returns parsed steam_array //throws Exception on any failure (transport, HTTP status, parse, privacy) //$profile_url is the canonical scheme-less profile URL produced by AdvancedSteamWidget_normalize_profile_input() function AdvancedSteamWidget_fetch($profile_url) { //fall back to plugin author's profile if none supplied if (empty($profile_url)) $profile_url = 'steamcommunity.com/id/slserpent'; //canonical form is scheme-less; add https for the actual request $profile_url = 'https://' . ltrim($profile_url, '/'); $xml_url = $profile_url . '?xml=1'; //fetch profile XML via WP HTTP API (picks curl or streams transport internally) $response = wp_remote_get($xml_url, array( 'timeout' => 20, 'redirection' => 2, 'sslverify' => true, 'user-agent' => 'AdvancedSteamWidget/2.0; ' . home_url(), )); //WP_Error means transport-level failure (DNS, timeout, TLS, etc.) if (is_wp_error($response)) throw new Exception("Error downloading XML data: " . $response->get_error_message()); //non-2xx counts as failure - profile removed, rate limit, outage, etc. $code = wp_remote_retrieve_response_code($response); if ($code < 200 || $code >= 300) throw new Exception("Error downloading XML data. HTTP status: " . $code); //parse XML body; LIBXML_NONET blocks any external-entity network fetches as defense against future libxml default changes if (($steam_xml = @simplexml_load_string(wp_remote_retrieve_body($response), null, LIBXML_NONET)) === false) throw new Exception("Error loading XML data. Possibly malformed."); //check for any profile-level errors in the XML provided by steam if (isset($steam_xml->error)) throw new Exception("XML Error: " . (string)$steam_xml->error); //check for profile privacy set to public. only username is available otherwise, which isn't very useful for this plugin if ((string)$steam_xml->privacyState != "public") throw new Exception("Profile is not public."); //parse out some values so they're easier to store / use $steam_array = array(); $steam_array['username'] = (string)$steam_xml->steamID; $steam_array['ID64'] = (string)$steam_xml->steamID64; $steam_array['profile_url'] = $profile_url; $steam_array['avatar']['icon'] = (string)$steam_xml->avatarIcon; $steam_array['avatar']['medium'] = (string)$steam_xml->avatarMedium; $steam_array['avatar']['large'] = (string)$steam_xml->avatarFull; $steam_array['hours_twoweeks'] = (string)$steam_xml->hoursPlayed2Wk; if ($steam_xml->onlineState == "in-game") { //game name is now embedded in stateMessage as "In-Game
Game Name" (inGameInfo element was removed) $steam_array['ingame'] = preg_match('#^In-Game
(.*)$#', (string)$steam_xml->stateMessage, $m) ? trim($m[1]) : true; } else $steam_array['ingame'] = false; if ($steam_xml->onlineState == "online") { $steam_array['online'] = true; } else $steam_array['online'] = false; if (isset($steam_xml->mostPlayedGames->mostPlayedGame) && count($steam_xml->mostPlayedGames->mostPlayedGame) > 0) { //workaround for steam no 2 wks played bug $cumulative_hours_from_games = false; if ($steam_array['hours_twoweeks'] == "0.0") { $steam_array['hours_twoweeks'] = 0; $cumulative_hours_from_games = true; } $k = 0; foreach ($steam_xml->mostPlayedGames->mostPlayedGame as $game) { if (strlen($game->gameName) < 1) continue; $steam_array['games'][$k]['name'] = (string)$game->gameName; $steam_array['games'][$k]['url'] = (string)$game->gameLink; $steam_array['games'][$k]['icon'] = (string)$game->gameIcon; $steam_array['games'][$k]['logo']['small'] = (string)$game->gameLogoSmall; $steam_array['games'][$k]['logo']['large'] = (string)$game->gameLogo; $steam_array['games'][$k]['hours_total'] = (string)$game->hoursOnRecord; $steam_array['games'][$k]['hours_twoweeks'] = (string)round((float)$game->hoursPlayed, 1); //cleans up trailing .0 if ($steam_array['ingame'] && $steam_array['ingame'] == $steam_array['games'][$k]['name']) { $steam_array['games'][$k]['ingame'] = true; } else $steam_array['games'][$k]['ingame'] = false; //see if stats name exists and is valid, i.e. not just the (alphabetical) app id if (isset($game->statsName) && preg_match('/^\d+$/', $game->statsName)) { $steam_array['games'][$k]['stats_url'] = $profile_url . "/stats/" . (string)$game->statsName; } else $steam_array['games'][$k]['stats_url'] = false; if ($cumulative_hours_from_games === true) { $steam_array['hours_twoweeks'] += (float)$game->hoursPlayed; } $k++; } } return $steam_array; }