Silverstripe 3:如何按标题、日期等对 CMS 站点树中的页面进行排序

Silverstripe 3: how to sort pages in the CMS sitetree by title, date etc

我正在寻找一个工作示例,说明如何在默认情况下按标题对站点树中的页面进行排序。理想情况下,我只想对 child 特定类型的页面进行排序。在我的例子中,我希望 parent 投资组合下的所有图库页面都按标题的字母顺序排序。 这是为了在后端 CMS 中轻松搜索,因为我知道如何在模板中对它们进行排序。

我找到了这些示例,但不足以解决 SS3.1+

http://www.ssbits.com/tutorials/2011/custom-sorting-in-the-cms-sitetree/ https://github.com/silverstripe/silverstripe-cms/issues/848

查看您提供的示例和当前的 Silverstripe 源代码,您可以通过几种方法来解决这个问题。我的解决方案涉及使用 Silverstripe 的扩展系统来操纵层次结构的生成方式。

如何加载 SiteTree

CMS 加载站点树的方式有点冗长,所以我将快速简化:

  • 模板 CMSPagesController_Content.ss(用于页面部分)具有指向 lazy-load 链接树视图的标记
  • 链接树视图(CMSMain中指定的函数)调用一些内部方法基本上加载CMSMain_TreeView模板
  • 此模板调用 CMSMain

    中的 SiteTreeAsUL 函数

    Note: SiteTreeAsUL allows us to hook in before returning using the extension system in Silverstripe though we don't want to manipulate the HTML directly.

  • getSiteTreeFor, a function part of LeftAndMain,在SiteTreeAsUL.

  • 里面调用
  • getSiteTreeFor 调用 getChildrenAsUL, a function part of Hierarchy,它实际上执行 HTML 构建,但最重要的是,调用正确的 "children" 方法。

我说正确的children方法有几个:

因为调用getSiteTreeFor时没有指定children方法,it uses a hardcoded default of AllChildrenIncludingDeleted.

现在,是时候对 children...

进行排序了

调用函数 AllChildrenIncludingDeleted 进行了几次调用,但我们想知道的是它在内部调用了扩展方法 augmentAllChildrenIncludingDeleted.

因此,要完成您想做的事情,您可能会希望使用扩展函数 augmentAllChildrenIncludingDeletedSiteTree 编写一个扩展。第一个参数是所有 children 的列表,它们存储为 ArrayList.

Technical Note: It actually can be an ArrayList OR DataList because if there are no live children, it returns the raw result of stageChildren which is a DataList. While both have sort functions, they may act differently.

ArrayList provides a sort function 这将使您能够按照自己的意愿去做。

像这样的东西应该可以工作:

class CMSSiteTreeSortingExtension extends Extension
{
    public function augmentAllChildrenIncludingDeleted($Children, $Context = null)
    {
        if ($this->owner->ClassName == 'GalleryPage')
        {
            //Do your class specific sorting here....
        }

        $Children = $Children->sort('Title DESC');
    }
}

并且只需将扩展名设置为 SiteTree(或者 Page 如果需要,应该仍然有效)。

免责声明:我没有亲自尝试过,但它遵循 Silverstripe 如何与扩展一起工作的标准模式,因此您应该不会有问题。

当我无法使上述代码工作时,我一直在寻找一种在 SS4 中实现此目的的方法。这就是我想出的。

use SilverStripe\ORM\DB;

class MemberPage extends Page
{
    public function onAfterWrite(){
        parent::onAfterWrite();

        $pages = MemberPage::get()->sort('Title');
        $sortIndex = 0;
        foreach ($pages as $page){
            //sort indexes start at 1
            $sortIndex++;
            if ($page->Sort != $sortIndex){
                //we can't use $page->write() here, otherwise it'll cause infinite loops,
                //we'll just have to run the query on the database directly
                DB::query("UPDATE SiteTree SET Sort = {$sortIndex} WHERE ID = {$page->ID}");
            }
        }
    }
}

它不完全是 'the silverstripe way' 但它有效。