Jump to content

Leaderboard

Popular Content

Showing content with the highest reputation on 05/03/2018 in all areas

  1. Just add it to your template file... it's only html with javascript code (site/templates/yourtemplatefile.php)
    4 points
  2. Here is some code I used which is working fine: https://github.com/horst-n/LocalAudioFiles/blob/master/site-default/templates/local-audio-files_stream.php#L34-L45 https://github.com/horst-n/LocalAudioFiles/blob/master/site-default/templates/local-audio-files_stream.php#L264
    4 points
  3. This may come handy ? https://google-webfonts-helper.herokuapp.com/fonts
    3 points
  4. In the beginning of the year, I relaunched the website of P. Jentschura and it took some time to publish the case study for it, but here it is (only in german atm, but you could use a translator tool). Wie wir P. Jentschura halfen, die Conversion Rate zu erhöhen, neue Interessenten zu gewinnen und eine Erfolgsmessbarkeit einführten. Translated title: How we helped P. Jentschura to increase the conversion rate, win new customers and measure success. I plan to publish the case study in english also, but it could take some time.
    3 points
  5. You don't want to chain methods together like that if there is a chance that one of them will return something unexpected. What I mean is if $page->find('name=foo|bar') finds zero pages, then there will be no first() page, and you can't get the children() of nothing. So you want to break it up a bit more, e.g. $mypages = $page->find('name=foo|bar'); if($mypages->count) { $mychildren = $mypages->first()->children(); if($mychildren->count) { // do something with $mychildren } } Or seeing as you only want the children of a single page (the first) then you can shorten it a bit by using child() instead of find()... $mychildren = $page->child('name=foo|bar')->children(); if($mychildren->count) { // do something with $mychildren } (Actually, $page->find() is different than $page->child() or $page->children() in that it will find pages at any depth under $page, but in your case I think you want to get only a direct child of $page).
    3 points
  6. I ever use absolute urls, because then I can match them from within different located css files. Normally I store all fonts under /site/templates/styles/fonts/.
    2 points
  7. There's an issue with from headers that I still have on the back burner, so I'll take a look at encoding options when I tackle that. Might be a few weeks though, as I'm up to my neck in work since we switched ERP systems at my workplace yesterday.
    2 points
  8. Hi @php ! I'd like to recommend to you a free PHP course by Jeffrey Way, the guy behind Laracasts: https://laracasts.com/series/php-for-beginners I think you're going to love it.
    2 points
  9. I come from the future and have to tell you ProcessWire is here to stay @gebeer My sync is not connected to git, I am planning to do so, but you know... missing time. I send you the rsync shell script via DM.
    2 points
  10. something like this should work: <?php class Submissions { protected $site = null; // <= add a handle for the site public function __construct($site) { $this->site = $site; // <= assign the site to the class handle } function insert($data) { $this->site->pages->find(....); // <= use the site through the class handle } } <?php require('/home/centralsite/public_html/wire/core/ProcessWire.php'); $site = new \ProcessWire\ProcessWire('/home/centralsite/public_html/site/', 'http://example.com'); include "submissions.class.php"; $submissions = new Submissions($site); // <= here you pass your pw instance ($site) into your class
    2 points
  11. thanks @horst will check it out and update the profile.
    2 points
  12. I think ProcessPageClone should give the user an opportunity to specify a title and name for the page before the clone is done, as is the case for cloning pages with children. I opened a request for this. But in the meantime you could check to see if a sibling page exists with the same name as the cloned page excluding the "-1" suffix. $base_name = rtrim($page->name, '-1'); if($page->siblings("name=$base_name", false)->count()) return; Edit: or maybe a better approach is not to write to your CSV for unpublished pages, as cloned pages are unpublished at first.
    2 points
  13. Each year we cycle 1000km with our company to fight against cancer. To participate with 4 teams we have to collect 20.000 euros. Our graphic designers made some goodies en we also organise a spaghetti fundraiser. To help the sales we decided to make a webshop with our webteam. And of course we used our favourite CMS for the job! ? https://shop.typografics.be/ At this moment we raised more than 20.000 euros, so all our teams can participate. This is a very special project for us, unfortunately one of our colleagues has been diagnosed with cancer and currently is fighting against this terrible disease. Premium PW modules used in this project: PadLoper FormBuilder ProFields Variations With a few hooks here and there we managed to make it work. To handle the payments we made use of Mollie, we created our own payment module and will opensource this soon. You can read more about this project in our blog (in dutch) Unfortunately we're currently only shipping to Belgium We’re already brainstorming to make a 2.0 version of this webshop, so all your feedback is more than welcome.
    1 point
  14. In ProcessWire itself I've never used custom fonts. For projects I do it the exact same way as @horst does. As I use .less for CSS I create a _fonts.less import with everything I need. One exception is Typekit. That always gets included with JS.
    1 point
  15. It's just like @kongondo said - you have to save a new page before you can add files or images to it. The directory needed to hold the files/images gets created on the first save - then you can add files/images. So in submit(), do $p->save() before setDummyData()... public function submit() { $input = $this->wire('input'); $page = $this->wire('page'); $session = $this->wire('session'); if ($input->post->submit && $this->canEdit()) { if (($p = $this->savePageBasic()) !== false) { $p->addStatus(Page::statusHidden); $p->save(); $this->setDummyData($p); } $session->redirect($page->path); } } P.S. This... $parent = $this->wire('pages')->get($page->path); $p->parent = $parent; ...could be better optimised as... $p->parent = $page;
    1 point
  16. Sounds like a circular reference issue...
    1 point
  17. It seems that I just forgot to use the foreach for it to work $related_page = $pages->find("template=template-2, mypagetable=$page"); if(count($related_page)) { foreach($related_page as $rp) { ?> <a href="<?= $rp->url ?>">Related Page</a> <?php } } ?>
    1 point
  18. Maybe... <?php if(count($pages->find("template=template-2, pageField=$page"))) { // do this } else { // or that }; ?>
    1 point
  19. 1 point
  20. Hi. Just looked at your issue quickly, so you might be already doing the right thing. Note that you need to first save a new page before adding images to its image field. Save the page first, then add the image, then save again.
    1 point
  21. Thank you both, this is exactly what I needed. @Sephiroth is your code PHP 7? My IDE didn't like it, but the method worked. I have learned something useful!
    1 point
  22. So the reason for uses Classes, is that you want to hide complexity and just expose the method in a clean manner, and also you want to deal with properties internally without side effects as you would when doing procedural type of coding. So if you want to pass any data to your classes, there are multiple ways but the best way is to always pass the data by copy in either constructor like this <?php class Submisssion{ private data; __construct(data){ $this->data=data } } or using a Setter method <?php class Submission { private data; public function insert($data){ $this->data = $data; } $submission->insert($data); What this does is pass the data through a method and achieves the same as the constructor, because this way the Submission class can handle manipulation of data without external change outside the class. Which is why OOP is usually preferred as alot of things are hidden and the methods are made simple so you can use a Class without having to read the internal details.
    1 point
  23. 1. There's a example in the code itself with email: if($email && (strpos($email->value,'@hotmail') !== FALSE)){ // attach an error to the field // and it will get displayed along the field $email->error("Sorry we don't accept hotmail addresses for now."); } Anything the API provides is possible. I can't go into details as there's too much and don't have any examples ready. 2. Of course an array is possible, input->post is also and array. You just have to make it a WireInputData array. https://github.com/processwire/processwire/blob/341342dc5b1c58012ae7cb26cffe2c57cd915552/wire/core/WireInputData.php 3. "Validation" is per Inputfield and it depends. Some inputfields do some sanitations to make sure an expected format or type of value is given (for example email https://github.com/processwire/processwire/blob/341342dc5b1c58012ae7cb26cffe2c57cd915552/wire/modules/Inputfield/InputfieldEmail.module) but most do nothing at all. You can look at all the Inputfields processInput() method to see what it does. Text and Textarea have some Inputfield settings to strip tags for example. It depends also on what the Form is used for and where you use the data afterwards. It's never an issue to save data to DB ie Pages, it's always about what and where you output the data (website, email, ...).
    1 point
  24. If I followed correct, you have a well running local site? You plain copied it to the online space? (Without running an installer before?) Maybe you can try to export your local site with the SiteProfileExporter Module, and then do a fresh installation online. But be aware, that all created roles & users & accessrights get not exported with the SiteProfileExporter Module. This you have to implement manually after installation. The advantage is that you don't have to deal with all the different caches and also get notifications during the installation routine if something with the online space is missing.
    1 point
  25. very good writeup and great website! Would you be willing to share your rsync setup for uploading changed files? I love rsync and use it a lot. Does your setup connect to git commit in any way?
    1 point
  26. ProcessWire 3.8? I must be using the wrong Github repo. ?
    1 point
  27. Oh right - sorry I missed your note about the 500 error - too busy to really read properly
    1 point
  28. @adrian, maybe the module needs a try/catch to show the login throttle message rather than the 500 error?
    1 point
  29. A feature request for the future: allow login only with a password. As a workaround I used a simple str_replace and added hardcoded "value=USERNAME" attribute to the username input, plus a good old display: none to it. This way it doesn't show up but contains the username pre-filled. The same could be perhaps achieved if there was a per-page setting where we could enter one username. Then the module could add a hidden input with an encrypted username (instead of a text type username input). But maybe you have a better idea. I needed this because the client needed a password protected page without asking for a username. Fortunately the protection doesn't need to be bulletproof so my workaround is fine for now, but in the future it would be nice having this built-in.
    1 point
  30. @wbmnfktr Thanks for the compliments. Regarding your question: It might be good to make an own thread for this. But to give you an answer: If there is some sensitive data in the case study, I ask my customers if it is okay, to have that data in the study. If not, I remove it. And sensitive data in the backend is replaced with dummy data or blurred, because if not, it could conflict with the law (regarding your country).
    1 point
  31. Just had a need to use this profile. Thanks for your work on this profile.
    1 point
  32. We only ask clients for permission to quote them (client testimonial). Don't know if it's legally a must, but it's certainly good form. And of course, if you show sensitive data (e.g. from the backend or if you did an intranet / web app), you should ask first (perhaps blur sensitive infos like names etc.)
    1 point
  33. server { listen 443 ssl http2; listen [::]:443 ssl http2; server_name example.com; root /home/forge/example.com/public; index index.html index.htm index.php; charset utf-8; # ----------------------------------------------------------------------------------------------- # Access Restrictions: Protect ProcessWire system files # ----------------------------------------------------------------------------------------------- # Block access to ProcessWire system files location ~ \.(inc|info|module|sh|sql)$ { deny all; } # Block access to any file or directory that begins with a period location ~ /\. { deny all; } # Block access to protected assets directories location ~ ^/(site|site-[^/]+)/assets/(cache|logs|backups|sessions|config|install|tmp)($|/.*$) { deny all; } # Block acceess to the /site/install/ directory location ~ ^/(site|site-[^/]+)/install($|/.*$) { deny all; } # Block dirs in /site/assets/ dirs that start with a hyphen location ~ ^/(site|site-[^/]+)/assets.*/-.+/.* { deny all; } # Block access to /wire/config.php, /site/config.php, /site/config-dev.php, and /wire/index.config.php location ~ ^/(wire|site|site-[^/]+)/(config|index\.config|config-dev)\.php$ { deny all; } # Block access to any PHP-based files in /templates-admin/ location ~ ^/(wire|site|site-[^/]+)/templates-admin($|/|/.*\.(php|html?|tpl|inc))$ { deny all; } # Block access to any PHP or markup files in /site/templates/ location ~ ^/(site|site-[^/]+)/templates($|/|/.*\.(php|html?|tpl|inc))$ { deny all; } # Block access to any PHP files in /site/assets/ location ~ ^/(site|site-[^/]+)/assets($|/|/.*\.php)$ { deny all; } # Block access to any PHP files in core or core module directories location ~ ^/wire/(core|modules)/.*\.(php|inc|tpl|module)$ { deny all; } # Block access to any PHP files in /site/modules/ location ~ ^/(site|site-[^/]+)/modules/.*\.(php|inc|tpl|module)$ { deny all; } # Block access to any software identifying txt files location ~ ^/(COPYRIGHT|INSTALL|README|htaccess)\.(txt|md)$ { deny all; } # Block all http access to the default/uninstalled site-default directory location ~ ^/site-default/ { deny all; } #Amplify dashboard location /nginx_status { stub_status on; allow 127.0.0.1; deny all; } # ----------------------------------------------------------------------------------------------- # If the request is for a static file, then set expires header and disable logging. # Give control to ProcessWire if the requested file or directory is non-existing. # ----------------------------------------------------------------------------------------------- location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|eot|woff|ttf)$ { expires 15d; log_not_found off; access_log off; try_files $uri $uri/ /index.php?it=$uri&$query_string; } # ----------------------------------------------------------------------------------------------- # ProCache Rules # ----------------------------------------------------------------------------------------------- set $cache_uri $request_uri; if ($request_method = POST) { set $cache_uri 'nocache'; } if ($http_cookie ~* "wires_challenge") { set $cache_uri 'nocache'; } if ($http_cookie ~* "persist") { set $cache_uri 'nocache'; } # ----------------------------------------------------------------------------------------------- # This location processes all other requests. If the request is for a file or directory that # physically exists on the server, then load the file. Else give control to ProcessWire. # ----------------------------------------------------------------------------------------------- location / { expires -1; try_files /site/assets/ProCache-b3d534d...d/$cache_uri/index.html $uri $uri/ /index.php?it=$uri&$args; } location = /favicon.ico { access_log off; log_not_found off; } location = /robots.txt { access_log off; log_not_found off; } access_log off; error_log /var/log/nginx/example.com-error.log error; error_page 404 /index.php; location ~ \.php$ { fastcgi_split_path_info ^(.+\.php)(/.+)$; fastcgi_pass unix:/var/run/php/php7.2-fpm.sock; fastcgi_index index.php; include fastcgi_params; } location ~ /\.ht { deny all; } }
    1 point
  34. Nice! Very interested in your padloper/mollie combination looking forward to your open sourcing of the payment module you built.
    1 point
  35. If anyone is interested, I have a new fork of this module available here: https://github.com/adrianbj/MarkupSEO/commits/various-fixes-enhancements It's very much a work in progress, but it includes several bug fixes and lots of new features. Please read the commit log to learn about what's fixed and what's new. At the moment you should not upgrade an existing site (new fields won't be created) and probably don't use it on a live site just yet. It's not well tested at all yet, so use at your own peril I'd really appreciate any feedback on it.
    1 point
  36. Just checked on: http://castfeedvalidator.com/ and still not delivering partial headers, anyone have any experience on this, I'm running PW on nginx. Here is my current php code for the file request: <?php namespace ProcessWire; if($page->mp3){ $page->of(false); $page->counter += 1; $page->save(); $page->of(true); // // adapted from GIST: https://gist.github.com/codler/3906826 // $options = array( // boolean: halt program execution after file send 'exit' => true, // boolean|null: whether file should force download (null=let content-type header decide) 'forceDownload' => false, // string: filename you want the download to show on the user's computer, or blank to use existing. 'downloadFilename' => '', ); $file_path = $page->mp3->filename; $fp = @fopen( $file_path, 'rb' ); $size = filesize( $file_path ); $length = $size; $start = 0; $end = $size - 1; header("Content-type: audio/{$page->mp3->ext}"); header( "Accept-Ranges: 0-$length" ); header( "Content-Length: $length" ); // find request headers for partial content if ( isset($_SERVER['HTTP_RANGE']) ) { // if the HTTP_RANGE header is set we're dealing with partial content $partialContent = true; } else { $partialContent = false; } if ( $partialContent ) { $c_start = $start; $c_end = $end; // Extract the range string list(, $range) = explode( '=', $_SERVER['HTTP_RANGE'], 2 ); // If the range starts with an '-' we start from the beginning // If not, we forward the file pointer if ( $range{0} == '-' ) { // The n-number of the last bytes is requested $c_start = $size - substr($range, 1); } else { $range = explode( '-', $range ); $c_start = $range[0]; $c_end = ( ( isset( $range[1] ) && is_numeric( $range[1] ) ) ? $range[1] : $size ); }; // End bytes can not be larger than $end. $c_end = ($c_end > $end) ? $end : $c_end; $start = $c_start; $end = $c_end; $length = $end - $start + 1; fseek( $fp, $start ); // Start buffered download $buffer = 1024 * 8; while ( ! feof( $fp ) && ( $p = ftell($fp) ) <= $end ) { if ( $p + $buffer > $end ) { $buffer = $end - $p + 1; }; set_time_limit( 0 ); echo fread( $fp, $buffer ); flush(); }; header( "Content-Range: bytes $start-$end/$size" ); header( 'HTTP/1.1 206 Partial Content' ); fclose( $fp ); }else{ // send file wireSendFile($page->mp3->filename, $options); } }
    1 point
  37. Are all podcasts in MP3 format? If 'Content-Type' => 'audio/mp3 header and mime type of podcasts do not match, you'd get the error. Try removing 'Content-Type' => 'audio/mp3' from $headers array. In case it doesnt work, https://gist.github.com/benrolfe/5453074 claims to solve iTunes byte range problem. Changing the $file_path at line 2 to $page->mp3->filename should be enough.
    1 point
  38. Yeah, that might be confusing somewhat. To summarize the changes: The part starting with $file = open($page->mp3->httpUrl, 'r'); should be <?php $filePath = $page->mp3->filename; $file = fopen($filePath, 'r'); fseek($filePath, $offset); $data = fread($filePath, $length); fclose($filePath); to read parts of the file client requested directly from the disk. While sending the file to the client, you should replace this part <?php // send partial file wireSendFile($page->mp3->filename, $options, $headers); } else { // send file wireSendFile($page->mp3->filename, $options); } with print($data); like so <?php // send partial file print($data); } else { // send file print($data); } Because you've set headers earlier, you dont need to set them again. With these changes, hopefully, you'll have saved server from wasting some precious bandwidth. Good luck
    1 point
  39. @benbyf, I am not sure if this is the whole code, but I want to point out some parts. <?php // you should use $page->mp3->filename to prevent unnecessary (and slower) network request // let PHP read file from the disk directly $file = fopen($page->mp3->httpUrl, 'r'); fseek($page->mp3->httpUrl, $offset); $data = fread($page->mp3->httpUrl, $length); fclose($page->mp3->httpUrl); // also, this forces client to download whole file wireSendFile($page->mp3->filename, $options, $headers); // whereas sending the parts you prepared is just cheaper print($data); So, the current implementation just sets the headers iTunes was checking for, but it sends whole file, not the parts client requested. This might total to an unnoticeable difference for lower traffic files, but you should opt for sending only the parts client requested. Just my 2 cents.
    1 point
  40. That anwser did the trick i think, i managed to make the implementation below. It must have been a new itunes requirement for byte-range headers. $filesize = filesize($page->mp3->httpUrl); $offset = 0; $length = $filesize; if ( isset($_SERVER['HTTP_RANGE']) ) { // if the HTTP_RANGE header is set we're dealing with partial content $partialContent = true; // find the requested range // this might be too simplistic, apparently the client can request // multiple ranges, which can become pretty complex, so ignore it for now preg_match('/bytes=(\d+)-(\d+)?/', $_SERVER['HTTP_RANGE'], $matches); $offset = intval($matches[1]); $length = intval($matches[2]) - $offset; } else { $partialContent = false; } $file = fopen($page->mp3->httpUrl, 'r'); // seek to the requested offset, this is 0 if it's not a partial content request fseek($page->mp3->httpUrl, $offset); $data = fread($page->mp3->httpUrl, $length); fclose($page->mp3->httpUrl); if ( $partialContent ) { // output the right headers for partial content $headers = array( 'HTTP/1.1 206 Partial Content' => true, 'Content-Type' => 'audio/mp3', 'Content-Length' => $filesize, 'Content-Disposition' => 'attachment; filename="' . $fileName . '"', 'Content-Range' => 'bytes ' . $offset . '-' . ($offset + $length) . '/' . $filesize, 'Accept-Ranges' => 'bytes', ); // send partial file wireSendFile($page->mp3->filename, $options, $headers); }else{ // send file wireSendFile($page->mp3->filename, $options); }
    1 point
  41. @benbyf just a shot in the dark, but have you considered that with the 2.7.2 version, when you submitted it, Apple was not validating the byte-range request support?
    1 point
  42. Hi zyON, I think the problem is that the used fonts don't contain your portuguese characters. Can you try to change your WirePDF settings: Mode: "s" instead of "c" Font: "DejaVuSans" See this post for more information: https://processwire.com/talk/topic/3008-pages2pdf/page-6#entry96263 If this does not work, you'd probably need to add a font that supports your character set by yourself to mPDF.
    1 point
×
×
  • Create New...