thanks for response; follow-up; I've got something working…
[ikiwiki] / doc / todo / publishing_in_the_future.mdwn
1 [[!tag wishlist]]I would quite like the ability to write a page (blog post in
2 practice) but for the page to not be displayed until a date and time after it
3 is added to the wiki. I've thought this through a bit, but would appreciate
4 feedback from people before I go any further. Would anyone else find this
5 useful?
6
7 Thinking about how to implement this in ikiwiki, perhaps a conditional
8 pagespec would be best (which could be tidied up into a template)
9
10     \[[!if test="current_date_before(<TMPL_VAR date>)"
11     then="""[[!tag draft]]"""
12     else="""[[!meta date="<TMPL_VAR date>"]]"""
13     ]]
14
15 …pre-supposing a scheme whereby tagging 'draft' hides the page from an
16 aggregation somewhere.  With a template, this could collapse to
17
18     \[[!template id=publishafter date="Thu Aug 30 14:13:06 BST 2012"]]
19
20 This would require implementing the `current_date_before` pagespec.
21
22 You would also need a regularly scheduled wiki refresh and a way of marking the
23 unpublished pages as 'dirty' so they were always scanned on refresh until their
24 publish date has occurred. That could perhaps be implemented via a small plugin
25 which defined a pagespec which ensured the page was 'dirty':
26
27     \[[!meta date="<TMPL_VAR date>"]]
28     \[[!if test="!current_date_before(<TMPL_VAR date>)"
29     then="""[[!tag draft]][[!dirty]]"""
30     ]]
31
32 The following is an attempt at the dirty part:
33
34     #!/usr/bin/perl
35     package IkiWiki::Plugin::dirty;
36     # provides a pagespec 'dirty' which ensures the page will always be
37     # re-scanned for content on wiki refresh.
38     
39     use warnings;
40     use strict;
41     use IkiWiki 3.00;
42     
43     hook(type => "preprocess", id => "dirty", call => \&preprocess);
44     hook(type => "needsbuild", id => "dirty", call => \&needsbuild);
45     
46     sub preprocess (@) {
47       my %params = @_;
48       $pagestate{$params{page}}{dirty}{dirty} = 1;
49       return '';
50     }
51     
52     sub needsbuild (@) {
53       my $pages= shift;
54       my %p2 = map { $_ => 1 } @$pages;
55       my %d2 = map { $_ => 1 } @$deleted;
56     
57       foreach my $page (keys %pagestate) {
58         if(exists $pagestate{$page}{dirty}{dirty}) {
59           push @$pages, $pagesources{$page} unless
60             (exists $p2{$pagesources{$page}} or exists $d2{$pagesources{$page}});
61           delete $pagestate{$page}{dirty}{dirty};
62         }
63       }
64     
65       return $pages;
66     }
67     
68     1
69
70 Although it doesn't fit, the `current_date_before` pagespec could be implemented
71 in the same plugin. I tried the following (before the trailing `1`):
72
73     package IkiWiki::PageSpec;
74     use Date::Parse;
75     
76     sub match_current_date_before ($$;@) {
77       shift;
78       my $date = shift;
79       my $out = str2time($date);
80       if(defined $out) {
81         return IkiWiki::SuccessReason->new("time before now") if $out < time();
82         return IkiWiki::FailReason->new("time not before now");
83       } else { return IkiWiki::ErrorReason->new("couldn't parse time $date")};
84     }
85
86 I always hit the `ErrorReason` branch when I try to use it, even with strings
87 which work fine in test scripts.  If anyone can help me debug that I'd be very
88 grateful.
89 If anyone has any clues as to why this doesn't work 
90
91 Thoughts on the whole idea? — [[Jon]]
92
93 > There is an old todo about it: [[tagging_with_a_publication_date]].
94 > I feel my idea there about making a pagespec that is limited to
95 > items in the present/past, combined with setting the meta data, is a good
96 > way.. --[[Joey]]  
97
98 >> Thanks for your response Joey. Should I merge these two TODOs, then?
99 >> So if I understand you correctly, you would prefer some new pagespecs
100 >> to match future/past dates, and a plugin which kept track of pages with
101 >> a future date and kept them 'dirty' (similar to the above), which means
102 >> avoiding the need for a `dirty` pagespec in the page itself. Is that
103 >> about right?
104 >> 
105 >> I came up with the following, but I haven't adapted `dirty.pm` inline
106 >> with my understanding above, yet.
107
108     sub match_infuture ($$;@) {
109       my $page = shift;
110       return IkiWiki::SuccessReason->new("page time is in the future")
111         if $IkiWiki::pagectime{$page} > time;
112       return IkiWiki::FailReason->new("page time is not in the future");
113     }
114
115 >> I've managed to get my original suggestion working. The problem was
116 >> I was using quotes when invoking the pagespec, which stopped `str2time`
117 >> working. 
118 >> 
119 >> Let me know if I've understood your POV correctly and I'll see about
120 >> tidying this up and putting it in a branch.
121 >> 
122 >> Finally, a way of scheduling future runs of ikiwiki *within ikiwiki
123 >> itself* might be useful for other things too, and would avoid the 
124 >> need for a cron job in this case. (I'm thinking of a plugin that
125 >> implemented itself in terms of cron, or at, or both, or possibly
126 >> other things depending on what people want to support). But that would
127 >> be substantially more work, more than I can afford atm at least. — [[Jon]]