Leaderboard
Popular Content
Showing content with the highest reputation on 08/14/2017 in all areas
-
Hi @OLSA Because SEO is very important in that kind of business/site I would first of all stick to its requirements and that to other things like the usability of administration etc.d In your second example, you can change "showers and bathtubs" to something more general like "bathroom". In that case, you will have additions keyword in your URL. If your page name includes stop words (and, or, but, of, the, a, etc.), it's not critical to putting them in the URL. You don't have to leave them out, either, but it can sometimes help to make a URL shorter and more readable in some sharing contexts. Use your best judgment on whether to include or not based on the readability vs. length. As for best URL structure, I would recommend "site.com/bathroom/showers/product". You can do it by using URL segments, so you can have desired page tree in admin and perfect URL structure on the frontend. Of course, it's much more work and there is a lot of small things like canonical links, redirect etc that you have to think about. As another way to make your URL shorter you can move only last "product" part to "products", so you will have "products/product". Don't forget to use schema.org or other for breadcrumbs.5 points
-
Interesting... I've been saying for a while that I'd love to help the docs get better. As they are now, I think they're pretty good - but things could always improve, and if there is one thing in development I am uber-passionate about, it's documentation!!2 points
-
Have done this for image fields, it adds a button to the end of the inputfield, code below. Checks for ZipArchive class before installing. Now that I read the code it should work for files but haven't tested! It's got configuration options too, to enable per field basis, either way should it should be super quick to edit if something is not working. <?php class ExportFieldImages extends WireData implements Module, ConfigurableModule { static public function getDefaultConfig() { return array( "includeFields" => '' ); } public static function install(){ $session = wire("session"); if(!class_exists('\ZipArchive')){ throw new WireException("ZipArchive is required to create the zip file"); } } public static function getModuleInfo() { return array( 'title' => 'ExportFieldImages', 'version' => 0.1, 'summary' => "Adds a button bellow images field to download a zip containing files.", 'author' => 'Eduardo San Miguel Garcia', 'singular' => true, 'href' => '', 'autoload' => true ); } public function init() { $this->addHookAfter('InputfieldImage::render', $this, 'afterInputfieldImageRender'); $this->addHookAfter("ProcessPageEdit::execute", $this, "pageEditExecuteBefore"); } public function pageEditExecuteBefore(HookEvent $event){ $session = wire("session"); $input = wire("input"); $page = wire('pages')->get($input->get->id); $name = $page->name; $zip = $config->paths->cache . "${$name}.zip"; if($input->get->downloadImages == "true"){ wire("log")->save("custom", "excecuted page edit!"); $array = wire('files')->zip($zip, $page->get($input->get->field)->explode("filename"), array("overwrite" => true) ); if(!empty($array["errors"])){ foreach($array["errors"] as $error){ $this->error($error); } return; } else{ header('Content-Type: application/zip'); header("Content-Disposition: attachment; filename='{$name}.zip'"); echo readfile($zip); return $this->halt(); } } } public function afterInputfieldImageRender(HookEvent $event){ $field = $event->object; $input = wire("input"); $configData = wire('modules')->getModuleConfigData($this); $out = $event->return; if(in_array( $field->name, $configData['includeFields'])){ $button = wire('modules')->get('InputfieldButton'); $button->class = $button->class . " ExportFieldImages"; $button->icon = 'download'; $button->href = "./?downloadImages=true&field={$field->name}&id={$input->get->id}"; $button->value = "Download Files"; $btn .= "<span style='display:block; position:relative; float:right;' class='InputfieldPageTableButtons'>" . $button->render() . "</span>"; $out .= $btn; } $event->return = $out; } public function getModuleConfigInputfields(array $data){ $modules = wire("modules"); $fields = wire('fields'); $defaults = self::getDefaultConfig(); $data = array_merge($defaults, $data); $form = new InputfieldWrapper(); $field = $modules->get("InputfieldAsmSelect"); $field->name = "includeFields"; $field->label = __("Fields to enable download button"); $field->description = __("Choose the image fields where download button should appear"); foreach($fields as $f){ if($f->flags & Field::flagSystem) continue; if($f->type == "FieldtypeImage" || $f->type == "FieldtypeFile"){ $field->addOption($f->name); } } $field->value = $data['includeFields']; $form->add($field); return $form; } }2 points
-
Hej, A module which helps including Photoswipe and brings some modules for rendering gallery markup. Feedback highly appreciated (Also pull requests are appreciated ? - have a new Job now and don't work a lot with ProcessWire anymore, yet, feel free to contact me here or on GitHub, Im'm still "online"!) Modules directory: http://modules.processwire.com/modules/markup-processwire-photoswipe .zip download: https://github.com/blynx/MarkupProcesswirePhotoswipe/archive/master.zip You can add a photoswipe enabled thumbnail gallery / lightbox to your site like this. Just pass an image field to the renderGallery method: <?php $pwpswp = $modules->get('Pwpswp'); echo $pwpswp->renderGallery($page->nicePictures); Options are provided like so: <?php $galleryOptions = [ 'imageResizerOptions' => [ 'size' => '500x500' 'quality' => 70, 'upscaling' => false, 'cropping' => false ], 'loresResizerOptions' => [ 'size' => '500x500' 'quality' => 20, 'upscaling' => false, 'cropping' => false ], 'pswpOptions' => (object) [ 'shareEl' => false, 'indexIndicatorSep' => ' von ', 'closeOnScroll' => false ] ]; echo $pswp->renderGallery($page->images, $galleryOptions); More info about all that is in the readme: https://github.com/blynx/MarkupProcesswirePhotoswipe What do you think? Any ideas, bugs, critique, requests? cheers Steffen1 point
-
OAuth2Login for ProcessWire A Module which give you ability to login an existing user using your favorite thrid-party OAuth2 provider (i.e. Facebook, GitHub, Google, LinkedIn, etc.).. You can login from the backend to the backend directly or render a form on the frontend and redirect the user to a choosen page. Built on top of ThePhpLeague OAuth2-Client lib. Registration is not handled by this module but planned. Howto Install Install the module following this procedure: - http://modules.processwire.com/modules/oauth2-login/ - https://github.com/flydev-fr/OAuth2Login Next step, in order to use a provider, you need to use Composer to install each provider ie: to install Google, open a terminal, go to your root directory of pw and type the following command-line: composer require league/oauth2-google Tested providers/packages : Google : league/oauth2-google Facebook: league/oauth2-facebook Github: league/oauth2-github LinkedIn: league/oauth2-linkedin More third-party providers are available there. You should be able to add a provider by simply adding it to the JSON config file. Howto Use It First (and for testing purpose), you should create a new user in ProcessWire that reflect your real OAuth2 account information. The important informations are, Last Name, First Name and Email. The module will compare existing users by firstname, lastname and email; If the user match the informations, then he is logged in. ie, if my Google fullname is John Wick, then in ProcessWire, I create a new user Wick-John with email johnwick@mydomain.com Next step, go to your favorite provider and create an app in order to get the ClientId and ClientSecret keys. Ask on the forum if you have difficulties getting there. Once you got the keys for a provider, just paste it into the module settings and save it. One or more button should appear bellow the standard login form. The final step is to make your JSON configuration file. In this sample, the JSON config include all tested providers, you can of course edit it to suit your needs : { "providers": { "google": { "className": "Google", "packageName": "league/oauth2-google", "helpUrl": "https://console.developers.google.com/apis/credentials" }, "facebook": { "className": "Facebook", "packageName": "league/oauth2-facebook", "helpUrl": "https://developers.facebook.com/apps/", "options": { "graphApiVersion": "v2.10", "scope": "email" } }, "github": { "className": "Github", "packageName": "league/oauth2-github", "helpUrl": "https://github.com/settings/developers", "options": { "scope": "user:email" } }, "linkedin": { "className": "LinkedIn", "packageName": "league/oauth2-linkedin", "helpUrl": "https://www.linkedin.com/secure/developer" } } } Backend Usage In ready.php, call the module : if($page->template == 'admin') { $oauth2mod = $modules->get('Oauth2Login'); if($oauth2mod) $oauth2mod->hookBackend(); } Frontend Usage Small note: At this moment the render method is pretty simple. It output a InputfieldForm with InputfieldSubmit(s) into wrapped in a ul:li tag. Feedbacks and ideas welcome! For the following example, I created a page login and a template login which contain the following code : <?php namespace ProcessWire; if(!$user->isLoggedin()) { $options = array( 'buttonClass' => 'my_button_class', 'buttonValue' => 'Login with {provider}', // {{provider}} keyword 'prependMarkup' => '<div class="wrapper">', 'appendMarkup' => '</div>' ); $redirectUri = str_lreplace('//', '/', $config->urls->httpRoot . $page->url); $content = $modules->get('Oauth2Login')->config( array( 'redirect_uri' => $redirectUri, 'success_uri' => $page->url ) )->render($options); } The custom function lstr_replace() : /* * replace the last occurence of $search by $replace in $subject */ function str_lreplace($search, $replace, $subject) { return preg_replace('~(.*)' . preg_quote($search, '~') . '~', '$1' . $replace, $subject, 1); } Screenshot1 point
-
I like to showcase my new website acniti on the forum here. History Building and managing a website is a hobby, over the years, making websites got more complicated and more technologies, knowledge and wisdom are required. I started building my first website around 1997. It started out with a static site built with FrontPage, a WYSIWYG HTML editor. A few years later it was time for the first content management system, I looked at Joomla but settled for MediaWiki. I run those websites for 2 years on the MediaWiki platform and then moved on to WordPress. WordPress was good, it did a good job but over time, it became more complicated to make something out of the box, if it's not a blog, it becomes complicated and to have a feature rich website requires a lot of plugins. Little by little it became less fun and more and more hassle juggling the various plugins. In 2014 I became interested in learning PHP programming, I wanted to do this already for many years, but never had enough time to bite the bullet and work my way through the basics. At the end of the courses I though and now what have I learned, how to put this into action? To built modern website with PHP only is difficult, it also requires knowledge of html, MySQL, CSS, java-script etc. I started looking for a framework experimented a little with CakePHP and then came across Processwire via a CMS Critic blog post. Development setup I developed the acniti website on a Linux Ubuntu 16, with PHP 7 and MySQL as the development server. For the IDE I use PhpStorm, before using Storm I have used and tried some other IDE's such as Zend, Eclipse, Netbeans, Aptana but none of them I liked, some were feature poor, Zend and Eclipse were slow and use a lot of memory. PhpStorm not free but definitely worth the investment. I make use of the free tier Git repository of AWS called CodeCommit, I still use GIT Cola to commit the changes, I could also use PhpStorm for this but I never took the time to change my workflow. For project management I am a big fan of Redmine, Redmine is a web-based open-source project management and issue tracking tool. I use this also for my other work so it easily integrates with the website building flow as well. It's easy for maintaining lists of features you want to carry out per version, it supports a wiki which is easy for making notes and keeping a log of the activities. I use it everyday and it runs on Ruby. For images and graphics I switch back to Windows for some Photoshop. Processwire The acniti website runs on the latest stable Processwire version at the time of writing 3.0.62, the website has 4 languages including an Asian language. The Japanese language URL's are implemented with their 3 alphabets kanji, hiragana, katakana i.e. https://www.acniti.com/ja/インレットフィルタ. Some images on the site have text and image language tags help to select the correct language, the Processwire blog post from 30 June was helpful to get this running. The main site has a bootstrap theme, for the mobile version of the site the google AMP specification is implemented. This was really fun to do but challenging at times as the AMP specification is still a little limited. To visit the AMP pages type /amp/ behind any URL like https://www.acniti.com/amp/ for the homepage. The Google webmaster portal is really easy to troubleshoot and check for the correct AMP implementation. Finally structured data according to schema.org is added to the site via the JSON-LD markup. The commercial modules ProCache and Formbuilder are installed. The ProCache module is really amazing and makes the website lightning fast. Besides the commercial modules around eleven open-source modules are used, Database Backups, Tracy Debugger, Wire Mail SMTP, Protected Mode, Batcher, Upgrades, PublishAsHidden, URL (Multi-language), Twitter Feed Markup, Email Obfuscation (EMO), Login History, Selector test. During development the Processwire forum is really helpful and checked often. The forum is good for two reasons, most of the questions, I had during development of the site, are already on the site. Secondly the only 6 questions I posted over the last 2 years, are quickly and accurately answered. The downside I didn't become a very active member on the forum but see that as a compliment. An open issue on the acniti site is the AMP contact form with Formbuilder, the restricted usage of java-script for the AMP specification requires some more in-depth study. Hosting setup For the hosting services the acniti site uses Amazon EC2, I use AWS already many years to manage my cloud office so it was easy to decide to use it for the web hosting as well. The site is running on a micro instance of EC2 and with the ProCache module CloudFront is serving webpages worldwide fast. Updates from the development server are sent to CodeCommit and from there to the production server. From a site management point of view it would be nice to use AWS RDS to manage the MySQL databases, but from a cost perspective I decide not to do that for now. Via a cron I have set up automatic MySQL backups and these are via another cron job uploaded to AWS S3. To make sure the server is safe, a cron job runs daily snapshots of the server, this is getting initiated via AWS Lambda. Lambda also removes older snapshots because during creation a delete tag is attached for sevens days after their creation. It's important to make a separate MySQL backup as with snapshots the database often gets corrupted and its easier to restore a database backup than to fix a corrupted database. Another nice feature to use AWS Lambda for is a simple HTTP service health checker, which reports to you by email or sms when the website is down. Making use of all these Amazon services cost me probably somewhere between 10 - 15 $ a month, I have to estimate a little since I am running a lot more things on AWS than only the website. The site is running on a Comodo SSL certificate but next year I will change to the free LetsEncrypt, as it is easier to add and will automatically renew after 90 days. The Comodo certificate requires manually copy pasting and editing the certificates in place. Writing Content The content for the site I write in the Redmine wiki, most of the content I write requires research and it takes about two weeks before I publish the content to the Processwire site. For writing content I use the google spell checker with the grammar checker, After the Deadline. To ensure catchy headlines they are optimized with the Headline Analyzer from CoSchedule Social Media Now the site is running, it needs promotion. The robots.txt files shows the search engines the way as does the sitemap.xml both of these I have made in a template file. Most of the blog articles I promote are republished on social networks like, LinkedIn, Tumblr, Google+, Twitter, and some branch specific networks as the Waternetwork and Environmental XPRT. To check, the search engines index the site well, Google webmaster and Bing webmaster check for any problems with the site. For statics on the same server there is an instance installed of Piwik. Piwik is a leading open alternative to Google Analytics that gives full control over data. The Piwik setup works very well and gives a good overview of the site usage both on the desktop via the site or via a mobile app. As a part of a test I have installed the open-source SEO-panel on the same server to manage keywords and to further improve the scores in the search engine, a nice feature is that you can also track your competitors. I am still new to SEO panel and have to learn more how to use the tool effectively.1 point
-
+1 I have products/product (-> parent/children in the tree) and separate categories/sub-categoies/.../category, tags/tag-group/tag, etc. parent/children in the tree and Page references + URLsegments to do the routing. Otherwise one faces the issues @OLSA is facing.1 point
-
Hi @Karl_T Take a look at this module https://github.com/plauclair/AutodetectLanguage/blob/master/AutodetectLanguage.module1 point
-
You definitely should take a look at URL segments. The power of URL segments is that your URL structure can be different from you page tree structure and in your case, as, for me, it is highly desirable. I think that is not a good way to place products under categories because some products can be relative to several categories. How will you handle it?1 point
-
@Mustafa Online The Admin Theme Uikit is ready to take to the next level by the community, however, no one has taken a grasp of that project yet. I sadly don't have the time yet to work on it, however I have ideas for it. I expect @renobird will pick it up at some point and guide the project. It will not hit master until UIkit comes out of beta, which from what they say, will be a very long time.1 point
-
This also appears to be the last blog post: https://processwire.com/blog/posts/new-2.8-version-current-projects-and-pw-usage/ - suggests it's ready for others to tinker with (the original idea with that theme was for Ryan to build the framework and others to come up with designs).1 point
-
Just a few random thoughts... From what I can see, your code is very much heading in a good direction - splitting the task into manageable chunks is IMHO a good way to go. I assume your product names are in German, based on your location. If so, AFAIK you may not be able to use some of the cool stuff available for English like mySQL's SOUNDS LIKE (bit of discussion here). How many products is 'just a few', BTW? One thing to consider is making your product search AJAX powered. Then users can see instantly if they are finding products or otherwise, and you can kind of 'lead' their searching efforts. (One easy way is intercooler.js - see http://intercoolerjs.org/examples/activesearch.html. There is a PW module.) A small thing that I have found useful in the past is to proactively deal with common misspellings - see and the rest of that thread. (YMMV)1 point
-
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
-
@benbyf Thanks Ben The token request could be on the admin side BUT the Dropbox call back URL must be a publicly viewable page to receive the token. I chose to put both the request and response on the same page and then unpublish the page once I'd received the token. According to the documentation, https://github.com/kunalvarma05/dropbox-php-sdk/wiki/Working-with-files the answer is yes. The PW module really does little more than authenticate the user and allow you to create the $dropbox object (as in example above for sending a file). Add all the appropriate "use" namespace statements in your template and you'll have full access to the API, including the ability to List Folder Contents1 point
-
Hello guys ! The Gitlab server is fixed and running, you can update the module to the latest version. All SDKs can be downloaded separately without using composer, the link of each SDK is provided in the module settings. You must uninstall the previous version before testing it. Thanks!1 point
-
Just some explanation because it is interesting... This isn't something that is specific to Repeaters - it applies to any selector used on a PageArray/WireArray (a Repeater field returns a PageArray). When you do $some_pagearray->find() this is different to a $pages->find() - the method name is the same but they are actually totally different methods. See find() method in the PageFinder class vs the WireArray class. When using $pages->find() the method refers back to the fieldtype for each queried field and the fieldtypes can do some special preparation to the queried value. In the case of a Datetime field the value is passed through strtotime() if it is a string. So this allows "today" to be converted to a timestamp. But when using $some_pagearray->find() this process does not happen, so the queried value must be a timestamp. Another gotcha to watch out for is using the page status as a string in a selector. With $pages->find() you can do something like "status!=hidden" but this won't work with a selector in $some_pagearray->find(). I think it would be nice if things like this did work with PageArrays - there is an open request for it.1 point
-
Is this what you are referring to: http://processwire.com/api/ref/fieldgroups/ Not sure why it isn't linked - must be missing from the API Explorer script that @ryan runs to generate the ref pages. There actually seems to be the opposite problem with: http://processwire.com/api/ref/wire-database-backup/ - that page 404s, but is linked to under Core Classes > WireDatabaseBackup in the dropdown.1 point
-
@DedMoroz Did you see my PW 3 compatible module https://github.com/jmartsch/processwire-social-login? Maybe you want to use it instead?1 point
-
That one failed that exact check. For me that was mostly a matter of refreshing modules once or twice an they were gone, but I'm not sure what exactly could fail for those rarely changed core modules.1 point