# Change dataset field Status from Published to Draft

**URL:** <https://forum.wixstudio.com/t/change-dataset-field-status-from-published-to-draft/79712>\
**Category:** Ask the community\
**Tags:** wix-data, cms, code\
**Created:** [September 11, 2026, 9:07pm UTC](https://forum.wixstudio.com/t/change-dataset-field-status-from-published-to-draft/79712 "2026-09-11T21:07:55Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![John-Dunham](https://sea1.discourse-cdn.com/wix/user_avatar/forum.wixstudio.com/john-dunham/32/122072_2.png) [@John-Dunham](https://forum.wixstudio.com/u/John-Dunham)\
**Post date:** [September 11, 2026, 9:07pm UTC](https://forum.wixstudio.com/t/change-dataset-field-status-from-published-to-draft/79712/1 "2026-09-11T21:07:55Z")

</div>

**I’m having trouble with**  
Code to change the “Status” field in my CMS dataset from Published to Draft.

**Working in**  
Dev mode

**Site link**  
See screenshot below.

**What I’m trying to do**  
Set the Status record flag from Published to Draft 14 days after the Created Date and the Perpetual value is false. I’m trying to unpublished old records in the dataset as a way to retain the data but not have them appear on my site. Some of the records stay published by excluding them with the Perpetual boolean field.

This code is currently connected to a button but I will move it to an automations schedule or the “back end” once I figure out how to accomplish that.

**What I’ve tried so far**

This code was generated with velo AI and is crashes saying the classifieds collection does not exist.

````javascript
import wixData from 'wix-data';

const COLLECTION_NAME = 'Classifieds';
const PAGE_SIZE = 1000;
const AGE_IN_DAYS = 14;

$w.onReady(async function () {
  try {
    const updatedCount = await updateExpiredClassifieds();
    console.log(`Updated ${updatedCount} classified record(s) to draft.`);
  } catch (error) {
    console.error('Failed to update expired classifieds:', error);
  }
});

async function updateExpiredClassifieds() {
  const cutoffDate = new Date();
  cutoffDate.setDate(cutoffDate.getDate() - AGE_IN_DAYS);

  let queryResult = await wixData.query(COLLECTION_NAME)
    .lt('_createdDate', cutoffDate)
    .eq('perpetual', false)
    .limit(PAGE_SIZE)
    .find();

  let updatedCount = 0;

  while (queryResult.items.length > 0) {
    for (const item of queryResult.items) {
      if (item.status !== 'draft') {
        await wixData.update(COLLECTION_NAME, {
          ...item,
          status: 'draft'
        });
        updatedCount += 1;
      }
    }

    if (!queryResult.hasNext()) {
      break;
    }

    queryResult = await queryResult.next();
  }

  return updatedCount;
}```

**Extra context**
Anything else that might help - edge cases, screenshots, etc.

````

Screenshot of the CMS dataset named Classifieds showing the Status system field and the Perpetual boolean field.

 ![Screenshot 2026-09-11 at 2.55.39 PM](https://us1.discourse-cdn.com/wix/original/3X/2/9/290b7ea86cfe157a639be61d9f1a5fa6302e1bc2.png)

---

<div class="post-metadata">

**Author:** ![Webhil](https://sea1.discourse-cdn.com/wix/user_avatar/forum.wixstudio.com/webhil/32/122559_2.png) [@Webhil](https://forum.wixstudio.com/u/Webhil)\
**Post date:** [September 15, 2026, 4:44am UTC](https://forum.wixstudio.com/t/change-dataset-field-status-from-published-to-draft/79712/2 "2026-09-15T04:44:08Z")

</div>

That error is WDE0025, and it means what it says — there’s no collection with that ID on the site.

Collections are referenced by collection ID, not display name. “Classifieds” in your CMS list is the label. The ID may be lowercase, or carry a prefix. Open CMS → your collection → the settings panel and copy the ID exactly. It’s case-sensitive.

Same trap on the fields. “Status” and “Perpetual” are labels; the IDs are likely status and perpetual. Check those in the collection’s field settings before assuming.

Once the IDs are right, this is a backend job with suppressAuth — collection permissions will block the write otherwise:

import wixData from ‘wix-data’;

export async function unpublishOld() {  
const cutoff = new Date();  
cutoff.setDate(cutoff.getDate() - 14);

const results = await wixData.query(‘YOUR\_COLLECTION\_ID’)  
.lt(‘\_createdDate’, cutoff)  
.eq(‘perpetual’, false)  
.eq(‘status’, ‘published’)  
.find({ suppressAuth: true });

if (results.items.length) {  
const updated = results.items.map(i =\> ({ …i, status: ‘draft’ }));  
await wixData.bulkUpdate(‘YOUR\_COLLECTION\_ID’, updated, { suppressAuth: true });  
}  
return results.items.length;  
}

Swap the collection ID and confirm the field IDs against your own collection — I can’t see them.

To run it on a schedule, call it from a scheduled job. Note the floor: most plans allow a minimum one-hour interval, and job times are UTC. For a 14-day rule that’s irrelevant, but worth knowing before you write the cron.

---

<div class="post-metadata">

**Author:** ![John-Dunham](https://sea1.discourse-cdn.com/wix/user_avatar/forum.wixstudio.com/john-dunham/32/122072_2.png) [@John-Dunham](https://forum.wixstudio.com/u/John-Dunham)\
**Post date:** [September 15, 2026, 4:26pm UTC](https://forum.wixstudio.com/t/change-dataset-field-status-from-published-to-draft/79712/3 "2026-09-15T16:26:36Z")

</div>

It is all looking good I mis-spelled the “Classifieds” collection, so I renamed the label after the fact. However I’am still not achieving the change in the system Status field. The code runs but changes nothing. Any ideas?

 ![Screenshot 2026-09-15 at 9.59.01 AM](https://us1.discourse-cdn.com/wix/original/3X/b/d/bd3d78536f73aec7759a9d1fbb29602f80eacc17.png)

 ![Screenshot 2026-09-15 at 9.59.29 AM](https://us1.discourse-cdn.com/wix/original/3X/c/4/c4140a87709e453d6a4a82d06023094fd88d318c.png)

 ![Screenshot 2026-09-15 at 9.59.53 AM](https://us1.discourse-cdn.com/wix/original/3X/f/3/f356b3b0f9fddcb624e9e4cee54b1246c1e57a39.png)

 ![Screenshot 2026-09-15 at 10.22.59 AM](https://us1.discourse-cdn.com/wix/original/3X/7/e/7e00b042a5601db7606717ceb96c727077489c5a.png)

```javascript
import wixData from 'wix-data';

const COLLECTION_ID = 'Classifides'

export async function unpublishOld() {
const cutoff = new Date();
cutoff.setDate(cutoff.getDate() - 14);

const results = await wixData.query('COLLECTION_ID')
.lt("_createdDate", cutoff)
.eq("perpetual", false)
.eq("status", "published")
.find({ suppressAuth: true });

if (results.items.length) {
const updated = results.items.map(i => ({ …i, status: `draft` }));
await wixData.bulkUpdate(COLLECTION_ID, updated, { suppressAuth: true });
}
return results.items.length;
}

```

---

<div class="post-metadata">

**Author:** ![Webhil](https://sea1.discourse-cdn.com/wix/user_avatar/forum.wixstudio.com/webhil/32/122559_2.png) [@Webhil](https://forum.wixstudio.com/u/Webhil)\
**Post date:** [September 15, 2026, 4:47pm UTC](https://forum.wixstudio.com/t/change-dataset-field-status-from-published-to-draft/79712/4 "2026-09-15T16:47:49Z")

</div>

Status isn’t a field, so bulkUpdate can’t write it. When drafts are enabled the  
published and draft copies live in two separate collections — your published  
collection, and a shadow collection called Classifides\_\_drafts. Moving an item  
between them is a lifecycle operation, not a field update, so there is nothing  
bulkUpdate can do here. That’s why it runs clean and changes nothing.

There are two separate reasons you’re seeing zero effect:

.eq(“status”, “published”) filters on a field that doesn’t exist in the data,  
so your query almost certainly returns 0 items and the loop never runs. Drop  
that line entirely — the published collection only ever contains published  
items, so the filter is redundant as well as wrong.

.eq(“perpetual”, false) only matches items where the boolean is explicitly  
false. Any row where you never touched the toggle is null, not false, and gets  
skipped. Use .ne(“perpetual”, true) so unset rows are included.

The method you actually want is unpublishDataItem from @wix/data. Pass the  
PUBLISHED collection ID; it removes the live copy and creates a draft seeded  
with the old data. There is no bulk version, so loop.

import { items } from ‘@wix/data’;  
import { auth } from ‘@wix/essentials’;

const COLLECTION\_ID = ‘Classifides’;

export async function unpublishOld() {  
const cutoff = new Date();  
cutoff.setDate(cutoff.getDate() - 14);

const results = await items  
.query(COLLECTION\_ID)  
.lt(‘\_createdDate’, cutoff)  
.ne(‘perpetual’, true)  
.find();

console.log(‘matched’, results.items.length);

const elevatedUnpublish = auth.elevate(items.unpublishDataItem);

let count = 0;  
for (const item of results.items) {  
await elevatedUnpublish(COLLECTION\_ID, item.\_id);  
count++;  
}  
return count;  
}

Log the match count before the loop. That tells you in one run whether you have  
a query problem or a write problem, instead of guessing.

Three things that will bite you next:

The SDK has no suppressAuth. It’s elevate() from @wix/essentials instead, and  
only the unpublish needs it — your permissions already let the query read.

find() returns one page. For a retention job that will eventually matter, so  
set .limit() high enough or page through the results, or you’ll quietly retire  
only the first batch each run.

After unpublishing, the item is in Classifides\_\_drafts, not gone. That’s where  
you edit or republish it from — publishDataItemDraft puts it back live.

Your collection ID is fine, by the way. Renaming the label to “Classifieds”  
left the ID as “Classifides”, and your code uses the ID, which is correct.  
Just make sure the query and the update both use COLLECTION\_ID and not the  
display name.

---

<div class="post-metadata">

**Author:** ![John-Dunham](https://sea1.discourse-cdn.com/wix/user_avatar/forum.wixstudio.com/john-dunham/32/122072_2.png) [@John-Dunham](https://forum.wixstudio.com/u/John-Dunham)\
**Post date:** [September 15, 2026, 7:39pm UTC](https://forum.wixstudio.com/t/change-dataset-field-status-from-published-to-draft/79712/6 "2026-09-15T19:39:00Z")

</div>

Okay. Looks like I’ll have to rethink this. Maybe have another field in the dataset that distinguishes if it is expired. Then add a filter to the repeater to not display the expired records. Your thoughts?

---

<div class="post-metadata">

**Author:** ![Webhil](https://sea1.discourse-cdn.com/wix/user_avatar/forum.wixstudio.com/webhil/32/122559_2.png) [@Webhil](https://forum.wixstudio.com/u/Webhil)\
**Post date:** [September 16, 2026, 3:42am UTC](https://forum.wixstudio.com/t/change-dataset-field-status-from-published-to-draft/79712/7 "2026-09-16T03:42:24Z")

</div>

That’s the right call, and it’s a better design than what you started with —  
not a retreat.

Publish state is an editorial lifecycle. It’s built for “this article isn’t  
finished yet.” Expiry is a fact about the listing. Trying to store one in the  
other is why the first approach fought you at every step.

One change to your plan though: make it a date, not a boolean.

A boolean needs something to flip it, and that something is a scheduled job.  
Most plans cap jobs at hourly, so there’s always a window where an expired  
listing is still live. Worse, if the job fails you don’t find out — the site  
just quietly keeps showing stale ads. You’ve added a moving part that can  
break silently.

A date has nothing to flip. The listing expires because time passed. Nothing  
runs, nothing fails.

Add a Date and Time field, expiresOn, and set it when the listing is created:  
created date plus 14 days. Then filter at read time:

import wixData from ‘wix-data’;

$w.onReady(() =\> {  
$w(‘#classifiedsDataset’).setFilter(  
wixData.filter()  
.eq(‘perpetual’, true)  
.or(wixData.filter().gt(‘expiresOn’, new Date()))  
);  
});

Perpetual listings always show. Everything else shows while expiresOn is still  
in the future. No job anywhere.

Do this in code rather than the dataset’s filter panel — the panel wants a  
fixed value, and “later than right now” isn’t a fixed value.

The trap to avoid: if you add expiresOn now, every existing row has it empty,  
and gt() won’t match an empty field. Your whole catalogue disappears the moment  
you publish the filter. Backfill first — one pass setting expiresOn to each  
item’s \_createdDate plus 14 days — then add the filter.

Two things you get for free that the boolean wouldn’t have given you: you can  
show a seller “expires in 3 days”, and renewing a listing is just pushing the  
date out. With a flag you’d need a job to un-flip it and no way to know how  
long is left.
