Jump to content

Leaderboard

Popular Content

Showing content with the highest reputation on 04/28/2019 in all areas

  1. @ryan, may I point you to a WebP pull request? https://github.com/processwire/processwire/pull/141 And a ".htaccess only solution" for site wide webp support: https://processwire.com/talk/topic/14236-webp-support/page/2/?tab=comments#comment-184669 ?
    5 points
  2. Just a brief update today. I’m going to give it another week before bumping the core version, as I don’t think there’s enough changes yet to warrant a version bump. For whatever reason, several of my clients have needed integration with Stripe (payments) over the last few weeks. I’d not worked with it before the last month or so, but now all of the sudden am working with it a lot, because that's what my clients have asked for. I’ve found myself working on four different Stripe integrations on existing PW sites, both Stripe Elements and Stripe Checkout. None of these are for sites that have an actual “store” where they would need a cart, but rather just “pay for your reservation”, “buy this book”, “buy this song”, and “make a donation of $10”, “make a recurring donation”, type things. After doing a few of these, I thought it would make a lot of sense to have this built into FormBuilder, which would save us time on this stuff. So this week I built Stripe support into FormBuilder (using the Stripe Elements API). It’s already fully functional, so I will be releasing a new version of FormBuilder with this capability quite soon. To add a Stripe payment input to your form you just add a new field of type “Stripe payment for FormBuilder”, and then it asks you for some info about it (like amount to charge) and then your form works as a payment processor. Stripe has a clever way of making this all work, so that the user never leaves your site, but your site (and FormBuilder) never sees credit card numbers or anything like that, so it’s secure and you don’t have to consider things like PCI compliance. I've also got some other unrelated updates for FormBuilder that I'll be covering soon as well. Have a great weekend!
    3 points
  3. I have recently started to integrate Twig in my ProcessWire projects to have a better separation between logic and views as well as have cleaner, smaller template files as opposed to large multi-purpose PHP-templates. Though there is a Twig module, I have opted to initialize twig manually to have more control over the structure and settings of the twig environment. This is certainly not required to get started, but I find that having no "secret sauce" gives the me as a developer more agency over my code structure, and better insights into how the internals of the libraries I'm using work. Framework like Drupal or Craft have their own Twig integration, which comes with some opinionated standards on how to organize your templates. Since Twig is not native to ProcessWire, integrating Twig requires one to build a solid template structure to be able to keep adding pages and partials without repeating oneself or having templates grow to unwieldy proportions. This will be an (opinionated) guide on how to organize your own flexible, extensible template system with ProcessWire and Twig, based on the system I developed for some projects at work. Somehow this post got way too long, so I'm splitting it in two parts. I will cover the following topics: Part 1: Extendible template structures How to initialize a custom twig environment and integrate it into ProcessWire How to build an extendible base template for pages, and overwrite it for different ProcessWire templates with custom layouts and logic How to build custom section templates based on layout regions and Repeater Matrix content sections Part 2: Custom functionality and integrations How to customize and add functionality to the twig environment How to bundle your custom functionality into a reusable library Thoughts on handling translations A drop-in template & functions for responsive images as a bonus However, I will not include a general introduction to the Twig language. If you are unfamiliar with Twig, read the Twig guide for Template Designers and Twig for Developers and then come back to this tutorial. That's a lot of stuff, so let's get started ? Initializing the Twig environment First, we need to install Twig. If you set up your site as described in my tutorial on setting up Composer, you can simply install it as a dependency: composer require "twig/twig:^2.0" I'll initialize the twig environment inside a prependTemplateFile and call the main render function inside the appendTemplateFile. You can use this in your config.php: $config->prependTemplateFile = '_init.php'; $config->appendTemplateFile = '_main.php'; Twig needs two things: A FilesystemLoader to load the templates and an Environment to render them. The FilesystemLoader needs the path to the twig template folder. I'll put my templates inside site/twig: $twig_main_dir = $config->paths->site . 'twig'; $twig_loader = new \Twig\Loader\FilesystemLoader($twig_main_dir); As for the environment, there are a few options to consider: $twig_env = new \Twig\Environment( $twig_loader, [ 'cache' => $config->paths->cache . 'twig', 'debug' => $config->debug, 'auto_reload' => $config->debug, 'strict_variables' => false, 'autoescape' => true, ] ); if ($config->debug) { $twig_env->addExtension(new \Twig\Extension\DebugExtension()); } Make sure to include a cache directory, or twig can't cache the compiled templates. The development settings (debug, auto_reload) will be dependent on the ProcessWire debug mode. I turned strict_variables off, since it's easier to check for non-existing and non-empty fields with some parts of the ProcessWire API. You need to decide on an escaping strategy. You can either use the autoescape function of twig, or use textformatters to filter out HTML tags (you can't use both, as it will double escape entities, which will result in a broken frontend). I'm using twig's inbuilt autoescaping, as it's more secure and I don't have to add the HTML entities filter for every single field. This means pretty much no field should use any entity encoding textformatter. I also added the Debug Extension when $config->debug is active. This way, you can use the dump function, which makes debugging templates much easier. Now, all that's left is to add a few handy global variables that all templates will have access to, and initialize an empty array to hold additional variables defined by the individual ProcessWire templates. // add the most important fuel variables to the environment foreach (['page', 'pages', 'config', 'user', 'languages', 'sanitizer'] as $variable) { $twig_env->addGlobal($variable, wire($variable)); }; $twig_env->addGlobal('homepage', $pages->get('/')); $twig_env->addGlobal('settings', $pages->get('/site-settings/')); // each template can add custom variables to this, it // will be passed down to the page template $variables = []; This includes most common fuel variables from ProcessWire, but not all of them. You could also just iterate over all fuel variables and add them all, but I prefer to include only those I will actually need in my templates. The "settings" variable I'm including is simply one page that holds a couple of common settings specific to the site, such as the site logo and site name. Page templates By default, ProcessWire loads a PHP file in the site/templates folder with the same name of the template of the current page; so for a project template/page, that would be site/templates/project.php. In this setup, those files will only include logic and preprocessing that is required for the current page, while the Twig templates will be responsible for actually rendering the markup. We'll get back to the PHP template file later, but for the moment, it can be empty (it just needs to exist, otherwise ProcessWire won't load the page at all). For our main template, we want to have a base html skeleton that all sites inherit, as well as multiple default regions (header, navigation, content, footer, ...) that each template can overwrite as needed. I'll make heavy use of block inheritance for this, so make sure you understand how that works in twig. For example, here's a simplified version of the html skeleton I used for a recent project: {# site/twig/pages/page.twig #} <!doctype html> <html lang="en" dir="ltr"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>{% block title %}{{ '%s | %s'|format(page.get('title'), homepage.title) }}{% endblock %}</title> <link rel="stylesheet" type="text/css" href="{{ config.urls.site }}css/main.css"> </head> <body class="{{ page.template }}"> {% block navigation %}{{ include("components/navigation.twig") }}{% endblock %} {% block header %}{{ include("components/header.twig") }}{% endblock %} {% block before_content %}{% endblock %} {% block content %} {# Default content #} {% endblock %} {% block after_content %}{% endblock %} {% block footer %}{{ include("components/footer.twig") }}{% endblock %} </body> </html> All layout regions are defined as twig blocks, so each page template can override them individually, without having to touch those it doesn't need. I'll fill the content block with default content soon, but for now this will do. Now, templates for our content types can just extend this base. This is the template for the homepage: {# site/twig/templates/pages/page--home.twig #} {% extends "pages/page.twig" %} {# No pipe-seperated site name on the homepage #} {% block title page.get('title') %} {# The default header isn't used on the homepage #} {% block header %}{% endblock %} {# The homepage has a custom slider instead of the normal header #} {% block before_content %} {{ include('sections/section--homepage-slider.twig', { classes: ['section--homepage-slider'] }) }} {% endblock %} Note that I don't do most of the actual html markup in the page templates, but in individual section templates (e.g. section--homepage-slider.twig) that can be reused across content types. More on this in the next section. We still need to actually render the template. The page template (which will be the entry point for twig) will be loaded in our _main.php, which we defined as the appendTemplateFile earlier, so it will always be included after the template specific PHP file. $template_file = 'pages/page--' . $page->template->name . '.twig'; $twig_template = file_exists($twig_main_dir . '/' . $template_file) ? $template_file : 'pages/page.twig'; echo $twig_env->render($twig_template, $variables); This function checks if a specific template for the current content type exists (e.g. pages/page--home.twig) and falls back to the default page template if it doesn't (e.g. pages/page.twig). This way, if you want a blank slate for a specific content type, you can just write a twig template that doesn't extend page.twig, and you will get a blank page ready to be filled with whatever you want. Note that it passes the $variables we initialized in the _init.php. This way, if you need to do any preprocessing or data crunching for this request, you can do it inside the PHP template and include the results in the $variables array. At this point, you can start building your default components (header, footer, navigation, et c.) and they will be included on every site that extends the base page template. Custom sections Now we've done a great deal of setup but haven't actually written much markup yet. But now that we have a solid foundation, we can add layout components very easily. For most of my projects, I use the brilliant Repeater Matrix module to set up dynamic content sections / blocks (this is not the focus of this tutorial, here's a detailed explanation). The module does have it's own built-in template file structure to render it's blocks, but since it won't work with my Twig setup, I'll create some custom twig templates for this. The approach will be the same as with the page template itself: create a "base" section template that includes some boilerplate HTML for recurring markup (such as a container element to wrap the section content in) and defines sections that can be overwritted by section-specific templates. First, let's create a template that will iterate over our the Repeater Matrix field (here it's called sections) and include the relevant template for each repeater matrix type: {# components/sections.twig #} {% for section in page.sections %} {% set template = 'sections/section--' ~ section.type ~ '.twig' %} {{ include( [template, 'sections/section.twig'], { section: section }, with_context = false ) }} {% endfor %} Note that the array syntax in the include function tells Twig to render the first template that exists. So for a section called downloads, it will look look for the template sections/section--downloads.twig and fallback to the generic sections/section.twig. The generic section template will only include the fields that are common to all sections. In my case, each section will have a headline (section_headline) and a select field to choose a background colour (section_background) : {# sections/section.twig #} {% set section_classes = [ 'section', section.type ? 'section--' ~ section.type, section.section_background.first.value ? 'section--' ~ section.section_background.first.value ] %} <div class="{{ section_classes|join(' ')|trim }}"> <section class="container"> {% block section_headline %} {% if section.section_headline %} <h2 class="section__headline">{{ section.section_headline }}</h2> {% endif %} {% endblock %} {% block section_content %} {{ section.type }} {% endblock %} </section> </div> This section template generates classes based on the section type and background colour (for example: section section--downloads section--green) so that I can add corresponding styling with CSS / SASS. The specific templates for each section will extend this base template and fill the block section_content with their custom markup. For example, for our downloads section (assuming it contains a multivalue files field download_files): {# sections/section--download.twig #} {% extends "sections/section.twig" %} {% block section_content %} <ul class="downloads"> {% for download in section.download_files %} <li class="downloads__row"> <a href="{{ download.file.url }}" download class="downloads__link"> {{ download.description ?: download.basename }} </a> </li> {% endfor %} </ul> {% endblock %} It took some setup, but now every section needs only care about their own unique fields and markup without having to include repetitive boilerplate markup. And it's still completely extensible: If you need, for example, a full-width block, you can just not extend the base section template and get a clean slate. Also, you can always go back to the base template and add more blocks as needed, without having to touch all the other sections. By the way, you can also extend the base section template from everywhere you want, not only from repeater matrix types. Now we only need to include the sections component inside the page template {# pages/page.twig #} {% block content %} {% if page.hasField('sections') and page.sections.count %} {{ include('components/sections.twig' }} {% endif %} {% endblock %} Conclusion This first part was mostly about a clean environment setup and template structure. By now you've probably got a good grasp on how I organize my twig templates into folders, depending on their role and importance: blocks: This contains reusable blocks that will be included many times, such as a responsive image block or a link block. components: This contains special regions such as the header and footer that will probably be only used once per page. sections: This will contain reusable, self-contained sections mostly based on the Repeater Matrix types. They may be used multiple times on one page. pages: High-level templates corresponding to ProcessWire templates. Those contain very little markup, but mostly include the appropriate components and sections. Depending on the size of the project, you could increase or decrease the granularity of this as needed, for example by grouping the sections into different subfolders. But it's a solid start for most medium-sized projects I tackle. Anyway, thanks for reading! I'll post the next part in a couple of days, where I will go over how to add more functionality into your environment in a scalable and reusable way. In the meantime, let me know how you would improve this setup!
    2 points
  4. @horst Thanks Horst that's great news!
    2 points
  5. It's not quite that simple for a few reasons. Repeater pages are not directly accessible for non-superusers meaning that selector won't work for guests. So you'd need to specify "include=all", but then you'd also need to exclude any unpublished or "ready" repeater pages with "status!=unpublished". Also, the selector would match all repeater items from that field from all pages, when probably what is wanted is only items from one page. So then you'd need to match repeater pages under only one parent, maybe by building the name of the parent from "for-page-" plus the ID of the page you want the repeater items from. But the simplest way and only marginally less efficient is to match by the IDs of the repeater pages in the field value: $results = $pages->find("id=$page->feedback_repeat, include=all, limit=10");
    2 points
  6. Please can someone test the .htaccess solution for WebP support in other environments? It is not much work, you don't have to install test branches or anything else. You only need to copy some lines into your .htaccess file and create a single webp image with the tool of your choice. Or if you don't have a converter tool for webp, simply make a copy of a jpeg and rename it with type .webp instead of .jpg. Steps to proceed: Copy the rewrite directives into the top of your .htaccess file Grab any image variation you already have embedded into a PW site, create a webp variation of and save it into the same assets/files/{ID}/ folder. (Maybe you want to invert the colors of the webp copy for better detection!) Create or go to a page where this image should be rendered as jpeg in a regular img tag, and look if the webp copy is served and displayed. (Don't forget to flush browser caches) The .htaccess code: My matched.php for debugging: Examples in Opera with opened Network-Tab, requesting one image that has a webp copy, and requesting the second image that do not have a webp copy: Same page in Opera and old IE11: If we have a wider test case, the chance that this can be embedded into the PW .htaccess file for optional usage (commented by default) would be helpful for many users to support webp with less effort on their sites!
    2 points
  7. Confession bear meme on tests: I'm a virgin. Never implemented any of them, mostly because I work alone for many years now. But found this cool project today, called Cypress. This is the easiest way to test a website or app I've found. Check their intro video out: https://docs.cypress.io/guides/getting-started/writing-your-first-test.html Note: I recommend this Chrome extension to speed up videos: https://github.com/igrigorik/videospeed as the narration of this video is kinda slow. ?
    2 points
  8. I have sent a pull request on github for webP support in the core: https://github.com/processwire/processwire/pull/141 Explanation of its usage: I implemented two new options for the imagesizer that can be set globally in the site/config.php or can be passed within an individual options array to any size-method: $options = [ "webpAdd" => true, // boolean, if true, an additional webp variation will be created "webpQuality" => 80 // integer range 0 - 100, 100 is best ]; This creates an additional webp variation file besides the regular JPEG, PNG or GIF variations. In the template files you have two new image properties to work with the webp variation: $image->hasWebp; // boolean, true indicates that a webp variation is available for that image variation ?> <img src="<?= $image->srcWebp ?>" alt="" /> So we can create conditional markup like in this example: $image = $page->images->first()->size(300, 300); ?> <picture> <?php if($image->hasWebp) { ?> <source srcset="<?=$image->srcWebp?>" type="image/webp" /> <?php } ?> <source srcset="<?=$image->src?>" type="image/jpeg" /> <img src="<?=$image->url?>" alt="Alt Text!" /> </picture> The pull request and my test branch are based on this weeks pw dev branch. So if someone want to test it, please grab a copy, play with it and report back here. I don't know what timeline @ryan has and what parts need to be modified / rearanged, etc. Maybe the property names or the option names will be changed, but I think the main functionality will be close to that in the current test branch. ----- And here are a filesize comparision with different quality settings and with both engines, GD-Lib and IMagick: EDIT: An approach without conditional markup for webp comes from @arjen see lazyload. ...
    2 points
  9. I think the Github acquisition all ties back to selling Cloud and other services to the Developer community. MS is now a services company as Nadella likes to state. I guess future iterations of Github where it integrates with Azure and other MS Products will be the telltale sign
    1 point
  10. I'm doing something similar with MobaXterm. My dev machine for this project is an Acer W10 laptop, then I use MobaXTerm's VNC (as well as SSH & SFTP tools) to remote into a CentOS 7 server running TigerVNC server. If using VNC, you should set it to only serve on localhost, then you're SSH-ing into that securely. Haven't tried VcXsrc, but VNC in this setup has no noticeable latency. While I also have Ubuntu running though Windows Subsystem for Linux (WSL) on my dev machine, the MobaXTerm tools wrap up the remote access tools in a decent desktop GUI, and also serve as a good multi-tabbed, configurable terminal frontend to WSL (which appears to use the same basic wretched Windows teminal as CMD.exe). Coder.com looks interesting, will have to check that out!
    1 point
  11. Yes exactly @szabesz, ProFields Table (no pages involved). I also get confused haha
    1 point
  12. I do some tests with custom code because I need a simple way to set (recursive) fields to view for different page types and fields. public function ___WireToArray($obj, $filter = array()) { $values = array(); foreach ($obj AS $item) { $array = array(); foreach ($filter AS $key => $val) { if (is_array($val)) { $array[$key] = WireToArray($item->$key, $val); } else { $string = (string)$item->$val; $array[$val] = strpos($string, '|') ? explode('|', $string) : $string; } } $values[] = $array; } return $values; } I built a module which used that way: $userFilter = array('id', 'name', 'email', 'roles' => array('id', 'name')); $pages->find('template=user')->toJSON($userFilter, JSON_PRETTY_PRINT) Output [ { "id": "40", "name": "guest", "email": "", "roles": [ { "id": "37", "name": "guest" } ] }, { "id": "41", "name": "admin", "email": "andre.hoeg@gmail.com", "roles": [ { "id": "37", "name": "guest" }, { "id": "38", "name": "superuser" } ] } ] Example with images $wa = $pages->find('template=basic-page'); $filter = array( 'id', 'name', 'images' => array('url', 'width', 'height'), 'files' => array('url', 'name', 'filesize'), 'pageref', ); Output [ { "id": "1016", "name": "test1", "images": [ { "url": "\/site\/assets\/files\/1016\/dscn2585.jpg", "width": "4608", "height": "3456" }, { "url": "\/site\/assets\/files\/1016\/dscn2823.jpg", "width": "4608", "height": "3456" } ], "files": [ { "url": "\/site\/assets\/files\/1016\/aufstellung_und_taktische_aufgaben.pdf", "name": "aufstellung_und_taktische_aufgaben.pdf", "filesize": "68628" }, { "url": "\/site\/assets\/files\/1016\/1und1_leistungsbeschreibung_mobilfunk.pdf", "name": "1und1_leistungsbeschreibung_mobilfunk.pdf", "filesize": "207816" } ], "pageref": [ "1017", "27" ] }, { "id": "1017", "name": "test2", "images": [ { "url": "\/site\/assets\/files\/1017\/dscn2813.jpg", "width": "4608", "height": "3456" } ], "files": [], "pageref": "" } ] Because Pageimages and Pagefiles are based on WireArray it's possible to get just images as JSON $img = $page->images; $imgFilter = array('url', 'name', 'filesize', 'width'); $img->toJSON($imgFilter); Output [ { "url": "\/site\/assets\/files\/1016\/dscn2585.jpg", "name": "dscn2585.jpg", "filesize": "4085826", "width": "4608" }, { "url": "\/site\/assets\/files\/1016\/dscn2823.jpg", "name": "dscn2823.jpg", "filesize": "3225062", "width": "4608" } ]
    1 point
  13. That's exactly the post I remembered! At least on Table field 0.1.4 you can enable it in the Details tab.
    1 point
  14. It's working here in Laragon, Windows. But won't this have the effect that if a visitor saves the image from their browser they will be saving a WEBP image with a JPG (PNG, GIF, etc) file extension? Might cause some confusion.
    1 point
  15. I get this kind of error when... 1) I re-use a laragon www site name. If I ever used site name projectabc, delete it and use it again, I often end in database problems. So... if you already used it before, try another name. 2) I use protected names. I once had an older profile in which some field names were protected names. One was limit, one was modules and another one I can't remember. I looked into the install.php or install.sql, tried to find these fields, changed their names to something not-protected and everything worked well. 3) I have cached files in that profile. /site/assets/ has several cache folders and maybe even session folders. I don't know why but my profile had tons of these cached files. I deleted them it worked. Another thing... in install.php (if I remember correctly) is a flag which enables kind of a debug installations that only checks so you can find errors way easier.
    1 point
  16. Are you sure? I'd love to know how to enable this if possible. All I could find is this post: https://processwire.com/blog/posts/fieldtype-pagination/ Quote: However, because it's being added as a core capability, it's likely we'll be supporting the same in other Fieldtypes like Repeater, Repeater Matrix, PageTable, Multiplier, Files and Images. So this "likely we'll be supporting" statement never seemed to become reality.
    1 point
  17. $results = $pages->find('template=repeater_your_repeater_field, limit=10'); $content = $results->each(function($item) { $out = "<h2>{$item->title}</h2>"; $out .= "<p>{$item->title}</p>"; return $out; }); $pagination = $results->renderPager(); d($content); d($pagination);
    1 point
  18. For mac apps I can also recommend https://paw.cloud/.
    1 point
  19. Just found another nice tool for debugging rest apis: https://insomnia.rest/
    1 point
  20. Hi @Tom. the new code is online in my test branch. And following is a test with also the .htaccess solution installed. My template code: <?php $image1 = $page->images->first->size(100, 100, $options); ?> <img src="<?=$image1->url?>" alt="<?=$image1->alt?>" /> <img src="<?=$image1->url?>?skiprewrite" alt="<?=$image1->alt?>" /> <?php $image2 = $page->images->first->size(100, 100, $options); ?> <img src="<?=$image2->url?>" alt="<?=$image2->alt?>" /> <img src="<?=$image2->url?>?skiprewrite" alt="<?=$image2->alt?>" /> The quality settings for the regular variation is set to 10, it is created first in the image engines. The webpQuality was set to 100, and it is created after the regular variation. The following screen first shows the webp copy and due to the "?skiprewrite" GET varname, it shows the (distorted) jpegs at second place. Once with GD and once with IMagick: I really love the .htaccess only solution! With this, you simply can update any existing site by upgrade to the new PW core that include the webp support and running a maintenance script over all image variations to create the webp copies. After that you are done! ?
    1 point
  21. I have played with a .htaccess only solution to serve WEBP instead of JPEGs or PNGs. This way you can - leave your existing template markup untouched, and the apache_rewrite will - detect if the browser supports WEBP - if a WEBP copy is available for a JPEG or PNG image. Locally it's working out nicely! ? This markup automatically serves a WEBP copy to all browsers that support it: $options = ['webpAdd'=>true, 'webpQuality'=>90]; $image = $page->images->first()->size(300, 300, $options); // this will create a 300x300 Thumb for JPEGs and PNGs with an additional WEBP copy ?> <img src="<?=$image->src?>" alt="<?=$image->alt?>" /> <!-- this will serve the WEBP image to all Browsers that supports it, and the JPEG/PNG to other browsers --> AddType image/webp .webp <IfModule mod_rewrite.c> RewriteEngine On AddDefaultCharset UTF-8 ### Redirect regular PW JPEGs and PNGs to their WEBP image copies, ### if available and if the Browser supports WEBP: ## Does Browser accept WEBP images? RewriteCond %{HTTP_ACCEPT} image/webp ## Is it an existing file? RewriteCond %{REQUEST_FILENAME} -f ## Does a WEBP copy exist for it? RewriteCond %{DOCUMENT_ROOT}/$1$2$3/$4.webp -f ## With an added GET var or GET value of skiprewrite we do send the original JPEG or PNG RewriteCond expr "! %{QUERY_STRING} -strmatch '*skiprewrite*'" ## With an added GET var or GET value from the PW Page Editor, we do send the original JPEG or PNG RewriteCond expr "! %{QUERY_STRING} -strmatch 'nc=*'" ## Is it a regular PW JPEG or PNG image, stored under site/assets/files? RewriteRule ^(.*?)(site/assets/files/)([0-9]+)/(.*)\.(jpe?g|png)(.*)$ /$1$2$3/$4.webp [L] </IfModule> Adding a GET var or GET value with the string "skiprewrite" added to an image bypasses serving the WEBP copy in favour for the original variation. (Maybe useful for debug purposes!)
    1 point
  22. Hello, this module has been updated to conform to recent Facebook regulations that won't allow publishing content on a user profile. Instead, a post may be published on a Facebook page by the Facebook page only. To set it up, configure the module with a Facebook app ID, secret and a Page ID. Following is additional configuration on Facebook for developers: Minimum Required Facebook App configuration: on Settings -> Basics, provide the App Domains, provide the Site URL, on Settings -> Advanced, set the API version (has been tested up to v3.3), add Product: Facebook Login, on Facebook Login -> Settings, set Client OAuth Login: Yes, set Web OAuth Login: Yes, set Enforce HTTPS: Yes, add "https://www.example.com/processwire/page/" to field Valid OAuth Redirect URIs.  You may also view the revised first post of this topic. Thank you for your valuable input and I hope this update helps! Kind regards, Dimitrios
    1 point
  23. I'd say it's... GOOD! Today Microsoft isn't the Microsoft it was decades ago and Microsoft does a lot of things right nowadays. They listen. They deliver. They do better than Apple. Microsoft has the money to keep Github up and running. I'd be much more concerned if it was Facebook, Oracle, IBM, SAP, Adobe, Amazon, Apple, Alibaba (and similar) or several others. Who would have been better... Canonical, RedHat, any other free software foundation or company? I don't think so. Update: just saw that Nat Friedman will be part of the new team. This is awesome.
    1 point
  24. Dates are stored as timestamp not in the format you specify. It will be formated when output. So you would have to use a timestamp to use in the selector. For recieving page of today, you would have to create a start and end time range and use them in the selector. <?php $start = strtotime( date('Y-m-d') . " 00:00:00"); $end = strtotime( date('Y-m-d') . " 23:59:59"); $items = $pages->find("template=linkmain,publishdate>=$start,publishdate<=$end,sort=-userid"); haven't tested it but should work along these lines
    1 point
  25. Many thanks for your swift and detailed reply , Ryan. With a couple of minor changes your code works fine. I have to check the count was above 0, and pass the starttime into $date. This is what worked for me: <?php $channel = $pages->get("/news/"); $startYear = date("Y"); // this year $endYear = 2009; // or whenever you want it to end $now = time(); for($year = $startYear; $year >= $endYear; $year--) { for($month = 12; $month > 0; $month--) { $startTime = strtotime("$year-$month-01"); // 2011-12-01 example if($startTime > $now) continue; // don't bother with future dates if($month == 12) $endTime = strtotime(($year+1) . "-01-01"); else $endTime = strtotime("$year-" . ($month+1) . "-01"); $entries = $channel->children("created>=$startTime, created<$endTime"); // or substitute your own date field $date = date("F, Y",$startTime); $url = "/news/" . date("Y",$startTime) . "/" . date("m",$startTime); $count = count($entries); if($count > 0) echo "<li><a href='$url'>$date <b>" . $count . "</b></a></li>"; // output the month and count } }
    1 point
  26. Hi Stephen, Welcome to the forums and good question. Here's one way you could approach it, assuming all those posts were under the same page (like /blog/). I'm somewhat limited on time right now, so this is written in the browser and not tested, but I can follow up with more detail later if you'd like. <?php $blog = $pages->get("/blog/"); $startYear = date("Y"); // this year $endYear = 2009; // or whenever you want it to end $now = time(); for($year = $startYear; $year >= $endYear; $year--) { for($month = 12; $month > 0; $month--) { $startTime = strtotime("$year-$month-01"); // 2011-12-01 example if($startTime > $now) continue; // don't bother with future dates if($month == 12) $endTime = strtotime(($year+1) . "-01-01"); else $endTime = strtotime("$year-" . ($month+1) . "-01"); $entries = $blog->children("created>=$starttime, created<$endTime"); // or substitute your own date field $date = date("m-Y"); echo "<li><a href='./$date'>$date - " . count($entries) . "</a></li>"; // output the month and count } } Then you'd use the same template to list the entries when a $input->urlSegment1 has a date specified in it. Basically you'd cycle through the $entries found above and link to them. This is rough and just approximate. I'll be glad to follow up with more detail... but wife is telling me to get off the computer.
    1 point
×
×
  • Create New...