wp/wp-content/plugins/include-mastodon-feed/plugin.php
changeset 23 417f20492bf7
parent 21 48c4eec2b7e6
equal deleted inserted replaced
22:8c2e4d02f4ef 23:417f20492bf7
     1 <?php
     1 <?php
     2 /*
     2 /*
     3   Plugin Name: Include Mastodon Feed
     3   Plugin Name: Include Mastodon Feed
     4 	Plugin URI: https://wolfgang.lol/code/include-mastodon-feed-wordpress-plugin
     4 	Plugin URI: https://wolfgang.lol/code/include-mastodon-feed-wordpress-plugin
     5 	Description: Plugin providing [include-mastodon-feed] shortcode
     5 	Description: Plugin providing [include-mastodon-feed] shortcode
     6 	Version: 1.9.4
     6 	Version: 1.13.1
     7 	Author: wolfgang.lol
     7 	Author: wolfgang.lol
     8 	Author URI: https://wolfgang.lol
     8 	Author URI: https://wolfgang.lol
       
     9   License: MIT
       
    10   License URI: https://directory.fsf.org/wiki/License:Expat
     9 */
    11 */
    10 
    12 
    11 namespace IncludeMastodonFeedPlugin;
    13 namespace IncludeMastodonFeedPlugin;
    12 
    14 
    13 // set defaults
    15 // set defaults
    47   [
    49   [
    48     'key' => 'INCLUDE_MASTODON_FEED_PRESERVE_IMAGE_ASPECT_RATIO',
    50     'key' => 'INCLUDE_MASTODON_FEED_PRESERVE_IMAGE_ASPECT_RATIO',
    49     'value' => false,
    51     'value' => false,
    50   ],
    52   ],
    51   [
    53   [
       
    54     'key' => 'INCLUDE_MASTODON_FEED_IMAGE_SIZE',
       
    55     'value' => 'preview',
       
    56   ],
       
    57   [
       
    58     'key' => 'INCLUDE_MASTODON_FEED_IMAGE_LINK',
       
    59     'value' => 'status',
       
    60   ],
       
    61   [
    52     'key' => 'INCLUDE_MASTODON_FEED_TAGGED',
    62     'key' => 'INCLUDE_MASTODON_FEED_TAGGED',
    53     'value' => false,
    63     'value' => false,
    54   ],
    64   ],
    55   [
    65   [
    56     'key' => 'INCLUDE_MASTODON_FEED_LINKTARGET',
    66     'key' => 'INCLUDE_MASTODON_FEED_LINKTARGET',
    74     'key' => 'INCLUDE_MASTODON_FEED_STYLE_BG_DARK_COLOR',
    84     'key' => 'INCLUDE_MASTODON_FEED_STYLE_BG_DARK_COLOR',
    75     'value' => 'rgba(155, 155, 155, 0.15)',
    85     'value' => 'rgba(155, 155, 155, 0.15)',
    76   ],
    86   ],
    77   [
    87   [
    78     'key' => 'INCLUDE_MASTODON_FEED_STYLE_ACCENT_COLOR',
    88     'key' => 'INCLUDE_MASTODON_FEED_STYLE_ACCENT_COLOR',
    79     'value' => 'rgb(99, 100, 255)',
    89     'value' => 'rgb(86, 58, 204)',
    80   ],
    90   ],
    81   [
    91   [
    82     'key' => 'INCLUDE_MASTODON_FEED_STYLE_ACCENT_FONT_COLOR',
    92     'key' => 'INCLUDE_MASTODON_FEED_STYLE_ACCENT_FONT_COLOR',
    83     'value' => 'rgb(255, 255, 255)',
    93     'value' => 'rgb(255, 255, 255)',
    84   ],
    94   ],
    99     'key' => 'INCLUDE_MASTODON_FEED_TEXT_LOADING',
   109     'key' => 'INCLUDE_MASTODON_FEED_TEXT_LOADING',
   100     'value' => 'Loading Mastodon feed...',
   110     'value' => 'Loading Mastodon feed...',
   101   ],
   111   ],
   102   [
   112   [
   103     'key' => 'INCLUDE_MASTODON_FEED_TEXT_NO_STATUSES',
   113     'key' => 'INCLUDE_MASTODON_FEED_TEXT_NO_STATUSES',
   104     'value' => 'No statuses availablae',
   114     'value' => 'No statuses available',
   105   ],
   115   ],
   106   [
   116   [
   107     'key' => 'INCLUDE_MASTODON_FEED_TEXT_BOOSTED',
   117     'key' => 'INCLUDE_MASTODON_FEED_TEXT_BOOSTED',
   108     'value' => 'boosted 🚀',
   118     'value' => 'boosted 🚀',
   109   ],
   119   ],
   147   return '[include-mastodon-feed] ' . $msg;
   157   return '[include-mastodon-feed] ' . $msg;
   148 }
   158 }
   149 
   159 
   150 
   160 
   151 function init_styles() {
   161 function init_styles() {
   152   ob_start();
       
   153 ?>
   162 ?>
   154   <style>
   163   <style>
   155     :root {
   164     :root {
   156       --include-mastodon-feed-bg-light: <?php echo filter_var( INCLUDE_MASTODON_FEED_STYLE_BG_LIGHT_COLOR, FILTER_UNSAFE_RAW ); ?>;
   165       --include-mastodon-feed-bg-light: <?php echo filter_var( INCLUDE_MASTODON_FEED_STYLE_BG_LIGHT_COLOR, FILTER_UNSAFE_RAW ); ?>;
   157       --include-mastodon-feed-bg-dark: <?php echo filter_var( INCLUDE_MASTODON_FEED_STYLE_BG_DARK_COLOR, FILTER_UNSAFE_RAW ); ?>;
   166       --include-mastodon-feed-bg-dark: <?php echo filter_var( INCLUDE_MASTODON_FEED_STYLE_BG_DARK_COLOR, FILTER_UNSAFE_RAW ); ?>;
   158       --include-mastodon-feed-accent-color: <?php echo filter_var( INCLUDE_MASTODON_FEED_STYLE_ACCENT_COLOR, FILTER_UNSAFE_RAW ); ?>;
   167       --include-mastodon-feed-accent-color: <?php echo filter_var( INCLUDE_MASTODON_FEED_STYLE_ACCENT_COLOR, FILTER_UNSAFE_RAW ); ?>;
   159       --include-mastodon-feed-accent-font-color: <?php echo filter_var( INCLUDE_MASTODON_FEED_STYLE_ACCENT_FONT_COLOR, FILTER_UNSAFE_RAW ); ?>;
   168       --include-mastodon-feed-accent-font-color: <?php echo filter_var( INCLUDE_MASTODON_FEED_STYLE_ACCENT_FONT_COLOR, FILTER_UNSAFE_RAW ); ?>;
   160       --include-mastodon-feed-border-radius: <?php echo filter_var( INCLUDE_MASTODON_FEED_STYLE_BORDER_RADIUS, FILTER_UNSAFE_RAW ); ?>;
   169       --include-mastodon-feed-border-radius: <?php echo filter_var( INCLUDE_MASTODON_FEED_STYLE_BORDER_RADIUS, FILTER_UNSAFE_RAW ); ?>;
   161     }
   170     }
   162 
   171 
       
   172     .include-mastodon-feed-wrapper .include-mastodon-feed {
       
   173       list-style: none;
       
   174       padding-left: 0;
       
   175     }
   163     .include-mastodon-feed .status {
   176     .include-mastodon-feed .status {
       
   177       display: block;
   164       margin: 0.5rem 0 1.5rem;
   178       margin: 0.5rem 0 1.5rem;
   165       border-radius: var(--include-mastodon-feed-border-radius);
   179       border-radius: var(--include-mastodon-feed-border-radius);
   166       padding: 0.5rem;
   180       padding: 0.5rem;
   167       background: var(--include-mastodon-feed-bg-light);
   181       background: var(--include-mastodon-feed-bg-light);
   168     }
   182     }
   173     }
   187     }
   174     .include-mastodon-feed .status a:hover {
   188     .include-mastodon-feed .status a:hover {
   175       text-decoration: underline;
   189       text-decoration: underline;
   176     }
   190     }
   177     .include-mastodon-feed .avatar {
   191     .include-mastodon-feed .avatar {
       
   192       display: inline-block;
   178       height: 1.25rem;
   193       height: 1.25rem;
   179       border-radius: var(--include-mastodon-feed-border-radius);
   194       border-radius: var(--include-mastodon-feed-border-radius);
   180       vertical-align: top;
   195       vertical-align: top;
   181     }
   196     }
   182     .include-mastodon-feed .account {
   197     .include-mastodon-feed .account {
   223     .include-mastodon-feed .content .invisible {
   238     .include-mastodon-feed .content .invisible {
   224       display: none;
   239       display: none;
   225     }
   240     }
   226     .include-mastodon-feed .media {
   241     .include-mastodon-feed .media {
   227       display: flex;
   242       display: flex;
       
   243       list-style: none;
       
   244       padding: 0;
   228       justify-content: space-around;
   245       justify-content: space-around;
   229       align-items: center;
   246       align-items: center;
   230       flex-wrap: wrap;
   247       flex-wrap: wrap;
   231       gap: 0.5rem;
   248       gap: 0.5rem;
   232       margin: 1rem;
   249       margin: 1rem;
   233     }
   250     }
   234     .include-mastodon-feed .media > div {
   251     .include-mastodon-feed .media > * {
       
   252       display: block;
   235       flex-basis: calc(50% - 0.5rem);
   253       flex-basis: calc(50% - 0.5rem);
   236       flex-grow: 1;
   254       flex-grow: 1;
   237     }
   255     }
   238     .include-mastodon-feed .media > .image {
   256     .include-mastodon-feed .media > .image {
   239       font-size: 0.8rem;
   257       font-size: 0.8rem;
   301     .include-mastodon-feed.dark .card {
   319     .include-mastodon-feed.dark .card {
   302       background: var(--include-mastodon-feed-bg-dark);
   320       background: var(--include-mastodon-feed-bg-dark);
   303     }
   321     }
   304   </style>
   322   </style>
   305 <?php
   323 <?php
   306   echo ob_get_clean();
       
   307 }
   324 }
   308 add_action('wp_head', __NAMESPACE__ . '\init_styles', 7);
   325 add_action('wp_head', __NAMESPACE__ . '\init_styles', 7);
   309 
   326 
   310 function init_scripts() {
   327 function init_scripts() {
   311   ob_start();
       
   312 ?>
   328 ?>
   313   <script>
   329   <script>
   314 
   330 
   315     const mastodonFeedCreateElement = function(type, className = null) {
   331     const mastodonFeedCreateElement = function(type, className = null) {
   316       let element = document.createElement(type);
   332       let element = document.createElement(type);
   321     }
   337     }
   322 
   338 
   323     const mastodonFeedCreateElementAccountLink = function(account) {
   339     const mastodonFeedCreateElementAccountLink = function(account) {
   324       let accountLinkElem = mastodonFeedCreateElement('a');
   340       let accountLinkElem = mastodonFeedCreateElement('a');
   325       accountLinkElem.href = account.url;
   341       accountLinkElem.href = account.url;
       
   342       accountLinkElem.setAttribute('aria-label', 'Link to Mastodon account of ' + account.display_name);
   326 
   343 
   327       let accountImageElem = mastodonFeedCreateElement('img', 'avatar');
   344       let accountImageElem = mastodonFeedCreateElement('img', 'avatar');
   328       accountImageElem.src = account.avatar_static;
   345       accountImageElem.src = account.avatar_static;
       
   346       accountImageElem.loading = 'lazy';
       
   347       accountImageElem.alt = 'Mastodon avatar image of ' + account.display_name;
   329 
   348 
   330       accountLinkElem.addEventListener('mouseover', (event) => {
   349       accountLinkElem.addEventListener('mouseover', (event) => {
   331         accountLinkElem.querySelector('.avatar').src = account.avatar;
   350         accountLinkElem.querySelector('.avatar').src = account.avatar;
   332       });
   351       });
   333       accountLinkElem.addEventListener('mouseout', (event) => {
   352       accountLinkElem.addEventListener('mouseout', (event) => {
   344       }
   363       }
   345       accountLinkElem.innerHTML += ' ' + displayName;
   364       accountLinkElem.innerHTML += ' ' + displayName;
   346       return accountLinkElem;
   365       return accountLinkElem;
   347     }
   366     }
   348 
   367 
   349     const mastodonFeedCreateElementPermalink = function(status, label) {
   368     const mastodonFeedCreateElementPermalink = function(status, label, ariaLabel) {
   350       let linkElem = mastodonFeedCreateElement('a');
   369       let linkElem = mastodonFeedCreateElement('a');
   351       linkElem.href = status.url;
   370       linkElem.href = status.url;
   352       linkElem.appendChild(document.createTextNode(label));
   371       linkElem.appendChild(document.createTextNode(label));
       
   372       linkElem.setAttribute('aria-label', ariaLabel);
   353       return linkElem;
   373       return linkElem;
   354     }
   374     }
   355 
   375 
   356     const mastodonFeedCreateElementMediaAttachments = function(status, options) {
   376     const mastodonFeedCreateElementMediaAttachments = function(status, options) {
   357       let attachments = status.media_attachments;
   377       let attachments = status.media_attachments;
   358       let mediaWrapperElem = mastodonFeedCreateElement('div', 'media');
   378       let mediaWrapperElem = mastodonFeedCreateElement('ol', 'media');
   359       for(let mediaIndex = 0; mediaIndex < attachments.length; mediaIndex++) {
   379       for(let mediaIndex = 0; mediaIndex < attachments.length; mediaIndex++) {
   360         let media = attachments[mediaIndex];
   380         let media = attachments[mediaIndex];
   361         let mediaElem = mastodonFeedCreateElement('div', media.type);
   381         let mediaElem = mastodonFeedCreateElement('li', media.type);
   362         if('image' == media.type) {
   382         if('image' == media.type) {
   363           let mediaElemImgLink = mastodonFeedCreateElement('a');
   383           let mediaElemImgLink = mastodonFeedCreateElement('a');
       
   384           let imageUrl = media.url;
       
   385           if('full' !== options.images.size && null !== media.preview_url) {
       
   386             imageUrl = media.preview_url;
       
   387           }
   364           mediaElemImgLink.href = status.url;
   388           mediaElemImgLink.href = status.url;
   365           if(null === media.remote_url) {
   389           if('image' === options.images.link) {
   366             mediaElemImgLink.style.backgroundImage = 'url("' + media.preview_url + '")';
   390             mediaElemImgLink.href = media.remote_url ?? media.url;
       
   391           }
       
   392           let mediaElemImgImage = mastodonFeedCreateElement('img');
       
   393           mediaElemImgImage.src = imageUrl;
       
   394           mediaElemImgImage.loading = 'lazy';
       
   395           if(null === media.description) {
       
   396             mediaElemImgImage.alt = 'Image attachment of Mastodon post';
   367           }
   397           }
   368           else {
   398           else {
   369             mediaElemImgLink.style.backgroundImage = 'url("' + media.remote_url + '")';
   399             mediaElemImgImage.alt = media.description;
   370           }
   400           }
   371           if(null !== media.description) {
   401           if(!options.images.preserveImageAspectRatio) {
   372             mediaElem.title = media.description;
   402             mediaElemImgLink.style.backgroundImage = 'url("' + imageUrl + '")';
   373           }
   403             mediaElemImgImage.style.width = '100%';
   374           if(options.preserveImageAspectRatio) {
   404             mediaElemImgImage.style.height = '100%';
   375             let mediaElemImgImage = mastodonFeedCreateElement('img');
   405             mediaElemImgImage.style.opacity = 0;
   376             if(null === media.remote_url) {
   406           }
   377               mediaElemImgImage.src = media.preview_url;
   407           mediaElemImgLink.appendChild(mediaElemImgImage);
   378             }
       
   379             else {
       
   380               mediaElemImgImage.src = media.remote_url;
       
   381             }
       
   382             mediaElemImgLink.appendChild(mediaElemImgImage);
       
   383           }
       
   384           mediaElem.appendChild(mediaElemImgLink);
   408           mediaElem.appendChild(mediaElemImgLink);
   385         }
   409         }
   386         else if('gifv' == media.type) {
   410         else if('gifv' == media.type) {
   387           let mediaElemGifvLink = mastodonFeedCreateElement('a');
   411           let mediaElemGifvLink = mastodonFeedCreateElement('a');
   388           mediaElemGifvLink.href = status.url;
   412           mediaElemGifvLink.href = status.url;
   393           else {
   417           else {
   394             mediaElemGifv.src = media.remote_url;
   418             mediaElemGifv.src = media.remote_url;
   395           }
   419           }
   396           mediaElemGifv.loop = true;
   420           mediaElemGifv.loop = true;
   397           mediaElemGifv.muted = 'muted';
   421           mediaElemGifv.muted = 'muted';
   398           if(null !== media.description) {
   422           if(null === media.description) {
   399             mediaElemGifv.title = media.description;
   423             mediaElemGifv.alt = 'Video attachment of Mastodon post';
       
   424           }
       
   425           else {
       
   426             mediaElemGifv.alt = media.description;
   400           }
   427           }
   401           mediaElemGifvLink.appendChild(mediaElemGifv);
   428           mediaElemGifvLink.appendChild(mediaElemGifv);
   402           mediaElem.appendChild(mediaElemGifvLink);
   429           mediaElem.appendChild(mediaElemGifvLink);
   403 
   430 
   404           mediaElemGifv.addEventListener('mouseover', (event) => {
   431           mediaElemGifv.addEventListener('mouseover', (event) => {
   412         else {
   439         else {
   413           // TODO implement support for other media types
   440           // TODO implement support for other media types
   414           //      currently only image and gifv support implemented
   441           //      currently only image and gifv support implemented
   415           mediaElem.innerHTML = 'Stripped ' + media.type + ' - only available on instance<br />';
   442           mediaElem.innerHTML = 'Stripped ' + media.type + ' - only available on instance<br />';
   416           let permalinkElem = mastodonFeedCreateElement('span', 'permalink');
   443           let permalinkElem = mastodonFeedCreateElement('span', 'permalink');
   417           permalinkElem.appendChild(mastodonFeedCreateElementPermalink(status, options.text.viewOnInstance));
   444           permalinkElem.appendChild(mastodonFeedCreateElementPermalink(status, options.text.viewOnInstance, 'Link to Mastodon post'));
   418           mediaElem.appendChild(permalinkElem);
   445           mediaElem.appendChild(permalinkElem);
   419         }
   446         }
   420         mediaWrapperElem.appendChild(mediaElem);
   447         mediaWrapperElem.appendChild(mediaElem);
   421       }
   448       }
   422       return mediaWrapperElem;
   449       return mediaWrapperElem;
   429         let cardElemMeta = mastodonFeedCreateElement('div', 'meta');
   456         let cardElemMeta = mastodonFeedCreateElement('div', 'meta');
   430 
   457 
   431         if(null !== card.image) {
   458         if(null !== card.image) {
   432           let cardElemImageWrapper = mastodonFeedCreateElement('div', 'image');
   459           let cardElemImageWrapper = mastodonFeedCreateElement('div', 'image');
   433           let cardElemImage = mastodonFeedCreateElement('img');
   460           let cardElemImage = mastodonFeedCreateElement('img');
       
   461           if(null === card.image_description) {
       
   462             cardElemImage.alt = 'Preview image content card';
       
   463           }
       
   464           else {
       
   465             cardElemImage.alt = card.image_description;
       
   466           }
   434           cardElemImage.src = card.image;
   467           cardElemImage.src = card.image;
       
   468           cardElemImage.loading = 'lazy';
   435           cardElemImageWrapper.appendChild(cardElemImage);
   469           cardElemImageWrapper.appendChild(cardElemImage);
   436           cardElemMeta.appendChild(cardElemImageWrapper);
   470           cardElemMeta.appendChild(cardElemImageWrapper);
   437         }
   471         }
   438 
   472 
   439         let cardElemTitle = mastodonFeedCreateElement('div', 'title');
   473         let cardElemTitle = mastodonFeedCreateElement('div', 'title');
   448           cardElem.appendChild(cardElemMeta);
   482           cardElem.appendChild(cardElemMeta);
   449         }
   483         }
   450         else {
   484         else {
   451           let cardElemLink = mastodonFeedCreateElement('a');
   485           let cardElemLink = mastodonFeedCreateElement('a');
   452           cardElemLink.href = card.url;
   486           cardElemLink.href = card.url;
       
   487           cardElemLink.setAttribute('aria-label', 'Link embedded in Mastodon post');
   453           cardElemLink.appendChild(cardElemMeta);
   488           cardElemLink.appendChild(cardElemMeta);
   454           cardElem.appendChild(cardElemLink);
   489           cardElem.appendChild(cardElemLink);
   455         }
   490         }
   456       }
   491       }
   457       else {
   492       else {
   465       createdInfo.innerHTML = ' ' + options.text.permalinkPre + ' ';
   500       createdInfo.innerHTML = ' ' + options.text.permalinkPre + ' ';
   466       if(false === url) {
   501       if(false === url) {
   467         createdInfo.innerHTML += new Date(status.created_at).toLocaleString(options.localization.date.locale, options.localization.date.options);
   502         createdInfo.innerHTML += new Date(status.created_at).toLocaleString(options.localization.date.locale, options.localization.date.options);
   468       }
   503       }
   469       else {
   504       else {
   470         createdInfo.appendChild(mastodonFeedCreateElementPermalink(status, new Date(status.created_at).toLocaleString(options.localization.date.locale, options.localization.date.options)));
   505         createdInfo.appendChild(mastodonFeedCreateElementPermalink(status, new Date(status.created_at).toLocaleString(options.localization.date.locale, options.localization.date.options), 'Link to Mastodon post'));
   471       }
   506       }
   472       createdInfo.innerHTML += ' ' + options.text.permalinkPost;
   507       createdInfo.innerHTML += ' ' + options.text.permalinkPost;
   473       return createdInfo;
   508       return createdInfo;
   474     }
   509     }
   475 
   510 
   477       return string.replaceAll(':' + emoji.shortcode + ':', '<img class="emoji" src="' + emoji.url + '" title="' + emoji.shortcode + '" />');
   512       return string.replaceAll(':' + emoji.shortcode + ':', '<img class="emoji" src="' + emoji.url + '" title="' + emoji.shortcode + '" />');
   478     }
   513     }
   479 
   514 
   480     const mastodonFeedRenderStatuses = function(statuses, rootElem, options) {
   515     const mastodonFeedRenderStatuses = function(statuses, rootElem, options) {
   481       if(statuses.length < 1) {
   516       if(statuses.length < 1) {
   482         console.log(options);
       
   483         rootElem.innerHTML = options.text.noStatuses;
   517         rootElem.innerHTML = options.text.noStatuses;
   484       }
   518       }
   485       else {
   519       else {
   486         for(let i = 0; i < statuses.length; i++) {
   520         for(let i = 0; i < statuses.length; i++) {
   487           let status = statuses[i];
   521           let status = statuses[i];
   488           let isEdited = (null === status.edited_at ? true : false);
   522           let isEdited = (null === status.edited_at ? true : false);
   489           let isReblog = (null === status.reblog ? false : true);
   523           let isReblog = (null === status.reblog ? false : true);
   490 
   524 
   491           let statusElem = mastodonFeedCreateElement('div', 'status');
   525           let statusElem = mastodonFeedCreateElement('li', 'status');
   492 
   526 
   493           // add account meta info
   527           // add account meta info
   494           if(!options.content.hideStatusMeta) {
   528           if(!options.content.hideStatusMeta) {
   495             let accountElem = mastodonFeedCreateElement('div', 'account');
   529             let accountElem = mastodonFeedCreateElement('div', 'account');
   496             if(isReblog) {
   530             if(isReblog) {
   537               cwElem.appendChild(cwTitleElem);
   571               cwElem.appendChild(cwTitleElem);
   538             }
   572             }
   539 
   573 
   540             let cwLinkElem = mastodonFeedCreateElement('a');
   574             let cwLinkElem = mastodonFeedCreateElement('a');
   541             cwLinkElem.href = '#';
   575             cwLinkElem.href = '#';
       
   576             cwLinkElem.setAttribute('aria-label', 'Show content despite warning');
   542             cwLinkElem.onclick = function() {
   577             cwLinkElem.onclick = function() {
   543               this.parentElement.style = 'display: none;';
   578               this.parentElement.style = 'display: none;';
   544               this.parentElement.nextSibling.style = 'display: block;';
   579               this.parentElement.nextSibling.style = 'display: block;';
   545               return false;
   580               return false;
   546             }
   581             }
   576           contentWrapperElem.appendChild(contentElem);
   611           contentWrapperElem.appendChild(contentElem);
   577           statusElem.appendChild(contentWrapperElem);
   612           statusElem.appendChild(contentWrapperElem);
   578           rootElem.appendChild(statusElem);
   613           rootElem.appendChild(statusElem);
   579         }
   614         }
   580       }
   615       }
   581       if('_self' != options.linkTarget) {
   616       rootElem.querySelectorAll('a').forEach(function(e) {
   582         rootElem.querySelectorAll('a').forEach(function(e) {
   617         if('_self' != options.linkTarget) {
   583           e.target = options.linkTarget;
   618           e.target = options.linkTarget;
   584         });
   619         }
   585       }
   620       });
   586     }
   621     }
   587 
   622 
   588     const mastodonFeedLoad = function(url, elementId, options) {
   623     const mastodonFeedLoad = function(url, elementId, options) {
   589       const xhr = new XMLHttpRequest();
   624       const xhr = new XMLHttpRequest();
   590       xhr.open('GET', url, true);
   625       xhr.open('GET', url, true);
   592       xhr.onload = function() {
   627       xhr.onload = function() {
   593         const statuses = xhr.response;
   628         const statuses = xhr.response;
   594         const rootElem = document.getElementById(elementId);
   629         const rootElem = document.getElementById(elementId);
   595         rootElem.innerHTML = '';
   630         rootElem.innerHTML = '';
   596         <?php if(true === INCLUDE_MASTODON_FEED_DEBUG) : ?>
   631         <?php if(true === INCLUDE_MASTODON_FEED_DEBUG) : ?>
   597           console.log("<?php echo __NAMESPACE__; ?>", url);
   632           console.log("<?php echo __NAMESPACE__; ?>", 'url', url);
       
   633           console.log("<?php echo __NAMESPACE__; ?>", 'elementId', elementId);
       
   634           console.log("<?php echo __NAMESPACE__; ?>", 'options', options);
   598         <?php endif; ?>
   635         <?php endif; ?>
   599         if (xhr.status === 200) {
   636         if (xhr.status === 200) {
   600           <?php if(true === INCLUDE_MASTODON_FEED_DEBUG) : ?>
   637           <?php if(true === INCLUDE_MASTODON_FEED_DEBUG) : ?>
   601             console.log("<?php echo __NAMESPACE__; ?>", xhr.response);
   638             console.log("<?php echo __NAMESPACE__; ?>", 'response', xhr.response);
   602           <?php endif; ?>
   639           <?php endif; ?>
   603           if(options.excludeConversationStarters && statuses.length > 0) {
   640           if(options.excludeConversationStarters && statuses.length > 0) {
   604             const filteredStatuses = [];
   641             const filteredStatuses = [];
   605             for(let i = 0; i < statuses.length; i++) {
   642             for(let i = 0; i < statuses.length; i++) {
   606               let includeStatus = true;
   643               let includeStatus = true;
   623             mastodonFeedRenderStatuses(statuses, rootElem, options);
   660             mastodonFeedRenderStatuses(statuses, rootElem, options);
   624           }
   661           }
   625         }
   662         }
   626         else {
   663         else {
   627           <?php if(true === INCLUDE_MASTODON_FEED_DEBUG) : ?>
   664           <?php if(true === INCLUDE_MASTODON_FEED_DEBUG) : ?>
   628             console.log("<?php echo __NAMESPACE__; ?>", xhr);
   665             console.log("<?php echo __NAMESPACE__; ?>", 'response error', xhr);
   629           <?php endif; ?>
   666           <?php endif; ?>
   630           rootElem.appendChild(document.createTextNode(xhr.response.error));
   667           rootElem.appendChild(document.createTextNode(xhr.response.error));
   631         }
   668         }
   632       };
   669       };
   633       xhr.send();
   670       xhr.send();
   634     }
   671     }
   635   </script>
   672   </script>
   636 <?php
   673 <?php
   637   echo ob_get_clean();
       
   638 }
   674 }
   639 add_action('wp_footer', __NAMESPACE__ . '\init_scripts');
   675 add_action('wp_footer', __NAMESPACE__ . '\init_scripts');
   640 
   676 
   641 function display_feed($atts) {
   677 function display_feed($atts) {
   642   $atts = shortcode_atts(
   678   $atts = shortcode_atts(
   649           'excludereplies' => filter_var(esc_html(INCLUDE_MASTODON_FEED_EXCLUDE_REPLIES), FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE),
   685           'excludereplies' => filter_var(esc_html(INCLUDE_MASTODON_FEED_EXCLUDE_REPLIES), FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE),
   650           'excludeconversationstarters' => filter_var(esc_html(INCLUDE_MASTODON_FEED_EXCLUDE_CONVERSATIONSTARTERS), FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE),
   686           'excludeconversationstarters' => filter_var(esc_html(INCLUDE_MASTODON_FEED_EXCLUDE_CONVERSATIONSTARTERS), FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE),
   651           'onlypinned' => filter_var(esc_html(INCLUDE_MASTODON_FEED_ONLY_PINNED), FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE),
   687           'onlypinned' => filter_var(esc_html(INCLUDE_MASTODON_FEED_ONLY_PINNED), FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE),
   652           'onlymedia' => filter_var(esc_html(INCLUDE_MASTODON_FEED_ONLY_MEDIA), FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE),
   688           'onlymedia' => filter_var(esc_html(INCLUDE_MASTODON_FEED_ONLY_MEDIA), FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE),
   653           'preserveimageaspectratio' => filter_var(esc_html(INCLUDE_MASTODON_FEED_PRESERVE_IMAGE_ASPECT_RATIO), FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE),
   689           'preserveimageaspectratio' => filter_var(esc_html(INCLUDE_MASTODON_FEED_PRESERVE_IMAGE_ASPECT_RATIO), FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE),
       
   690           'imagesize' => INCLUDE_MASTODON_FEED_IMAGE_SIZE,
       
   691           'imagelink' => INCLUDE_MASTODON_FEED_IMAGE_LINK,
   654           'tagged' => INCLUDE_MASTODON_FEED_TAGGED,
   692           'tagged' => INCLUDE_MASTODON_FEED_TAGGED,
   655           'linktarget' => INCLUDE_MASTODON_FEED_LINKTARGET,
   693           'linktarget' => INCLUDE_MASTODON_FEED_LINKTARGET,
   656           'showpreviewcards' => filter_var(esc_html(INCLUDE_MASTODON_FEED_SHOW_PREVIEWCARDS), FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE),
   694           'showpreviewcards' => filter_var(esc_html(INCLUDE_MASTODON_FEED_SHOW_PREVIEWCARDS), FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE),
   657           'hidestatusmeta' => filter_var(esc_html(INCLUDE_MASTODON_FEED_HIDE_STATUS_META), FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE),
   695           'hidestatusmeta' => filter_var(esc_html(INCLUDE_MASTODON_FEED_HIDE_STATUS_META), FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE),
   658           'hidedatetime' => filter_var(esc_html(INCLUDE_MASTODON_FEED_HIDE_DATETIME), FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE),
   696           'hidedatetime' => filter_var(esc_html(INCLUDE_MASTODON_FEED_HIDE_DATETIME), FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE),
   663           'text-showcontent' => INCLUDE_MASTODON_FEED_TEXT_SHOW_CONTENT,
   701           'text-showcontent' => INCLUDE_MASTODON_FEED_TEXT_SHOW_CONTENT,
   664           'text-permalinkpre' => INCLUDE_MASTODON_FEED_TEXT_PERMALINK_PRE,
   702           'text-permalinkpre' => INCLUDE_MASTODON_FEED_TEXT_PERMALINK_PRE,
   665           'text-permalinkpost' => INCLUDE_MASTODON_FEED_TEXT_PERMALINK_POST,
   703           'text-permalinkpost' => INCLUDE_MASTODON_FEED_TEXT_PERMALINK_POST,
   666           'text-edited' => INCLUDE_MASTODON_FEED_TEXT_EDITED,
   704           'text-edited' => INCLUDE_MASTODON_FEED_TEXT_EDITED,
   667           'date-locale' => INCLUDE_MASTODON_FEED_DATE_LOCALE,
   705           'date-locale' => INCLUDE_MASTODON_FEED_DATE_LOCALE,
   668           'date-options' => INCLUDE_MASTODON_FEED_DATE_OPTIONS,
       
   669           'darkmode' => filter_var(esc_html(INCLUDE_MASTODON_FEED_DARKMODE), FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE),
   706           'darkmode' => filter_var(esc_html(INCLUDE_MASTODON_FEED_DARKMODE), FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE),
   670       ), array_change_key_case($atts, CASE_LOWER)
   707       ), array_change_key_case($atts, CASE_LOWER)
   671   );
   708   );
   672 
   709 
   673   if(false === filter_var($atts['instance'], FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE)) {
   710   if(false === filter_var($atts['instance'], FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE)) {
   711   ob_start();
   748   ob_start();
   712 ?>
   749 ?>
   713   <script>
   750   <script>
   714     window.addEventListener("load", () => {
   751     window.addEventListener("load", () => {
   715       mastodonFeedLoad(
   752       mastodonFeedLoad(
   716         "<?php echo sanitize_url( $apiUrl, ['https'] ); ?>",
   753         "<?php echo esc_url( $apiUrl, ['https'], 'apicall' ); ?>",
   717         "<?php echo filter_var( $elemId, FILTER_UNSAFE_RAW ); ?>",
   754         "<?php echo filter_var( $elemId, FILTER_UNSAFE_RAW ); ?>",
   718         {
   755         {
   719           linkTarget: "<?php echo filter_var( $atts['linktarget'], FILTER_UNSAFE_RAW ); ?>",
   756           linkTarget: "<?php echo esc_js(filter_var( $atts['linktarget'], FILTER_UNSAFE_RAW )); ?>",
   720           showPreviewCards: <?php echo (filter_var( $atts['showpreviewcards'], FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE) ? "true" : "false"); ?>,
   757           showPreviewCards: <?php echo (filter_var( $atts['showpreviewcards'], FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE) ? "true" : "false"); ?>,
   721           excludeConversationStarters: <?php echo (filter_var( $atts['excludeconversationstarters'], FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE) ? "true" : "false"); ?>,
   758           excludeConversationStarters: <?php echo (filter_var( $atts['excludeconversationstarters'], FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE) ? "true" : "false"); ?>,
   722           preserveImageAspectRatio: <?php echo (filter_var( $atts['preserveimageaspectratio'], FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE) ? "true" : "false"); ?>,
       
   723           content: {
   759           content: {
   724             hideStatusMeta: <?php echo (filter_var( $atts['hidestatusmeta'], FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE) ? "true" : "false"); ?>,
   760             hideStatusMeta: <?php echo (filter_var( $atts['hidestatusmeta'], FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE) ? "true" : "false"); ?>,
   725             hideDateTime: <?php echo (filter_var( $atts['hidedatetime'], FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE) ? "true" : "false"); ?>
   761             hideDateTime: <?php echo (filter_var( $atts['hidedatetime'], FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE) ? "true" : "false"); ?>
   726           },
   762           },
       
   763           images: {
       
   764             preserveImageAspectRatio: <?php echo (filter_var( $atts['preserveimageaspectratio'], FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE) ? "true" : "false"); ?>,
       
   765             size: "<?php echo ( "full" === $atts['imagesize'] ? "full" : "preview" ); ?>",
       
   766             link: "<?php echo ( "image" === $atts['imagelink'] ? "image" : "status" ); ?>",
       
   767           },
   727           text: {
   768           text: {
   728             boosted: "<?php echo esc_js( $atts['text-boosted'] ); ?>",
   769             boosted: "<?php echo esc_html( $atts['text-boosted'] ); ?>",
   729             noStatuses: "<?php echo esc_html( $atts['text-nostatuses'] ); ?>",
   770             noStatuses: "<?php echo esc_html( $atts['text-nostatuses'] ); ?>",
   730             viewOnInstance: "<?php echo esc_js( $atts['text-viewoninstance'] ); ?>",
   771             viewOnInstance: "<?php echo esc_js( $atts['text-viewoninstance'] ); ?>",
   731             showContent: "<?php echo esc_js( $atts['text-showcontent'] ); ?>",
   772             showContent: "<?php echo esc_html( $atts['text-showcontent'] ); ?>",
   732             permalinkPre: "<?php echo esc_js( $atts['text-permalinkpre'] ); ?>",
   773             permalinkPre: "<?php echo esc_html( $atts['text-permalinkpre'] ); ?>",
   733             permalinkPost: "<?php echo esc_js( $atts['text-permalinkpost'] ); ?>",
   774             permalinkPost: "<?php echo esc_html( $atts['text-permalinkpost'] ); ?>",
   734             edited: "<?php echo esc_js( $atts['text-edited'] ); ?>",
   775             edited: "<?php echo esc_html( $atts['text-edited'] ); ?>",
   735           },
   776           },
   736           localization: {
   777           localization: {
   737             date: {
   778             date: {
   738               locale: "<?php echo filter_var( $atts['date-locale'], FILTER_UNSAFE_RAW ); ?>",
   779               locale: "<?php echo esc_js( filter_var( $atts['date-locale'], FILTER_UNSAFE_RAW ) ); ?>",
   739               options: <?php echo filter_var( $atts['date-options'], FILTER_UNSAFE_RAW ); ?>,
   780               options: <?php echo filter_var( INCLUDE_MASTODON_FEED_DATE_OPTIONS, FILTER_UNSAFE_RAW ); ?>,
   740             }
   781             }
   741           }
   782           }
   742         }
   783         }
   743       );
   784       );
   744     });
   785     });
   745   </script>
   786   </script>
   746   <div class="include-mastodon-feed<?php echo (true == $atts['darkmode'] ? ' dark' : ''); ?>" id="<?php echo esc_attr( $elemId ); ?>"><?php echo esc_html( $atts['text-loading'] ); ?></div>
   787   <div class="include-mastodon-feed-wrapper"><ol class="include-mastodon-feed<?php echo (true == $atts['darkmode'] ? ' dark' : ''); ?>" id="<?php echo esc_attr( $elemId ); ?>"><li><?php echo esc_html( $atts['text-loading'] ); ?></li></ol></div>
   747 <?php
   788 <?php
   748   return ob_get_clean();
   789   return ob_get_clean();
   749 }
   790 }
   750 add_shortcode('include-mastodon-feed', __NAMESPACE__ . '\display_feed');
   791 add_shortcode('include-mastodon-feed', __NAMESPACE__ . '\display_feed');