0

I have this HTML code that haven't been able to display in a post or page.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta charset="utf-8">
    <title>Stocks!</title>
    <link rel="icon" href="https://d3v3cbxkdlyonc.cloudfront.net/stocks/favicon.ico">
    <link rel="apple-touch-icon" href="https://d3v3cbxkdlyonc.cloudfront.net/stocks/apple-touch-icon.png">
    <meta name="description" content="A free, lightweight, blazing-fast page to get stock quotes using the IEX API">

    <style>
      body {
        font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto",
          "Oxygen", "Ubuntu", "Helvetica Neue", Arial, sans-serif;
      }
      table { font-family: Courier, monospace; }
      .stocks-container {
        margin-bottom: 1.5em;
        width: 100%;
        max-width: 600px;
      }
      .stocks-container a { text-decoration: none; }
      table {
        border-collapse: collapse;
        width: 100%;
        font-size: 1.1em;
      }
      .stock-symbol {
        width: 12%;
        padding: 2px 4px 2px 0px;
      }
      .stock-price, .stock-change, .stock-change-pct, .stock-mkt-cap {
        width: 22%;
        text-align: right;
        padding: 2px 4px;
      }
      @media (max-width: 576px) {
        table { margin-bottom: 3em; }
        .stock-mkt-cap { display: none; }
        .stock-symbol { width: 16%; }
        .stock-price, .stock-change, .stock-change-pct { width: 28%; }
        td.stock-symbol, td.stock-price, td.stock-change, td.stock-change-pct {
          padding-top: 1em;
          padding-bottom: 1em;
        }
      }
      summary:hover { cursor: pointer; }
      summary::-webkit-details-marker { display: none; }
    </style>
  </head>

  <body>
    <div class="stocks-container"></div>

    <p class="attribution">
      Data provided for free by <a href="https://iextrading.com/developer/" target="_blank">IEX</a>.
      Subject to <a href="https://iextrading.com/api-exhibit-a/" target="_blank">IEX Exhibit A</a>.
    </p>

    <p class="updated-timestamp"></p>

    <p>Customize <a href="https://github.com/toddwschneider/stocks" target="_blank">on GitHub</a></p>

    <script>
      'use strict';

      const DEFAULT_PORTFOLIOS = [
        {'name': 'Market ETFs', 'symbols': ['SPY', 'DIA', 'QQQ', 'IWM']},
        {'name': 'Sector ETFs', 'symbols': ['XLF', 'XLK', 'XLC', 'XLV', 'XLP', 'XLY', 'XLE', 'XLB', 'XLI', 'XLU', 'XLRE']},
        {'name': 'Banks', 'symbols': ['GS', 'MS', 'JPM', 'WFC', 'C', 'BAC']},
        {'name': 'Tech', 'symbols': ['AAPL', 'MSFT', 'AMZN', 'GOOGL', 'FB', 'TWTR', 'NFLX', 'SNAP', 'PINS', 'ABNB', 'UBER', 'LYFT', 'DASH', 'SPOT', 'SQ', 'PTON', 'HOOD', 'NVDA', 'INTC']},
        {'name': 'Cryptos', 'symbols': ['BTCUSDT', 'ETHUSDT']},
        {'name': 'Other ETFs', 'symbols': ['VOO', 'VTI', 'VXUS', 'VGK', 'VPL', 'VWO', 'BND', 'IEF', 'TLT', 'HYG']},
        {'name': 'Other', 'symbols': ['XOM', 'WMT', 'JNJ', 'BA', 'T', 'DIS', 'MCD', 'PG', 'TSLA']}
      ];

      // register for a token at https://iexcloud.io/
      const API_TOKEN = 'pk_c90e450576474695aae80e04b06050cb';

      if (API_TOKEN === 'YOUR_TOKEN_HERE') {
        alert('You need to register for a token at https://iexcloud.io/');
      }

      const PORTFOLIOS = portfoliosFromQueryParams() || DEFAULT_PORTFOLIOS;
      const REFRESH_SECONDS = 10;
      const BATCH_SIZE = 100;
      const BASE_URL = 'https://cloud.iexapis.com/stable/stock/market/batch';
      const FAVICON_SYMBOL = 'SPY';
      const FAVICON_BASE_URL = 'https://d3v3cbxkdlyonc.cloudfront.net/stocks';

      let symbols = [FAVICON_SYMBOL];
      let containerDiv = document.querySelector('.stocks-container');
      let updatedDiv = document.querySelector('.updated-timestamp');

      PORTFOLIOS.forEach((p, i) => addPortfolio(p, i === 0));
      symbols = symbols.filter((s, i) => symbols.indexOf(s) === i);
      updateData('addTitle');
      setInterval(updateData, REFRESH_SECONDS * 1000);

      function addPortfolio(portfolio, includeHeader) {
        let tableHeaderHtml = '';
        if (includeHeader) {
          tableHeaderHtml = `
            <thead>
              <tr>
                <th></th>
                <th class="stock-price">Last</th>
                <th class="stock-change">Change</th>
                <th class="stock-change-pct">Change%</th>
                <th class="stock-mkt-cap">Mkt Cap</th>
              </tr>
            </thead>
          `
        }

        let tableBodyHtml = portfolio.symbols.map(symbol => {
          symbol = symbol.toUpperCase();
          symbols.push(symbol);

          let html = `
            <tr data-symbol="${symbol}">
              <td class="stock-symbol"><a href="${symbolUrl(symbol)}" target="_blank">${symbol}</a></td>
              <td class="stock-price"></td>
              <td class="stock-change"></td>
              <td class="stock-change-pct"></td>
              <td class="stock-mkt-cap"></td>
            </tr>
          `

          return html;
        }).join('');

        let portfolioDiv = document.createElement('div');

        portfolioDiv.innerHTML = `
          <details open>
            <summary><h2>${portfolio.name}</h2></summary>
            <table>${tableHeaderHtml}<tbody>${tableBodyHtml}</tbody></table>
          </details>
        `;

        containerDiv.appendChild(portfolioDiv);
      }

      function updateData(addTitle) {
        let numberOfBatches = Math.ceil(symbols.length / BATCH_SIZE);

        for (let i = 0; i < numberOfBatches; i++) {
          let symbolsBatch = symbols.slice(i * BATCH_SIZE, (i + 1) * BATCH_SIZE);
          updateDataForBatch(symbolsBatch, addTitle);
        }

        updatedDiv.innerHTML = `Data updated at ${(new Date()).toLocaleString()}`;
      }

      function updateDataForBatch(symbols, addTitle) {
        let filters = ['latestPrice', 'change', 'changePercent', 'marketCap'];
        if (addTitle) filters.push('companyName');
        let url = `${BASE_URL}?types=quote&symbols=${symbols.join(',')}&filter=${filters.join(',')}&token=${API_TOKEN}`;

        fetch(url).then(response => response.json()).then(json => {
          symbols.forEach(symbol => {
            let data = json[symbol];
            if (typeof(data) === 'undefined' || !data.quote.latestPrice) return;

            let formattedPrice = formatQuote(Number(data.quote.latestPrice));
            let formattedChange = formatChange(data.quote.change);
            let formattedChangePercent = formatChangePercent(data.quote.changePercent);
            let formattedMarketCap = formatMarketCap(data.quote.marketCap);
            let bgColorStyle = calculateBgColorStyle(data.quote.changePercent)

            document.querySelectorAll(`[data-symbol="${symbol}"] .stock-price`).forEach(e => {
              e.innerHTML = formattedPrice;
              e.setAttribute('style', bgColorStyle);
            });

            document.querySelectorAll(`[data-symbol="${symbol}"] .stock-change`).forEach(e => {
              e.innerHTML = formattedChange;
              e.setAttribute('style', bgColorStyle);
            });

            document.querySelectorAll(`[data-symbol="${symbol}"] .stock-change-pct`).forEach(e => {
              e.innerHTML = formattedChangePercent;
              e.setAttribute('style', bgColorStyle);
            });

            document.querySelectorAll(`[data-symbol="${symbol}"] .stock-mkt-cap`).forEach(e => {
              e.innerHTML = formattedMarketCap;
              e.setAttribute('style', bgColorStyle);
            });

            if (addTitle) {
              document.querySelectorAll(`[data-symbol="${symbol}"] .stock-symbol a`).forEach(e => {
                e.setAttribute('title', data.quote.companyName);
              });
            }

            if (symbol === FAVICON_SYMBOL) {
              updateFavicon(data.quote);
            }
          });
        });
      }

      function portfoliosFromQueryParams() {
        if (!window.location.search) return;

        let params = new URLSearchParams(window.location.search);
        let portfolios = [];

        for (let p of params) {
          portfolios.push({'name': p[0], 'symbols': p[1].split(',')});
        }

        return portfolios;
      }

      function symbolUrl(symbol) {
        return `https://finance.yahoo.com/quote/${symbol}`;
      }

      function formatChange(value) {
        if (value === null || value === undefined) return '';
        return value.toLocaleString('en', {'minimumFractionDigits': 2});
      }

      function formatChangePercent(value) {
        if (value === null || value === undefined) return '';
        return (value * 100).toFixed(1) + '%';
      }

      function formatQuote(value) {
        let options = {
          'minimumFractionDigits': 2,
          'style': 'currency',
          'currency': 'USD'
        };
        return value.toLocaleString('en', options);
      }

      function formatMarketCap(marketCap) {
        if (marketCap === null || marketCap === 0 || marketCap === undefined) return '';

        let value, suffix;
        if (marketCap >= 1e12) {
          value = marketCap / 1e12;
          suffix = 'T';
        } else if (marketCap >= 1e9) {
          value = marketCap / 1e9;
          suffix = 'B';
        } else {
          value = marketCap / 1e6;
          suffix = 'M';
        }

        let digits = value < 10 ? 1 : 0;

        return '$' + value.toFixed(digits) + suffix;
      }

      function calculateBgColorStyle(changePercent) {
        if (changePercent === undefined) return '';

        let rgbColor = changePercent > 0 ? '0,255,0' : '255,0,0';
        let rgbOpacity = Math.min(Math.abs(changePercent) * 20, 1);

        return `background-color: rgba(${rgbColor}, ${rgbOpacity})`;
      }

      function updateFavicon(quote) {
        let favicon = document.querySelector('link[rel="icon"]');
        let path = quote.change < 0 ? 'favicon_down.ico' : 'favicon.ico';
        let href = `${FAVICON_BASE_URL}/${path}`;

        if (favicon.getAttribute('href') !== href) {
          favicon.setAttribute('href', href);
        }
      }
    </script>
  </body>
</html>

When I paste in the Wordpress HMTL plugin (widget), I don't see the values expected like in this URL like in this example https://toddwschneider.com/stocks/ it's working locally but not in wordpress. enter image description here

This is what WP is displaying with no errors. enter image description here

1 Answer 1

3

WordPress doesn't allow you to paste in a full HTML page, as you're trying to do. In addition to the nested <html> tag, WP typically prevents JavaScript pasted into the editor from running because it could cause security risks or unknown conflicts.

You could create a child theme, which will allow you to set up your entire HTML page almost as you've done here. You'll just create it as a page template, something along the lines of tpl-stocks.php. However, within that child theme you'll also need to enqueue your JavaScript. You can also enqueue your CSS as a separate stylesheet, and make sure the stylesheet and JS are only enqueued on that particular template and not throughout the rest of the theme.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.