== Extension Point : ''IWikiPageManipulator'' == ||'''Interface'''||''IWikiPageManipulator''||'''Since'''||0.10|| ||'''Module'''||''trac.wiki''||'''Source'''||[source:trunk/trac/wiki/api.py#/IWikiPageManipulator api.py]|| The ''IWikiPageManipulator'' can manipulate and validate wiki pages before saving or before rendering. == Purpose == A plugin can add new restrictions on users when creating or changing wiki pages. They can also show validation warnings whenever a wiki page is rendered. (E.g. to help find validation errors in old content.) It's also possible to manipulate a page (although a [wiki:../trac.wiki.api.IWikiSyntaxProvider IWikiSyntaxProvider] may be more appropriate for that) or it's fields before saving. == Usage == Implementing the interface follows the standard guidelines found in [wiki:TracDev/ComponentArchitecture] and of course [wiki:TracDev/PluginDevelopment]. The `validate_wiki_page` method is called when a user creates or modifies a wiki page. Returning a list of messages rejects the (changed) page, returning `[]` accepts it. Note that the `validate_wiki_page` method can also be used to ''manipulate'' the page's fields before they are saved. Note that the previous values of a changed page can be accessed in `page.old_text`. (See comment:3:ticket:7731) The `prepare_wiki_page` method is called when a page is rendered. (Currently this is the only `prepare_*` method of a `I*Manipulator` interface that actually gets called.) It can for example add validation warnings using `trac.web.chrome.add_warning`. == Examples == The following example implementation was taken from comment:3:ticket:9096. It validates wiki pages before saving and when rendering a page. {{{#!python from trac.core import * from trac.wiki.api import IWikiPageManipulator from trac.web.chrome import add_warning class TracWikiValidator(Component): implements(IWikiPageManipulator) def validate(self, page): lines = page.text.splitlines() if not lines: return ["Page shouldn't be empty"] messages = [] if not lines[0].lstrip().startswith("= "): messages.append("First line must be the page's '= title ='") # etc. return messages # IWikiPageManipulator def prepare_wiki_page(self, req, page, fields): for message in self.validate(page): add_warning(req, message) def validate_wiki_page(self, req, page): for message in self.validate(page): yield ('text', message) }}} == Available Implementations == * SpamFilter: Rejects spam. * th:InputfieldTrapPlugin: Rejects spam with a hidden input field. * th:MathCaptchaPlugin: Rejects spam with math question CAPTCHA. * th:HierWikiPlugin: Rejects hierarchically unstructured wiki sub-pages. * th:TagsPlugin: Uses a redirection trick to ''skip'' default validation. * [http://code.optaros.com/trac/oforge/ OForge] (!WikiToolsPlugin): Uses a redirection trick to ''skip'' default validation. * th:ForceCommentPlugin: Rejects changes where the ''comment'' field is not filled out. == Additional Information and References == * [http://www.edgewall.org/docs/trac-trunk/epydoc/trac.wiki.api.IWikiPageManipulator-class.html epydoc] * [http://www.edgewall.org/docs/trac-trunk/html/api/trac_ticket_api.html#trac.wiki.api.IWikiPageManipulator API Reference] * See [../trac.wiki.api.IWikiChangeListener trac.wiki.api.IWikiChangeListener] * See [../trac.attachment.IAttachmentManipulator trac.attachment.IAttachmentManipulator], [../trac.ticket.api.ITicketManipulator trac.ticket.api.ITicketManipulator] * Related tickets: * [query:keywords=~IWikiPageManipulator IWikiPageManipulator keyword] * [query:"status!=closed&component=wiki system" wiki system component] * #10125 Discusses how `prepare_wiki_page` is the only `prepare_*` method of an `I*Manipulator` interface that actually gets called and how the others should be modelled after this. API Evolution: * 0.10: Introduced * [ticket:5992 0.11]: Collect all warnings instead of raising `InvalidWikiPage`. * (Contains a SPAM test plugin) * [wiki:TracDev/ApiChanges/0.12#IWikiPageManipulator 0.12]: Provide both `page.text` and `page.old_text`. (#7731) * [ticket:9096 0.12] Introduced the call to `prepare_wiki_page` before rendering.