Jump to content


  • Posts

  • Joined

  • Last visited

  • Days Won


Everything posted by nbcommunication

  1. Hi @jonatan, I've been able to pick away at this over the weekend... too cold yet to plant tatties! With the discovery of the hidden limit option in the API, I had to rewrite some of the module, but everything should just work the same, if not even better... However, I'm not sure it'll help too much with API rate limiting in your case, as each carousel album is still a separate API call. There is now the option to prevent the "children" (the rest of the album carousel images) from being retrieved: <?php $instagram = $modules->get("InstagramBasicDisplayApi"); $items = $instagram->getMedia(["children" => false]); When working with this over the weekend, I kept an eye on the rate limiting page and it did get nudged frequently, but didn't go beyond 30% used. The account I was using for testing only had a few carousels though. I've also been able to implement "lazy loading". The example I've added to the README is based on the getMedia() example, using UIkit's javascript utilities. I've attached a short clip of how this looks. Here's how it might work using Bootstrap/jQuery: In your template file: <?php $instagram = $modules->get("InstagramBasicDisplayApi"); // The pagination cursor is reset if the request is not AJAX, e.g. when the page is loaded. if($config->ajax) { header("Content-Type: application/json"); echo $instagram->getMedia(); // ["json" => true] is inferred by $config->ajax die(); } echo "<div id='instagram' class='row'></div>"; In your javascript: // Totally untested!!!! var instagram = { $el: {}, // Where the items go $loading: {}, // The loading spinner total: 0, // The total number of items init: function() { this.$el = $("#instagram"); if(!this.$el.length) return; // Add the spinner this.$el.after("<div id='instagram-loading'>...Your choice of spinner!</div>"); this.$loading = $("#instagram-loading"); this.$loading.hide(); // Get the first batch of items this.get(); }, get: function() { var this$1 = this; // Show spinner this$1.$loading.show(); // Request $.getJSON(window.location.href, function(data) { // Hide spinner this$1.$loading.hide(); if(!$.isArray(data) || !data.length) return; // If no items do not render var items = []; data.forEach(function(item, index) { switch(item.type) { case "VIDEO": items.push(this$1.renderItem(item.poster, item.alt, item.src, index)); break; case "CAROUSEL_ALBUM": var out = ""; for(var i = 0; i < item.children.length; i++) { var src = item.children[i].src; out += "<a class='carousel-item' data-fancybox='gallery-ig' data-height='600' data-caption='" + item.alt + "' href='" + src + "'>" + "<div style='background-image: url(" + src + ")' class='pics'></div>" + "</a>"; } items.push( "<div data-interval='3000' class='carousel slide carousel-fade col-4 p-3 pics' data-ride='carousel' id='instagram-item-" + (this$1.total + index) + "'>" + "<div class='carousel-inner'>" + out + "<a class='carousel-control-prev' href='#_{$post->id}' role='button' data-slide='prev'>" + "<span class='carousel-control-icon-bg' aria-hidden='true'></span>" + "<span class='carousel-control-prev-icon' aria-hidden='true'></span>" + "<span class='sr-only'>Previous</span>" + "</a>" + "<a class='carousel-control-next' href='#_{$post->id}' role='button' data-slide='next'>" + "<span class='carousel-control-icon-bg' aria-hidden='true'></span>" + "<span class='carousel-control-next-icon' aria-hidden='true'></span>" + "<span class='sr-only'>Next</span>" + "</a>" + "</div>" + "</div>" ); break; default: // IMAGE items.push(this$1.renderItem(item.src, item.alt, item.src, index)); break; } }); var count = items.length; if(count) { // Append items to the container this$1.$el.append(items.join("")); // Attach listener // No idea if this works!!! $(window).on("resize scroll", function() { var next = $("#instagram-item-" + (this$1.total + count - (count < 5 ? 1 : 6))); if(!next.hasClass("seen") && this$1.inViewport()) { next.addClass("seen"); this$1.get(); } }); // Update total this$1.total = this$1.total + count; } }, function(e) { this$1.$loading.hide(); console.log(e); // ERROR }) }, inViewport: function(el) { // Untested, got the code from // https://medium.com/talk-like/detecting-if-an-element-is-in-the-viewport-jquery-a6a4405a3ea2 var elementTop = el.offset().top; var elementBottom = elementTop + el.outerHeight(); var viewportTop = $(window).scrollTop(); var viewportBottom = viewportTop + $(window).height(); return elementBottom > viewportTop && elementTop < viewportBottom; }, renderItem: function(src, alt, href, index) { return "<div class='col-4 p-3 pics' id='instagram-item-" + (this.total + index) + "'>" + "<a data-fancybox='gallery-ig' data-height='600' data-caption='" + alt + "' href='" + href + "'>" + "<div style='background-image: url(" + src + ")' class='pics'>" + (src !== href ? "<div class='overlay-video-icon'></div>" : "") + "</div>" + "</a>" + "</div>"; } }; $(document).ready(function() { instagram.init(); }); I've just done the jQuery from memory with the addition of an inViewport function I found online. No idea if it works! Let me know how you get on! Cheers, Chris instagram-basic-display-api-lazy-2020-03-29.mp4
  2. Hi @jonatan, I'm making good progress on this but not finished yet. Discovered that there's a hidden "limit" API option which has necessitated a bit of a rewrite. May get to it this weekend (weather is looking good though, so might be out in the garden!), if not on Monday. Cheers, Chris
  3. Hi @jonatan, Aye lazy loading is proving to be a little tricky, mainly because of caching. I need to think through this more and will get back to it tomorrow. Cheers, Chris
  4. Hi @jonatan, I've managed to get access to an account with 20 items for testing. The "counting" in the module is actually correct, I think the issue is maybe that after the limit is reached the API just returns blank records? Anyway, I've added a little bit of code that removes any items without a media_url before they are returned, which should fix your issue. Code not pushed yet, should be later today. Cheers, Chris
  5. Hi @jonatan, Thanks for the debug array. Yep there's definitely an issue with asking for more items than there actually is. Will get that sorted. Each carousel requires a separate API call. That means each request for 80 items (that isn't cached) uses up 50 API calls. The error isn't at that point. Try this: <?php switch($post->type) { case "VIDEO": // ... break; case "CAROUSEL_ALBUM": // If the post does not have children, continue without rendering if(!$post->children) break; // ... break; // ... } Cheers, Chris
  6. Hi @jonatan, No, I think echoing as you are doing would probably be faster if anything. Basically no difference - I just like to use the array so I don't have to wrap with <div></div> in three separate places. I'm going to look into making the pagination more available through the module tomorrow. Might be tricky, and it probably will need to be batches of 24, but I definitely think you've made a good case that it should be available. I think that may have been from the previous API. This one returns the first 24 items, and a link for getting the next 24. You can keep going on until all items have been received or until the API limits have been maxed out. Indeed, this is what would happen if you were to call something like InstagramBasicDisplayApi::getMedia(10000), although I think there would be a timeout before completion. If you request 89 and there are only 80, it should return 80, but I don't think I actually tested that. I don't have access to an account at the moment with a relatively small amount of items, but should do soon, so will test this when I can. I suspect there is an issue and this is why you are getting the undefined offset errors and the blank items. For debugging, I'd add the following to your code: <?php $images = $instagram->getMedia(89); echo count($images) . "<br>" . print_r($images, 1); If you are requesting 80 items, and 10 of those are album carousels, that should be 14 calls to the API (24, 24, 24, 24[8] + a call for each carousel). How many carousels do you have? When I was developing and testing I didn't budge the limit off 0%. Will have another look at this tomorrow. I think it may be useful to have an option to not get the full carousel when using getMedia() as this does seem to be the issue. I'm not following this. I think I know what you mean now I've gone through the following... I'll tweak your code to what I think you are trying to achieve and that'll maybe get us closer: <?php $username = "a_username"; $account = $instagram->getProfile($username); $postsnum = $account["media_count"] ?? 0; // If the API request is unsuccessful, the post count below will not be displayed ?> <div class="col-12 text-center mb-3"> <a href="https://instagram.com/<?= $username ?>/" target="_blank" class="marked"> <h3 class="marked my-5 instalink">@<?= $username ?></h3> </a> <?php if($postsnum): ?><h5 class="marked-dark"><?= $postsnum ?> POSTS / OPSLAG </h5><?php endif; ?> </div> getProfile() is a single call which will be cached for either an hour or however long you have the cache time set to so I wouldn't consider this a resource issue. Given that the cache time will be the same for getMedia(), the count and the number of items you get if you were to get them all should be the same, but the count won't update until the cache has expired. getUserAccount() should have the same value for media_count, but it is only updated when getProfile() is called (and an API request is made) so I don't think it is worth using in this situation. It is a public method but only so it could be used in the config - I can't think of a situation where it should be used over getProfile(). The errors you've pointed out in your last post are related to the total number issue which I'll get fixed as soon as I can. I'll hopefully have some progress on this tomorrow! Thanks again for your feedback! Cheers, Chris
  7. Hi @jonatan, I'll have a think about how best to implement a lazy-load. I'll need to provide a way to return the "next" link to do this. The cache time is set in the module configuration, should be 3600 by default. Quite possible that the single request is maxing out the limit, will look at that later. Cheers, Chris
  8. Hi @jonatan, I'll provide a fuller response later but just a couple of things now: The API doesn't actually allow for querying a specific number of items like the old one did. The module actually uses the built in pagination to retrieve as many items as requested in the call. That's why it is taking a while. You should have a cache time of at least 3600 seconds (an hour) if you are requesting this many items. This will prevent maxing out the limits (which is a lot easier to do when developing anyway!). If I were in your position, I'd be weighing whether so many items need to be displayed. I'd probably just display the first batch (e.g. $images = $instagram->getMedia()) which returns 24 items normally. For the PHP error: <?php foreach($images = $instagram->getMedia(89) as $post) { ... } // I'd change this to: $images = $instagram->getMedia(89); if(count($images)) { foreach($images as $post) { ... } } Cheers, Chris
  9. Hi @gowthamg, The instructions for this module, for setting up the facebook app are here: https://github.com/nbcommunication/InstagramBasicDisplayApi/blob/master/README.md and relate exclusively to this part of the facebook/instagram docs: https://developers.facebook.com/docs/instagram-basic-display-api/overview#user-token-generator. I'd advise reviewing the errors displayed on your screenshot - notes and screencast are missing. If you do have success in getting the app reviewed and approved, please share here, but as I said previously, this isn't in the purview of this module. Cheers, Chris
  10. Hi @gowthamg - I can't help you here I'm afraid. This module and the instructions provided are not geared toward app review. Cheers, Chris
  11. Hi @gowthamg, What do you mean by all users? In the past, getting Instagram data from any user was pretty simple, but it is locked down now. You can only retrieve data from users who have authorised your app. This module is built around the oAuth token generator provided by facebook, which allows you to add a "test" Instagram user, and then generate a token by logging in as that user and authorising the app. This bypasses the need to submit the app for review, which is intended for apps that would be public facing. You can only get data from users that have authorised your app, and in this case of this module, you need to login as the user to authorise it. For a number of clients recently we've arranged a time where they change their password to something temporary and let us know the temp password, we run through the steps in the README and get the app/module set up, and then let the client know so they can change their password back. It has worked well so far. Cheers, Chris
  12. Hi @jonatan, Many thanks for your feedback, and for helping out @gowthamg. You are correct - looks like he's trying to set up the full API which isn't what this module uses. I've updated the README with the module call in each example, and also added an example for getMedia() which demonstrates how to build a multi-media gallery using UIkit. I've attached a video example of the result 🙂 Here's the code I added to the README: // Function for rendering items function renderInstagramItem($src, $alt, $href = null) { if(is_null($href)) $href = $src; return "<a href='$href' data-caption='$alt' " . ($src !== $href ? "data-poster='$src' " : "") . "class='uk-display-block uk-cover-container'>" . "<canvas width='640' height='640'></canvas>" . "<img src='$src' alt='$alt' data-uk-cover>" . "</a>"; } // Get the module $instagram = $modules->get("InstagramBasicDisplayApi"); // Get the 16 most recent items and render them based on type $items = []; foreach($instagram->getMedia(16) as $item) { switch($item->type) { case "VIDEO": $items[] = renderInstagramItem($item->poster, $item->alt, $item->src); break; case "CAROUSEL_ALBUM": // If 4 or greater items, display a grid of the first 4 images // Otherwise display the main image (no break, moves to default) if($item->children->count() >= 4) { $items[] = "<div class='uk-grid-collapse uk-child-width-1-2' data-uk-grid>" . $item->children->find("limit=4")->each(function($item) { return "<div>" . renderInstagramItem($item->src, $item->alt) . "</div>"; }) . "</div>"; break; } default: // IMAGE $items[] = renderInstagramItem($item->src, $item->alt); break; } } // Render the items as a grid echo "<div class='uk-grid-collapse uk-child-width-1-2 uk-child-width-1-4@s' data-uk-grid data-uk-lightbox>"; foreach($items as $item) { echo "<div>$item</div>"; } echo "</div>"; The query about data-width - this is a totally separate thing unfortunately. That's the oEmbed implementation from which you get a HTML embed code which normally includes javascript from the provider, and in the case of Instagram includes code which handles a data-width attribute. There's nothing like that here. This API gives you basic data, and it is up to you to render it. I'd actually recommend looking more into oEmbed if you are looking to embed single posts in articles or similar. The main purpose of this module and the API itself is a standalone "feed" or gallery of user media. Cheers, Chris instagram-basic-display-api-2020-03-21.mp4
  13. Hey, If anyone has installed and implemented this module, please let me know if you've any feedback! I've currently only used it as a replacement for InstagramFeed, and it has worked great 🙂 Cheers, Chris
  14. Hi @Ben Sayers, The `src` returned is a direct link to the image on Instagram's CDN - there are no API options for resizing. When I've used a lightbox I just use `src` for both the "img src" and "a href" attributes. Cheers, Chris
  15. Hi Ben, Glad to hear you got the account authorised 🙂 Pop this before your call: $instagram = $modules->get("InstagramBasicDisplayApi"); Cheers, Chris
  16. Hello, With the API being deprecated at the end of this month, I've built a replacement module which uses the Instagram Basic Display API. Find out more here: Cheers, Chris
  17. Hi, The module is now ready for use in production. It is still in Beta as I need to test token renewal, but cannot do this yet due to how token renewal works. Cheers, Chris
  18. Hi @lpa, Apologies for the late response. I've had a look at this... Number 2 - width and height attributes not rendering - this isn't anything to do with PageimageSrcset. These options, when passed to Pageimage::render(), resize the image, but don't get rendered as attributes. If you want this behaviour, adding a markup option should do the trick: $content .= $img->render([ 'alt'=> $img->name, 'height' => $img->height, 'width' => $img->width, 'srcset' => '883, 687, 369', 'markup' => "<img src='{url}' alt='{alt}' width='{width}' height='{height}' />" ]); As for portrait mode, I'm not getting this when I test. I get: <img src='/site/assets/files/1033/placeholder-city.691x499.1000x667.webp' alt='placeholder-city.jpg' srcset=' /site/assets/files/1033/placeholder-city.369x266-srcset.webp 369w, /site/assets/files/1033/placeholder-city.687x496-srcset.webp 687w, /site/assets/files/1033/placeholder-city.691x499.webp 883w' > In your example, the image isn't being resized as portrait, so it is odd that the sizes attribute is being added. What settings do you have in the module config for Portrait mode? Are you on the latest version of the module (1.01)? Cheers, Chris
  19. Thanks @LAPS, have added that to my master copy and will add it to the repo soon.
  20. Hi @LAPS, Have a look at new() in WireMailTools. This is where the WireMail module is set either explicitly through a passed option or config setting, or inferred. Going by your first post, I think you may be able to set $config->wireMail, so it just uses default WireMail. Cheers, Chris
  21. @LAPS, @adrian - I only use WireMailgun and don't use ProMailer, so I'm not the best person to check with... However, as I understand it, any WireMail module installed supersedes the core WireMail functionality. For example, system error / forgot password emails we receive are sent through Mailgun. I've no idea how multiple WireMail modules are handled, but I assume that ProMailer gives you the option to choose which to use? Cheers, Chris
  22. Hi, this module is now in Beta. Still to add full documentation and Facebook App tips. Aiming to complete by the end of the week!
  23. Hi, I've updated this module with a lot of progress - still should be considered alpha, but should be ready for production soon. Cheers, Chris
  24. Hi @montero4, That all makes sense. You can also do the following: // Create an image variation 1200px wide with -srcset suffix $image = $page->image->width(1200, ["suffix" => "srcset"]); echo "<img src='$image->url' alt='$alt_text' srcset='$image->srcset'>"; // PageimageSrcset will use the original to generate the srcset value If you have a look at the Pageimage options, you can add a suffix to the filename when resizing. Cheers, Chris
  25. Hi @montero4, I'm sorry, I'm still not following? There's nothing stopping you changing the src - you should resize the image first: // Get the image $image = $page->images->first; // Resize the image $image = $image->size(1024, 468); // Output the image echo "<img src='$image->url' alt='$image->description' srcset='$image->srcset'>"; // Or alternatively echo $image->render(); PageimageSrcset recognises that it is an image variation and then uses the original to generate srcset variations. It isn't really this module's job to handle the src attribute. In theory you could do some manipulations of the "srcset" value to extract the first or last image for use, but I'd say it is a lot cleaner just to resize the image. Cheers, Chris
  • Create New...