diff --git a/scribus/pageitem.cpp b/scribus/pageitem.cpp
index 8ecb6661d..2367d3e19 100644
--- a/scribus/pageitem.cpp
+++ b/scribus/pageitem.cpp
@@ -72,6 +72,7 @@ for which a new license (GPL+exception) is in place.
 #include "scribusdoc.h"
 #include "scribusview.h"
 #include "scribuswin.h"
+#include "scribusXml.h"
 #include "sctextstream.h"
 #include "selection.h"
 #include "text/storytext.h"
@@ -8749,6 +8750,56 @@ void PageItem::getOldBoundingRect(double *x1, double *y1, double *x2, double *y2
 	}
 }
 
+PageItem* PageItem::duplicate()
+{
+	// DoDrawing = false;
+	// view()->updatesOn(false);
+
+	UndoTransaction activeTransaction;
+	if (UndoManager::undoEnabled())
+		activeTransaction = undoManager->beginTransaction(getUName(), getUPixmap(), Um::MultipleDuplicate, "", Um::IMultipleDuplicate);
+
+	Selection selection(this, false);
+	selection.addItem(this);
+
+	ScriXmlDoc ss;
+	QString BufferS = ss.writeElem(doc(), &selection);
+
+	auto nItems = doc()->Items->count();
+
+	ss.readElem(BufferS, doc(), doc()->currentPage()->xOffset(), doc()->currentPage()->yOffset(), false, true);
+
+	// TODO: what todo if there is no one more item?
+	auto newItem = doc()->Items->at(nItems);
+
+	if (activeTransaction)
+		activeTransaction.commit("", nullptr, "", tr("%1 duplicated").arg(getUName()), nullptr);
+
+	// DoDrawing = true;
+	// view()->updatesOn(true);
+	// m_View->deselectItems(true);
+	// view()->DrawNew();
+	changed();
+	return newItem;
+}
+
 void PageItem::getVisualBoundingRect(double * x1, double * y1, double * x2, double * y2) const
 {
 	double minx =  std::numeric_limits<double>::max();
diff --git a/scribus/pageitem.h b/scribus/pageitem.h
index 4e7dc56ab..5f68e1eb3 100644
--- a/scribus/pageitem.h
+++ b/scribus/pageitem.h
@@ -500,6 +500,8 @@ public: // Start public functions
 
 	//<< ********* Attributes of the item *********
 	//Position
+	PageItem* duplicate();
 	double xPos() const { return m_xPos; }
 	double yPos() const { return m_yPos; }
 	virtual double visualXPos() const;
diff --git a/scribus/plugins/scriptplugin/cmdobj.cpp b/scribus/plugins/scriptplugin/cmdobj.cpp
index fc76020ee..712d4f79c 100644
--- a/scribus/plugins/scriptplugin/cmdobj.cpp
+++ b/scribus/plugins/scriptplugin/cmdobj.cpp
@@ -825,27 +825,20 @@ PyObject *scribus_setcharstyle(PyObject* /* self */, PyObject* args)
 
 PyObject *scribus_duplicateobject(PyObject * /* self */, PyObject *args)
 {
-	char* name = const_cast<char*>("");
-	if (!PyArg_ParseTuple(args, "|es", "utf-8", &name))
-		return nullptr;
 	if (!checkHaveDocument())
 		return nullptr;
 
-	// Is there a special name given? Yes -> add this to selection
-	ScribusMainWindow* currentWin = ScCore->primaryMainWindow();
-	ScribusDoc* currentDoc = currentWin->doc;
+	char* name = const_cast<char*>("");
+	if (!PyArg_ParseTuple(args, "|es", "utf-8", &name))
+		return nullptr;
 
-	PageItem *i = GetUniqueItem(QString::fromUtf8(name));
-	if (i == nullptr)
+	PageItem *pageItem = GetSingleItem(name);
+	if (pageItem == nullptr)
 		return nullptr;
-	currentDoc->m_Selection->clear();
-	currentDoc->m_Selection->addItem(i);
 
-	// do the duplicate
-	currentWin->slotEditCopy();
-	currentWin->slotEditPaste();
+	auto newItem = pageItem->duplicate();
 
-	return PyUnicode_FromString(currentDoc->m_Selection->itemAt(0)->itemName().toUtf8());
+	return PyUnicode_FromString(newItem->itemName().toUtf8());
 }
 
 PyObject *scribus_duplicateobjects(PyObject * /* self */, PyObject *args)
@@ -1071,6 +1064,29 @@ PyObject *scribus_pasteobjects(PyObject * /* self */, PyObject * /*args*/)
 	return pyList;
 }
 
 /*! HACK: this removes "warning: 'blah' defined but not used" compiler warnings
 with header files structure untouched (docstrings are kept near declarations)
 PV */
@@ -1096,6 +1112,7 @@ void cmdobjdocwarnings()
 	  << scribus_getparagraphstyle__doc__
 	  << scribus_getstyle__doc__
 	  << scribus_gettextflowmode__doc__
 	  << scribus_objectexists__doc__
 	  << scribus_pasteobject__doc__
 	  << scribus_pasteobjects__doc__
