Jump to content

BitPoet

Members
  • Posts

    1,331
  • Joined

  • Last visited

  • Days Won

    61

Everything posted by BitPoet

  1. Attention: please don't install this module at the time being! It is not compatible with current PW versions, and it will be some time until I can work in all the changes. Due to a discussion here in the forums, I was inspired to finally have a take on datetime fields and see if I couldn't get them to be searched a little more conveniently. Here's a small module - still in alpha state, but I'd be happy to get some feedback - that allows searching for individual components of a date like year, month, day, hour or even day_of_week or day_of_year, and also returning them. Github repo: DatetimeAdvanced Current version: 0.0.5 Tested in: ProcessWire 2.8 + 3.0 Possible subfields: day month year hour minute second day_of_week day_of_year week_of_year Examples: // Database search: $pagelist = $pages->find("mydatefield.year=2016"); // Filtering PageArray in memory: $maypages = $pagelist->filter("mydatefield.month=5"); // Back to our starting point: $start = date('z'); $end = $start + 7; $sevendays = $pages->find("mydatefield.day_of_year>=$start, mydatefield.day_of_year<$end"); // Nice side effect: subfields are now directly accessible $blogentry = $pages->get('blog-entry-1'); echo $blogentry->title . "(" . $blogentry->publishdate->year . ")"; // New in 0.0.4: shorthand methods echo $blogentry->publishdate->strftime("%Y-%m-%d %H:%M:%S") . PHP_EOL; echo $blogentry->publishdate->date("Y-m-d H:i:s") . PHP_EOL; ToDos for the future: See if there's a possibility to specify ranges more conveniently Check if this can perhaps wiggle its way into the PW core Changes: example for direct subfield access and shorthand methods to strftime() and date() added.
  2. Okay, here we go. FieldtypeDatetimeAdvanced with database and PageArray filtering support and descriptive naming. Possible subfields: day month year (4-digit) hour (0..23) minutes seconds day_of_week (0..6, 0 = Sunday) day_of_year (0..365) week_of_year (1..53) Examples: // Database search: $pagelist = $pages->find("mydatefield.year=2016"); // Filtering PageArray in memory: $maypages = $pagelist->filter("mydatefield.month=5"); // Back to our starting point: $start = date('z'); $end = $start + 7; $sevendays = $pages->find("mydatefield.day_of_year>=$start, mydatefield.day_of_year<$end");
  3. Calling arbitrary MySQL functions would be nice, but I think these date features should probably be a different topic, as I'd prefer it if they also worked for filtering PageArrays. That would AFAIK mean using a wrapper class in place of the plain timestamp that is currently used as the unformatted value though. Got to fiddle with that when I have time in the evening.
  4. As I've been pondering that same task a few times before, I've drawn up a quick&dirty proof-of-concept module that extends PW's regular FieldtypeDatetime, adding (database) search functionality by using date_format. It's lacking sanitizing and not really thought through all the way, but I'd love to get some thoughts on whether this might be worthwhile to pursue. <?php /** * Advanced Datetime Field * * Allows searching for datetime fields by passing a format string * to MySQL's format_date function as a subfield (only one format option * and without the % sign). * * A list of all format strings can be found at * http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_date-format * * Examples: * $pages->find("my_date_field.e=27") * // Searches for all pages having the 27th in my_date_field * * $pages->find("my_date_field.Y=2016") * // Searches for pages with year 2016 in my_date_field * * $start = date('z') + 1; // PHP starts at 0, MySQL at 1 * $end = $start + 6; * $pages->find("my_date_field.j>=$start, my_date_field.j<$end") * // All pages in the seven day period starting today **/ class FieldtypeDatetimeAdvanced extends FieldtypeDatetime implements Module { public static function getModuleInfo() { return array( "title" => "Advanced Datetime field", "summary" => "Datetime field with extended search syntax", "version" => "0.0.1", ); } /** * Match a date/time value in the database, as used by PageFinder * */ public function getMatchQuery($query, $table, $subfield, $operator, $value) { if($subfield != "data") { $value = $this->_sanitizeValue($value); $database = $this->wire("database"); if($database->isOperator($operator)) { $table = $database->escapeTable($table); $value = $database->escapeStr($value); $query->where("DATE_FORMAT({$table}.data, '%{$subfield}'){$operator}'$value'"); $this->log->message($query->getQuery()); } } else { $this->log->message("Regular query"); $value = (int) $this->_sanitizeValue($value); if($value) $value = date('Y-m-d H:i:s', $value); else $value = ''; $database = $this->wire('database'); if($database->isOperator($operator)) { $table = $database->escapeTable($table); $subfield = $database->escapeCol($subfield); $value = $database->escapeStr($value); $query->where("$table.{$subfield}{$operator}'$value'"); } } return $query; } }
  5. I had to do some tinkering around with WebODF and Wodo.texteditor to see if this was a possible approach for modifying report templates in the backend. Turned out there were too many features missing, but I've nonetheless uploaded a very basic (and experimental) module to github that let's you edit ODT (Open Document Text, format used by OpenOffice and LibreOffice). I'll be brushing it up a bit when/if time allows. If anybody wants to take a look or steal/improve on the idea: FieldtypeOdfFile Have fun!
  6. You can specify the fields to display in the page tree in the templates' "Advanced" tab. Just enter something like {title} - [{template.name}] where it says "List of fields to display in the admin Page List". It may also be sufficient to assign a different icon for each template in the Advanced tab. These will be shown in front of the title (or custom label as above) in the page tree.
  7. Have a look here, your problem sounds quite similar to what is described in the article.
  8. Here's a snippet that should do what you need. I don't know of any pre-built solution for it, since all pagination features that I've seen want to work with Pages/PageArrays. $limit = 20; $offset = ($input->pageNum - 1) * $limit; $images = array(); $total = 0; // Iterating through all image pages, make sure to put the right page into $parentpage foreach($parentpage->children("sort=sort") as $pg) { // If we're at or above our offset and do still need more images to output if(count($images) < $limit && $pg->images->count() + $total >= $offset) { // If offset is above total count so far, calculate start, else go from beginning $start = ($offset > $total) ? $offset - $total : 0; // How many images do we still need? $missing = $limit - count($images); // Add up to $limit images to our array, perhaps you might need to call // $pg->image->sort("name") beforehand to get images in the right order $images = array_merge($images, array_slice($pg->images->getArray(), $start, $missing)); } $total += $pg->images->count(); } // Output images foreach($images as $img) { echo "<img src='$img->url'><br>\n"; } $prevlink = $nextlink = ""; // Build prev link only if we aren't at first page if($input->pageNum > 1) $prevlink = "<a href='{$page->url}page" . ($input->pageNum - 1) . "/'>< Prev</a>"; // Build next link only if there are more images to display if($total > $input->pageNum * $limit ) $nextlink = "<a href='{$page->url}page" . ($input->pageNum + 1) . "/'> Next ></a>"; ?> <div style='border: 1px solid grey;'><?= $prevlink ?> ... <?= $nextlink ?></div>
  9. @adrian: that's why there's a Page::getLanguageValue method as well, and since $language is an descendant of Page, you can say: $langtitle = $language->getLanguageValue($language, "title");
  10. It's actually not difficult at all to add the button and make it do what you want. PW is all about HTML + PHP, no fancy magical layers and MV(V)C patterns to bump your head against (unless you really want them, that is). Like @Sephiroth said, you can use PW's Inputfields to get consistent appearance for the backend, but you don't have to. The code in _pagereport_backend.php echoes the HTML making up the interface, so just output a button with a unique name you can check for as well: echo "<h1>Reports to manage:</h1>\n" . "<form method='POST' action='$page->url'><input type='submit' name='delete_read' value='Delete all read'></form><br />\n" . $table->render(); Now you only have to check at the top of _pagereport_backend.php if a POST value of delete_read has been passed, and if yes, find all pages with report_read=1 and delete them. Deleting pages is done through the $pages variable, and finding them can be either done through $pages too, directly through the current page ($page->find()) or by limiting $page->children() to those with a read status. The syntax for finding pages (i.e. selectors) is well-documented. It boils down to snippet of code like this: if($input->post->delete_read) { foreach($page->children("report_read=1") as $read) { $pages->delete($read); // Could also use $pages->trash($read) instead to have a failsafe } }
  11. I do, as processwire doesn't have this functionality out of the box. I need a way to review reported links or pages in the admin panel, when someone clicks to report a link, a new report is created for me to review. I have to review these links or pages in the admin panel. The only way for me to have a page in the admin panel where I review all the reported pages (or links), is to create a module. Believe me, you don't. If you'd followed my link, you would have realized that too. Ranting without reading the help given won't get you closer to a solution. As for the time issues you mention: there's always the choice between doing things quick&dirty and doing things right, especially in programming. Why do people build regular pages on Wordpress? Because they know it and get a quick solution to an immediate problem, but in the long run, they fight against the software they are using because it wasn't meant for this kind of thing. When I estimated that the time would, initially, be roughly the same for using PW and another framework, I was taking into account starting at zero with both, since there's yet no clickading thingy that plucks ideas from a brain and automagically adds it to a web page. ProcessWire is a framework too, and it also has its concepts and best practices. They aren't that many, but they need to be understood. The docs do give a good introduction to them, and there's plenty of information in the forum if you search for the keywords if you need more explanation. Here's a short step-by-step approach to solving your task without a custom module and just one non-core module: Preparations Download and Install the AdminCustomPages module from the module repository The template with the fields used to store reports Create a new field "reported_page" and set the field type as Page, in the settings select "single page or null page" Create a new field "report_message" and set the field type to Text Create a new field "report_read" and set the field type to Checkbox Create a new template "pagereport" in the backend and add the three fields you just created, ignore the message that there isn't a template file present The backend interface Create a file named "_pagereport_backend.php" in site/templates Go to "Page" and expand the tree to "Admin" -> "Pages", then click "New" next to that Set the title of the new page "Manage Reported Pages" and save. The template will automatically be set to "admin". Now, as the process for this template, select "ProcessAdminCustomPages". You can now select the "_pagereport_backend.php" file you created earlier. Click "Publish" The frontend page with the reporting form Create a file named "enterreport.php" in site/templates Create a new template and check "enterreport" Save Create a new page under "home", title it "Report Page" and select the template "enterreport" On the "Settings" tab, check "hidden" so it won't appear in searches and lists Publish You're all set up now, all you need is the PHP code and markup now. Edit "_pagereport_backend.php" and enter the following code, which will render a table with all reports, has links to the reported page and lets you directly mark them as read. It uses the core module MarkupAdminDataTable so you don't have to build the table manually. <?php if($input->get->mark_id_read) { $report = $pages->get($input->get->mark_id_read); $report->of(false); $report->report_read = 1; $report->save(); } $children = $page->children("sort=report_read, sort=-created"); $table = $modules->get("MarkupAdminDataTable"); $table->setEncodeEntities(false); $table->headerRow(array( "Reported", "Page", "Message", "Read" )); foreach($children as $report) { $table->row(array( strftime("%Y-%m-%d %H:%M", $report->created), "<a href='{$report->reported_page->url}' target='_blank'>{$report->reported_page->title}</a>", $report->report_message, $report->report_read ? "Yes" : "<a href='$page->url?mark_id_read={$report->id}'>No</a>" )); } echo "<h1>Reports to manage:</h1>\n" . $table->render(); Now, edit the "enterreport.php" file and add the code to enter a report: <?php if($input->get->page_id) { $pg = $pages->get($input->get->page_id); ?> <h1>Report page <?= $pg->title ?> (<?= $pg->url ?>)</h1> <form method="POST" action="<?= $page->url ?>"> <input type="hidden" name="page_id" value="<?= $input->get->page_id ?>"> Please leave a short reason why you are reporting this page (e.g. SPAM or offensive):<br /> <input type="text" name="report_message" size="80"><br /> <input type="submit" name="submit_report" value="Report this page"> </form> <?php } else if($input->post->submit_report) { $pg = $pages->get($input->post->page_id); $prnt = $pages->get("name=manage-reported-pages"); $report = new Page(); $report->template = "pagereport"; $report->parent = $prnt; $report->name = (new DateTime)->format("Ymd-Hisu"); $report->reported_page = $input->post->page_id; $report->report_message = $input->post->report_message; $report->save(); echo "<h1>Page '{$pg->title}' has been reported. Thank you!</h1><a href='#' onclick='window.close();'>Close this window</a>"; } else { echo "<p>No page given. If this problem persists when you try to report a page, please contant the administrator.</p>"; } All that's left to do is add the link to the report page somewhere in your template file, e.g. in a basic profile in _foot.php: <a href="<?= $pages->get("name=report-page")->url ?>?page_id=<?= $page->id ?>" target="_blank">Report this page</a> Creating a module would just mean wrapping most of the things I described here into an install routine and adding some shortcut routines (e.g. for rendering the markup that links to the report page form). You can now easily tweak the interface, e.g. by filtering the children in _pagereport_backend.php by "report_read!=1" to only show unread reports. You can add a field (e.g. the client IP) to the reportpage template and need only two lines in enterreport.php to render and save it and two in _pagereport_backend.php to display it (column header and value). Each report is actually a page underneath Manage Reported Pages, and you can even use PW's regular page tree to view or delete reports.
  12. @desbest: You don't even need to write a module for that kind of thing, but you will have to build the logic for reporting and storing reported pages somewhere - that storage though may well be a page in the admin with e.g. a Page Table field or a Repeater, but you'll have to read up on those a bit to get a feel for what each entails. The logic to report a page can be built into the main page or into a page on its own (with its own template), where the later options gives you more flexibility and avoids a page reload if you popup the form for reporting in an iframe. Your backend interface to the reported pages list can then be built using the AdminCustomPages module. Since you're new to PW, there will be a bit of a learning curve, and I'd guess that it won't be much quicker initially than using a barebone framework where you can plumb a few odd pieces together until it works, but in the long run, it will be far easier to extend and much more intuitive to maintain, since all you'll be dealing with will be PW pages and fields.
  13. I only get the same incorrect output as you if the script that invokes pageNameUTF8 (or the passed string) is encoded in iso-8859 instead of utf8. When everything is properly encoded, I get back the string with umlauts intact.
  14. I just had a déjà vu.
  15. Silly question perhaps, but is your site/config.php saved as UTF8?
  16. Did you try it? The translated contents of an option are in its properties title$languageid and value$languageid.
  17. Yes, switching to a non-debug build is the way to go.
  18. foreach($all_options as $option) { $title = $language->isDefault() ? $option->title : $option->get("title$language"); echo "<option value='$title'>$title</option>"."\n"; } ?>
  19. Yes, in the first table phpinfo prints, there should be a line starting with "Debug Build".
  20. @verdeandrea: This notice is shown when PHP was compiled with Zend debugger enabled and an empty file field is submitted. The best course of action would be to install a non-debug build of PHP. Temporarily, a possible workaround might be to disable E_NOTICE warnings by setting "error_reporting(E_ALL & ~E_NOTICE);" in site/config.php.
  21. I was thinking of Inputfields return from getModuleConfigInputfields. Here's a snippet to illustrate my thought: wire()->addHookAfter("Modules::saveConfig", function(HookEvent $event) { wire('log')->message("Hook after Modules::saveConfig"); $class = $event->arguments(0); if(is_object($class)) $class = $class->className(); $moduleName = wireClassName($class, false); $id = wire('modules')->getModuleID($class); $data = $event->arguments(1); $fields = wire('modules')->getModuleConfigInputfields($moduleName); foreach(array_keys($data) as $key) { if(! $fields->get($key)) { unset($data[$key]); wire('log')->message("Removed property $key from module {$moduleName} config"); } } // Code shamelessly stolen from Modules::saveConfig $json = count($data) ? wireEncodeJSON($data, true) : ''; wire('log')->message("Data = $json"); $database = $this->wire('database'); $query = $database->prepare("UPDATE modules SET data=:data WHERE id=:id", "modules.saveConfig($moduleName)"); // QA $query->bindValue(":data", $json, \PDO::PARAM_STR); $query->bindValue(":id", (int) $id, \PDO::PARAM_INT); $result = $query->execute(); $this->log("Stripped module '$moduleName' config data"); $event->return = $result; });
  22. Can I leave a vote to make the restore optional? @tpr: the topic also came up here. Currently, PW carries over old field settings infinitely, though it might be worth a thought to make PW core (Modules::saveConfig) forget no longer applicable field values.
  23. I think using an after or replacement hook on Modules::saveConfig should be possible, even if it creates a bit of repetition overhead. Retrieve the fields list (again) through getModuleConfigInputfields(), then iterate over all configuration values, unset() the respective entry if $fields->get($key) returns null and finally save (again). It's actually a tiny bit more complex since language support also needs to be taken into account, but not that much.
  24. And you can find all 12 if you run a find for template=municipality_page without a province?
  25. Hm, I understood your original post so that searching for words with accented characters only works if you substitute the hyphen, but I may have misread that. Still, trying to solve one mystery at a time: are the pages that aren't found activated for the French language? (Since Colombie-Britannique should be found in any case)
×
×
  • Create New...