Notice: Undefined property: stdClass::$data in /home/customer/www/resultswebsitedesign.com/public_html/wp-content/plugins/insert-php-code-snippet/shortcode-handler.php(65) : eval()'d code on line 82

Warning: Invalid argument supplied for foreach() in /home/customer/www/resultswebsitedesign.com/public_html/wp-content/plugins/insert-php-code-snippet/shortcode-handler.php(65) : eval()'d code on line 91

Warning: fopen(/home/result63/public_html/schaplin/twitch/arrays.js): failed to open stream: No such file or directory in /home/customer/www/resultswebsitedesign.com/public_html/wp-content/plugins/insert-php-code-snippet/shortcode-handler.php(65) : eval()'d code on line 123

Warning: fwrite() expects parameter 1 to be resource, boolean given in /home/customer/www/resultswebsitedesign.com/public_html/wp-content/plugins/insert-php-code-snippet/shortcode-handler.php(65) : eval()'d code on line 125

Warning: fclose() expects parameter 1 to be resource, boolean given in /home/customer/www/resultswebsitedesign.com/public_html/wp-content/plugins/insert-php-code-snippet/shortcode-handler.php(65) : eval()'d code on line 126
Results Website Design's company banner with logo showing increased sales.
Results Website Design's company banner with logo showing increased sales.

Twitch Live Stream Status

PHP - get token, user and stream arrays, write sorted users to js file
<?php 
$ch=curl_init();
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 2);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$token = getToken($ch);
$headers = ['Content-type: application/json','Authorization: Bearer '.$token];
$logins = ["freecodecamp","ninja", "summit1g", "alanzoka", "riotgames", "syndicate", "esl_csgo", "easportsfifa", "shroud", "imaqtpie", "nightblue3", "drdisrespectlive", "lirik", "tsm_myth", "playhearthstone", "timthetatman", "overwatchleague", "rocketleague"];
$usersInfoJSON = getInfo($ch, $headers, $logins);
//makes use of same headers as above function call
$streamsJSON = getStreams($ch, $logins);

#get access token - had to be post request
function getToken($ch)
{
    curl_setopt($ch, CURLOPT_URL, 'https://id.twitch.tv/oauth2/token?client_id=XXXX&client_secret=YYYY&grant_type=client_credentials');
    curl_setopt($ch, CURLOPT_POST, true);
    //$result is a string
    $result = curl_exec($ch);
    if (curl_errno($ch) > 0) {
        $result = retry($ch);
    }
    //convert string to JSON
    $resJSON = json_decode($result);
    //the token itself - a string
    return $resJSON->access_token;
}

#retry if there's an error connecting
function retry($ch)
{
    $retry =0;
    while (curl_errno($ch) > 0 && $retry < 3) {
        $result = curl_exec($ch);
        $retry++;
    }
    return $result;
}

#send access token to API to get basic user info - had to be get request
function getInfo($ch, $headers, $logins)
{
    $url = "https://api.twitch.tv/helix/users?";
    //build url parameters
    foreach ($logins as $login) {
        $url= $url."login=".$login."&";
    }
    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_POST, false);
    //$usersInfo is a string
    $usersInfo = curl_exec($ch);
    //retry if there's an error connecting
    if (curl_errno($ch) > 0) {
        $usersInfo = retry($ch);
    }
    //convert string to JSON
    return json_decode($usersInfo);
}

#send access token to API to get user streams info - had to be get request
function getStreams($ch, $logins)
{
    $streamsUrl = "https://api.twitch.tv/helix/streams?";
    //build url parameters
    foreach ($logins as $login) {
        $streamsUrl= $streamsUrl."user_login=".$login."&";
    }
    curl_setopt($ch, CURLOPT_URL, $streamsUrl);
    //$streams is a string
    $streams = curl_exec($ch);
    //retry if there's an error connecting
    if (curl_errno($ch) > 0) {
        $streams = retry($ch);
    }
    curl_close($ch);
    //convert $streams to JSON
    return json_decode($streams);
}

#setup array variables
//array of streams
$streamsArr =$streamsJSON->data;
//array of all users
$usersArr = $usersInfoJSON->data;
$onlineUsers = [];
$offlineUsers = [];

#sort users into online and offline arrays
$length = count($streamsArr);
//cycle through each user
foreach ($usersArr as $user) {
    $userID = $user->id;

    $i=0;
    //cycle through each stream
    foreach ($streamsArr as $stream) {
        $liveID = $stream->user_id;
        //if streaming, add user to online array
        if ($liveID === $userID) {
            //add stream title to user array
            $title = $stream->title;
            $user->title = $title;
            array_push($onlineUsers, $user);
            break;
        }
        //if not streaming, add user to offline array
        if ($i===$length-1) {
            array_push($offlineUsers, $user);
        }
        $i++;
    }
}
unset($user);

#write arrays to JS file
//convert arrays to JSON formatted string, with prefix for JS variable assignment
$onlineStr = "let online = ".json_encode($onlineUsers).";";
$offlineStr = "let offline = ".json_encode($offlineUsers).";";
$combinedStr = $onlineStr.$offlineStr;
//place to save JS file
$filename = "/home/result63/public_html/schaplin/twitch/arrays.js";
$handle =  fopen($filename, "wb");
//save JavaScript file - overwrite old file if it exists
$numBytes = fwrite($handle, $combinedStr);
fclose($handle);
HTML - most of the html is generated dynamically by js
<section class="twitch-section">
  <h2 class="top-twitch">Twitch Live Stream Status</h2>
  <div class="results-wrap">
  </div>
</section>
<script src="https://resultswebsitedesign.com/schaplin/twitch/arrays.js"></script>
JavaScript - populate page with user info, add classes for icon animation
  (function ($) {

    let offlinePng = "https://resultswebsitedesign.com/wp-content/uploads/2018/04/offline.png";
    let onlinePng = "https://resultswebsitedesign.com/wp-content/uploads/2018/04/on.png";

    populate(online, onlinePng);
    populate(offline, offlinePng);

    function populate(group, iconSrc) {
      //iterate over array of objects
      group.forEach((item, index) => {
        let name = item.display_name;
        //display stream title if online
        let title = iconSrc === onlinePng ? item.title : "";
        let avatarSrc = item.profile_image_url;
        let link = "https://www.twitch.tv/" + item.login;
        let $result = $('<a class ="result-link" target="_blank" href="' + link +
          '"><div class="result-block"><div class="name-contain"><h3 class="result-name">' + name +
          '</h3> <div class="wifi-wrap"><img class="twitch-wifi" src="' + iconSrc +
          '"></div></div><img class="player-logo" src="' +
          avatarSrc + '"><p class="result-snippet">' + title + '</p></div></a>');
        //add notice if offline
        if (iconSrc === offlinePng) {
          $result.find(".result-block").prepend(
            '<p class="notice transparent">I may be playing a rerun or hosting another player.</p>');
        }
        //don't display newly created element until ready to fade in
        $result.css('display', 'none');
        $('.results-wrap').append($result);
        //fade in newly created element
        $result.fadeIn();
      });
    }

    //animate online & offline icons on block hover
    $('.result-link').hover(function () {
      let $image = $(this).find('.twitch-wifi');
      let src = $image.attr('src');
      let $contain = $image.parent();
      let gif = 'https://resultswebsitedesign.com/wp-content/uploads/2018/04/on2.gif';
      //online
      if (src === onlinePng) $image.attr("src", gif);
      else if (src === gif) $image.attr("src", onlinePng);
      //offline
      else if (src === offlinePng) {
        $contain.toggleClass('bounce');
        $(this).find('.notice').toggleClass('transparent opaque');
      };
    });

    //only display widget containing PHP in content mgr
    let loc = window.location.href.toLowerCase();
    if (loc.indexOf('elementor') === -1) {
      $('.elementor-element-d0fa9c0').css('display', 'none');
    }

  })(jQuery);
CSS - responsive layout with flexbox
 .twitch-section {
    background: rgba(255, 255, 255, .8);
    border-radius: 13px;
    margin-top: 27px;
  }
  .results-wrap {
    padding: 16px 30px 30px;
    display: flex;
    flex-wrap: wrap;
    justify-content: space-around;
  }
  .top-twitch {
    text-align: center;
    padding-top: 18px;
    text-decoration: underline;
  }
  .result-link {
    max-width: 300px;
    width: 100%;
  }
  .result-block {
    padding: 0 5px;
    position: relative;
  }
  .notice {
    position: absolute;
    background: rgba(255, 255, 255, .8);
    margin: 0;
    left: 50%;
    transform: translateX(-50%);
    bottom: 5px;
    line-height: 1.5;
    text-align: center;
    border-radius: 11px;
    padding: 6px;
    width: 90%;
  }
  .transparent {
    opacity: 0;
    transition: opacity .7s;
  }
  .opaque {
    opacity: 1;
    transition: opacity .7s;
  }
  #content .top-twitch,
  #content .results-wrap h3,
  #content .results-wrap p {
    font-family: Montserrat, "Helvetica Neue", sans-serif;
  }
  #content .results-wrap h3 {
    font-size: 21px;
  }
  #content .results-wrap p {
    font-size: 14px;
    margin-top: 1px;
  }
  .name-contain {
    display: flex;
    justify-content: center;
  }
  .result-name {
    text-transform: lowercase;
  }
  .result-snippet {
    line-height: 1.2;
    text-align: center;
  }
  .wifi-wrap {
    height: 29px;
    position: relative;
    top: 3px;
    margin-left: 9px;
  }
  .twitch-wifi {
    width: 29px;
  }
  /*!
 * animate.css -http://daneden.me/animate
 * Version - 3.6.0
 * Licensed under the MIT license - http://opensource.org/licenses/MIT
 *
 * Copyright (c) 2018 Daniel Eden
 */
 
/*for 'offline' icon */
  .bounce {
    -webkit-animation-duration: 1s;
    animation-duration: 1s;
    -webkit-animation-fill-mode: both;
    animation-fill-mode: both;
    -webkit-animation-name: bounce;
    animation-name: bounce;
    -webkit-transform-origin: center bottom;
    transform-origin: center bottom;
  }
  @-webkit-keyframes bounce {
    from,
    20%,
    53%,
    80%,
    to {
      -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
      animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
      -webkit-transform: translate3d(0, 0, 0);
      transform: translate3d(0, 0, 0);
    }
    40%,
    43% {
      -webkit-animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
      animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
      -webkit-transform: translate3d(0, -3px, 0);
      transform: translate3d(0, -3px, 0);
    }
    70% {
      -webkit-animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
      animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
      -webkit-transform: translate3d(0, -2px, 0);
      transform: translate3d(0, -2px, 0);
    }
    90% {
      -webkit-transform: translate3d(0, -1px, 0);
      transform: translate3d(0, -1px, 0);
    }
  }
  @keyframes bounce {
    from,
    20%,
    53%,
    80%,
    to {
      -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
      animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
      -webkit-transform: translate3d(0, 0, 0);
      transform: translate3d(0, 0, 0);
    }
    40%,
    43% {
      -webkit-animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
      animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
      -webkit-transform: translate3d(0, -3px, 0);
      transform: translate3d(0, -3px, 0);
    }
    70% {
      -webkit-animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
      animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
      -webkit-transform: translate3d(0, -2px, 0);
      transform: translate3d(0, -2px, 0);
    }
    90% {
      -webkit-transform: translate3d(0, -1px, 0);
      transform: translate3d(0, -1px, 0);
    }
  }