Jump to content

Leaderboard

Popular Content

Showing content with the highest reputation on 04/20/2018 in all areas

  1. Hi, just wanted to share something I came across while working on an import module for XML data from a web service. The XML I got was not huge, but still, loading around 3.5 MB of XML with 250+ large child nodes into memory at once with simplexml_load_file() and then looping over it had significant impact on performance. I searched for a solution and found this great article about how to parse large XML files. It basically explains how to utilize the native XMLReader class together with SimpleXMLElement to handle such situations in a memory efficient way. After implementing it I got a significant improval on perceived performance. No comparison in numbers to share here as I'm a bit short on time.
    10 points
  2. This week's version of ProcessWire on the dev branch includes some useful updates to the included AdminThemeUikit module. It also adds a new config setting for disabling HTTPS requirements in dev/staging environments, as well as some other updates: https://processwire.com/blog/posts/pw-3.0.99/
    7 points
  3. One way to do something like that is with the repeater field. You have a repeater field and the repeater has two page ref fields (people, roles). And you repeat the fields for every person. The way i described in my first comment the roles field would go to the people template, so on the video page you would only have the people field. You add a person and then click on it, a modal opens to edit the persons page where you can set the role.
    4 points
  4. Up until now not one of the many softwares on github that I have been using even had branding attached. With pro modules the user knows exactly what to expect: buy and then use. With free modules that ask for money to remove brandings, the user could feel tricked. I'd rather prefer that for the same reason mentioned above. I happily pay for pro modules and use them a lot. I totally respect the way you see things in this matter and it is your freedom as a module developer to handle things like you do. Just wanted to share my thouights and feelings about it and explain some negative views people might have on your approach, especially since it is the first time I come across this in the PW module world. Enough said. Thank you for everything you're giving to the community and keep up the great work!
    4 points
  5. According to the image above. // loop over repeater items // repeater is the name of my repeater field foreach ($page->repeater as $r) { // person is the name of my page ref field for selecting persons // can hold a single page (can be set in field's settings, details tab) echo $r->person->title, " "; // skills is the name of my page ref field for selecting skills // can hold multiple pages so we have to loop (can be set in field's settings, details tab) foreach ($r->skills as $s) { echo $s->title, " "; } // or use eq echo $r->skills->eq(0)->title, " "; echo $r->skills->eq(1)->title, " "; } // outputs // Jim Programmer Designer Programmer Designer
    3 points
  6. I know this may sound strange, but when it comes to https and redirects browsers become very "cachehappy"! When running into problems with this I use the browsers incognito/private mode, have to empty cache, restart browser, use different browser, use a VPN, and so on. Tiresome sometimes...
    3 points
  7. Not a big problem, but the only other thing I would say is: imagine if every PW module developer did this. Would it be cool if there was an extra branding link in every MarkupSimpleNavigition menu? Maybe nobody would use that module then...
    3 points
  8. I think you need quotes to get accurate results. How about this one: https://nerdydata.com/search?query="%2Fsite%2Fassets%2Ffiles%2F" Although I don't think the total count is relevant, but definitely show some sites I haven't seen, especially of interest is: https://www.payrexx.com/
    3 points
  9. It would be great if an optional text field will be added to the inputfield integer to add additional text next to the integer field (fe. weeks, days,..). Multilanguage support would be nice .
    2 points
  10. Sorry, please try to rename your module's folder to "RockFinder" instead of "RockSqlFinder"
    2 points
  11. 2 points
  12. Of course it works. getForpage() returns the page where the repeater item lives. your code snippet was not clear to me, so you might use it differently, but using getForpage() is the key. You didn't provide any information of what your code does, which variables are what kind of data (pages, repeater items) etc.; Also you didn't provide information what you did exactly (where you placed my code) and what did not work. "doesn't work" is not a lot of information... Yes, that's correct and totally makes sense, since it is a repeater item and not a page with a parent page.
    2 points
  13. I wouldn't consider forking an open source project and amending it to one's need as bad karma at all. This is what places like github, gitlab etc. is all about. I have to agree with @Robin S For me personally, it feels wrong having obligatory powered by links in a free module in the PW universe. You see that very rarely here. It is more common on other platforms, e.g. Joomla, and this was one of the many reasons that drove me away from there. Most of my clients do not accept links like that on their website. Contacting the developer to have this removed would cost extra time, both for me and the developer. So why not make it optional in the first place? I understand that this is a way to generate backlinks which generate traffic which generates attention and ideally more jobs which in the end generate money. But, again, it does not feel right to me to use a free PW module for that purpose. I totally appreciate the time that developers spend on releasing free modules and this is the spirit that makes projects like PW stand out. To generate income from a module one can always release a paid version. Free versions shouldn't have any strings attached.
    2 points
  14. I have used the script below to do that, but must emphasise that this is destructive. The script does copy the original image to a "for_deletion" folder in the site root, but in case of disaster it would be a big PITA to go through and put the original images back to their relevant pages. So use at your own risk! // You could run this script manually, or put it on LazyCron if you have a lot of images // Maximum image dimensions $max_width = 1600; $max_height = 1600; // Images to process per operation $limit = 5; // Create array of large images $large_images = []; $i = 1; foreach($fields->find("type=FieldtypeImage") as $field) { if(!count($field->getFieldgroups())) continue; foreach($pages->find("{$field->name}.count>0") as $p) { foreach($p->getUnformatted($field->name) as $image) { if($i > $limit) break; if($image->width > $max_width || $image->height > $max_height) { $large_images[] = [ 'basename' => $image->basename, 'filename' => $image->filename, 'page' => $p->url, ]; $i++; } } } } // Iterate over images foreach($large_images as $large_image) { // Make backup copy of image (create the "for_deletion" folder first) $destination = $config->paths->root . 'for_deletion/' . $large_image['basename']; if(!file_exists($destination)) { $success = copy($large_image['filename'], $destination); // Don't carry on to the resizing stage if the copy wasn't successful if(!$success) continue; // Log file copy $log->save('resized_images', "Copied original image {$large_image['basename']} from {$large_image['page']} to /for_deletion/"); } /* @var ImageSizer $sizer */ $sizer = new ImageSizer($large_image['filename'], ['cropping' => false]); $sizer->resize($max_width, $max_height); // Log file resize $log->save('resized_images', "Resized image {$large_image['basename']} on page {$large_image['page']} to max width $max_width, max height $max_height"); } If you are using image field types besides the core FieldtypeImage you could modify the identification of image fields to something like this.
    2 points
  15. I have posted this link in some other thread, but as this thread also relevant leave it here Search by "X-Powered-By" header - 8599 https://publicwww.com/websites/"X-Powered-By%3A+ProcessWire"/ Seach by "site/assets/files" - 17384 https://publicwww.com/websites/"%2Fsite%2Fassets%2Ffiles%2F"/
    2 points
  16. ~488 websites listed here using ProCache: https://nerdydata.com/search?query=%2Fsite%2Fassets%2Fpwpc%2Fpwpc
    2 points
  17. $exhibitions->append($exhibition->getForpage());
    2 points
  18. Same here: I think they are really great! It makes the setup so much cleaner and more readable and also more flexible. For example I'm using a region "scriptsbottom" at the end of my <body> and whenever an included section needs some javascript I just write the markup and append the script to that region: // _main.php <region id="header"></region> [...] <script><region id="scriptsbottom"></region></script> // slider.php <section id="header">... my great slider markup ...</section> <region pw-append="scriptsbottom"> $('#slider').init(); </region> IMHO this is much more readable than using delayed output with php variables and then "messing" around with $config->scriptsbottom .= '$(\'#slider ... ' (doing some crazy escaping or ob_get_clean() or the like.
    2 points
  19. An Images field allows you to: Rename images by clicking the filename in the edit panel or in list view. Replace images, keeping metadata and filename (when possible) by dropping a new image on the thumbnail in the edit panel. Introduced here. But neither of these things is possible in File fields, which prompted this module. The way that files are renamed or replaced in this module is not as slick as in the Images field but it gets the job done. The most time-consuming part was dealing with the UI differences of the core admin themes. @tpr, gives me even more respect for the work that must go into AdminOnSteroids. Most of the code to support the rename/replace features is already present in InputfieldFile - there is just no UI for it currently. So hopefully that means these features will be offered in the core soon and this module can become obsolete. Files Rename Replace Allows files to be renamed or replaced in Page Edit. Usage Install the Files Rename Replace module. If you want to limit the module to certain roles only, select the roles in the module config. If no roles are selected then any role may rename/replace files. In Page Edit, click "Rename/Replace" for a file... Rename Use the text input to edit the existing name (excluding file extension). Replace Use the "Replace with" select to choose a replacement file from the same field. On page save the file will be replaced with the file you selected. Metadata (description, tags) will be retained, and the filename also if the file extensions are the same. Tip: newly uploaded files will appear in the "Replace with" select after the page has been saved. https://github.com/Toutouwai/FilesRenameReplace http://modules.processwire.com/modules/files-rename-replace/
    1 point
  20. As a web developer I always want to improve the search results of my websites in popular search engines. Because of that I find the topic of structured data very interesting and want to learn more about them. Recently I tried out a few of the ways how to provide more information to a website and want to share my solutions. Most of the structured data can be included directly in the markup or as JSON-LD at the end of your document (right before the closing body tag). I prefer the last one, because I don't like to have bloated HTML markup. Breadcrumbs Breadcrumbs are an alternative way to show the your page hierarchy inside search results, instead of showing just the plain URL. Just like the breadcrumbs on a website. Following the example, I ended up with this code: <?php if(strlen($page->parents()) > 0) { ?> <!-- Breadcrumbs --> <script type="application/ld+json"> { "@context": "http://schema.org", "@type": "BreadcrumbList", "itemListElement": [ <?php $positionCounter = 1; $separator = ','; foreach($page->parents() as $parent) { if($parent->id == $page->parents()->last()->id) { $separator = ''; } echo ' { "@type": "ListItem", "position": "' . $positionCounter . '", "item": { "@id": "' . $parent->httpUrl . '", "name": "' . $parent->title . '" } }' . $separator . ' '; $positionCounter++; } ?> ] } </script> <?php } ?> First I am checking if the page has parents, then I follow the follow the markup of the example. I save the position of each parent in the variable positionCounter and increase its amount after each loop. As a last step I tried to end the JSON objects by not include the separating comma after the last object. This is why I am using the separator variable. Site name and sitelinks searchbox Using JSON-LD you can provide an alternative site name and a sitelinks searchbox inside the search results (Inception ). <!-- WebSite --> <script type="application/ld+json"> { "@context": "http://schema.org", "@type": "WebSite", "name" : "Your site name", "alternateName" : "Your alternative site name", "url": "<?= $pages->get(1)->httpUrl ?>", "potentialAction": { "@type": "SearchAction", "target": "<?= $pages->get(1)->httpUrl ?>search/?q={search_term_string}", "query-input": "required name=search_term_string" } } </script> I am not 100% sure, if the sitelinks searchbox works this way. Maybe someone who made this work before could confirm it, that would help me out. Organization For organizations you could provide a logo and links to your social profiles. <!-- Organization --> <script type="application/ld+json"> { "@context": "http://schema.org", "@type" : "Organization", "name" : "Your organization name", "url" : "<?= $pages->get(1)->httpUrl ?>", "logo": "<?= $pages->get(1)->httpUrl ?>site/templates/images/logo.png", "sameAs" : [ "https://www.facebook.com/your-organization-url", "https://www.instagram.com/your-organization-url/" // All your social profiles ] } </script> This one I think is self explanatory. Article If you have an blog or a news site you could enhance your articles with structured data with an thumbnail and author. <?php if($page->template == "post") { ?> <!-- Article --> <script type="application/ld+json"> { "@context": "http://schema.org", "@type": "NewsArticle", "mainEntityOfPage": { "@type": "WebPage", "@id": "<?= $page->httpUrl ?>" }, "headline": "<?= $page->title ?>", "image": { "@type": "ImageObject", "url": "<?= $page->thumbnail->httpUrl ?>", // Image field in template "height": <?= $page->thumbnail->height ?>, "width": <?= $page->thumbnail->width ?> }, "datePublished": "<?= date('c', $page->created) ?>", "dateModified": "<?= date('c', $page->modified) ?>", "author": { "@type": "Person", "name": "<?= $page->createdUser->first_name . ' ' . $page->createdUser->last_name ?>" // Text fields added to core module ProcessProfile }, "publisher": { "@type": "Organization", "name": "Your organization name", "logo": { "@type": "ImageObject", "url": "<?= $pages->get(1)->httpUrl ?>site/templates/images/logo.png", "width": 244, // Width of your logo "height": 36 // Height of your logo } }, "description": "<?= $page->summary ?>" // Text field in template } </script> <?php } ?> Here I am enabling structured data for the template called post. I also have the text fields first_name and last_name added to the core module ProcessProfile, the image field thumbnail and the text field summary added to the template. Just a small note: I know you could use $config->httpHost instead of $pages->get(1)->httpUrl, but I found the second one more flexibel for changing environments where you have for example HTTPS enabled. Those are the structured data I have in use so far. I hope I haven't made a mistake, at least the testing tool doesn't complain. But if you find something, please let me know. I love how easy it is with ProcessWire to get all the information from various pages and use them in this context. As mentioned above, I am nowhere an expert with structured data, but maybe some of you would like to provide also some examples in this thread. Regards, Andreas
    1 point
  21. DEPRECATED - this module will not see any updates. I'm short before releasing RockGrid as commercial module. If you are interested contact me via PM this is a preview of a module that i'm working on for quite a long time. I needed it for an intranet office management application that i'm still working on. It makes it very easy to create very customized Datatables using the awesome jquery datatables plugin (www.datatables.net) Download - sorry, removed as it changes too frequently; closed alpha - contact me if you think you can contribute Remarks: The module is intended to be used on the backend. Loading styles is at the moment only done via adding files to the $config->styles/scripts arrays. Also the communicaton to javascript is done via the $config->js() method that is built into the admin and would have to be implemented manually on frontend use. But it would not be difficult of course Installation: Nothing special here, just download + install edit: removed some parts, because i made a complete rewrite of the module (and may not have been the last one)! [...] removed Why i created this module: of course i know @Soma s module but i needed a lot more features and the newer datatables version. also i like to define all the columns as objects and have everything on one place. lister & markupadmindatatable: nice for basic tables but lacks of features to modify the appearance of the cell values (like rendering icons, background colors and so on) datatables provides a great frontend API for filtering, showing/hiding columns, getting data, modifying it... it also plays well together with frontend charts like google chart api in this case: todo / roadmap: reload only one row add filters to all columns (in future also dropdowns, smaller than, bigger than, Regex, ...) make it possible to add table on frontend pages make buttons look like pw buttons make it possible to set settings globally and only for one table provide easy way of colorbars (percentage, red/green), maybe at different positions (left, top, right, bottom) provide easy way of adding action items (edit, show, link etc - visible or onhover) make own layout for tables (topleft, topright, bottom etc to make it easy to create extensions and show messages) privide way of simple javascript plugins (like I already have for row sums etc) provide easy way of handling actions for all selected items (delete selected, update selected...) provide easy way of reloading data (--> easy when using ajax source) easy way of showing/hiding columns excel/csv/clipboard export GUI for table setup processmodule to show different tables (lister replacement)
    1 point
  22. I'm with @Macrura as i'm using wireRenderFile() extensively with a dedicated /views/ folder where I can organise my output in components / atoms / whatever you want to call it, using templates (and sometimes /fields/field.php) more or less as controllers. @bernhard brings up some good points I haven't thought of though, especially the JS part - I awkwardly tucked that into wire('config')->scripts, which isn't as elegant / nice. Anway, it's great having the flexibility and options to use PW as you see fit Quite liberating.
    1 point
  23. 1 point
  24. Hi Bernhard and thanks for your attention. I used your tip in a bad way... now it works
    1 point
  25. I think the check for "NullPage" was wrong. We have to check for id<>0 https://processwire.com/api/ref/null-page/ Like this it works. $item= $this->wire('pages')->get('template=language,id=' . $lang_id); if($item->id) { $this->wire('user')->language = $lang_id; } Thank you.
    1 point
  26. Hi @Robin S - sorry about that. I can try to take a look tomorrow, but maybe in the meantime @Torsten Baldes could also see if there is an alternative to that commit of his that fixed the password issue, but not have the side-effect of breaking user saving?
    1 point
  27. Hi @adrian, just a heads up: I was again experiencing this issue that you raised in the PW issues repo a while ago: https://github.com/processwire/processwire-issues/issues/432 It was a bit puzzling but I traced it back to the Email New User module which I was testing out. Due to this commit the module is undoing the fix that was applied in the PW core.
    1 point
  28. i also stumbled on this issue! Needed a drink too! Even asked a few days ago why this behaves like this! https://processwire.com/talk/topic/14638-no-input-data-when-post-form-with-ajax/?tab=comments#comment-163444
    1 point
  29. This might help: https://processwire.com/blog/posts/august-2014-core-updates-4/#database-backup-capability-now-in-the-core https://processwire.com/blog/posts/august-2014-core-updates-4/#database-backups-module
    1 point
  30. Another year has passed... I was looking for a way to include database backup in my deployment process. I did not want to use some external secrets storage yet, so looked for a way to use db credentials already present in PW config. So I wrote a simple script, which I put in the project repo and call from cli during the deployment process like this: php -f backup.php For the sake of simplicity backup.php is in the web root. Here are its contents: <?php // backup.php include("index.php"); $backup = $database->backups(); $file = $backup->backup(); if($file) { echo "Backed up to: $file"; } else { echo "Backup failed: " . implode("<br>", $backup->errors()); } The full docs on how to customize it as you need should be here, but are now missing for some reason. One can still get them from the source code anyway) P.S. I am looking for a way to do it with a simple one-liner in cli to get rid of the backup.php, but not sure it is possible with php an easy way. Any advice appreciated! P.P.S. I knew I could do it, because @adrian done it in his wonderful Admin Actions module. Go read its code for inspiration and for education, if you are not a PW guru yet.
    1 point
  31. You access it like any other property of the field... ...or am I misunderstanding your question?
    1 point
  32. Looks cool, but I'm sort of addicted to the WireRender Pattern now... https://github.com/NinjasCL-processwire/wire-render-pattern https://medium.com/@clsource/the-wire-render-pattern-806bf6d6097a
    1 point
  33. I just relaunched my portfolio website. It's my first ajax driven website using ProcessWire as a CMS. Its a showcase of some of my work as well as a digital playground to improve my coding skills. If you encounter any bugs or have feedback, feel free to share janploch.de
    1 point
  34. This is just an idea I've been playing with a while: adding support for SOUNDS LIKE operator. I'm not sure how much sense it makes in the larger context, but I'm posting it here nevertheless in case it results in something useful As a bit of a background, in MySQL SOUNDS LIKE is just a shortcut for comparing two strings passed to SOUNDEX() and as Wikipedia kindly explains, "soundex is a phonetic algorithm for indexing names by sound, as pronounced in English". In other words, SOUNDEX() converts a string to an "index" of sorts, and comparing index values of two separate strings answers the question of "do these two sound alike (in English)". SOUNDS LIKE works best with English words, and literally words, since comparing entire sentences is often much less sensible (there's no native "wildcard soundex operator" in MySQL) -- names of people, products, countries, cities, etc. are a good example where one might benefit from SOUNDS LIKE. Cases I've really wished this would've been possible have included especially name and city searches, where people tend to mistype things a lot. Yesterday I decided that this would be a cool experiment, so I applied following hack to the DatabaseQuerySelectFulltext.php and Selector.php, making "€=" the SOUNDS LIKE operator. This is wrong at many levels, but works as a simple proof of concept: diff --git a/wire/core/DatabaseQuerySelectFulltext.php b/wire/core/DatabaseQuerySelectFulltext.php index 9c6064f..421f38a 100644 --- a/wire/core/DatabaseQuerySelectFulltext.php +++ b/wire/core/DatabaseQuerySelectFulltext.php @@ -83,6 +83,12 @@ class DatabaseQuerySelectFulltext extends Wire { $query->where("$tableField LIKE '%$v%'"); // SLOW, but assumed break; + case '€=': + $v = $database->escapeStr($value); + $v = $this->escapeLIKE($v); + $query->where("$tableField SOUNDS LIKE '$v'"); // SLOW, but assumed + break; + case '^=': case '%^=': // match at start using only LIKE (no index) $v = $database->escapeStr($value); diff --git a/wire/core/Selector.php b/wire/core/Selector.php index 31748f9..fccfe8a 100644 --- a/wire/core/Selector.php +++ b/wire/core/Selector.php @@ -204,6 +204,7 @@ abstract class Selector extends WireData { Selectors::addType(SelectorLessThanEqual::getOperator(), 'SelectorLessThanEqual'); Selectors::addType(SelectorContains::getOperator(), 'SelectorContains'); Selectors::addType(SelectorContainsLike::getOperator(), 'SelectorContainsLike'); + Selectors::addType(SelectorSoundsLike::getOperator(), 'SelectorSoundex'); Selectors::addType(SelectorContainsWords::getOperator(), 'SelectorContainsWords'); Selectors::addType(SelectorStarts::getOperator(), 'SelectorStarts'); Selectors::addType(SelectorStartsLike::getOperator(), 'SelectorStartsLike'); @@ -284,6 +285,10 @@ class SelectorContainsLike extends SelectorContains { public static function getOperator() { return '%='; } } +class SelectorSoundsLike extends SelectorContains { + public static function getOperator() { return '€='; } +} + /** * Selector that matches one string value that happens to have all of it's words present in another string value (regardless of individual word location) * Just for fun I've been testing this new operator with a script like this (and using one of the most mistyped names I've seen on this forum as a test subject), to see if it works at all: <?php require 'index.php'; foreach (wire('pages')->find('title€=antti') as $k => $p) { echo $k . ". " . $p->url . "\n"; } // results look something like this: // 0. /anttti/ // 1. /antti/ // 2. /anti/ // 3. /antii/ So, what do you folks think -- is there anything in this that might be worth taking further? Can you think of a better approach to this, such as a custom fieldtype with SOUNDS LIKE support, or something? Anything else?
    1 point
  35. Quick update: there's now a 2.0 branch and 2.0 milestone for this module at GitHub. For the time being the 2.0 branch is identical with master branch, but it's a start. I'm going to get another project I've been working on out there today, and after that I should have some time to work on VersionControl 2.0
    1 point
  36. Here is an alternative of editing the .htaccess file. You could use Jumplinks from @Mike Rockett and manage all of your 404 hits easily (as well all others redirects needed). OT: about the wp-login itself, you could create a page and a template for this, reproduce the WP login form and play a bit with the "hackers" by giving them a nice memes on login submission (last example: https://rockett.pw/jumplinks/examples)
    1 point
  37. I don't think it would resolve the issue. SHDB just saves to DB instead of the file-system. But PHP will still do one session request after another and probably uses db table locks instead of file locks (at least that's my guess). Are you using PW session functions or native PHP? Towards the bottom of this article there is PHP 7 option: session_start([ 'read_and_close' => true, ]); https://ma.ttias.be/php-session-locking-prevent-sessions-blocking-in-requests/ The author also mentions Redis (there's also a redis session handler db module for PW), but if you're not using it it won't be of much use...
    1 point
  38. I agree. I'd really like to be able to support ProcessWire and @ryan much more. We should have a git-backed documentation site. The Meteor Docs, as an example, are built in Hexo and managed on Github: https://docs.meteor.com We can then make sure it is up to date as a community instead of it resting on Ryan's shoulders.
    1 point
  39. Finally got a chance to try it and this module is great, and will solve innumerable content management conundrums.. Here's my first use, on a quotes rotator section: Field Config: var colheaders = ['Author', 'Publication', 'Quote']; hot.updateSettings({ colHeaders: colheaders, minCols: colheaders.length, maxCols: colheaders.length, rowHeaders: false, minRows: 1, minSpareRows: 1, maxRows: 5, width: 900, contextMenu: true, autoWrapRow: true, autoWrapCol: true, colWidths: [200,200,500], }); edit screen: output:
    1 point
  40. @Vayu Robins, to be honest I wouldn't be surprised if it wasn't. Repeaters, I believe, are somewhat supported, but Repeater Matrix is a lot more complex, at least as a concept. I'll look into this as soon as possible. @apeisa, I'll look into that image issue too. Unless that's really easy to fix, it might be time to release a 3.x branch of this module though. Could probably solve a bunch of things more cleanly now. API level tests still look good, so I'm thinking that this file issue might have something to do either with the "recent" UI updates, or perhaps the temp file thing..
    1 point
  41. fyi MySQL >= 5.7.8 supports searching inside JSON
    1 point
  42. @Macrura: Exactly that is the reason, why I want to dig deeper into this topic. I also noticed, that some WordPress themes for example provide a basic support for structured data. But mostly they are not very accurate and assume a lot of the data or generalize them. Luckily with the API of ProcessWire you have complete control of your data you want to use. If you have some examples you would like to share, feel free to do so. The main purpose of this thread was to see if some of you also want to share your experience with structured data. @Peter Knight: The benefit I noticed so far is that the search results provide more information (especially with breadcrumbs). But I don't have them in use for very long and Google takes its time to update their indexes, although they are fast compared to other search engines. So time will tell the difference. If you ever remember the article you have read, I would be interested in a link. @Craig A Rodway: Thank you for the hint. Using json_encode() is much more elegant than my original solution. I updated my code and you can see it below. This time I haven't separated my code into sections. Also there are probably still some thinks I can improve. <?php $homeUrl = $pages->get(1)->httpUrl; // Organization $organization = array( "@context" => "http://schema.org", "@type" => "Organization", "name" => "Your organization name", "url" => $homeUrl, "logo"=> "{$homeUrl}site/templates/images/logo.png", "sameAs" => [ "https://www.facebook.com/your-organization-url", "https://www.instagram.com/your-organization-url/" ] ); // WebSite $website = array( "@context" => "http://schema.org", "@type" => "WebSite", "name" => "Your site name", "alternateName" => "Your alternative site name", "url" => $homeUrl, "potentialAction" => [ "@type" => "SearchAction", "target" => "{$homeUrl}search/?q={search_term_string}", "query-input" => "required name=search_term_string" ] ); // Breadcrumbs $breadcrumbs; if(strlen($page->parents()) > 0) { $listItems = array(); $positionCounter = 1; foreach($page->parents() as $parent) { $listItems[] = [ "@type" => "ListItem", "position" => $positionCounter, "item" => [ "@id" => $parent->httpUrl, "name" => $parent->title ] ]; $positionCounter++; } $breadcrumbs = array( "@context" => "http://schema.org", "@type" => "BreadcrumbList", "itemListElement" => $listItems ); } // Article if($page->template == "post") { $article = array( "@context" => "http://schema.org", "@type" => "NewsArticle", "mainEntityOfPage" => [ "@type" => "WebPage", "@id" => $page->httpUrl ], "headline" => $page->title, "image" => [ "@type" => "ImageObject", "url" => $page->thumbnail->httpUrl, "height" => $page->thumbnail->height, "width" => $page->thumbnail->width ], "datePublished" => date('c', $page->created), "dateModified" => date('c', $page->modified), "author" => [ "@type" => "Person", "name" => "{$page->createdUser->first_name} {$page->createdUser->last_name}" ], "publisher" => [ "@type" => "Organization", "name" => "Your organization name", "logo" => [ "@type" => "ImageObject", "url" => "{$homeUrl}site/templates/images/logo.png", "width" => 244, "height" => 36 ] ], "description" => $page->summary ); } ?> <!-- Schema --> <!-- Organization --> <script type="application/ld+json"> <?= json_encode($organization, JSON_PRETTY_PRINT); ?> </script> <!-- WebSite --> <script type="application/ld+json"> <?= json_encode($website, JSON_PRETTY_PRINT); ?> </script> <?php if(strlen($page->parents()) > 0) { ?> <!-- Breadcrumbs --> <script type="application/ld+json"> <?= json_encode($breadcrumbs, JSON_PRETTY_PRINT); ?> </script> <?php } ?> <?php if($page->template == "post") { ?> <!-- Article --> <script type="application/ld+json"> <?= json_encode($article, JSON_PRETTY_PRINT); ?> </script> <?php } ?> Regards, Andreas
    1 point
×
×
  • Create New...