Using PnP JS Core: How do I get a list of files from the "Pages" folder of an "Enterprise Wiki"




Using PnP JS Core, How would I go about getting a list of files from the "Pages" folder of an "Enterprise Wiki" and then getting the properties associated with each file?


Eventually I want to get all the properties associated with each file. In particular I'm interested in Title, ServerRelativePath and ServerRelativeUrl for now.


In case it helps, we use an "Enterprise Wiki" with folders. For each folder I want to generate a table of contents. So for a given folder I would want to filter by the url (ServerRelatieUrl?) for only files in that folder.



8 Replies
Would you not just use csom for that in combination with JS Core?

@Deleted, thanks for the reply.


If possible, I really want to do this in JavaScript. As you say, I could create an add-in and have that do the work. I'm new to SharePoint development it looks like the JavaScript way is simpler, in that I don't have to host it externally.


Also, if this was successful, a follow on project would be to create an enhanced left hand menu. It seems that the easiest way to do this, without creating/editing templates or page layouts, is with JavaScript embedding.


I'm using the judgement, feel free to correct me, that add-ins are for users to add to pages they create. Whereas, JavaScript embedding can be used to make changes to all pages.


BTW I never used Azure, have beginners skills in JavaScript, average skills in C#. I've spent most of the last 5 years or so doing PowerShell and Transact-SQL. I have good skills on both of these.

best response confirmed by Alan Trafford (Contributor)

Hi Alan,


First, 'Pages' is not a folder, it's a document library.

You can query a doc lib by multiple available methods in SharePoint REST API and PnP JS Core REST wrapper, like:


// Get by title
$pnp.sp.web.lists.getByTitle('Pages').items.get().then(function(item) { console.log(item); });



// Get by list url is more preferable way as list renaming won't crash the logic
$pnp.sp.web.getList(_spPageContextInfo.webServerRelativeUrl + '/Pages').items.get().then(function(item) { console.log(item); });

or by querying the real folder objects with `GetFolderByServerRelativeUrl` method like:


.getFolderByServerRelativeUrl(_spPageContextInfo.webServerRelativeUrl + '/Pages') // Here comes a folder/subfolder path .files .expand('Files/ListItemAllFields') // For Metadata extraction .select('Title,Name') // Fields to retrieve .get().then(function(item) { console.log(item); });



@Andrew Koltyakov, thanks for the reply.


After some investigation I figured out that 'Pages' was a list and not a folder.


In our "Enterprise Wiki" we have used folders to create a hierarchy. Your last code snippet worked great for getting a list of files, but did not return folders. I modified it slightly (replaced .files with .folders) and was able to get folder information. So it now looks like this:



var files;
   .getFolderByServerRelativeUrl(_spPageContextInfo.webServerRelativeUrl + '/Pages') // Here comes a folder/subfolder path
   .expand('Files/ListItemAllFields') // For Metadata extraction
   .select('Title,Name')              // Fields to retrieve
.then(function(item) { files = item; }); var folders; $pnp.sp.web .getFolderByServerRelativeUrl(_spPageContextInfo.webServerRelativeUrl + '/Pages') // Here comes a folder/subfolder path .files .expand('Folders/ListItemAllFields') // For Metadata extraction .select('Title,Name') // Fields to retrieve .get()
.then(function(item) { folders = item; });

Is this OK or is there a better way?




Hi @Alan Trafford,


There could be at least 2 strategies with your case:


  1. When a number of articles (with folders) is relatively small (less than 5000) - it's possible to use one single query for getting all the structure you have in a document library recursively then with the use of FileDirRef build your custom navigation UI;
  2. When a number of the wiki pages is unpredictably large, then an on-demand query per folder's files and folders during a category (folder) drill down UI interaction.

In case of the first scenario, I would recommend using `$pnp.sp.web.getList(_spPageContextInfo.webServerRelativeUrl + '/Pages').items` ... with the conditions and so on.


With the second one, imo, it's better to deal with `$pnp.sp.web.getFolderByServerRelativeUrl('[...path to folder...]').files` and `$pnp.sp.web.getFolderByServerRelativeUrl('[...path to folder...]').folders` in a batch request. Or using plain REST call `/_api/Web/GetFolderByServerRelativeUrl(@FolderServerRelativeUrl)?$expand=Folders,Files,Folders/ListItemAllFields,Files/ListItemAllFields$select=...`.


Using search API also can be a good idea. A lot depends on usage scenarios and data amount.

For instance, I would decide to show only categories structure in the wiki menu. In the case of folders, it can be easily one single cached request to a list's folders. In some more advanced cases you would need to apply multiple categories to the wiki article, then managed metadata is better (with MMD you can even use OOTB tree MMD navigation).

@Andrew Koltyakov, thanks for your help, it's much appreciated.


Looks like I've some learning to do!


I'm visiting the PnP JS Core API pages regularly, but they lack examples. I'm sure this will make more sense in a few months.


Can you recommend any resources (articles, examples, references) for learning about searching, even if it's just terms I should search for?





@Alan Trafford,


PnP JS Core is mostly the wrapper around SharePoint REST APIs with syntax sugar and helpers it doesn't cover all the API.

I would recommend learning SharePoint REST API reference and PnP JS Core simultaneously. PnP JS Core has nice chaining logic and based on promises. During chaining helpers methods it constructs REST endpoint URL and builds requests data parameters (in POST calls), then initiates a promise.


I found myself learning such open source libraries which evolve faster than the documentation with the use of "debug-first learning" by logging in the console intermediate objects and results and checking the available options, like this:



var requestObject = $pnp.sp.web.getFolderByServerRelativeUrl(_spPageContextInfo.webServerRelativeUrl + '/Pages')

console.log('Valuable methods and props', requestObject);
console.log('Url endpoint', requestObject.toUrl());

var promise = requestObject.get();

promise.then(function(data) {


and diving in the sources and issues history.


It's not so scary like it seems. E.g., in the API reference documentation you might have found something like `GetFolderByServerRelativeUrl` method, it probably can be already implemented in the library (we know it is), the easiest way to check it is to search on GitHub repo. In most cases it's rather straightforward to figure out that: 1) implemented or not, 2) how to use a specific option. Also, issues area is opened for issues and questions if the previously described learning pattern can't help.


Hi @Andrew Koltyakov


Thanks for your help and suggestions.