Leaderboard
Popular Content
Showing content with the highest reputation on 02/01/2014 in all areas
-
Congratulations to everyone! We have now officially won as seen on the Bitnami contest page. Thanks for everyone's efforts for this, as this should be a great thing for the ProcessWire project. I'll follow up with more later, but just wanted to thank and congratulate everyone for this community led effort.13 points
-
I've just upgraded a new site I'm building and I'm pleased to say it all went smoothly. All modules worked perfectly and I'm still testing it with joy! I'm loving the improvements on the new default Theme. I'm a designer myself so I'm hard to please. I haven't been following the new theme discussion lately but I wish to point out some things I came across. Notifications I found the notices/notifications very annoying as they push the page down depending on the quantity of such notifications. ProcessWire is quite verbose and the new design reminded me more of it. Kind of made it a little bit more annoying as well. Even more with intensive editing/usage. I wonder if it could be a way to have like 2 levels of "verbosity": one more suitable for an editor and one for and admin. Maybe the editor just wants to see 1 notification for "page saved" or one with the errors in case they are any. The admin would see "field x saved, field x saved..." just like it today. I can see this setting an improvement to the UI and to the UX of content editors as wells. Also, the phrasing could be more user-friendly to editors/not techie people, just by removing the word "Session:" or using the fields titles instead of the names. Maybe it can be configured and haven't noticed it. Edited: As WillyC pointed out, this only happens with debug mode on so it's not a problem for the client. My critique should focus on the UI pattern and not the notification system, then. Also, it could be possible to condense all notifications in one phrase and make it collapsible (like the Debug mode tools) with an arrow or gears icon that let's admins/anyone see all the notifications (fields saved, etc) related to the event (either saved-green/error-red). This would solve the annoying push down of the page when saving 10 images for example (this is a worst case scenario which I can see has been addressed already). But modifying 10 field gives you 10/11 green bands which is the same effect. Other solutions might be to place notifications where they were. I guess there is a reason for this new change, but wanted to simply express my opinion on it. I found a client of mine panicking when seeing 10 green notifications over the screen. It almost seemed like an error, even though they were all successful notifications. I guess that the top notification/pushing down the page pattern is better suited for just for one line of text. Having a collapsible icon seems like a good solution to accommodate and further extend this UI pattern. Let me know what you guys think! Otherwise, everything looks sharp, fresher and more user-friendly so I'm very happy about it!! Congrats to everyone involved! Edited I made some quick concepts to see what it would look like. Certainly this is easier said than done (what isn't?). It looks simple but I maybe there are some situations/notifications I'm not considering. The idea, in fact is to simplify it to two possible messages (Success/Error) and make less intrusive. Each message can be expanded to see what has changed or which fields have errors. When having an error notification, one can simply scroll/scan the form to see which fields have errors anyway, so it's not necessary to expand the notification banner. This is just an idea and maybe it can be built upon it.8 points
-
Cheers Wishbone. I don't use bitnami much but really wanted to help Processwire get a higher profile. Hopefully this will help. Darren6 points
-
Almost one year later I'm happy to say that I finally got this autocomplete feature implemented to exclude pages option. Also forced mailto links can now be disabled from module config. Version got bumped to 1.0.2. This also means that our love and relationship with PW is soon having it's first birthday. What a year! Still having butterflies in stomach.6 points
-
One other small thing is that Ametys is a Java application. Having worked within two other java applications and been involved in their communities, they are a very tight knit and mutually supportive bunch. The Java communities are like a hidden part of the developer community, sometimes - or it can feel like that. When I started looking at Liferay, it was like I had found an entire new world. Here were hard working developers who said things like "yes, heard of Wordpress - never used it though so I haven't the foggiest" or "Joomla - is that still around?" And there tends to be a general distrust of anything PHP which many see as a security risk waiting to pounce. So, if Ametys got a lot of support from the java community, it would not necessarily be very obvious. Anyway .... probably enough of this subject now! There is the potential in the next couple of months of a few more people turning up to these forums looking for help and advice, so adding to any documentation might be more productive than moaning about a competition we just won! There, I had to say that - as an old fart of a bear, I kind of saw it as a duty! (or perhaps just a bad habit) Joss5 points
-
4 points
-
Okay, About time I put the lyrics down - you have to appreciate that I ad-libbed the entire thing at the time, playing the piano at the same time. Now are you wired? Soma's got the code, gonna make it right He's gonna program all damn night Diogo's got php on his mind Got stuck in a loop, he's in a bit of a bind Pete keeps panicking! His forum just broke He hopes all the others Just think its a joke They're all at Processwire They're living the Processwire Dream I've got it wired Processwire... Ryan is watching He knows that its true ProcessWire can kill the blues Its so real, it feels good! Processwire underneath the hood...4 points
-
i do this sort of thing now a lot, thanks to Ryan's CMS Critic Case Study; this is almost the same as WillyC's code at the above link /** * This hook modifies the default behavior of the Page::path function (and thereby Page::url) * * The primary purpose is to redefine blog posts to be accessed at a URL off the root level * rather than under /posts/ (where they actually live). * */ wire()->addHookBefore('Page::path', function($event) { $page = $event->object; if($page->template == 'post') { // ensure that pages with template 'post' live off the root rather than '/posts/' $event->replace = true; $event->return = "/$page->name/"; } });3 points
-
I could be wrong but I think those are carried over from the social network votes. Meaning, those 620 votes are probably their combined Facebook, g+1 and Twitter votes, which maybe are allowed to accumulate across contests? There clearly wasn't any gaming going on there though, because they started with 620 votes immediately the first second the contest began. All the other big players there also started with certain quantities before anyone had voted. That's why I think it's carried over from social networks. We do have 1-click module installing already. But we'll setup whatever else they need. I agree, thanks Darren for getting this started! There are a lot of other thanks to go around here too. I for one had kind of given up yesterday when it seemed like there was no legitimate way to win. Then Joss's dog started tweeting and he and others started asking for help from big players like @smashingmag, @modx, etc., and some of us found it very inspiring, among all the other things people were doing. Seeing people work so hard on something becomes contagious. The entire ProcessWire community got involved yesterday, which was fantastic to see whether we won or lost. I looked into their voting system in more detail yesterday after folks had expressed concerns (and after I'd sent that tweet). What I found was that whoever put it together knows what they are doing, unlike most similar voting systems. Their voting system is protected from iframe and/or ajax manipulation, meaning it's unlikely an exploit could take advantage of other users IP addresses without their knowledge (which was the problem with the opensourcecms.com voting system). The only exception would be users on old browsers like IE6 and IE7, but they may be accounting for that in some way I don't know about too. So while you can't accurately log these kinds of exploits, that point may not matter if the exploits are blocked in the first place. Regarding the 50 votes in a minute we may have seen from Ametys, I think the only thing that could produce that kind of result in this case would be if they sent a bulk-mailing to a big list. Social networks would be another way, but they don't have the social network reach to account for those numbers (unless they got a mention from someone else that does). It seems unlikely to me that 50 votes could be faked in a minute in this particular contest. Where the voting system does seem potentially problematic is when it comes to anonymizers (anonymous proxy servers). These are the kinds of services one uses if they might otherwise be blocked from a site due to geography, government, etc. These proxy server sites enable you to browse anonymously, automatically clear cookies, randomize the user agent, change the "location" (and thus IP) you are coming from, sometimes among hundreds or thousands of choices. They mask the identity of the original requester, as they don't pass through the usual headers that would lead you to the original IP. So as someone that has written voting systems similar to Bitnami's, these anonymizers scare me. I personally don't know of any way to account for or log that type of manipulation to votes. Though perhaps they do. The only silver lining in that I'd assume it takes real time, effort and money to use an anonymizer in this way–it's still manual labor, not a script, and probably not worth the effort for someone that wants to make a big dent (not a good way to get 50 votes in a minute). I'm assuming the previously mentioned Tor browser is a front-end to anonymous proxy servers, which falls in a similar scope. I think that a more accurate voting system would use a 1-to-1 mapping system between votes and social accounts from Facebook, g+1 and Twitter. But even that could be manipulated, as users might create numerous social network accounts. However, that's where it starts to take a whole lot more effort from that folks wishing to manipulate results (creating and validating accounts one after the other), increasing the odds of an accurate vote. The downside is that social-network oriented vote competitions are completely dependent upon social networks and it simply doesn't look as good as hosting your own. Not to mention, a certain percentage of very legitimate users avoid these social networks (our social network is our forum, after all). And philosophically, do we really want to hand any more of our keys and responsibilities over to these giant social networks? I prefer to get along without them intruding on everything in the web business. When it gets down to it, there really is no perfect way to handle an online voting system. So I think we need to cut the Bitnami folks some slack, as it does look like they are accounting for everything they can in the environment they have to work with (which is a lot more than most do). While I'd rather they just included the best software and avoided the whole contest thing in the first place... I'm sure the marketing folks want a contest (it's good for business). And if there has to be a contest, then at least they are taking the vote quality seriously.3 points
-
@dragan Add 'permission' => 'your-permission' to the array returned by the method getModuleInfo(). After this line: https://github.com/teppokoivula/ProcessChangelog/blob/master/ProcessChangelog.module#L35 Example: If all users who can edit pages should be able to access the module public static function getModuleInfo() { return array( 'title' => __('Changelog'), 'summary' => __('Keep track of changes (edits, removals, additions etc.)'), 'href' => 'http://modules.processwire.com/modules/process-changelog/', 'author' => 'Teppo Koivula', 'version' => 126, 'singular' => true, 'autoload' => false, 'installs' => 'ProcessChangelogHooks', 'permission' => 'page-edit', ); }2 points
-
Hi mlcb, welcome to processwire. A lot of beginners questions, like you are asking now, have already been answered in the forum. Just go through the forum channels to see if your questions are already answered there. http://processwire.com/talk/topic/4173-grouped-forum-posts-links-articles-tutorials-code-snippets/ What makes PW so different from other cms'es is that with PW you can directly use any html, css, php, etc, experience you already have. This is not the case with the other cms'es out there, where you have to learn their rules first before you can use them. In other words, PW can be used by both designers and coders even with little html and css experience. With PW you can make your own templates and fill them with your own api calls. Which brings me to what you have to learn with PW and that is it's powerfull api, http://processwire.com/api/ Feel free to work with wordpress, joomla, drupal, etc, so that you can compare them with PW and make your own conclusions. That is what I have done and made me see the open potential that PW has compared to the others. I wouldn't start with something so ambitious like that. Start with the tutorials first, learn the api and then work your way up.2 points
-
Hi, After reading this thread, I decided to make a module that helps generating PDF files of ProcessWire pages. GitHub: https://github.com/wanze/Pages2Pdf Modules Directory: http://modules.processwire.com/modules/pages2-pdf/ This module uses the mPDF library to generate the PDF files. It has fully UTF-8 and basic HTML/CSS support for rendering the PDF files. The output is customizable with ProcessWire templates. Example I've enabled generating PDF files for the skyscraper template of ryans Skyscrapers-profile with a template that outputs the data in a table along with the body text and the images: one-atlantic-center-pdf-4177.pdf Please take a look at the README on GitHub for instructions and further information/examples. Cheers1 point
-
This module tracks changes, additions, removals etc. of public (as in "not under admin") pages of your site. Like it's name says, it doesn't attempt to be a version control system or anything like that - just a log of what's happened. At the moment it's still a work in progress and will most likely be a victim of many ruthless this-won't-work-let's-try-that-instead cycles, but I believe I've nailed basic functionality well enough to post it here.. so, once again, I'll be happy to hear any comments you folks can provide https://modules.processwire.com/modules/process-changelog/ https://github.com/teppokoivula/ProcessChangelog How does it work? Exactly like it's (sort of) predecessor, Process Changelog actually consists of two modules: Process Changelog and Process Changelog Hooks. Hooks module exists only to serve main module by hooking into various functions within Pages class, collecting data of performed operations, refining it and keeping up a log of events in it's own custom database table (process_changelog.) Visible part is managed by Process Changelog, which provides users a (relatively) pretty view of the contents of said log table. How do you use it? When installed this module adds new page called Changelog under Admin > Setup which provides you with a table view of collected data and basic filtering tools See attached screenshots to get a general idea about what that page should look like after a while. For detailed installation instructions etc. see README.md.1 point
-
Hi! Just finished my first module This module adds a new "Google-Analytics" Page in your Admin-Panel and displays various Statistics from a Google Analytics Account. It uses the JQuery plugin "jqplot" to display the charts. Github: https://github.com/w...GoogleAnalytics Modules directory: http://modules.proce...ogle-analytics/ Features Visits by Date (Chart) General Statistics about Visits (Total visits, Visit duration, New visitors, Returning visitors etc.) Demographics: Countries, Cities, Languages System: Browsers, Operating Systems, Screen Resolutions Mobile: Operating Systems, Screen Resolutions Pageviews by Date (Chart) Top Content Traffic Sources: Keywords, Referral Traffic by Domain and URI Choose a default date range displaying statistics: last 24 hours, 2 days, 1 week, 1 month etc. Custom date range by setting a "start date" and "end date" Requirements Google Account and Analytics Account A Project in the Google APIs Console cURL Installation 1) Create a Project in the Google APIs Console: Create a new Project in the APIs Console: code.google.com/apis/console/ Under Services, enable the Analytics API Under API Access: create an Oauth 2.0 Client-ID Give a Product Name, choose "Web-Application", Domain doesn't matter Enter a Redirect URI to the GA-Page in your Processwire Installation: http://yourdomain.com/processwire/google-analytics/ Notes: The redirect URI must exactly match with the URL from the new "Google Analytics" page in Processwire. Open the Page and copy the URL from the address-bar (localhost does work too!) The project created in the APIs Console can be reused for every Processwire installation using this module. You just have to enter more redirect URIs 2) Install the module: Place the module's files in /site/modules/ProcessGoogleAnalytics Install the Module via the Admin-Panel Enter Client-ID and Client-Secret keys from the created project in the module config Load the newly created page "Google-Analytics" and click on the button "authenticate" Grant the module access to the Analytics Data Choose a Google Analytics account (Domain) from the dropdown Done: You should see the statistics. Check out the module config options for further customization In order to let other users see the Google Analytics page, you must give their role access to the "ga-view" permission. Ps. Processwire is awesome and so is this community!1 point
-
This tiny module is intended as a helper for Ryan's Hanna Code module by providing a way to select existing Hanna Code tags within the editor. This is something I felt our clients needed in order to start properly using Hanna Code tags. See attached screenshot for details -- there's really not that much to it at the moment. Each editor requires it's own plugin and currently I've only cooked one up for CKEditor, where the plugin presents itself as a context menu item (visible on right click). I'm planning to expand the feature set of that one slightly and then probably convert the CKEditor plugin to TinyMCE, but that's just about it. Ideas are welcome, though. Some of the code is pretty much duplicated from Ryan's original module. I hope he doesn't mind -- though for the record I've also tried to make it very clear in the source what part that is and where it's from.. GitHub: https://github.com/teppokoivula/HannaCodeHelper Modules directory: http://modules.processwire.com/modules/hanna-code-helper/1 point
-
Hi Folks, today we will learn how to set up a simple jquery plugin called calendario and fill events trough our admin backend. || ATTENTION || Modern Browser needed First of all, we need the jquery plugin. Grab your copy here: http://tympanus.net/...alendar-plugin/ Now create a new template file, lets call the file calendar.php In the next step we have to include all the needed files from the .zip package. You need the following .css files: calendar.css custom_2.css demo.css Just include them in the <head> </head> of your template file. Feel free to merge them together, so you could save some http connects. Now we need to include the needed javascript. Make sure you have included the latest jQuery library. Include the jquery.calendario.js and the modernizr.custom.63321.js right into the bottom of your template file. Save the calendar.php Now we will set up Processwire where the magic wil happen. We just need one new template. Create a new template called calendar. Assign the field headline to our template. Allow children to just use this template. Hit the save button. Now create a new Page as child of home and call it Calendar. Assign our calendar template to this page. Almost ready. Now we have to do some little scripting in our template file calendar.php Add this html markup to our calendar.php <div class="custom-calendar-wrap"> <div id="custom-inner" class="custom-inner"> <div class="custom-header clearfix"> <nav> <span id="custom-prev" class="custom-prev"></span> <span id="custom-next" class="custom-next"></span> </nav> <h2 id="custom-month" class="custom-month"></h2> <h3 id="custom-year" class="custom-year"></h3> </div> <div id="calendar" class="fc-calendar-container"></div> </div> </div> Now we have to call the javascript function, to get the calendar running. Just put this snippet right under the included jquery.calendario.js <script type="text/javascript" $(function() { var transEndEventNames = { 'WebkitTransition' : 'webkitTransitionend', 'MozTransition' : 'transitionend', 'OTransition' : 'oTransitionend', 'msTransition' : 'MSTransitionend', 'transition' : 'transitionend' }, transEndEventName = transEndEventNames[ Modernizr.prefixed( 'transition' ) ], $wrapper = $( '#custom-inner' ), $calendar = $( '#calendar' ), cal = $calendar.calendario( { onDayClick : function( $el, $contentEl, dateProperties ) { if( $contentEl.length > 0 ) { showEvents( $contentEl, dateProperties ); } }, caldata : { <?= getEvents(); ?> // this is our function to grab our events }, displayWeekAbbr : false } ), $month = $( '#custom-month' ).html( cal.getMonthName() ), $year = $( '#custom-year' ).html( cal.getYear() ); $( '#custom-next' ).on( 'click', function() { cal.gotoNextMonth( updateMonthYear ); } ); $( '#custom-today' ).on( 'click', function() { cal.gotoNow( updateMonthYear ); } ); $( '#custom-prev' ).on( 'click', function() { cal.gotoPreviousMonth( updateMonthYear ); } ); function updateMonthYear() { $month.html( cal.getMonthName() ); $year.html( cal.getYear() ); } // just an example.. function showEvents( $contentEl, dateProperties ) { hideEvents(); var $events = $( '<div id="custom-content-reveal" class="custom-content-reveal"><h4>Termine am ' + dateProperties.day + '. ' + dateProperties.monthname + ' ' + dateProperties.year + '</h4></div>' ), $close = $( '<span class="custom-content-close"></span>' ).on( 'click', hideEvents ); $events.append( $contentEl.html() , $close ).insertAfter( $wrapper ); setTimeout( function() { $events.css( 'top', '0%' ); }, 25 ); } function hideEvents() { var $events = $( '#custom-content-reveal' ); if( $events.length > 0 ) { $events.css( 'top', '100%' ); Modernizr.csstransitions ? $events.on( transEndEventName, function() { $( this ).remove(); } ) : $events.remove(); } } }); </script> We are almost finished, but we are missing some very essential, have a look to our javascript. We are calling a function named getEvents() This function will grab our events and fire it right to our calendar. So here is the code: function getEvents() { $events = wire('pages')->get("/calendar/")->children(); foreach ($events as $event) { echo "'$event->title' : '<span>$event->headline</span> ',"; } } Put this snippet above the javascript includes. We will now create our first entry. Go back to the PW admin backend and create a Child of Calendar. Title and name need the Date on which the event has to be displayed. You have to form a date in this format: mm-dd-yyyy e.g. 12-27-2012. The headline field is our Event description. Hit the save button, go to your site and enjoy your event calendar. With a little coding you could extend the calendar to let it look like mine attached as screenshot. Hope this was useful to somebody. Cheerio.1 point
-
Hey PW, I am only a starting developer and I am still in school and my experience with processwire is quite small but recently I've created my own module for Processwire and I kind of had to ask and copy a lot from other sources, now I want to create a small walk through tutorial for people with the same lack of knowledge as me And as a guide for myselfs in the future 1) Setting up the file. Okay, so we start of by making a new document in the Module root folder and call it Harmster.module for this example, we dont need to add the .php extension. Now every module in Processwire needs to extends the classes and methods from Processwire itselfs so we start off by typing class Harmster extends Process{ } You can also extend WireData, I don't really understand the difference but both work for me A module contains 2 standart classes, init() and getModuleInfo() init() This is kind of, or the same as a __construct() method, this always executes and is executed almost at creation. getModuleInfo() This is a method that is used to show the information in the Processwire CMS. We both need to add these to our fresh class like following: class Harmster extends WireData { public static function getModuleInfo() { return array( 'title' => 'Harmster', 'version' => 100, 'summary' => 'Harmster module' 'singular' => true, ); } public function init() { $this->setFuel("harmster", $this); } This is where I, as a starting developer, get really excited about this little code in the init() method $this->setFuel("harmster", $this); Basically creates your class in every template you are going to use and it is callable by $harmster Woah! awesome right! Now this is where I got stuck on, I the user to configure some options in the module :\ hmm... Well I just went asking on the forums and the super nice community of PW came to help me, Wanze in this case (no emoticon because its not allowed) (Check it for yourselfs, http://processwire.c...lds-for-module/) And basically you need to implement some methods from an another object, you should replace this, class Harmster extends WireData implements Module with class Harmster extends Process implements Module, ConfigurableModule But when you add that and try to use your module you'll see you get an error, we need to add one more method to the class called getModuleConfigInputfields add static public function getModuleConfigInputfields(array $data) { } 2) Adding a configurable and usable textbox But now you want to add some input fields, now this is pretty hmm complicated For a simple textbox you put this inside the method you just made: $modules = Wire::getFuel('modules'); $fields = new InputfieldWrapper(); $field = $modules->get("InputfieldText"); $field->attr('name+id', ''some_text_field_saved_name''); $field->attr('value', $data['some_text_field_saved_name']); $field->label = "Hamsters rule!"; $field->description = 'Enter a nice sentance here if you like hamsters'; $fields->append($field); Now you've created a input field and you can use it with $this->get(''some_text_field_saved_name''); in all your methods in this class (no emoticon because its not allowed) If you're lazy Now what you've created is a configurable module, heres a I am lazy and i want to pastey (no emoticon because its not allowed) class Harmster extends Process implements Module, ConfigurableModule { public static function getModuleInfo() { return array( 'title' => 'Harmster', 'version' => 001, 'summary' => '', 'href' => '', 'singular' => true, 'autoload' => true, ); } public function init() { $this->fuel->set("harmster", $this); } static public function getModuleConfigInputfields(array $data) { } } Now if you want to add a overview page, much like the setup, pages, acces and module tab in Processwire CMS default you can easily do this by adding 2 new methods in your class, install and uninstall 3) Creating your install and uninstall So you want to get a nice overview for your module now eh? Well we can do that because Processwire is awesome like that I did this for my module Now, we need to add 2 methods to our class, ___install and ___uninstall (yes, 3 underscores) So add this to your class: public function ___install() { } public function ___uninstall() { } I think that these are kind of self explaing, the one method gets executed when the user installs the module and the other one gets executed when the user deinstalls the module. Now we want to add a page to PW CMS, but how (no emoticon because its not allowed) Thats actually really easy, $page = $this->pages->get('template=admin,name='.self::PAGE_NAME); if (!$page->id) { $page = new Page(); $page->template = $this->templates->get('admin'); $page->parent = $this->pages->get($this->config->adminRootPageID); $page->title = 'MailChimp'; $page->name = self::PAGE_NAME; $page->process = $this; $page->save(); } This is how you install a page, notice that we name the page to self::PAGE_NAME therefor you want to add const PAGE_NAME = 'harmster-module'; with the name of your module BUT BUT now everyone can look in to this module D:< i dont want that! Ofcourse you dont want that. Clients are famous for breaking everything where they put their hands on, so we need to create permissions! Now the way you make permissions is just genius and so easy, you just add this to your ___install method, $permission = $this->permissions->get(self::PERMISSION_NAME); if (!$permission->id) { $p = new Permission(); $p->name = self::PERMISSION_NAME; $p->title = $this->_('View Harmster Page statistics and synchronize pages with lists'); $p->save(); } And you create a permission constant just like PAGE_NAME like this const PERMISSION_NAME = 'hr-view'; And of course you can create more permissions, just genius! Now what our install method should look like is this: public function ___install() { $page = $this->pages->get('template=admin,name='.self::PAGE_NAME); if (!$page->id) { $page = new Page(); $page->template = $this->templates->get('admin'); $page->parent = $this->pages->get($this->config->adminRootPageID); $page->title = 'Harmster'; $page->name = self::PAGE_NAME; $page->process = $this; $page->save(); } $permission = $this->permissions->get(self::PERMISSION_NAME); if (!$permission->id) { $p = new Permission(); $p->name = self::PERMISSION_NAME; $p->title = $this->_('View Harmster Page statistics and synchronize pages with lists'); $p->save(); } } This will set a module page up for you And we create an uninstall method, this basicly reverts your installed permissions and pages. public function ___uninstall() { $permission = $this->permissions->get(self::PERMISSION_NAME); if ($permission->id) { $permission->delete(); } $page = $this->pages->get('template=admin, name='.self::PAGE_NAME); if ($page->id) { $page->delete(); } } Now you are might be wondering, how do i get to display content in my page :S Well, I kinda stole this from other modules and it does work, but I am open for suggestions. the method ___execute gets executed when you click on your page in the PWCMS. What i wrote in there is public function ___execute() { return $this->_renderInterface(); } and in renderInterface() i put the next code: private function _renderInterface() { $this->setFuel('processHeadline', 'MailChimp synchronize tool'); $form = $this->modules->get('InputfieldForm'); $form->attr('id','ga_form'); $wrapper_audience = new InputfieldWrapper(); $field = $this->modules->get("InputfieldMarkup"); $field->label = $this->_("Gebruikers"); $field->columnWidth = 100; $members = $this->list_members($this->get_apikey()); $html = "<table class='AdminDataTable AdminDataList AdminDataTableSortable'>"; foreach($members['data'] as $member) { $html .= "<tr><td>" . $member['email'] . "</td><td>" . $member['timestamp'] . "</td></tr>"; } $html .= "</table>"; $field->attr('value',$html); $wrapper_audience->append($field); $form->append($wrapper_audience); return $form->render(); } Bascily you create a form and you render the form and that displays it for you, just play around with it for a bit and you'll get into it, as i am still getting into it. I am lazy, here a copy, pastey (no emoticon because its not allowed) <?php class Harmster extends Process implements Module, ConfigurableModule { const PAGE_NAME = 'harmster-module'; const PERMISSION_NAME = 'hr-view'; public static function getModuleInfo() { return array( 'title' => 'Harmster', 'version' => 001, 'summary' => '', 'href' => '', 'singular' => true, 'autoload' => true, ); } public function init() { $this->fuel->set("harmster", $this); } static public function getModuleConfigInputfields(array $data) { } public function ___install() { $page = $this->pages->get('template=admin,name='.self::PAGE_NAME); if (!$page->id) { $page = new Page(); $page->template = $this->templates->get('admin'); $page->parent = $this->pages->get($this->config->adminRootPageID); $page->title = 'Harmster'; $page->name = self::PAGE_NAME; $page->process = $this; $page->save(); } $permission = $this->permissions->get(self::PERMISSION_NAME); if (!$permission->id) { $p = new Permission(); $p->name = self::PERMISSION_NAME; $p->title = $this->_('View Harmster Page statistics and synchronize pages with lists'); $p->save(); } } public function ___uninstall() { $permission = $this->permissions->get(self::PERMISSION_NAME); if ($permission->id) { $permission->delete(); } $page = $this->pages->get('template=admin, name='.self::PAGE_NAME); if ($page->id) { $page->delete(); } } public function ___execute() { return $this->_renderInterface(); } private function _renderInterface() { $this->setFuel('processHeadline', 'MailChimp synchronize tool'); $form = $this->modules->get('InputfieldForm'); $form->attr('id','ga_form'); $wrapper_audience = new InputfieldWrapper(); $field = $this->modules->get("InputfieldMarkup"); $field->label = $this->_("Gebruikers"); $field->columnWidth = 100; $members = $this->list_members($this->get_apikey()); $html = "<table class='AdminDataTable AdminDataList AdminDataTableSortable'>"; foreach($members['data'] as $member) { $html .= "<tr><td>" . $member['email'] . "</td><td>" . $member['timestamp'] . "</td></tr>"; } $html .= "</table>"; $field->attr('value',$html); $wrapper_audience->append($field); $form->append($wrapper_audience); return $form->render(); } } I'll update this tutorial in the near future as i am still working my way up (no emoticon because its not allowed) Aww, i get an error when i save it, thats not nice. Thanks for reading (no emoticon because its not allowed)EDIT Updating this tutorial very soon, its horrible and incorrect1 point
-
Would it much work to build it as a universal module? Maybe with a config file to match the database table fields? So everybody can use it independent of use case. Just an idea. Maybe to much work to do it.1 point
-
@Wanze. This module is even more useful then the analytics at google.com/analytics/ Those contain so much info, customers drowning in it. Your's has the right balance, just what we/they need.1 point
-
<qoute>. It would be cool to have them generated via the admin ui </quote> Thats easy for simple tables use repeaters.1 point
-
I'm glad you like it landitus. In a sense, PW already has those tables by default - they are just not set up yet . As you know, PW gives you the tools to build what you want (in this case MarkupAdminDataTable). If you look at the code in my example module, it is all PW API. Yes, it has some in built classes to interact with javascript, but it is all PW. Part of PW philosophy is to be clean, lean and mean and not make presumptions. I am liking your idea about generating such tables via the admin UI. Actually, similar things have been done. See the proof-of-concept module by Soma DataTable. Batcher also comes close. Ryan has also spoken of developing a site where pages appeared in a table (IIRC) when they reached a certain number in the tree or toggable or something. I can't really remember the details. But yes, it can be done. Back to the admin tables, if it is something you'd like to discuss, let's open a new thread. In a sense though, Batcher already fulfils some of the functions you are talking about, albeit it is not configurable in terms of what to display.1 point
-
@dragan...a clarification - if you have a chance, have a look at Wanze's code in his module Batcher. He creates a permission "batcher" which you can give a certain role. Although the batcher page appears under setup, it doesn't have to be moved manually from under setup in order for the non-supersuser (manager in your case) to see it. They will only see "batcher" or in your case "changelog" under the setup menu; nothing else. Try it and see! Speaking of batcher, I prefer the route batcher takes of creating a permission to give access to the module rather than applying it site-wide with a page-edit permission (Wanze was just giving an example above). Of course, there will be times you don't mind giving permissions site-wide....OK, enough rambling...Hope this makes sense! Edited for clarity1 point
-
WillyC, that's great!!!!! I didn't realize that cause I'm in the DEV environment all the time. Perfect! At least for the client it won't be a problem as it's on the server with debug off. This is a relief. Notifications still annoys me while developing. The new debug tools ui is such a good example I'm keen on replicating the collapsible UI this for notifications. But guess is not such a priority as the client won't be flooded with messages. Either way, I stand by the notion the notifications UI is better as one line of text as it pushes the page down. It would a better UI IMHO1 point
-
One (definitely not fool-proof but still useful) approach is to rely on those same proxy sites and implement a simple blacklist. Hide My Ass! has a nice list of public proxy site IP's you can use -- and, surprise surprise, even buy as a .txt file. For $25 they even promise to email you updated copy every day "for life". How's that for a business model?1 point
-
well said, Ryan!! it's the difference between being right and getting right ;-) justiciable arguments are rare...1 point
-
And by fishing, I mean the sort with a line, hook and dinner attached to the end. http://harlestonanglingclub.co.uk/ I haven't done any of the content this time - it is all the clients work directly onto the site, including any images. It is mostly a pretty straightforward website with a few bits and pieces. They can change the main header image as well as the large site background image. They can manage the slideshow of course. There is a link system with categories that automatically generates a list of places that also sell tickets. Repeater fields are used for things like the ticket prices tables. The fixture list is a bit of fun and thanks to various people here for helping with that a few months ago. It automatically sorts into Years, then months, then days. Graphically, all I did was create their main header banner and a map on the contact page. Since the "management" have a pretty dry way of writing, my main concern was to give the site a lot of air and openness to try and take away from that a little. The site was built with Bootstrap 3 in about two days or so. It has taken nearly three months to get the content sorted out I had one amusing issue. When I uploaded to their host (having persuaded them to upgrade from the Zeus server they were still on), I discovered that the page name for the admin I had chosen, happened to be one of a pile of aliases the hosts use for their control panel. So I could not login. Oops. Thankfully, changing the page name in the database solved the problem.1 point
-
Congratulations! After fretting over it for nine pages I'm glad it turned out well.1 point
-
Well, to start with I suggest you go play with one of the tutorials. http://wiki.processwire.com/index.php/Basic_Website_Tutorial This is a pretty thorough one which demonstrates some very basic use of php and so on - it walks you through it very simply, so you wont get lost. The chances are, if you have some basic understanding of how this works together, then you will find you learn faster than you think. The advantages are that even though you have to actually get your hands dirty rather than use plug-and-play addons, the resulting site is much leaner, faster, more efficient and far more maintainable - after all, you will know every nook and cranny of it! So, play with that tutorial, maybe try the news one after which is also on the wiki site, and see how you get on. Good luck!1 point
-
Thanks kongondo!! This module is just what I needed. I will check it out! I've been working on my own version of an admin table, so this is a lifesaver I definitely think that PW should have these tables by default with search and filtering. It would be cool to have them generated via the admin ui, with options as which templates to list or from which parent or a custom search (just like the Page field options). It would complement the site tree in a nice way. Blogs and other kinds of data are better displayed as a table. This module looks neat!1 point
-
There are a few different ways to do this, including htaccess rewrites, but this code from willyc is a good option: http://processwire.com/talk/topic/1799-routes-and-rewriting-urls/ A few other posts worth reading: http://processwire.com/talk/topic/4847-redirect-in-htaccess/ http://processwire.com/talk/topic/3275-hide-parent-page-from-url/ http://processwire.com/talk/topic/4521-how-to-customize-urls/1 point
-
If interested in further developing your php skills, some handy tips I have received/learned from the pros in these forums include.. var_dump gettype - this will tell you the data type - object, array, etc. exit - this will allow you to go get some coffee ;-) - instead of smashing your head against the wall! (kidding!) Happy coding!1 point
-
I have a setup with several templates without a templatefile. But I want to render some of the pages using these templates with $page->render($filename). I think I did not understand how the $page->render options work. A simple example: In the default profile I just delete the "basic-page.php" file and create a new file "basic-page-alt.php" with this simple code <?php // basic-page-alt.php echo "<h1>$page->template</h1>"; and I modify the home.php file to<?php // home.php include("./head.inc"); echo $pages->get('/about')->render("basic-page-alt.php"); include("./foot.inc"); When I try to view the homepage I get an errorError: Exception: Template file does not exist: '/XXX/Sites/pw_test/site/templates/basic-page.php' (in /Users/XXX/pw_test/wire/core/TemplateFile.php line 67) When I put a empty "basic-page.php" back in my templates folder I get the expected result. I am using the latest dev from github. Is this the intended behaviour?1 point
-
This is not intended behavior. Good call. It's happening because the TemplateFile class is checking if the file it's given exists from the constructor rather than from the render() method. The PageRender module gets a copy of the TemplateFile instance from the Page, and then changes the filename if you've given if one. As a result I think I can solve this just by moving the "file does not exist" exception out of the TemplateFile constructor and to the render() method. I've just made the change, so it should appear in the next batch of commits to dev.1 point
-
Here are my docs for the shop I've been building with PrestaShop: presta-docs.zip Using prism.js to highlight code and this wonderful js function to escape html entities I discovered at the last minute after worrying about this for over a month. If he has time to review it, I'm interested in what Antti thinks about my Checkout.fi implementation (I'm still a newbie to stuff like this and serious development in general). The docs show how PrestaShop users have to jump through all kinds of flaming hoops to bend the shop to their will. I also have one open issue that you SQL wizards might know the answer to: in the PrestaShop SQL manager that does CSV exports, I'd like to be able to concatenate all the addresses of a single customer into one field, while this creates a new row for every address: SELECT CONCAT_WS(' ', g.lastname, g.firstname) AS Customer, g.id_customer AS customerID, CONCAT_WS(' ', ad.address1, ad.address2, 'City:', ad.postcode, ad.city, ad.other, 'Phone:', ad.phone, 'Mobile:', ad.phone_mobile) AS Addresses, gl.name AS group_name, g.email FROM ps_customer g LEFT JOIN ps_address ad ON (g.id_customer = ad.id_customer) LEFT JOIN ps_group_lang gl ON (g.id_default_group = gl.id_group) AND gl.name LIKE 'piiri%'1 point
-
Ok, i just build paypal module, will release it soon after little testing. Will also test everything with shopping cart that alll work with latest PW.1 point
-
Many thanks for the info pwFoo! I really should go about test this myself asap, but have been busy developing my first PW site I'm not sure the .htaccess file should be a too big problem. For rilpartner.se, .for example, we are successfully ourselves using nginx, which has its own URL handling, and I could easily add the single rewrite rule needed to get it to work ... and I from what I've hear, hhvm should be able to run with nginx, using fastCGI / fasterCGI. Will also report if I get the time to test this out more!1 point
-
Hi, doesn't see hhvm before but looks interesting... htaccess and php.ini support seems missing at the moment, but is planned. I'll read some more about it and maybe do some (simple) tests with it... *update* Simple installation (CentOS 6 yum repo) and a simple php test works fine, but to run PW, Drupal ... I think the htaccess file have to be converted, because apache, htacess, php.ini isn't supported by hhvm yet... But seems to be work in progress.1 point
-
Just pushed some updates. Module is now v1.3.0 Form readme: Changes in 1.3.0 Changed module setting singular to false. This enables you load the module as a new instance with $nav = $modules->MarkupSimpleNavigation. This changes behavior for hooks attached to such an instance as it will only be called for this instance. This allows you to create multiple instances of the module to create different navigations with separate hooks. Added support for Page::listable. So you can exclude listing of pages in runtime by modifying this page permission. This can be done using a system hook on Page::listable and set the hook event to return false. Added new option date_format for created and modified native page properties. Added new option code_formatting, to enable or disable code formatting (indentation and newlines) of output markup. Added new option debug that will output rendertime and selector infos as commented inline html. Added support for Page::listable Usually you won't need this, but I needed it in a project so thought it wouldn't hurt. Usually you can hide pages from rendering in a list/navigation by setting the page to hidden in the admin. So this additional check in the module itself, allows you to make pages not listed on runtime. This can be used to check for logged in users that only should see the page listed when logged in. Example hook inside template just before calling render(): wire()->addHookAfter("Page::listable", null, "hookPageListable"); function hookPageListable($event){ $page = $event->object; if($page->template == "internal-page") { $event->return = false; // set listable to false if template "internal-page" } } Added new option debug If set to true this option will add an inline <!-- [MarkupSimpleNavigation Rendertime: 0.0171] --> after the markup output to show rendertime, and <!-- [Selector Level1: limit=3] --> on each item to see selector being used. This new version should still be compatible with older versions. But there could be instances where it could behave different when you have multiple navigations and using hooks. But chances are very small you run into this. If you have questions to the above just ask.1 point
-
1 point
-
Started a new module for creating <tables> from repeater fields. Feel free to grab it from github, do with it what you want. It only works for simple text based fields inside a repeater. To use it: $table = $modules->get("RepeaterTable"); // initialize $table->thead = true; // (bool) true/false, default = true, will render <th> $table->indent = 3; // (mixed) false/int, where int is the level of indentation, default: false $table = $table->render($page->repeater); // repeaterfield called repeater <!-- output --> <table class="table-repeater"> <thead> <tr> <th class="col-1">Fieldlabel field 1</th> <th class="col-2">Fieldlabel field 2</th> <th class="col-3">Fieldlabel field 3</th> </tr> </thead> <tbody> <tr class="row-1"> <td class="col-1">data for field 1, first repeater item</td> <td class="col-2">data for field 2, first repeater item</td> <td class="col-3">data for field 3, first repeater item</td> </tr> <tr class="row-2"> <td class="col-1">data for field 1, second repeater item</td> <td class="col-2">data for field 2, second repeater item</td> <td class="col-3">data for field 3, second repeater item</td> </tr> </tbody> </table> For the HTML purist, I have added source code indentation where you can set how many tabs you wish to append before each element. Please let me know if I should add this to the modules directory ? Does someone have a good name for this ?1 point
-
Some fun stuff just pushed to the dev branch: the core now includes a Modules Manager "Lite". The screenshots below best describe how it works. But it lets you install modules from the directory just by typing (or pasting) in the module's class name. It also provides a 1-click capability to check for a given module's updates and upgrade it when necessary. Beyond that, the modules screen is now split into tabs: Site, Core and New. Site shows just your /site/modules/, and Core shows just your /wire/modules/. The New tab is where you can install modules. I really wanted a solution that kept the actual browsing for modules out of the CMS. Not because I think it's a bad idea (it's a great idea) but because I wanted the modules directory (modules.processwire.com) to serve that purpose as much as possible, at least as a default. That way I don't have to worry about scalability as the size of the modules directory increases. Plus less automation might make the newbies be a little more careful about what they are installing and where it's coming from. The power of the automation in ModulesManager here is so powerful it scares me, so think it's better for the users that know what they are doing. Lastly, ModulesManager is one of the best modules out there and Soma does an amazing job with it. Bringing a little taste of ModulesManager into the core I thought would help both projects. Most credit for the new core "Modules Manager Lite" goes to Soma (though he doesn't yet know that). It's all built around his code lifted directly from Modules Manager. Hope that's okay Soma? Your code now powers not just the new stuff in ProcessModule, but also the new WireHttp::download function, and the new wireUnzipFile() function, all added this week. People who want the most power will still want to use Soma's Modules Manager. That does a whole lot more than the built-in one does, including installation of themes, checking for updates en-masse, and browsing and filtering through the modules directory. But now you can install ModulesManager or other modules without having to manually FTP things to your server (so long as your /site/modules/ is writable). Please let me know if you guys run into any issues with it.1 point
-
Love your idea, Soma. I created a php file in the root of my site called tinymce.php which I can edit and then simply load in the browser www.mysite.com/tinymce.php to send all of the changes to all my tinyMCE fields. Here's my code for anyone who might be confused by this: <?php include('./index.php'); $fields = wire("fields")->find("name=body|sidebar|introduction|affiliates"); foreach($fields as $field) { $field->theme_advanced_buttons1 = "formatselect,|,styleselect,styleprops,|,fontsizeselect,forecolor,|,bold,italic,underline,strikethrough,|,hr,|,justifyleft,justifycenter,justifyright,|,bullist,numlist,|,indent,outdent,nonbreaking"; $field->theme_advanced_buttons2 = "undo,redo,|,tablecontrols,|,pastetext,|,link,unlink,anchor,|,image,|,replace,|,removeformat,|,code,|,fullscreen"; $field->theme_advanced_buttons3 = ""; $field->theme_advanced_blockformats = "p,h2,h3,h4"; $field->plugins = "inlinepopups,safari,media,paste,fullscreen,table,nonbreaking,searchreplace,style"; $field->valid_elements = "*[*]"; $field->content_css = "/site/templates/styles/content.css"; $field->custom = "theme_advanced_styles:Test Style=test paste_text_sticky:true"; $field->thirdparty = ""; $field->save(); } The name=body|sidebar|introduction|affiliates line selects all of my tinymce fields by name (Soma's example assumed that your tinymce fields all had tinymce_ prefixes on them, which mine do not, so I am just listing all of them out instead). It then loops through each matching field and updates each setting. Pretty cool!1 point
-
The parent_id and template_id are one way to go, but you could instead use 'findPagesSelector'. You can set this to a Field object, or you can set it to an InputfieldPageAutocomplete instance, like this: $f = $this->modules->get('InputfieldPageAutocomplete'); $f->label = 'Exclude in pages'; $f->attr('name', 'exclude_pages'); $f->attr('value', $this->exclude_pages); $selector = "parent_id=1, template!=admin"; foreach($this->exclude_tpls as $name) { $selector .= "|$name"; } // example: parent_id=1, template!=admin|this|that|whatever $f->findPagesSelector = $selector;1 point
-
In the Field setting screen of a TinyMCE field you can configure much if not everything. Tab "Input" you see the TinyMCE Advanced Configuration Options. Add "paste" to the plugins string. Add paste_text_sticky: true paste_text_sticky_default: true to the Additional TinyMCE Setting field. If you want to add it globally to al TinyMCE fields you could add following to the default.php in your admin theme. Before closing </head> <script> // overwrite TinyMCE skin setting globally // as defined in /wire/modules/Inputfields/InputfieldTinyMCE/InputfieldTinyMCE.js // and loaded before if('undefined' != typeof InputfieldTinyMCEConfigDefaults) { InputfieldTinyMCEConfigDefaults.plugins += ",paste"; InputfieldTinyMCEConfigDefaults.paste_text_sticky = true; InputfieldTinyMCEConfigDefaults.paste_text_sticky_default = true; } </script>1 point
-
Wow, tried this and it worked <script> InputfieldTinyMCEConfigDefaults.skin = "default"; </script> put it on the default.php of your theme after all the other scripts or before </body>1 point
-
i.am first you can puut this in your head.inc tamplate or some includeded file before.u are doing $page->url $pages->addHookAfter('Page::path', null, 'hookPagePath'); function hookPagePath(HookEvent $e) { $page = $e->object; if($page->template == 'article') $e->return = "/blog/$page->name/"; }1 point
-
You may also be able to setup an automatic sort by editing the repeater's template file and setting it under the 'Family' tab. Note that the repeater templates aren't visible in your templates list at first so you'll need to check the box to "show system templates" in the filter menu.1 point