Textpattern | PHP Cross Reference | Content Management Systems |
Description: Articles panel.
1 <?php 2 3 /* 4 * Textpattern Content Management System 5 * http://textpattern.com 6 * 7 * Copyright (C) 2005 Dean Allen 8 * Copyright (C) 2016 The Textpattern Development Team 9 * 10 * This file is part of Textpattern. 11 * 12 * Textpattern is free software; you can redistribute it and/or 13 * modify it under the terms of the GNU General Public License 14 * as published by the Free Software Foundation, version 2. 15 * 16 * Textpattern is distributed in the hope that it will be useful, 17 * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 * GNU General Public License for more details. 20 * 21 * You should have received a copy of the GNU General Public License 22 * along with Textpattern. If not, see <http://www.gnu.org/licenses/>. 23 */ 24 25 /** 26 * Articles panel. 27 * 28 * @package Admin\List 29 */ 30 31 use Textpattern\Validator\CategoryConstraint; 32 use Textpattern\Validator\SectionConstraint; 33 use Textpattern\Validator\Validator; 34 use Textpattern\Search\Filter; 35 36 if (!defined('txpinterface')) { 37 die('txpinterface is undefined.'); 38 } 39 40 if ($event == 'list') { 41 global $statuses, $all_cats, $all_authors, $all_sections; 42 43 require_privs('article'); 44 45 $statuses = status_list(); 46 47 $all_cats = getTree('root', 'article'); 48 $all_authors = the_privileged('article.edit.own'); 49 $all_sections = safe_column("name", 'txp_section', "name != 'default'"); 50 51 $available_steps = array( 52 'list_list' => false, 53 'list_change_pageby' => true, 54 'list_multi_edit' => true, 55 ); 56 57 if ($step && bouncer($step, $available_steps)) { 58 $step(); 59 } else { 60 list_list(); 61 } 62 } 63 64 /** 65 * The main panel listing all articles. 66 * 67 * @param string|array $message The activity message 68 * @param string $post Not used 69 */ 70 71 function list_list($message = '', $post = '') 72 { 73 global $statuses, $use_comments, $comments_disabled_after, $step, $txp_user, $article_list_pageby, $event; 74 75 pagetop(gTxt('tab_list'), $message); 76 77 extract(gpsa(array( 78 'page', 79 'sort', 80 'dir', 81 'crit', 82 'search_method', 83 ))); 84 85 if ($sort === '') { 86 $sort = get_pref('article_sort_column', 'posted'); 87 } else { 88 if (!in_array($sort, array('id', 'title', 'expires', 'section', 'category1', 'category2', 'status', 'author', 'comments', 'lastmod'))) { 89 $sort = 'posted'; 90 } 91 92 set_pref('article_sort_column', $sort, 'list', 2, '', 0, PREF_PRIVATE); 93 } 94 95 if ($dir === '') { 96 $dir = get_pref('article_sort_dir', 'desc'); 97 } else { 98 $dir = ($dir == 'asc') ? "asc" : "desc"; 99 set_pref('article_sort_dir', $dir, 'list', 2, '', 0, PREF_PRIVATE); 100 } 101 102 $sesutats = array_flip($statuses); 103 104 switch ($sort) { 105 case 'id': 106 $sort_sql = "textpattern.ID $dir"; 107 break; 108 case 'title': 109 $sort_sql = "textpattern.Title $dir, textpattern.Posted DESC"; 110 break; 111 case 'expires': 112 $sort_sql = "textpattern.Expires $dir"; 113 break; 114 case 'section': 115 $sort_sql = "section.title $dir, textpattern.Posted DESC"; 116 break; 117 case 'category1': 118 $sort_sql = "category1.title $dir, textpattern.Posted DESC"; 119 break; 120 case 'category2': 121 $sort_sql = "category2.title $dir, textpattern.Posted DESC"; 122 break; 123 case 'status': 124 $sort_sql = "textpattern.Status $dir, textpattern.Posted DESC"; 125 break; 126 case 'author': 127 $sort_sql = "user.RealName $dir, textpattern.Posted DESC"; 128 break; 129 case 'comments': 130 $sort_sql = "textpattern.comments_count $dir, textpattern.Posted DESC"; 131 break; 132 case 'lastmod': 133 $sort_sql = "textpattern.LastMod $dir, textpattern.Posted DESC"; 134 break; 135 default: 136 $sort = 'posted'; 137 $sort_sql = "textpattern.Posted $dir"; 138 break; 139 } 140 141 $switch_dir = ($dir == 'desc') ? 'asc' : 'desc'; 142 143 $search = new Filter($event, 144 array( 145 'id' => array( 146 'column' => 'textpattern.ID', 147 'label' => gTxt('ID'), 148 'type' => 'integer', 149 ), 150 'title_body_excerpt' => array( 151 'column' => array('textpattern.Title', 'textpattern.Body', 'textpattern.Excerpt'), 152 'label' => gTxt('title_body_excerpt'), 153 ), 154 'section' => array( 155 'column' => array('textpattern.Section', 'section.title'), 156 'label' => gTxt('section'), 157 ), 158 'keywords' => array( 159 'column' => 'textpattern.Keywords', 160 'label' => gTxt('keywords'), 161 'type' => 'find_in_set', 162 ), 163 'categories' => array( 164 'column' => array('textpattern.Category1', 'textpattern.Category2', 'category1.title', 'category2.title'), 165 'label' => gTxt('categories'), 166 ), 167 'status' => array( 168 'column' => array('textpattern.Status'), 169 'label' => gTxt('status'), 170 'type' => 'boolean', 171 ), 172 'author' => array( 173 'column' => array('textpattern.AuthorID', 'user.RealName'), 174 'label' => gTxt('author'), 175 ), 176 'article_image' => array( 177 'column' => array('textpattern.Image'), 178 'label' => gTxt('article_image'), 179 'type' => 'integer', 180 ), 181 'posted' => array( 182 'column' => array('textpattern.Posted'), 183 'label' => gTxt('posted'), 184 'options' => array('case_sensitive' => true), 185 ), 186 'lastmod' => array( 187 'column' => array('textpattern.LastMod'), 188 'label' => gTxt('article_modified'), 189 'options' => array('case_sensitive' => true), 190 ), 191 ) 192 ); 193 194 $search->setAliases('status', $statuses); 195 196 list($criteria, $crit, $search_method) = $search->getFilter(array( 197 'id' => array('can_list' => true), 198 'article_image' => array('can_list' => true), 199 'title_body_excerpt' => array('always_like' => true), 200 )); 201 202 $search_render_options = array( 203 'placeholder' => 'search_articles', 204 ); 205 206 $sql_from = 207 safe_pfx('textpattern')." textpattern 208 LEFT JOIN ".safe_pfx('txp_category')." category1 ON category1.name = textpattern.Category1 AND category1.type = 'article' 209 LEFT JOIN ".safe_pfx('txp_category')." category2 ON category2.name = textpattern.Category2 AND category2.type = 'article' 210 LEFT JOIN ".safe_pfx('txp_section')." section ON section.name = textpattern.Section 211 LEFT JOIN ".safe_pfx('txp_users')." user ON user.name = textpattern.AuthorID"; 212 213 if ($criteria === 1) { 214 $total = safe_count('textpattern', $criteria); 215 } else { 216 $total = getThing("SELECT COUNT(*) FROM $sql_from WHERE $criteria"); 217 } 218 219 echo n.'<div class="txp-layout">'. 220 n.tag( 221 hed(gTxt('tab_list'), 1, array('class' => 'txp-heading')), 222 'div', array('class' => 'txp-layout-4col-alt') 223 ); 224 225 $searchBlock = 226 n.tag( 227 $search->renderForm('list', $search_render_options), 228 'div', array( 229 'class' => 'txp-layout-4col-3span', 230 'id' => $event.'_control', 231 ) 232 ); 233 234 $createBlock = array(); 235 236 if (has_privs('article.edit')) { 237 $createBlock[] = 238 n.tag( 239 sLink('article', '', gTxt('add_new_article'), 'txp-button'), 240 'div', array('class' => 'txp-control-panel') 241 ); 242 } 243 244 $contentBlockStart = n.tag_start('div', array( 245 'class' => 'txp-layout-1col', 246 'id' => $event.'_container', 247 )); 248 249 $createBlock = implode(n, $createBlock); 250 251 if ($total < 1) { 252 if ($criteria != 1) { 253 echo $searchBlock. 254 $contentBlockStart. 255 $createBlock. 256 graf( 257 span(null, array('class' => 'ui-icon ui-icon-info')).' '. 258 gTxt('no_results_found'), 259 array('class' => 'alert-block information') 260 ); 261 } else { 262 echo $contentBlockStart. 263 $createBlock. 264 graf( 265 span(null, array('class' => 'ui-icon ui-icon-info')).' '. 266 gTxt('no_articles_recorded'), 267 array('class' => 'alert-block information') 268 ); 269 } 270 271 echo n.tag_end('div'). // End of .txp-layout-1col. 272 n.'</div>'; // End of .txp-layout. 273 274 return; 275 } 276 277 $limit = max($article_list_pageby, 15); 278 279 list($page, $offset, $numPages) = pager($total, $limit, $page); 280 281 echo $searchBlock.$contentBlockStart.$createBlock; 282 283 $rs = safe_query( 284 "SELECT 285 textpattern.ID, textpattern.Title, textpattern.url_title, textpattern.Section, 286 textpattern.Category1, textpattern.Category2, 287 textpattern.Status, textpattern.Annotate, textpattern.AuthorID, 288 UNIX_TIMESTAMP(textpattern.Posted) AS posted, 289 UNIX_TIMESTAMP(textpattern.LastMod) AS lastmod, 290 UNIX_TIMESTAMP(textpattern.Expires) AS expires, 291 category1.title AS category1_title, 292 category2.title AS category2_title, 293 section.title AS section_title, 294 user.RealName AS RealName, 295 (SELECT COUNT(*) FROM ".safe_pfx('txp_discuss')." WHERE parentid = textpattern.ID) AS total_comments 296 FROM $sql_from WHERE $criteria ORDER BY $sort_sql LIMIT $offset, $limit" 297 ); 298 299 if ($rs) { 300 $show_authors = !has_single_author('textpattern', 'AuthorID'); 301 302 echo n.tag( 303 toggle_box('articles_detail'), 'div', array('class' => 'txp-list-options')). 304 n.tag_start('form', array( 305 'class' => 'multi_edit_form', 306 'id' => 'articles_form', 307 'name' => 'longform', 308 'method' => 'post', 309 'action' => 'index.php', 310 )). 311 n.tag_start('div', array('class' => 'txp-listtables')). 312 n.tag_start('table', array('class' => 'txp-list')). 313 n.tag_start('thead'). 314 tr( 315 hCell( 316 fInput('checkbox', 'select_all', 0, '', '', '', '', '', 'select_all'), 317 '', ' class="txp-list-col-multi-edit" scope="col" title="'.gTxt('toggle_all_selected').'"' 318 ). 319 column_head( 320 'ID', 'id', 'list', true, $switch_dir, $crit, $search_method, 321 (('id' == $sort) ? "$dir " : '').'txp-list-col-id' 322 ). 323 column_head( 324 'title', 'title', 'list', true, $switch_dir, $crit, $search_method, 325 (('title' == $sort) ? "$dir " : '').'txp-list-col-title' 326 ). 327 column_head( 328 'posted', 'posted', 'list', true, $switch_dir, $crit, $search_method, 329 (('posted' == $sort) ? "$dir " : '').'txp-list-col-created date' 330 ). 331 column_head( 332 'article_modified', 'lastmod', 'list', true, $switch_dir, $crit, $search_method, 333 (('lastmod' == $sort) ? "$dir " : '').'txp-list-col-lastmod date articles_detail' 334 ). 335 column_head( 336 'expires', 'expires', 'list', true, $switch_dir, $crit, $search_method, 337 (('expires' == $sort) ? "$dir " : '').'txp-list-col-expires date articles_detail' 338 ). 339 column_head( 340 'section', 'section', 'list', true, $switch_dir, $crit, $search_method, 341 (('section' == $sort) ? "$dir " : '').'txp-list-col-section' 342 ). 343 column_head( 344 'category1', 'category1', 'list', true, $switch_dir, $crit, $search_method, 345 (('category1' == $sort) ? "$dir " : '').'txp-list-col-category1 category articles_detail' 346 ). 347 column_head( 348 'category2', 'category2', 'list', true, $switch_dir, $crit, $search_method, 349 (('category2' == $sort) ? "$dir " : '').'txp-list-col-category2 category articles_detail' 350 ). 351 column_head( 352 'status', 'status', 'list', true, $switch_dir, $crit, $search_method, 353 (('status' == $sort) ? "$dir " : '').'txp-list-col-status' 354 ). 355 ( 356 $show_authors 357 ? column_head('author', 'author', 'list', true, $switch_dir, $crit, $search_method, 358 (('author' == $sort) ? "$dir " : '').'txp-list-col-author name') 359 : '' 360 ). 361 ( 362 $use_comments == 1 363 ? column_head('comments', 'comments', 'list', true, $switch_dir, $crit, $search_method, 364 (('comments' == $sort) ? "$dir " : '').'txp-list-col-comments articles_detail') 365 : '' 366 ) 367 ). 368 n.tag_end('thead'); 369 370 include_once txpath.'/publish/taghandlers.php'; 371 372 echo n.tag_start('tbody'); 373 374 $validator = new Validator(); 375 376 while ($a = nextRow($rs)) { 377 extract($a); 378 379 if ($Title === '') { 380 $Title = '<em>'.eLink('article', 'edit', 'ID', $ID, gTxt('untitled')).'</em>'; 381 } else { 382 $Title = eLink('article', 'edit', 'ID', $ID, $Title); 383 } 384 385 // Valid section and categories? 386 $validator->setConstraints(array(new SectionConstraint($Section))); 387 $vs = $validator->validate() ? '' : ' error'; 388 389 $validator->setConstraints(array(new CategoryConstraint($Category1, array('type' => 'article')))); 390 $vc[1] = $validator->validate() ? '' : ' error'; 391 392 $validator->setConstraints(array(new CategoryConstraint($Category2, array('type' => 'article')))); 393 $vc[2] = $validator->validate() ? '' : ' error'; 394 395 $Category1 = ($Category1) ? span(txpspecialchars($category1_title), array('title' => $Category1)) : ''; 396 $Category2 = ($Category2) ? span(txpspecialchars($category2_title), array('title' => $Category2)) : ''; 397 398 if ($Status != STATUS_LIVE and $Status != STATUS_STICKY) { 399 $view_url = '?txpreview='.intval($ID).'.'.time(); 400 } else { 401 $view_url = permlinkurl($a); 402 } 403 404 if (isset($statuses[$Status])) { 405 $Status = $statuses[$Status]; 406 } 407 408 $comments = '('.$total_comments.')'; 409 410 if ($total_comments) { 411 $comments = href($comments, array( 412 'event' => 'discuss', 413 'step' => 'list', 414 'search_method' => 'parent', 415 'crit' => $ID, 416 ), array('title' => gTxt('manage'))); 417 } 418 419 $comment_status = ($Annotate) ? gTxt('on') : gTxt('off'); 420 421 if ($comments_disabled_after) { 422 $lifespan = $comments_disabled_after * 86400; 423 $time_since = time() - $posted; 424 425 if ($time_since > $lifespan) { 426 $comment_status = gTxt('expired'); 427 } 428 } 429 430 $comments = 431 tag($comment_status, 'span', array('class' => 'comments-status')).' '. 432 tag($comments, 'span', array('class' => 'comments-manage')); 433 434 echo tr( 435 td( 436 ( 437 ( 438 ($a['Status'] >= STATUS_LIVE and has_privs('article.edit.published')) 439 or ($a['Status'] >= STATUS_LIVE and $AuthorID === $txp_user and has_privs('article.edit.own.published')) 440 or ($a['Status'] < STATUS_LIVE and has_privs('article.edit')) 441 or ($a['Status'] < STATUS_LIVE and $AuthorID === $txp_user and has_privs('article.edit.own')) 442 ) 443 ? fInput('checkbox', 'selected[]', $ID, 'checkbox') 444 : '' 445 ), '', 'txp-list-col-multi-edit' 446 ). 447 hCell( 448 eLink('article', 'edit', 'ID', $ID, $ID). 449 span( 450 sp.span('|', array('role' => 'separator')). 451 sp.href(gTxt('view'), $view_url), 452 array('class' => 'txp-option-link articles_detail') 453 ), '', array( 454 'class' => 'txp-list-col-id', 455 'scope' => 'row', 456 ) 457 ). 458 td( 459 $Title, '', 'txp-list-col-title' 460 ). 461 td( 462 gTime($posted), '', 'txp-list-col-created date'.($posted < time() ? '' : ' unpublished') 463 ). 464 td( 465 gTime($lastmod), '', 'txp-list-col-lastmod date articles_detail'.($posted === $lastmod ? ' not-modified' : '') 466 ). 467 td( 468 ($expires ? gTime($expires) : ''), '', 'txp-list-col-expires date articles_detail' 469 ). 470 td( 471 span(txpspecialchars($section_title), array('title' => $Section)), '', 'txp-list-col-section'.$vs 472 ). 473 td( 474 $Category1, '', 'txp-list-col-category1 category articles_detail'.$vc[1] 475 ). 476 td( 477 $Category2, '', 'txp-list-col-category2 category articles_detail'.$vc[2] 478 ). 479 td( 480 href($Status, $view_url, join_atts(array('title' => gTxt('view')), TEXTPATTERN_STRIP_EMPTY)), '', 'txp-list-col-status' 481 ). 482 ( 483 $show_authors 484 ? td(span(txpspecialchars($RealName), array('title' => $AuthorID)), '', 'txp-list-col-author name') 485 : '' 486 ). 487 ( 488 $use_comments 489 ? td($comments, '', 'txp-list-col-comments articles_detail') 490 : '' 491 ) 492 ); 493 } 494 495 echo n.tag_end('tbody'). 496 n.tag_end('table'). 497 n.tag_end('div'). // End of .txp-listtables. 498 list_multiedit_form($page, $sort, $dir, $crit, $search_method). 499 tInput(). 500 n.tag_end('form'). 501 n.tag_start('div', array( 502 'class' => 'txp-navigation', 503 'id' => $event.'_navigation', 504 )). 505 pageby_form('list', $article_list_pageby). 506 nav_form('list', $page, $numPages, $sort, $dir, $crit, $search_method, $total, $limit). 507 n.tag_end('div'); 508 } 509 510 echo n.tag_end('div'). // End of .txp-layout-1col. 511 n.'</div>'; // End of .txp-layout. 512 } 513 514 /** 515 * Saves pageby value for the article list. 516 */ 517 518 function list_change_pageby() 519 { 520 event_change_pageby('article'); 521 list_list(); 522 } 523 524 /** 525 * Renders a multi-edit form widget for articles. 526 * 527 * @param int $page The page number 528 * @param string $sort The current sort value 529 * @param string $dir The current sort direction 530 * @param string $crit The current search criteria 531 * @param string $search_method The current search method 532 * @return string HTML 533 */ 534 535 function list_multiedit_form($page, $sort, $dir, $crit, $search_method) 536 { 537 global $statuses, $all_cats, $all_authors, $all_sections; 538 539 if ($all_cats) { 540 $category1 = treeSelectInput('Category1', $all_cats, ''); 541 $category2 = treeSelectInput('Category2', $all_cats, ''); 542 } else { 543 $category1 = $category2 = ''; 544 } 545 546 $sections = $all_sections ? selectInput('Section', $all_sections, '', true) : ''; 547 $comments = onoffRadio('Annotate', get_pref('comments_on_default')); 548 $status = selectInput('Status', $statuses, '', true); 549 $authors = $all_authors ? selectInput('AuthorID', $all_authors, '', true) : ''; 550 551 $methods = array( 552 'changesection' => array('label' => gTxt('changesection'), 'html' => $sections), 553 'changecategory1' => array('label' => gTxt('changecategory1'), 'html' => $category1), 554 'changecategory2' => array('label' => gTxt('changecategory2'), 'html' => $category2), 555 'changestatus' => array('label' => gTxt('changestatus'), 'html' => $status), 556 'changecomments' => array('label' => gTxt('changecomments'), 'html' => $comments), 557 'changeauthor' => array('label' => gTxt('changeauthor'), 'html' => $authors), 558 'duplicate' => gTxt('duplicate'), 559 'delete' => gTxt('delete'), 560 ); 561 562 if (!$all_cats) { 563 unset($methods['changecategory1'], $methods['changecategory2']); 564 } 565 566 if (has_single_author('textpattern', 'AuthorID') || !has_privs('article.edit')) { 567 unset($methods['changeauthor']); 568 } 569 570 if (!has_privs('article.delete.own') && !has_privs('article.delete')) { 571 unset($methods['delete']); 572 } 573 574 return multi_edit($methods, 'list', 'list_multi_edit', $page, $sort, $dir, $crit, $search_method); 575 } 576 577 /** 578 * Processes multi-edit actions. 579 */ 580 581 function list_multi_edit() 582 { 583 global $txp_user, $statuses, $all_cats, $all_authors, $all_sections; 584 585 extract(psa(array( 586 'selected', 587 'edit_method', 588 ))); 589 590 if (!$selected || !is_array($selected)) { 591 return list_list(); 592 } 593 594 $selected = array_map('assert_int', $selected); 595 596 // Empty entry to permit clearing the categories. 597 $categories = array(''); 598 599 foreach ($all_cats as $row) { 600 $categories[] = $row['name']; 601 } 602 603 $allowed = array(); 604 $field = $value = ''; 605 606 switch ($edit_method) { 607 // Delete. 608 case 'delete': 609 if (!has_privs('article.delete')) { 610 if (has_privs('article.delete.own')) { 611 $allowed = safe_column_num( 612 "ID", 613 'textpattern', 614 "ID IN (".join(',', $selected).") AND AuthorID = '".doSlash($txp_user)."'" 615 ); 616 } 617 618 $selected = $allowed; 619 } 620 621 if ($selected && safe_delete('textpattern', "ID IN (".join(',', $selected).")")) { 622 safe_update('txp_discuss', "visible = ".MODERATE, "parentid IN (".join(',', $selected).")"); 623 callback_event('articles_deleted', '', 0, $selected); 624 callback_event('multi_edited.articles', 'delete', 0, compact('selected', 'field', 'value')); 625 update_lastmod('articles_deleted', $selected); 626 now('posted', true); 627 now('expires', true); 628 629 return list_list(messenger('article', join(', ', $selected), 'deleted')); 630 } 631 632 return list_list(); 633 break; 634 // Change author. 635 case 'changeauthor': 636 $value = ps('AuthorID'); 637 if (has_privs('article.edit') && in_array($value, $all_authors, true)) { 638 $field = 'AuthorID'; 639 } 640 break; 641 642 // Change category1. 643 case 'changecategory1': 644 $value = ps('Category1'); 645 if (in_array($value, $categories, true)) { 646 $field = 'Category1'; 647 } 648 break; 649 // Change category2. 650 case 'changecategory2': 651 $value = ps('Category2'); 652 if (in_array($value, $categories, true)) { 653 $field = 'Category2'; 654 } 655 break; 656 // Change comment status. 657 case 'changecomments': 658 $field = 'Annotate'; 659 $value = (int) ps('Annotate'); 660 break; 661 // Change section. 662 case 'changesection': 663 $value = ps('Section'); 664 if (in_array($value, $all_sections, true)) { 665 $field = 'Section'; 666 } 667 break; 668 // Change status. 669 case 'changestatus': 670 $value = (int) ps('Status'); 671 if (array_key_exists($value, $statuses)) { 672 $field = 'Status'; 673 } 674 675 if (!has_privs('article.publish') && $value >= STATUS_LIVE) { 676 $value = STATUS_PENDING; 677 } 678 break; 679 } 680 681 $selected = safe_rows( 682 "ID, AuthorID, Status", 683 'textpattern', 684 "ID IN (".join(',', $selected).")" 685 ); 686 687 foreach ($selected as $item) { 688 if ( 689 ($item['Status'] >= STATUS_LIVE && has_privs('article.edit.published')) || 690 ($item['Status'] >= STATUS_LIVE && $item['AuthorID'] === $txp_user && has_privs('article.edit.own.published')) || 691 ($item['Status'] < STATUS_LIVE && has_privs('article.edit')) || 692 ($item['Status'] < STATUS_LIVE && $item['AuthorID'] === $txp_user && has_privs('article.edit.own')) 693 ) { 694 $allowed[] = $item['ID']; 695 } 696 } 697 698 $selected = $allowed; 699 700 if ($selected) { 701 $message = messenger('article', join(', ', $selected), 'modified'); 702 703 if ($edit_method === 'duplicate') { 704 $rs = safe_rows_start("*", 'textpattern', "ID IN (".join(',', $selected).")"); 705 706 if ($rs) { 707 while ($a = nextRow($rs)) { 708 unset($a['ID'], $a['comments_count']); 709 $a['uid'] = md5(uniqid(rand(), true)); 710 $a['AuthorID'] = $txp_user; 711 $a['LastModID'] = $txp_user; 712 $a['Status'] = ($a['Status'] >= STATUS_LIVE) ? STATUS_DRAFT : $a['Status']; 713 714 foreach ($a as $name => &$value) { 715 if ($name == 'Expires' && !$value) { 716 $value = "Expires = NULL"; 717 } else { 718 $value = "`$name` = '".doSlash($value)."'"; 719 } 720 } 721 722 if ($id = (int) safe_insert('textpattern', join(',', $a))) { 723 safe_update( 724 'textpattern', 725 "Title = CONCAT(Title, ' (', $id, ')'), 726 url_title = CONCAT(url_title, '-', $id), 727 LastMod = NOW(), 728 feed_time = NOW()", 729 "ID = $id" 730 ); 731 } 732 } 733 } 734 735 $message = gTxt('duplicated_articles', array('{id}' => join(', ', $selected))); 736 } elseif (!$field || safe_update('textpattern', "$field = '".doSlash($value)."'", "ID IN (".join(',', $selected).")") === false) { 737 return list_list(); 738 } 739 740 update_lastmod('articles_updated', compact('selected', 'field', 'value')); 741 now('posted', true); 742 now('expires', true); 743 callback_event('multi_edited.articles', $edit_method, 0, compact('selected', 'field', 'value')); 744 745 return list_list($message); 746 } 747 748 return list_list(); 749 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
title