PageRenderTime 71ms CodeModel.GetById 34ms RepoModel.GetById 0ms app.codeStats 0ms

/smd_each/smd_each.php

https://bitbucket.org/mrdale/txp-plugins
PHP | 624 lines | 431 code | 100 blank | 93 comment | 77 complexity | a88cb753178fb8d9d017ec7ffe3fd945 MD5 | raw file
  1. <?php
  2. // This is a PLUGIN TEMPLATE for Textpattern CMS.
  3. // Copy this file to a new name like abc_myplugin.php. Edit the code, then
  4. // run this file at the command line to produce a plugin for distribution:
  5. // $ php abc_myplugin.php > abc_myplugin-0.1.txt
  6. // Plugin name is optional. If unset, it will be extracted from the current
  7. // file name. Plugin names should start with a three letter prefix which is
  8. // unique and reserved for each plugin author ("abc" is just an example).
  9. // Uncomment and edit this line to override:
  10. $plugin['name'] = 'smd_each';
  11. // Allow raw HTML help, as opposed to Textile.
  12. // 0 = Plugin help is in Textile format, no raw HTML allowed (default).
  13. // 1 = Plugin help is in raw HTML. Not recommended.
  14. # $plugin['allow_html_help'] = 1;
  15. $plugin['version'] = '0.2';
  16. $plugin['author'] = 'Stef Dawson';
  17. $plugin['author_uri'] = 'http://stefdawson.com/';
  18. $plugin['description'] = 'Iterate over TXP, URL or smd_vars variables';
  19. // Plugin load order:
  20. // The default value of 5 would fit most plugins, while for instance comment
  21. // spam evaluators or URL redirectors would probably want to run earlier
  22. // (1...4) to prepare the environment for everything else that follows.
  23. // Values 6...9 should be considered for plugins which would work late.
  24. // This order is user-overrideable.
  25. $plugin['order'] = '5';
  26. // Plugin 'type' defines where the plugin is loaded
  27. // 0 = public : only on the public side of the website (default)
  28. // 1 = public+admin : on both the public and admin side
  29. // 2 = library : only when include_plugin() or require_plugin() is called
  30. // 3 = admin : only on the admin side (no AJAX)
  31. // 4 = admin+ajax : only on the admin side (AJAX supported)
  32. // 5 = public+admin+ajax : on both the public and admin side (AJAX supported)
  33. $plugin['type'] = '0';
  34. // Plugin "flags" signal the presence of optional capabilities to the core plugin loader.
  35. // Use an appropriately OR-ed combination of these flags.
  36. // The four high-order bits 0xf000 are available for this plugin's private use
  37. if (!defined('PLUGIN_HAS_PREFS')) define('PLUGIN_HAS_PREFS', 0x0001); // This plugin wants to receive "plugin_prefs.{$plugin['name']}" events
  38. if (!defined('PLUGIN_LIFECYCLE_NOTIFY')) define('PLUGIN_LIFECYCLE_NOTIFY', 0x0002); // This plugin wants to receive "plugin_lifecycle.{$plugin['name']}" events
  39. $plugin['flags'] = '0';
  40. // Plugin 'textpack' is optional. It provides i18n strings to be used in conjunction with gTxt().
  41. // Syntax:
  42. // ## arbitrary comment
  43. // #@event
  44. // #@language ISO-LANGUAGE-CODE
  45. // abc_string_name => Localized String
  46. /** Uncomment me, if you need a textpack
  47. $plugin['textpack'] = <<<EOT
  48. #@admin
  49. #@language en-gb
  50. abc_sample_string => Sample String
  51. abc_one_more => One more
  52. #@language de-de
  53. abc_sample_string => Beispieltext
  54. abc_one_more => Noch einer
  55. EOT;
  56. **/
  57. // End of textpack
  58. if (!defined('txpinterface'))
  59. @include_once('zem_tpl.php');
  60. # --- BEGIN PLUGIN CODE ---
  61. // -------------------------------------------------------------
  62. // Iterate over arbitrary matching variables, either from TXP fields or on the URL line
  63. // by Stef Dawson
  64. function smd_each($atts, $thing='') {
  65. global $pretext, $thisarticle, $thisfile, $thislink, $variable;
  66. extract(lAtts(array(
  67. 'type' => 'field',
  68. 'include' => '',
  69. 'exclude' => '',
  70. 'match' => '',
  71. 'matchwith' => 'name',
  72. 'subset' => '0',
  73. 'collate' => '',
  74. 'form' => '',
  75. 'delim' => ',',
  76. 'paramdelim' => ':',
  77. 'outdelim' => ',',
  78. 'wraptag' => '',
  79. 'break' => '',
  80. 'class' => '',
  81. 'var_prefix' => 'smd_',
  82. 'debug' => '0',
  83. ), $atts));
  84. // Lookups for allowable options
  85. $matchOpts = array('name', 'value');
  86. // Validate the options
  87. $thing = (empty($form)) ? $thing : fetch_form($form);
  88. $thing = (empty($thing)) ? '{'.$var_prefix.'var_value}' : $thing;
  89. $include = do_list($include, $delim);
  90. $include = ($include[0] == "") ? array() : $include;
  91. $exclude = do_list($exclude, $delim);
  92. $exclude = ($exclude[0] == "") ? array() : $exclude;
  93. $match = do_list($match, $delim);
  94. $match = ($match[0] == "") ? array() : $match;
  95. $matchwith = do_list($matchwith, $delim);
  96. foreach ($matchwith as $thismatch) {
  97. $matches[] = (in_array($thismatch,$matchOpts)) ? $thismatch : $matchOpts[0];
  98. }
  99. $matches = array_unique($matches);
  100. // Set up collated quoting if necessary
  101. if ($collate) {
  102. $quotes = array('SMDNONE');
  103. $collateOpts = do_list($collate, $delim);
  104. foreach ($collateOpts as $option) {
  105. $indexes = do_list($option, $paramdelim);
  106. $colType = array_shift($indexes);
  107. // Supplying 'quote' on its own will empty the relevant array, implying "ALL" fields are to be quoted
  108. switch ($colType) {
  109. case "quote":
  110. $quotes = $indexes;
  111. break;
  112. }
  113. }
  114. }
  115. // Make up an array of name => value pairs populated from the arrays of the chosen $types
  116. $types = array();
  117. $vars = array();
  118. $type = do_list($type, $delim);
  119. foreach ($type as $thistype) {
  120. switch ($thistype) {
  121. case "urlvar":
  122. if ($_POST) $vars = smd_each_grab($_POST, $vars, 'doSpecial, doStripTags', $delim, $subset);
  123. if ($_GET) $vars = smd_each_grab($_GET, $vars, 'doSpecial, doStripTags', $delim, $subset);
  124. break;
  125. case "svrvar":
  126. if ($_SERVER) $vars = smd_each_grab($_SERVER, $vars, 'doSpecial, doStripTags', $delim, $subset);
  127. break;
  128. case "cookie":
  129. if ($_COOKIE) $vars = smd_each_grab($_COOKIE, $vars, 'doSpecial, doStripTags', $delim, $subset);
  130. break;
  131. case "txpvar":
  132. if ($variable) $vars = smd_each_grab($variable, $vars, '', $delim, $subset);
  133. break;
  134. case "fixed":
  135. $newvars = array();
  136. foreach ($include as $key => $value) {
  137. $subs = do_list($value, $paramdelim);
  138. if (count($subs) > 1) {
  139. $newvar = array_shift($subs);
  140. $extravars[$newvar] = join($delim, $subs);
  141. // The new variable's values have been extracted and stored, so overwrite the array entry with just the variable name
  142. $include[$key] = $newvar;
  143. }
  144. }
  145. if ($extravars) $vars = smd_each_grab($extravars, $vars, 'doStripTags', $delim, $subset);
  146. break;
  147. case "field":
  148. case "default":
  149. if ($thisfile) $vars = smd_each_grab($thisfile, $vars, '', $delim, $subset);
  150. if ($thislink) $vars = smd_each_grab($thislink, $vars, '', $delim, $subset);
  151. if ($pretext) $vars = smd_each_grab($pretext, $vars, '', $delim, $subset);
  152. if ($thisarticle) $vars = smd_each_grab($thisarticle, $vars, 'doStripTags', $delim, $subset);
  153. break;
  154. }
  155. }
  156. if ($debug) {
  157. echo "++ VARIABLE POOL ++";
  158. dmp($vars);
  159. }
  160. // Filter the array if necessary into a smaller array of desired elements
  161. $filtervars = array();
  162. // Named variables are always copied across
  163. if ($include) {
  164. foreach ($include as $thisname) {
  165. if ($thisname != "") {
  166. $re = '/('.$thisname.'(_[0-9]*)?)/';
  167. $num = preg_match_all($re, join($delim,array_keys($vars)), $keynames);
  168. for ($ctr = 0; $ctr < $num; $ctr++) {
  169. $filtervars[$keynames[0][$ctr]] = $vars[$keynames[0][$ctr]];
  170. }
  171. }
  172. }
  173. }
  174. // Any names/values matching $match are also added
  175. if ($match) {
  176. foreach ($vars as $key => $val) {
  177. if (in_array("name", $matches) && (!array_key_exists($key, $filtervars))) {
  178. foreach ($match as $thismatch) {
  179. if ($thismatch && strpos($key, $thismatch) !== false) {
  180. if ($debug) {
  181. dmp("ADDING ".$key." (from name) ");
  182. }
  183. $filtervars[$key] = $val;
  184. break;
  185. }
  186. }
  187. }
  188. // No point checking the values if the variable has already been added to the filtered list
  189. if (in_array("value", $matches) && (!array_key_exists($key, $filtervars))) {
  190. foreach ($match as $thismatch) {
  191. if ($thismatch && strpos($val, $thismatch) !== false) {
  192. if ($debug) {
  193. dmp ("ADDING ".$key." (from value) ");
  194. }
  195. $filtervars[$key] = $val;
  196. break;
  197. }
  198. }
  199. }
  200. }
  201. }
  202. // Remove any excluded variables
  203. if ($exclude) {
  204. foreach ($exclude as $thisname) {
  205. if ($thisname != "") {
  206. $re = '/('.$thisname.'(_[0-9]*)?)/';
  207. $num = preg_match_all($re, join($delim,array_keys($filtervars)), $keynames);
  208. for ($ctr = 0; $ctr < $num; $ctr++) {
  209. if ($debug) {
  210. dmp("EXCLUDING ".$keynames[0][$ctr]);
  211. }
  212. unset ($filtervars[$keynames[0][$ctr]]);
  213. }
  214. }
  215. }
  216. }
  217. // If no filters are specified
  218. if (!$include && !$exclude && !$match) {
  219. $filtervars = $vars;
  220. }
  221. if ($debug && ($filtervars != $vars)) {
  222. echo "++ FILTERED VARS ++";
  223. dmp($filtervars);
  224. }
  225. // Throw the name => value pairs at the form
  226. $out = array();
  227. $collations = array();
  228. $ctr = 1;
  229. $totalvars = count($filtervars);
  230. foreach ($filtervars as $key => $val) {
  231. $replacements = array(
  232. '{'.$var_prefix.'var_name}' => $key,
  233. '{'.$var_prefix.'var_value}' => $val,
  234. '{'.$var_prefix.'var_counter}' => $ctr,
  235. '{'.$var_prefix.'var_total}' => $totalvars,
  236. );
  237. // Solos are items in the output form that require details from a specific row. Useful only in collation
  238. // mode, they are added to the replacements array on an as-needed basis to save space/time
  239. $soloRE = '/\{'.$var_prefix.'([a-z0-9_]+)#'.$ctr.'\}/';
  240. $numSolos = preg_match_all($soloRE, $thing, $solos);
  241. for ($soloCtr = 0; $soloCtr < $numSolos; $soloCtr++) {
  242. $fieldname = '{'.$var_prefix.$solos[1][$soloCtr].'#'.$ctr.'}';
  243. $grabfield = '{'.$var_prefix.$solos[1][$soloCtr].'}';
  244. $replacements[$fieldname] = $replacements[$grabfield];
  245. }
  246. if ($debug) {
  247. echo "++ REPLACEMENT #$ctr ++";
  248. dmp($replacements);
  249. }
  250. // In collate mode the form is only parsed at the end: build a collosal multi-dimension array of all items here
  251. if ($collate) {
  252. foreach ($replacements as $defName => $defVal) {
  253. $collations[$defName][] = $defVal;
  254. }
  255. } else {
  256. $out[] = parse(strtr($thing, $replacements));
  257. }
  258. $ctr++;
  259. }
  260. // Handle quoting of collations
  261. if ($collate) {
  262. foreach ($collations as $item => $list) {
  263. // Quote the lists if required
  264. $list = (empty($quotes) || in_array($item, $quotes)) ? doArray($list, 'doQuote') : $list;
  265. $collations[$item] = implode($outdelim, $list);
  266. }
  267. if ($debug) {
  268. echo "++ COLLATIONS ++";
  269. dmp($collations);
  270. }
  271. $out[] = parse(strtr($thing, $collations));
  272. }
  273. return doWrap($out, $wraptag, $break, $class);
  274. }
  275. // -------------------------------------------------------------
  276. // Take an array of name-value pairs, process and combine them with what is already in $out.
  277. // Handle sub-lists as well
  278. function smd_each_grab($item, $out='', $proc='', $dlm=',', $sub=0) {
  279. $out = ($out) ? $out : array();
  280. $proc = do_list($proc, $dlm);
  281. $proc = ($proc[0] == "") ? array() : $proc;
  282. while (list($key, $val) = each($item)) {
  283. $val = (is_array($val)) ? join($dlm, $val) : $val;
  284. if ($sub) {
  285. if ($sub == 1) {
  286. // Add the complete element before attempting to split it
  287. foreach($proc as $op) {
  288. $val = $op($val);
  289. }
  290. $out[$key] = $val;
  291. }
  292. $vals = do_list($val, $dlm);
  293. $ctr = 1;
  294. foreach ($vals as $subval) {
  295. foreach($proc as $op) {
  296. $subval = $op($subval);
  297. }
  298. $out[$key.'_'.$ctr++] = $subval;
  299. }
  300. } else {
  301. foreach($proc as $op) {
  302. $val = $op($val);
  303. }
  304. $out[$key] = $val;
  305. }
  306. }
  307. return $out;
  308. }
  309. # --- END PLUGIN CODE ---
  310. if (0) {
  311. ?>
  312. <!--
  313. # --- BEGIN PLUGIN CSS ---
  314. <style type="text/css">
  315. #smd_help { line-height:1.5 ;}
  316. #smd_help code { font-weight:bold; font: 105%/130% "Courier New", courier, monospace; background-color: #FFFFCC;}
  317. #smd_help code.block { font-weight:normal; border:1px dotted #999; background-color: #f0e68c; display:block; margin:10px 10px 20px; padding:10px; }
  318. #smd_help a:link, #smd_help a:visited { color: #00c; text-decoration: none; border-bottom: 1px solid blue; padding-bottom:1px;}
  319. #smd_help a:hover, #smd_help a:active { color: blue; text-decoration: none; border-bottom: 2px solid blue; padding-bottom:1px;}
  320. #smd_help h1 { color: #369; font: 20px Georgia, sans-serif; margin: 0; text-align: center; }
  321. #smd_help h2 { border-bottom: 1px solid black; padding:10px 0 0; color: #369; font: 17px Georgia, sans-serif; }
  322. #smd_help h3 { color: #079; font: bold 12px Arial, sans-serif; letter-spacing: 1px; margin: 10px 0 0;text-transform: uppercase; text-decoration:underline;}
  323. #smd_help h4 { font: bold 11px Arial, sans-serif; letter-spacing: 1px; margin: 10px 0 0 ;text-transform: uppercase; }
  324. #smd_help .atnm { font-weight:bold; color:#33d; }
  325. #smd_help .mand { background:#eee; border:1px dotted #999; }
  326. #smd_help table {width:90%; text-align:center; padding-bottom:1em; border:1px solid #666;}
  327. #smd_help td, #smd_help th {border:1px solid #999; padding:.5em 0;}
  328. #smd_help ul { list-style-type:square; }
  329. #smd_help li { margin:5px 20px 5px 30px; }
  330. #smd_help .break { margin-top:5px; }
  331. </style>
  332. # --- END PLUGIN CSS ---
  333. -->
  334. <!--
  335. # --- BEGIN PLUGIN HELP ---
  336. <div id="smd_help">
  337. <h1 id="top">smd_each</h1>
  338. <h2 id="features">Features</h2>
  339. <ul>
  340. <li>Iterate over any variables you can get your hands on. These can be anything from the current article (custom field, article_image, etc), any <span class="caps">URL</span>/SERVER variable or cookie (subject to normal escaping rules) or any <code>&lt;txp:variable /&gt;</code></li>
  341. <li>Include or exclude particular variables, or only choose variables that match particular text</li>
  342. <li>Iterate over subsets of data contained in any field</li>
  343. <li>Choose to process each variable one by one with a form, or collect them together into a delimited list to be processed only once by the form</li>
  344. <li>Provides free headaches if you don&#8217;t keep your wits about you</li>
  345. </ul>
  346. <h2 id="author">Author</h2>
  347. <p><a href="http://stefdawson.com/commentForm">Stef Dawson</a>. For other software by me, or to make a donation, see the <a href="http://stefdawson.com/sw">software page</a>.</p>
  348. <h2 id="install">Installation / Uninstallation</h2>
  349. <p>Download the plugin from either <a href="http://textpattern.org/plugins/986/smd_each">textpattern.org</a>, or the software page above, paste the code into the <span class="caps">TXP</span> Admin -&gt; Plugins pane, install and enable the plugin. Visit the <a href="http://forum.textpattern.com/viewtopic.php?id=27464">forum thread</a> for more info or to report a bug/feature request.</p>
  350. <p>To remove the plugin, simply delete it from the Admin-&gt;Plugins tab.</p>
  351. <h2 id="usage">Usage</h2>
  352. <p>For some ideas on usage scenarios, see the <a href="#examples">examples</a>.</p>
  353. <h3 class="tag " id="smd_each">smd_each</h3>
  354. <p class="tag-summary">Place one or more smd_each tags in any article, page or form, supply any of the following options to configure it and use a form (or container) to define what to do with each matching variable.</p>
  355. <p>In a nutshell, it grabs every array from the places you specify, allows you to filter the array with matches or specific items, then assigns each successive name/value pair to two replacement tags that you can use in your form to do stuff. You could simply display the values or populate new tables with them, plug values into queries, create smd_vars, test the values with smd_if, you name it.</p>
  356. <h4 id="attributes">Attributes</h4>
  357. <ul>
  358. <li><span class="atnm">type</span> : where to look for variables. They can be combined into a comma-separated list if you wish to search more than one place at once. Options are:
  359. <ul>
  360. <li><code>field</code> : a <span class="caps">TXP</span> article field (the default)</li>
  361. <li><code>urlvar</code> : the <span class="caps">URL</span>, e.g. name1=val&amp;name2=val&amp;&#8230;</li>
  362. <li><code>svrvar</code> : the server environment variables</li>
  363. <li><code>cookie</code> : any user cookies</li>
  364. <li><code>txpvar</code> : a value from any <code>&lt;txp:variable /&gt;</code> tag</li>
  365. <li><code>fixed</code> : specify your own list of variables to inject into the mix (via <code>include</code>)</li>
  366. </ul></li>
  367. <li><span class="atnm">include</span> : base list of variable names you definitely want to be returned in the result. If you are using <code>fixed</code> as one of the <code>type</code>s you can add your own variables here, delimited by <code>paramdelim</code>. For example <code>include=&quot;keywords, my_var:north:south:east:west&quot;</code> would include the <code>keywords</code> article field and create <code>my_var</code>, giving it a value of &#8220;north, south, east, west&#8221;. Note that if you are using a custom field, it is likely to have been converted to all lower case by Textpattern, so you should use an all lower case name here</li>
  368. <li><span class="atnm">exclude</span> : base list of variable names you definitely do not want to be returned in the result</li>
  369. <li><span class="atnm">match</span> : list of text strings to search for to refine the returned variables. By default this will match against <em>every</em> variable in every location you specified in <code>type</code>. It is automatically wild so will match portions of a variable</li>
  370. <li><span class="atnm">matchwith</span> : defaults to <code>name</code> which looks only at the variable&#8217;s name for a match. Can be set to <code>value</code> to look at its value or <code>name, value</code> to look in both for matches</li>
  371. <li><span class="atnm">subset</span> : if you think your variables are going to contain lists themselves, specify <code>subset=&quot;1&quot;</code> to have the plugin add each pseudo-variable to the array. For example, if you article_image field contained <code>14, 6, 17, 3, 9</code> you would get five more variables called <code>article_image_1</code> (value:14), <code>article_image_2</code> (value: 6), and so on.<div class="break">Note that you will also get the full article_image (and all other matching non-subset vars) included. If you wish to <em>only</em> see variables that contain sublists of data, use <code>subset=&quot;2&quot;</code></div></li>
  372. <li><span class="atnm">var_prefix</span> : if you are nesting smd_each tags you&#8217;ll find that any inner <code>{smd_var_value}</code> replacements will take on the values of the outer tag. For this reason you can specify a prefix that will be used in all replacements. Thus if you set <code>var_prefix=&quot;opt_&quot;</code> on your inner smd_each tag, you would use <code>{opt_var_value}</code> and {opt_var_name} in the inner container/form. Default: <code>smd_</code></li>
  373. <li><span class="atnm">form</span> : the <span class="caps">TXP</span> form to execute for every matching variable. If not specified, the container will be used. If there&#8217;s no container, a default form with just the {smd_var_value} is used</li>
  374. <li><span class="atnm">collate</span> : prevent the <code>form</code> being executed for every variable. Instead, collect the variable names internally and then process the entire list by the form once only, after all variables have been read. See <a href="#collate">collate mode</a></li>
  375. <li><span class="atnm">delim</span> : the delimiter to use for specifying plugin options. Defaults to comma (,)</li>
  376. <li><span class="atnm">paramdelim</span> : the delimiter to use for specifying inter-value plugin options (for example in collate mode). Defaults to colon (:)</li>
  377. <li><span class="atnm">outdelim</span> : the delimiter to use to separate each variable displayed in collate mode</li>
  378. <li><span class="atnm">wraptag</span> : the (X)HTML tag to wrap the form in, e.g. <code>wraptag=&quot;ul&quot;</code></li>
  379. <li><span class="atnm">break</span> : the (X)HTML tag to wrap each call to the form in, e.g. <code>break=&quot;li&quot;</code></li>
  380. <li><span class="atnm">class</span> : the <span class="caps">CSS</span> class name to give to the wraptag</li>
  381. </ul>
  382. <h4 class="atts " id="reps">Replacement tags</h4>
  383. <p>For every matching variable, you can use the following replacement tags in your form:</p>
  384. <ul>
  385. <li><span class="atnm">{smd_var_name}</span> : the variable name</li>
  386. <li><span class="atnm">{smd_var_value}</span> : the variable&#8217;s value</li>
  387. <li><span class="atnm">{smd_var_counter}</span> : the variable&#8217;s position in the list (1, 2, 3&#8230;)</li>
  388. <li><span class="atnm">{smd_var_total}</span> : the total number of matching variables being iterated</li>
  389. </ul>
  390. <p>(Note that each replacement tag will have whatever <code>var_prefix</code> you have designated: the default is <code>smd_</code>).</p>
  391. <p>These can be used for whatever devious means you see fit. e.g.</p>
  392. <ul>
  393. <li><code>&lt;txp:article_custom id=&quot;{smd_var_value}&quot; /&gt;</code> will display the given article for each matching ID.</li>
  394. <li><code>&lt;txp:article keywords=&quot;{smd_var_value}&quot; /&gt;</code> in collate mode, might display the given articles that have keywords matching every user-submitted search term</li>
  395. <li><code>&lt;txp:smd_if field=&quot;{smd_var_counter}&quot; operator=&quot;eq&quot; value=&quot;{smd_var_total}&quot;&gt;This is the last item&lt;/txp:smd_if&gt;</code></li>
  396. </ul>
  397. <h3 id="collate">Collate mode</h3>
  398. <p>Instead of parsing each variable with the form/container, you may elect to internally &#8216;collect&#8217; all matching variables and output them in one big list via the form. Thus, the form is only called once at the end. It may seem useless but it can be of value for creating lists of things from each matching variable.</p>
  399. <p>Starting simply, <code>collate=&quot;1&quot;</code> switches collation mode on. If the plugin matched 3 variables from your article and you were to use the replacement tags in your form like this:</p>
  400. <pre class="block"><code class="block">The matching vars: {smd_var_name} = {smd_var_value}
  401. </code></pre>
  402. <p>you might get this:</p>
  403. <pre class="block"><code class="block">The matching vars: section,category1,category2 = article,news,politics
  404. </code></pre>
  405. <p>Compare that with the regular mode, which outputs:</p>
  406. <pre class="block"><code class="block">The matching vars: section = article
  407. The matching vars: category1 = news
  408. The matching vars: category2 = politics
  409. </code></pre>
  410. <p>Sometimes it&#8217;s useful to be able to put quotes around each item; you can tell collate mode to do that:</p>
  411. <p><code>collate=&quot;quote:{smd_var_value}&quot;</code></p>
  412. <p>You would then get:</p>
  413. <pre class="block"><code class="block">The matching vars: section,category1,category2 = &#39;article&#39;,&#39;news&#39;,&#39;politics&#39;
  414. </code></pre>
  415. <p>The delimiter (a comma in this case) can be overridden with the <code>outdelim</code> attribute. You can quote more than one thing at once by specifying the items as a delimited list:</p>
  416. <p><code>collate=&quot;quote:{smd_var_name}:{smd_var_value}&quot;</code></p>
  417. <p>but there&#8217;s not much point because there are only two replacement tags and you can thus use the shortcut <code>collate=&quot;quote&quot;</code> to quote them all. The delimiter used between items (the colon) can be overriden with the <code>paramdelim</code> attribute.</p>
  418. <p>The second special feature of collation mode is that you do not have to always output the entire list. You can grab individual entities from within the internal array by using the &#8216;#&#8217; notation in your form:</p>
  419. <pre class="block"><code class="block">{smd_var_value} might output &#39;article&#39;,&#39;news&#39;,&#39;politics&#39; (as before)
  420. {smd_var_value#1} would only output article
  421. {smd_var_name#3} would only output category2
  422. </code></pre>
  423. <p>Note that when pulling out individual entries they <strong>do not</strong> get quotes added to them, regardless of whether you used <code>quote</code> or not. This is because it is a single item so you can easily put the quotes in the form itself (viz: <code>&quot;{smd_var_name#2}&quot;</code>)</p>
  424. <h2 id="examples">Examples</h2>
  425. <h3 id="eg1">Example 1</h3>
  426. <p>Display each article image from a comma-separated list of IDs in the Article Image field.</p>
  427. <pre class="block"><code class="block">&lt;txp:smd_each include=&quot;article_image&quot; subset=&quot;2&quot;&gt;
  428. &lt;txp:image id=&quot;{smd_var_value}&quot; /&gt;
  429. &lt;/txp:smd_each&gt;
  430. </code></pre>
  431. <h3 id="eg2">Example 2</h3>
  432. <p>Display each article image from a comma-separated list of IDs in the Article Image field, and also allow IDs to be given in the <span class="caps">URL</span> line via the variable name <code>my_image_list</code> :</p>
  433. <pre class="block"><code class="block">&lt;txp:smd_each type=&quot;field, urlvar&quot;
  434. include=&quot;article_image, my_image_list&quot;
  435. subset=&quot;2&quot; form=&quot;varout&quot; var_prefix=&quot;me_&quot; /&gt;
  436. </code></pre>
  437. <p>And in form <code>varout</code>:</p>
  438. <pre class="block"><code class="block">&lt;txp:image id=&quot;{me_var_value}&quot; /&gt;
  439. </code></pre>
  440. <h3 id="eg3">Example 3</h3>
  441. <p>This is simply to highlight the differences between the various matching modes. Let&#8217;s take a simple article:</p>
  442. <ul>
  443. <li>section: animals</li>
  444. <li>title (url_title) : The lion (the-lion)</li>
  445. <li>category1: mammal</li>
  446. <li>category2: dangerous</li>
  447. <li>article_image: 25, 28, 12</li>
  448. <li>keywords: big, cat, mane, fur, teeth, roar, chomp, ouch</li>
  449. <li>custom1 (&#8220;origin&#8221;): africa</li>
  450. </ul>
  451. <p>There are a whole host of other variables (switch debug=&#8220;1&#8221; on to see them all for your chosen <code>type</code>s) but we&#8217;ll concentrate on these for now to keep things simple.</p>
  452. <table>
  453. <tr>
  454. <th>tag options </th>
  455. <th>vars returned </th>
  456. <th>remarks </th>
  457. </tr>
  458. <tr>
  459. <td> match=&#8220;cat&#8221; </td>
  460. <td> category1, category2 </td>
  461. <td> default is to match name only </td>
  462. </tr>
  463. <tr>
  464. <td> match=&#8220;cat&#8221; matchwith=&#8220;name, value&#8221; </td>
  465. <td> category1, category2, keywords, id_keywords </td>
  466. <td> now checks value as well </td>
  467. </tr>
  468. <tr>
  469. <td> match=&#8220;cat&#8221; include=&#8220;article_image&#8221; </td>
  470. <td> category1, category2, article_image </td>
  471. <td> includes are always selected </td>
  472. </tr>
  473. <tr>
  474. <td> match=&#8220;cat&#8221; include=&#8220;article_image, origin&#8221; subset=&#8220;1&#8221; </td>
  475. <td> category1, category2, origin, article_image, article_image_1, article_image_2, article_image_3 </td>
  476. <td> looked &#8220;inside&#8221; each var to find any lists </td>
  477. </tr>
  478. <tr>
  479. <td> match=&#8220;cat&#8221; include=&#8220;article_image, origin&#8221; subset=&#8220;2&#8221; </td>
  480. <td> article_image_1, article_image_2, article_image_3 </td>
  481. <td> return <em>only</em> data sets that contain lists and removes the aggregate (base) entry </td>
  482. </tr>
  483. <tr>
  484. <td> match=&#8220;cat, article_image&#8221; matchwith=&#8220;name,value&#8221; subset=&#8220;2&#8221; </td>
  485. <td> article_image_1, article_image_2, article_image_3, keywords, id_keywords </td>
  486. <td> checks both name and value for each match term, and only shows items that have lists in them (if <code>keywords</code> held just one item &#8220;cat&#8221; it would <em>not</em> be displayed) </td>
  487. </tr>
  488. </table>
  489. <p>Note that if you are using this tag in an article, the &#8216;body&#8217; may match because it contains the smd_each tag which contains the very information you are matching! In this case, adding <code>exclude=&quot;body&quot;</code> will remove it from the results.</p>
  490. <h3 id="eg4">Example 4</h3>
  491. <p>From a page template, allow visitors to display any number of articles.</p>
  492. <pre class="block"><code class="block">&lt;form name=&quot;show_arts&quot; action=&quot;/my/results/page&quot;&gt;
  493. &lt;txp:article_custom form=&quot;list_checks&quot;
  494. category=&quot;animals&quot; limit=&quot;999&quot; /&gt;
  495. &lt;input type=&quot;submit&quot; /&gt;
  496. &lt;/form&gt;
  497. </code></pre>
  498. <p>Your form <code>list_checks</code> simply displays the article title and a checkbox:</p>
  499. <pre class="block"><code class="block">&lt;li&gt;
  500. &lt;txp:title /&gt;&lt;input type=&quot;checkbox&quot;
  501. name=&quot;article_lists[]&quot;
  502. value=&quot;&lt;txp:article_id /&gt;&quot; /&gt;
  503. &lt;/li&gt;
  504. </code></pre>
  505. <p>When the user submits the form we can use smd_each to find which checkboxes have been clicked and show the relevant articles:</p>
  506. <pre class="block"><code class="block">&lt;txp:smd_each type=&quot;urlvar&quot;
  507. match=&quot;article_lists&quot; subset=&quot;2&quot;&gt;
  508. &lt;txp:article_custom id=&quot;{smd_var_value}&quot; /&gt;
  509. &lt;/txp:smd_each&gt;
  510. </code></pre>
  511. <p>Alternatively, if you are using a copy of <span class="caps">TXP</span> that supports lists in article_custom&#8217;s <code>id</code> attribute you can drop the <code>subset</code>.</p>
  512. <h2 id="changelog">Changelog</h2>
  513. <ul>
  514. <li>12 Jun 08 | 0.1 | Initial release</li>
  515. <li>22 Jun 08 | 0.11 | Added type=fixed (thanks mrdale)</li>
  516. <li>04 Apr 09 | 0.12 | Fixed <code>subset=&quot;2&quot;</code> bug with single entries (thanks jeremywood) ; added <code>{var_counter}</code> and <code>{var_total}</code> (thanks mrdale)</li>
  517. <li>30 Aug 09 | 0.2 | Added <code>var_prefix</code> attribute and set it to <code>smd_</code> by default</li>
  518. </ul>
  519. </div>
  520. # --- END PLUGIN HELP ---
  521. -->
  522. <?php
  523. }
  524. ?>